From 8db09a42ff4670fdb600d503c687d0ea488b03b1 Mon Sep 17 00:00:00 2001 From: Martin Aeschlimann Date: Fri, 13 Sep 2019 12:15:50 +0200 Subject: [PATCH 001/352] introducing tokenScopes --- .../browser/standaloneThemeServiceImpl.ts | 6 + .../test/browser/standaloneLanguages.test.ts | 5 +- src/vs/platform/theme/common/themeService.ts | 3 + .../theme/common/tokenStyleRegistry.ts | 268 ++++++++++++++++++ .../theme/test/common/testThemeService.ts | 5 + .../terminalColorRegistry.test.ts | 6 +- .../services/themes/common/colorThemeData.ts | 153 +++++++++- .../themes/common/textMateScopeMatcher.ts | 111 ++++++++ .../tokenStyleResolving.test.ts | 89 ++++++ 9 files changed, 640 insertions(+), 6 deletions(-) create mode 100644 src/vs/platform/theme/common/tokenStyleRegistry.ts create mode 100644 src/vs/workbench/services/themes/common/textMateScopeMatcher.ts create mode 100644 src/vs/workbench/services/themes/test/electron-browser/tokenStyleResolving.test.ts diff --git a/src/vs/editor/standalone/browser/standaloneThemeServiceImpl.ts b/src/vs/editor/standalone/browser/standaloneThemeServiceImpl.ts index 613ec87b2deb8..b26e44bf76c95 100644 --- a/src/vs/editor/standalone/browser/standaloneThemeServiceImpl.ts +++ b/src/vs/editor/standalone/browser/standaloneThemeServiceImpl.ts @@ -14,6 +14,7 @@ import { IEnvironmentService } from 'vs/platform/environment/common/environment' import { Registry } from 'vs/platform/registry/common/platform'; import { ColorIdentifier, Extensions, IColorRegistry } from 'vs/platform/theme/common/colorRegistry'; import { Extensions as ThemingExtensions, ICssStyleCollector, IIconTheme, IThemingRegistry } from 'vs/platform/theme/common/themeService'; +import { TokenStyle, TokenStyleIdentifier } from 'vs/platform/theme/common/tokenStyleRegistry'; const VS_THEME_NAME = 'vs'; const VS_DARK_THEME_NAME = 'vs-dark'; @@ -23,6 +24,7 @@ const colorRegistry = Registry.as(Extensions.ColorContribution); const themingRegistry = Registry.as(ThemingExtensions.ThemingContribution); class StandaloneTheme implements IStandaloneTheme { + public readonly id: string; public readonly themeName: string; @@ -128,6 +130,10 @@ class StandaloneTheme implements IStandaloneTheme { } return this._tokenTheme; } + + getTokenStyle(tokenStyle: TokenStyleIdentifier, useDefault?: boolean | undefined): TokenStyle | undefined { + return undefined; + } } function isBuiltinTheme(themeName: string): themeName is BuiltinTheme { diff --git a/src/vs/editor/standalone/test/browser/standaloneLanguages.test.ts b/src/vs/editor/standalone/test/browser/standaloneLanguages.test.ts index b35c23cc03aca..5dfa7d92149a3 100644 --- a/src/vs/editor/standalone/test/browser/standaloneLanguages.test.ts +++ b/src/vs/editor/standalone/test/browser/standaloneLanguages.test.ts @@ -13,6 +13,7 @@ import { ILineTokens, IToken, TokenizationSupport2Adapter, TokensProvider } from import { IStandaloneTheme, IStandaloneThemeData, IStandaloneThemeService } from 'vs/editor/standalone/common/standaloneThemeService'; import { ColorIdentifier } from 'vs/platform/theme/common/colorRegistry'; import { IIconTheme, ITheme, LIGHT } from 'vs/platform/theme/common/themeService'; +import { TokenStyleIdentifier } from 'vs/platform/theme/common/tokenStyleRegistry'; suite('TokenizationSupport2Adapter', () => { @@ -54,7 +55,9 @@ suite('TokenizationSupport2Adapter', () => { defines: (color: ColorIdentifier): boolean => { throw new Error('Not implemented'); - } + }, + + getTokenStyle: (tokenStyleId: TokenStyleIdentifier) => undefined }; } public getIconTheme(): IIconTheme { diff --git a/src/vs/platform/theme/common/themeService.ts b/src/vs/platform/theme/common/themeService.ts index 42e93300a8501..7ac9788d1a736 100644 --- a/src/vs/platform/theme/common/themeService.ts +++ b/src/vs/platform/theme/common/themeService.ts @@ -10,6 +10,7 @@ import * as platform from 'vs/platform/registry/common/platform'; import { ColorIdentifier } from 'vs/platform/theme/common/colorRegistry'; import { Event, Emitter } from 'vs/base/common/event'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; +import { TokenStyleIdentifier, TokenStyle } from 'vs/platform/theme/common/tokenStyleRegistry'; export const IThemeService = createDecorator('themeService'); @@ -59,6 +60,8 @@ export interface ITheme { * default color will be used. */ defines(color: ColorIdentifier): boolean; + + getTokenStyle(color: TokenStyleIdentifier, useDefault?: boolean): TokenStyle | undefined; } export interface IIconTheme { diff --git a/src/vs/platform/theme/common/tokenStyleRegistry.ts b/src/vs/platform/theme/common/tokenStyleRegistry.ts new file mode 100644 index 0000000000000..5f593d41370b2 --- /dev/null +++ b/src/vs/platform/theme/common/tokenStyleRegistry.ts @@ -0,0 +1,268 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as platform from 'vs/platform/registry/common/platform'; +import { IJSONSchema, IJSONSchemaMap } from 'vs/base/common/jsonSchema'; +import { Color } from 'vs/base/common/color'; +import { ITheme } from 'vs/platform/theme/common/themeService'; +import { Event, Emitter } from 'vs/base/common/event'; + +import { Extensions as JSONExtensions, IJSONContributionRegistry } from 'vs/platform/jsonschemas/common/jsonContributionRegistry'; +import { RunOnceScheduler } from 'vs/base/common/async'; + +// ------ API types + +export type TokenStyleIdentifier = string; + +export interface TokenStyleContribution { + readonly id: TokenStyleIdentifier; + readonly description: string; + readonly defaults: TokenStyleDefaults | null; + readonly deprecationMessage: string | undefined; +} + +export const enum TokenStyleBits { + BOLD = 0x01, + UNDERLINE = 0x02, + ITALIC = 0x04 +} + +export class TokenStyle { + constructor( + public readonly foreground?: Color, + public readonly background?: Color, + public readonly styles?: number + ) { + + } + + hasStyle(style: number): boolean { + return !!this.styles && ((this.styles & style) === style); + } +} + +export namespace TokenStyle { + export function fromString(s: string) { + const parts = s.split('-'); + let part = parts.shift(); + if (part) { + const foreground = Color.fromHex(part); + let background = undefined; + let style = undefined; + part = parts.shift(); + if (part && part[0] === '#') { + background = Color.fromHex(part); + part = parts.shift(); + } + if (part) { + try { + style = parseInt(part); + } catch (e) { + // ignore + } + } + return new TokenStyle(foreground, background, style); + } + return new TokenStyle(Color.red); + } +} + + + +export interface TokenStyleFunction { + (theme: ITheme): TokenStyle | undefined; +} + +export interface TokenStyleDefaults { + scopesToProbe?: string[]; + light: TokenStyle | null; + dark: TokenStyle | null; + hc: TokenStyle | null; +} + +/** + * A TokenStyle Value is either a tokestyle literal, a reference to other color or a derived color + */ +export type TokenStyleValue = TokenStyle | string | TokenStyleIdentifier | TokenStyleFunction; + +// TokenStyle registry +export const Extensions = { + TokenStyleContribution: 'base.contributions.tokenStyles' +}; + +export interface ITokenStyleRegistry { + + readonly onDidChangeSchema: Event; + + /** + * Register a TokenStyle to the registry. + * @param id The TokenStyle id as used in theme description files + * @param defaults The default values + * @description the description + */ + registerTokenStyle(id: string, defaults: TokenStyleDefaults, description: string): TokenStyleIdentifier; + + /** + * Register a TokenStyle to the registry. + */ + deregisterTokenStyle(id: string): void; + + /** + * Get all TokenStyle contributions + */ + getTokenStyles(): TokenStyleContribution[]; + + /** + * Gets the default TokenStyle of the given id + */ + resolveDefaultTokenStyle(id: TokenStyleIdentifier, theme: ITheme, findTokenStyleForScope: (scope: string) => TokenStyle | undefined): TokenStyle | undefined; + + /** + * JSON schema for an object to assign TokenStyle values to one of the TokenStyle contributions. + */ + getTokenStyleSchema(): IJSONSchema; + + /** + * JSON schema to for a reference to a TokenStyle contribution. + */ + getTokenStyleReferenceSchema(): IJSONSchema; + +} + + + +class TokenStyleRegistry implements ITokenStyleRegistry { + + private readonly _onDidChangeSchema = new Emitter(); + readonly onDidChangeSchema: Event = this._onDidChangeSchema.event; + + private tokenStyleById: { [key: string]: TokenStyleContribution }; + private tokenStyleSchema: IJSONSchema & { properties: IJSONSchemaMap } = { type: 'object', properties: {} }; + private tokenStyleReferenceSchema: IJSONSchema & { enum: string[], enumDescriptions: string[] } = { type: 'string', enum: [], enumDescriptions: [] }; + + constructor() { + this.tokenStyleById = {}; + } + + public registerTokenStyle(id: string, defaults: TokenStyleDefaults | null, description: string, deprecationMessage?: string): TokenStyleIdentifier { + let colorContribution: TokenStyleContribution = { id, description, defaults, deprecationMessage }; + this.tokenStyleById[id] = colorContribution; + let propertySchema: IJSONSchema = { type: 'string', description, format: 'color-hex', default: '#ff0000' }; + if (deprecationMessage) { + propertySchema.deprecationMessage = deprecationMessage; + } + this.tokenStyleSchema.properties[id] = propertySchema; + this.tokenStyleReferenceSchema.enum.push(id); + this.tokenStyleReferenceSchema.enumDescriptions.push(description); + + this._onDidChangeSchema.fire(); + return id; + } + + + public deregisterTokenStyle(id: string): void { + delete this.tokenStyleById[id]; + delete this.tokenStyleSchema.properties[id]; + const index = this.tokenStyleReferenceSchema.enum.indexOf(id); + if (index !== -1) { + this.tokenStyleReferenceSchema.enum.splice(index, 1); + this.tokenStyleReferenceSchema.enumDescriptions.splice(index, 1); + } + this._onDidChangeSchema.fire(); + } + + public getTokenStyles(): TokenStyleContribution[] { + return Object.keys(this.tokenStyleById).map(id => this.tokenStyleById[id]); + } + + public resolveDefaultTokenStyle(id: TokenStyleIdentifier, theme: ITheme, findTokenStyleForScope: (scope: string) => TokenStyle | undefined): TokenStyle | undefined { + const tokenStyleDesc = this.tokenStyleById[id]; + if (tokenStyleDesc && tokenStyleDesc.defaults) { + const scopesToProbe = tokenStyleDesc.defaults.scopesToProbe; + if (scopesToProbe) { + for (let scope of scopesToProbe) { + const style = findTokenStyleForScope(scope); + if (style) { + return style; + } + } + } + const tokenStyleValue = tokenStyleDesc.defaults[theme.type]; + return resolveTokenStyleValue(tokenStyleValue, theme); + } + return undefined; + } + + public getTokenStyleSchema(): IJSONSchema { + return this.tokenStyleSchema; + } + + public getTokenStyleReferenceSchema(): IJSONSchema { + return this.tokenStyleReferenceSchema; + } + + public toString() { + let sorter = (a: string, b: string) => { + let cat1 = a.indexOf('.') === -1 ? 0 : 1; + let cat2 = b.indexOf('.') === -1 ? 0 : 1; + if (cat1 !== cat2) { + return cat1 - cat2; + } + return a.localeCompare(b); + }; + + return Object.keys(this.tokenStyleById).sort(sorter).map(k => `- \`${k}\`: ${this.tokenStyleById[k].description}`).join('\n'); + } + +} + +const tokenStyleRegistry = new TokenStyleRegistry(); +platform.Registry.add(Extensions.TokenStyleContribution, tokenStyleRegistry); + +export function registerTokenStyle(id: string, defaults: TokenStyleDefaults | null, description: string, deprecationMessage?: string): TokenStyleIdentifier { + return tokenStyleRegistry.registerTokenStyle(id, defaults, description, deprecationMessage); +} + +export function getTokenStyleRegistry(): ITokenStyleRegistry { + return tokenStyleRegistry; +} + +// ----- implementation + +/** + * @param colorValue Resolve a color value in the context of a theme + */ +function resolveTokenStyleValue(tokenStyleValue: TokenStyleValue | null, theme: ITheme): TokenStyle | undefined { + if (tokenStyleValue === null) { + return undefined; + } else if (typeof tokenStyleValue === 'string') { + if (tokenStyleValue[0] === '#') { + return TokenStyle.fromString(tokenStyleValue); + } + return theme.getTokenStyle(tokenStyleValue); + } else if (typeof tokenStyleValue === 'object') { + return tokenStyleValue; + } else if (typeof tokenStyleValue === 'function') { + return tokenStyleValue(theme); + } + return undefined; +} + +export const tokenStyleColorsSchemaId = 'vscode://schemas/workbench-tokenstyles'; + +let schemaRegistry = platform.Registry.as(JSONExtensions.JSONContribution); +schemaRegistry.registerSchema(tokenStyleColorsSchemaId, tokenStyleRegistry.getTokenStyleSchema()); + +const delayer = new RunOnceScheduler(() => schemaRegistry.notifySchemaChanged(tokenStyleColorsSchemaId), 200); +tokenStyleRegistry.onDidChangeSchema(() => { + if (!delayer.isScheduled()) { + delayer.schedule(); + } +}); + +// setTimeout(_ => console.log(colorRegistry.toString()), 5000); + + + diff --git a/src/vs/platform/theme/test/common/testThemeService.ts b/src/vs/platform/theme/test/common/testThemeService.ts index fd49d393a348c..e384b45738966 100644 --- a/src/vs/platform/theme/test/common/testThemeService.ts +++ b/src/vs/platform/theme/test/common/testThemeService.ts @@ -6,6 +6,7 @@ import { Event, Emitter } from 'vs/base/common/event'; import { IThemeService, ITheme, DARK, IIconTheme } from 'vs/platform/theme/common/themeService'; import { Color } from 'vs/base/common/color'; +import { TokenStyle, TokenStyleIdentifier } from 'vs/platform/theme/common/tokenStyleRegistry'; export class TestTheme implements ITheme { @@ -23,6 +24,10 @@ export class TestTheme implements ITheme { defines(color: string): boolean { throw new Error('Method not implemented.'); } + + getTokenStyle(tokenStyleIdentifier: TokenStyleIdentifier, useDefault?: boolean | undefined): TokenStyle | undefined { + return undefined; + } } export class TestIconTheme implements IIconTheme { diff --git a/src/vs/workbench/contrib/terminal/test/electron-browser/terminalColorRegistry.test.ts b/src/vs/workbench/contrib/terminal/test/electron-browser/terminalColorRegistry.test.ts index bf413e442d4a8..d2d64fa1a2452 100644 --- a/src/vs/workbench/contrib/terminal/test/electron-browser/terminalColorRegistry.test.ts +++ b/src/vs/workbench/contrib/terminal/test/electron-browser/terminalColorRegistry.test.ts @@ -9,6 +9,7 @@ import { Registry } from 'vs/platform/registry/common/platform'; import { ansiColorIdentifiers, registerColors } from 'vs/workbench/contrib/terminal/common/terminalColorRegistry'; import { ITheme, ThemeType } from 'vs/platform/theme/common/themeService'; import { Color } from 'vs/base/common/color'; +import { TokenStyleIdentifier } from 'vs/platform/theme/common/tokenStyleRegistry'; registerColors(); @@ -19,7 +20,8 @@ function getMockTheme(type: ThemeType): ITheme { label: '', type: type, getColor: (colorId: ColorIdentifier): Color | undefined => themingRegistry.resolveDefaultColor(colorId, theme), - defines: () => true + defines: () => true, + getTokenStyle: (tokenStyleId: TokenStyleIdentifier) => undefined }; return theme; } @@ -99,4 +101,4 @@ suite('Workbench - TerminalColorRegistry', () => { '#e5e5e5' ], 'The dark terminal colors should be used when a dark theme is active'); }); -}); \ No newline at end of file +}); diff --git a/src/vs/workbench/services/themes/common/colorThemeData.ts b/src/vs/workbench/services/themes/common/colorThemeData.ts index 6d39ebd157edf..fcb5bd87bd5b3 100644 --- a/src/vs/workbench/services/themes/common/colorThemeData.ts +++ b/src/vs/workbench/services/themes/common/colorThemeData.ts @@ -12,7 +12,7 @@ import * as nls from 'vs/nls'; import * as types from 'vs/base/common/types'; import * as objects from 'vs/base/common/objects'; import * as resources from 'vs/base/common/resources'; -import { Extensions, IColorRegistry, ColorIdentifier, editorBackground, editorForeground } from 'vs/platform/theme/common/colorRegistry'; +import { Extensions as ColorRegistryExtensions, IColorRegistry, ColorIdentifier, editorBackground, editorForeground } from 'vs/platform/theme/common/colorRegistry'; import { ThemeType } from 'vs/platform/theme/common/themeService'; import { Registry } from 'vs/platform/registry/common/platform'; import { getParseErrorMessage } from 'vs/base/common/jsonErrorMessages'; @@ -20,8 +20,12 @@ import { URI } from 'vs/base/common/uri'; import { IFileService } from 'vs/platform/files/common/files'; import { parse as parsePList } from 'vs/workbench/services/themes/common/plistParser'; import { startsWith } from 'vs/base/common/strings'; +import { Extensions as TokenStyleRegistryExtensions, TokenStyle, TokenStyleIdentifier, ITokenStyleRegistry, TokenStyleBits } from 'vs/platform/theme/common/tokenStyleRegistry'; +import { MatcherWithPriority, Matcher, createMatchers } from 'vs/workbench/services/themes/common/textMateScopeMatcher'; -let colorRegistry = Registry.as(Extensions.ColorContribution); +let colorRegistry = Registry.as(ColorRegistryExtensions.ColorContribution); + +let tokenStyleRegistry = Registry.as(TokenStyleRegistryExtensions.TokenStyleContribution); const tokenGroupToScopesMap = { comments: ['comment'], @@ -33,6 +37,10 @@ const tokenGroupToScopesMap = { variables: ['variable', 'entity.name.variable'] }; +interface ITokenStyleMap { + [id: string]: TokenStyle; +} + export class ColorThemeData implements IColorTheme { id: string; @@ -49,6 +57,11 @@ export class ColorThemeData implements IColorTheme { private colorMap: IColorMap = {}; private customColorMap: IColorMap = {}; + private tokenStyleMap: ITokenStyleMap | undefined; + + private themeTokenScopeMatchers: Matcher[] | undefined; + private customTokenScopeMatchers: Matcher[] | undefined; + private constructor(id: string, label: string, settingsId: string) { this.id = id; this.label = label; @@ -103,10 +116,81 @@ export class ColorThemeData implements IColorTheme { return color; } + public getTokenStyle(tokenStyleId: TokenStyleIdentifier): TokenStyle | undefined { + if (!this.tokenStyleMap) { + this.tokenStyleMap = this.initTokenStyleMap(); + } + let style: TokenStyle | undefined = this.tokenStyleMap[tokenStyleId]; + if (style) { + return style; + } + if (types.isUndefined(style)) { + style = this.getDefaultTokenStyle(style); + } + return style; + } + + private initTokenStyleMap(): ITokenStyleMap { + return {}; + } + public getDefault(colorId: ColorIdentifier): Color | undefined { return colorRegistry.resolveDefaultColor(colorId, this); } + public getDefaultTokenStyle(tokenStyleId: TokenStyleIdentifier): TokenStyle | undefined { + return tokenStyleRegistry.resolveDefaultTokenStyle(tokenStyleId, this, this.findTokenStyleForScope.bind(this)); + } + + /** Public for testing reasons */ + public findTokenStyleForScope(scope: string): TokenStyle | undefined { + + function findTokenStyleForScopeInScopes(scopeMatchers: Matcher[], tokenColors: ITokenColorizationRule[]) { + for (let i = scopeMatchers.length - 1; i >= 0; i--) { + let matcher = scopeMatchers[i]; + if (!matcher) { + scopeMatchers[i] = matcher = getScopeMatcher(tokenColors[i]); + } + if (matcher(scope)) { + const settings = tokenColors[i].settings; + if (settings) { + if (foreground === null && settings.foreground) { + foreground = settings.foreground; + } + if (fontStyle === null && types.isString(settings.fontStyle)) { + fontStyle = settings.fontStyle; + } + if (foreground !== null && fontStyle !== null) { + break; + } + } + } + } + } + + let foreground: string | null = null; + let fontStyle: string | null = null; + + if (!this.customTokenScopeMatchers) { + this.customTokenScopeMatchers = new Array(this.customTokenColors.length); + } + findTokenStyleForScopeInScopes(this.customTokenScopeMatchers, this.customTokenColors); + + if (foreground === null || fontStyle === null) { + if (!this.themeTokenScopeMatchers) { + this.themeTokenScopeMatchers = new Array(this.themeTokenColors.length); + } + findTokenStyleForScopeInScopes(this.themeTokenScopeMatchers, this.themeTokenColors); + } + + if (foreground !== null || fontStyle !== null) { + return getTokenStyle(foreground, fontStyle); + } + return undefined; + } + + + public defines(colorId: ColorIdentifier): boolean { return this.customColorMap.hasOwnProperty(colorId) || this.colorMap.hasOwnProperty(colorId); } @@ -132,6 +216,7 @@ export class ColorThemeData implements IColorTheme { public setCustomTokenColors(customTokenColors: ITokenColorCustomizations) { this.customTokenColors = []; + this.customTokenScopeMatchers = undefined; // first add the non-theme specific settings this.addCustomTokenColors(customTokenColors); @@ -180,6 +265,7 @@ export class ColorThemeData implements IColorTheme { return Promise.resolve(undefined); } this.themeTokenColors = []; + this.themeTokenScopeMatchers = undefined; this.colorMap = {}; return _loadColorTheme(fileService, this.location, this.themeTokenColors, this.colorMap).then(_ => { this.isLoaded = true; @@ -381,4 +467,65 @@ let defaultThemeColors: { [baseTheme: string]: ITokenColorizationRule[] } = { { scope: 'token.error-token', settings: { foreground: '#FF0000' } }, { scope: 'token.debug-token', settings: { foreground: '#b267e6' } } ], -}; \ No newline at end of file +}; + +const noMatch = (_scope: string) => false; + +export function nameMatcher(identifers: string[], scope: string) { + for (const identifier of identifers) { + if (scopesAreMatching(scope, identifier)) { + return true; + } + } + return false; +} + +function scopesAreMatching(thisScopeName: string, scopeName: string): boolean { + if (!thisScopeName) { + return false; + } + if (thisScopeName === scopeName) { + return true; + } + const len = scopeName.length; + return thisScopeName.length > len && thisScopeName.substr(0, len) === scopeName && thisScopeName[len] === '.'; +} + +function getScopeMatcher(rule: ITokenColorizationRule): Matcher { + const scope = rule.scope; + if (!scope || !rule.settings) { + return noMatch; + } + const matchers: MatcherWithPriority[] = []; + if (Array.isArray(scope)) { + for (let s of scope) { + matchers.push(...createMatchers(s, nameMatcher)); + } + } else { + matchers.push(...createMatchers(scope, nameMatcher)); + } + return (scope: string) => matchers.some(m => m.matcher(scope)); +} + +function getTokenStyle(foreground: string | null, fontStyle: string | null): TokenStyle | undefined { + let styles: number | undefined; + let foregroundColor = undefined; + if (foreground !== null) { + foregroundColor = Color.fromHex(foreground); + } + + if (fontStyle !== null) { + styles = 0; + if (fontStyle.indexOf('underline') !== -1) { + styles |= TokenStyleBits.UNDERLINE; + } + if (fontStyle.indexOf('italic') !== -1) { + styles |= TokenStyleBits.ITALIC; + } + if (fontStyle.indexOf('bold') !== -1) { + styles |= TokenStyleBits.BOLD; + } + } + return new TokenStyle(foregroundColor, undefined, styles); + +} diff --git a/src/vs/workbench/services/themes/common/textMateScopeMatcher.ts b/src/vs/workbench/services/themes/common/textMateScopeMatcher.ts new file mode 100644 index 0000000000000..16263c9ac8938 --- /dev/null +++ b/src/vs/workbench/services/themes/common/textMateScopeMatcher.ts @@ -0,0 +1,111 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +'use strict'; + +export interface MatcherWithPriority { + matcher: Matcher; + priority: -1 | 0 | 1; +} + +export interface Matcher { + (matcherInput: T): boolean; +} + +export function createMatchers(selector: string, matchesName: (names: string[], matcherInput: T) => boolean): MatcherWithPriority[] { + const results = []>[]; + const tokenizer = newTokenizer(selector); + let token = tokenizer.next(); + while (token !== null) { + let priority: -1 | 0 | 1 = 0; + if (token.length === 2 && token.charAt(1) === ':') { + switch (token.charAt(0)) { + case 'R': priority = 1; break; + case 'L': priority = -1; break; + default: + console.log(`Unknown priority ${token} in scope selector`); + } + token = tokenizer.next(); + } + let matcher = parseConjunction(); + if (matcher) { + results.push({ matcher, priority }); + } + if (token !== ',') { + break; + } + token = tokenizer.next(); + } + return results; + + function parseOperand(): Matcher | null { + if (token === '-') { + token = tokenizer.next(); + const expressionToNegate = parseOperand(); + return matcherInput => !!expressionToNegate && !expressionToNegate(matcherInput); + } + if (token === '(') { + token = tokenizer.next(); + const expressionInParents = parseInnerExpression(); + if (token === ')') { + token = tokenizer.next(); + } + return expressionInParents; + } + if (isIdentifier(token)) { + const identifiers: string[] = []; + do { + identifiers.push(token); + token = tokenizer.next(); + } while (isIdentifier(token)); + return matcherInput => matchesName(identifiers, matcherInput); + } + return null; + } + function parseConjunction(): Matcher { + const matchers: Matcher[] = []; + let matcher = parseOperand(); + while (matcher) { + matchers.push(matcher); + matcher = parseOperand(); + } + return matcherInput => matchers.every(matcher => matcher(matcherInput)); // and + } + function parseInnerExpression(): Matcher { + const matchers: Matcher[] = []; + let matcher = parseConjunction(); + while (matcher) { + matchers.push(matcher); + if (token === '|' || token === ',') { + do { + token = tokenizer.next(); + } while (token === '|' || token === ','); // ignore subsequent commas + } else { + break; + } + matcher = parseConjunction(); + } + return matcherInput => matchers.some(matcher => matcher(matcherInput)); // or + } +} + +function isIdentifier(token: string | null): token is string { + return !!token && !!token.match(/[\w\.:]+/); +} + +function newTokenizer(input: string): { next: () => string | null } { + let regex = /([LR]:|[\w\.:][\w\.:\-]*|[\,\|\-\(\)])/g; + let match = regex.exec(input); + return { + next: () => { + if (!match) { + return null; + } + const res = match[0]; + match = regex.exec(input); + return res; + } + }; +} diff --git a/src/vs/workbench/services/themes/test/electron-browser/tokenStyleResolving.test.ts b/src/vs/workbench/services/themes/test/electron-browser/tokenStyleResolving.test.ts new file mode 100644 index 0000000000000..27979e7eb9c66 --- /dev/null +++ b/src/vs/workbench/services/themes/test/electron-browser/tokenStyleResolving.test.ts @@ -0,0 +1,89 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { ColorThemeData } from 'vs/workbench/services/themes/common/colorThemeData'; +import * as assert from 'assert'; +import { ITokenColorCustomizations } from 'vs/workbench/services/themes/common/workbenchThemeService'; +import { TokenStyle, TokenStyleBits } from 'vs/platform/theme/common/tokenStyleRegistry'; +import { Color } from 'vs/base/common/color'; +import { isString } from 'vs/base/common/types'; + +function ts(foreground: string | undefined, styleFlags: number | undefined): TokenStyle { + const foregroundColor = isString(foreground) ? Color.fromHex(foreground) : undefined; + return new TokenStyle(foregroundColor, undefined, styleFlags); +} + +function tokenStyleAsString(ts: TokenStyle | undefined | null) { + return ts ? `${ts.foreground ? ts.foreground.toString() : 'no-foreground'}-${ts.styles ? ts.styles : 'no-styles'}` : 'tokenstyle-undefined'; +} + +function assertTokenStyle(expected: TokenStyle | undefined | null, actual: TokenStyle | undefined | null, message?: string) { + assert.equal(tokenStyleAsString(expected), tokenStyleAsString(actual), message); +} + + +suite('Themes - TokenStyleResolving', () => { + + // const fileService = new FileService(new NullLogService()); + // const diskFileSystemProvider = new DiskFileSystemProvider(new NullLogService()); + // fileService.registerProvider(Schemas.file, diskFileSystemProvider); + + + + + test('resolve resource', async () => { + const themeData = ColorThemeData.createLoadedEmptyTheme('test', 'test'); + + const customTokenColors: ITokenColorCustomizations = { + textMateRules: [ + { + scope: 'variable', + settings: { + fontStyle: '', + foreground: '#F8F8F2' + } + }, + { + scope: 'keyword', + settings: { + fontStyle: 'italic bold underline', + foreground: '#F92672' + } + }, + { + scope: 'storage', + settings: { + fontStyle: 'italic', + foreground: '#F92672' + } + }, + { + scope: 'storage.type', + settings: { + foreground: '#66D9EF' + } + } + ] + }; + + themeData.setCustomTokenColors(customTokenColors); + + let tokenStyle; + + tokenStyle = themeData.findTokenStyleForScope('variable'); + assertTokenStyle(tokenStyle, ts('#F8F8F2', 0), 'variable'); + + tokenStyle = themeData.findTokenStyleForScope('keyword'); + assertTokenStyle(tokenStyle, ts('#F92672', TokenStyleBits.ITALIC | TokenStyleBits.BOLD | TokenStyleBits.UNDERLINE), 'keyword'); + + tokenStyle = themeData.findTokenStyleForScope('storage'); + assertTokenStyle(tokenStyle, ts('#F92672', TokenStyleBits.ITALIC), 'storage'); + + tokenStyle = themeData.findTokenStyleForScope('storage.type'); + assertTokenStyle(tokenStyle, ts('#66D9EF', TokenStyleBits.ITALIC), 'storage.type'); + + + }); +}); From fb7cc04c0763af9daf042bc6d34ddb3790a45229 Mon Sep 17 00:00:00 2001 From: Martin Aeschlimann Date: Fri, 13 Sep 2019 17:17:25 +0200 Subject: [PATCH 002/352] more --- .../theme/common/tokenStyleRegistry.ts | 43 ++++++++++----- .../services/themes/common/colorThemeData.ts | 52 +++++++++++-------- .../tokenStyleResolving.test.ts | 24 ++++++--- 3 files changed, 80 insertions(+), 39 deletions(-) diff --git a/src/vs/platform/theme/common/tokenStyleRegistry.ts b/src/vs/platform/theme/common/tokenStyleRegistry.ts index 5f593d41370b2..5be9d6a650deb 100644 --- a/src/vs/platform/theme/common/tokenStyleRegistry.ts +++ b/src/vs/platform/theme/common/tokenStyleRegistry.ts @@ -8,6 +8,7 @@ import { IJSONSchema, IJSONSchemaMap } from 'vs/base/common/jsonSchema'; import { Color } from 'vs/base/common/color'; import { ITheme } from 'vs/platform/theme/common/themeService'; import { Event, Emitter } from 'vs/base/common/event'; +import * as nls from 'vs/nls'; import { Extensions as JSONExtensions, IJSONContributionRegistry } from 'vs/platform/jsonschemas/common/jsonContributionRegistry'; import { RunOnceScheduler } from 'vs/base/common/async'; @@ -69,21 +70,21 @@ export namespace TokenStyle { } } - +export type ProbeScope = string[] | string; export interface TokenStyleFunction { (theme: ITheme): TokenStyle | undefined; } export interface TokenStyleDefaults { - scopesToProbe?: string[]; - light: TokenStyle | null; - dark: TokenStyle | null; - hc: TokenStyle | null; + scopesToProbe?: ProbeScope[]; + light: TokenStyleValue | null; + dark: TokenStyleValue | null; + hc: TokenStyleValue | null; } /** - * A TokenStyle Value is either a tokestyle literal, a reference to other color or a derived color + * A TokenStyle Value is either a token style literal, a reference to other token style or a derived token style */ export type TokenStyleValue = TokenStyle | string | TokenStyleIdentifier | TokenStyleFunction; @@ -117,7 +118,7 @@ export interface ITokenStyleRegistry { /** * Gets the default TokenStyle of the given id */ - resolveDefaultTokenStyle(id: TokenStyleIdentifier, theme: ITheme, findTokenStyleForScope: (scope: string) => TokenStyle | undefined): TokenStyle | undefined; + resolveDefaultTokenStyle(id: TokenStyleIdentifier, theme: ITheme, findTokenStyleForScope: (scope: ProbeScope) => TokenStyle | undefined): TokenStyle | undefined; /** * JSON schema for an object to assign TokenStyle values to one of the TokenStyle contributions. @@ -147,9 +148,18 @@ class TokenStyleRegistry implements ITokenStyleRegistry { } public registerTokenStyle(id: string, defaults: TokenStyleDefaults | null, description: string, deprecationMessage?: string): TokenStyleIdentifier { - let colorContribution: TokenStyleContribution = { id, description, defaults, deprecationMessage }; - this.tokenStyleById[id] = colorContribution; - let propertySchema: IJSONSchema = { type: 'string', description, format: 'color-hex', default: '#ff0000' }; + let tokenStyleContribution: TokenStyleContribution = { id, description, defaults, deprecationMessage }; + this.tokenStyleById[id] = tokenStyleContribution; + let propertySchema: IJSONSchema = { + type: 'object', + description, + properties: { + 'foreground': { type: 'string', format: 'color-hex', default: '#ff0000' }, + 'italic': { type: 'boolean' }, + 'bold': { type: 'boolean' }, + 'underline': { type: 'boolean' } + } + }; if (deprecationMessage) { propertySchema.deprecationMessage = deprecationMessage; } @@ -177,7 +187,7 @@ class TokenStyleRegistry implements ITokenStyleRegistry { return Object.keys(this.tokenStyleById).map(id => this.tokenStyleById[id]); } - public resolveDefaultTokenStyle(id: TokenStyleIdentifier, theme: ITheme, findTokenStyleForScope: (scope: string) => TokenStyle | undefined): TokenStyle | undefined { + public resolveDefaultTokenStyle(id: TokenStyleIdentifier, theme: ITheme, findTokenStyleForScope: (scope: ProbeScope) => TokenStyle | undefined): TokenStyle | undefined { const tokenStyleDesc = this.tokenStyleById[id]; if (tokenStyleDesc && tokenStyleDesc.defaults) { const scopesToProbe = tokenStyleDesc.defaults.scopesToProbe; @@ -229,7 +239,16 @@ export function getTokenStyleRegistry(): ITokenStyleRegistry { return tokenStyleRegistry; } -// ----- implementation +// colors + + +export const comments = registerTokenStyle('comments', { scopesToProbe: ['comment'], dark: null, light: null, hc: null }, nls.localize('comments', "Token style for comments.")); +export const strings = registerTokenStyle('strings', { scopesToProbe: ['strings'], dark: null, light: null, hc: null }, nls.localize('strings', "Token style for strings.")); +export const keywords = registerTokenStyle('keywords', { scopesToProbe: ['keyword.control', 'storage', 'storage.type'], dark: null, light: null, hc: null }, nls.localize('keywords', "Token style for keywords.")); +export const numbers = registerTokenStyle('numbers', { scopesToProbe: ['constant.numeric'], dark: null, light: null, hc: null }, nls.localize('numbers', "Token style for numbers.")); +export const types = registerTokenStyle('types', { scopesToProbe: ['entity.name.type', 'entity.name.class', 'support.type', 'support.class'], dark: null, light: null, hc: null }, nls.localize('types', "Token style for types.")); +export const functions = registerTokenStyle('functions', { scopesToProbe: ['entity.name.function', 'support.function'], dark: null, light: null, hc: null }, nls.localize('functions', "Token style for functions.")); +export const variables = registerTokenStyle('variables', { scopesToProbe: ['variable', 'entity.name.variable'], dark: null, light: null, hc: null }, nls.localize('variables', "Token style for variables.")); /** * @param colorValue Resolve a color value in the context of a theme diff --git a/src/vs/workbench/services/themes/common/colorThemeData.ts b/src/vs/workbench/services/themes/common/colorThemeData.ts index fcb5bd87bd5b3..68281aaa572b8 100644 --- a/src/vs/workbench/services/themes/common/colorThemeData.ts +++ b/src/vs/workbench/services/themes/common/colorThemeData.ts @@ -20,7 +20,7 @@ import { URI } from 'vs/base/common/uri'; import { IFileService } from 'vs/platform/files/common/files'; import { parse as parsePList } from 'vs/workbench/services/themes/common/plistParser'; import { startsWith } from 'vs/base/common/strings'; -import { Extensions as TokenStyleRegistryExtensions, TokenStyle, TokenStyleIdentifier, ITokenStyleRegistry, TokenStyleBits } from 'vs/platform/theme/common/tokenStyleRegistry'; +import { Extensions as TokenStyleRegistryExtensions, TokenStyle, TokenStyleIdentifier, ITokenStyleRegistry, TokenStyleBits, ProbeScope } from 'vs/platform/theme/common/tokenStyleRegistry'; import { MatcherWithPriority, Matcher, createMatchers } from 'vs/workbench/services/themes/common/textMateScopeMatcher'; let colorRegistry = Registry.as(ColorRegistryExtensions.ColorContribution); @@ -59,8 +59,8 @@ export class ColorThemeData implements IColorTheme { private tokenStyleMap: ITokenStyleMap | undefined; - private themeTokenScopeMatchers: Matcher[] | undefined; - private customTokenScopeMatchers: Matcher[] | undefined; + private themeTokenScopeMatchers: Matcher[] | undefined; + private customTokenScopeMatchers: Matcher[] | undefined; private constructor(id: string, label: string, settingsId: string) { this.id = id; @@ -143,9 +143,9 @@ export class ColorThemeData implements IColorTheme { } /** Public for testing reasons */ - public findTokenStyleForScope(scope: string): TokenStyle | undefined { + public findTokenStyleForScope(scope: ProbeScope): TokenStyle | undefined { - function findTokenStyleForScopeInScopes(scopeMatchers: Matcher[], tokenColors: ITokenColorizationRule[]) { + function findTokenStyleForScopeInScopes(scopeMatchers: Matcher[], tokenColors: ITokenColorizationRule[]) { for (let i = scopeMatchers.length - 1; i >= 0; i--) { let matcher = scopeMatchers[i]; if (!matcher) { @@ -469,15 +469,25 @@ let defaultThemeColors: { [baseTheme: string]: ITokenColorizationRule[] } = { ], }; -const noMatch = (_scope: string) => false; +const noMatch = (_scope: ProbeScope) => false; -export function nameMatcher(identifers: string[], scope: string) { - for (const identifier of identifers) { - if (scopesAreMatching(scope, identifier)) { - return true; - } +function nameMatcher(identifers: string[], scope: ProbeScope) { + if (!Array.isArray(scope)) { + scope = [scope]; + } + if (scope.length < identifers.length) { + return false; } - return false; + let lastIndex = 0; + return identifers.every(identifier => { + for (let i = lastIndex; i < scope.length; i++) { + if (scopesAreMatching(scope[i], identifier)) { + lastIndex = i + 1; + return true; + } + } + return false; + }); } function scopesAreMatching(thisScopeName: string, scopeName: string): boolean { @@ -491,20 +501,20 @@ function scopesAreMatching(thisScopeName: string, scopeName: string): boolean { return thisScopeName.length > len && thisScopeName.substr(0, len) === scopeName && thisScopeName[len] === '.'; } -function getScopeMatcher(rule: ITokenColorizationRule): Matcher { - const scope = rule.scope; - if (!scope || !rule.settings) { +function getScopeMatcher(rule: ITokenColorizationRule): Matcher { + const ruleScope = rule.scope; + if (!ruleScope || !rule.settings) { return noMatch; } - const matchers: MatcherWithPriority[] = []; - if (Array.isArray(scope)) { - for (let s of scope) { - matchers.push(...createMatchers(s, nameMatcher)); + const matchers: MatcherWithPriority[] = []; + if (Array.isArray(ruleScope)) { + for (let rs of ruleScope) { + matchers.push(...createMatchers(rs, nameMatcher)); } } else { - matchers.push(...createMatchers(scope, nameMatcher)); + matchers.push(...createMatchers(ruleScope, nameMatcher)); } - return (scope: string) => matchers.some(m => m.matcher(scope)); + return (scope: ProbeScope) => matchers.some(m => m.matcher(scope)); } function getTokenStyle(foreground: string | null, fontStyle: string | null): TokenStyle | undefined { diff --git a/src/vs/workbench/services/themes/test/electron-browser/tokenStyleResolving.test.ts b/src/vs/workbench/services/themes/test/electron-browser/tokenStyleResolving.test.ts index 27979e7eb9c66..c8c3ef86ccf81 100644 --- a/src/vs/workbench/services/themes/test/electron-browser/tokenStyleResolving.test.ts +++ b/src/vs/workbench/services/themes/test/electron-browser/tokenStyleResolving.test.ts @@ -60,11 +60,18 @@ suite('Themes - TokenStyleResolving', () => { } }, { - scope: 'storage.type', + scope: ['storage.type', 'meta.structure.dictionary.json string.quoted.double.json'], settings: { foreground: '#66D9EF' } - } + }, + { + scope: 'entity.name.type, entity.name.class, entity.name.namespace, entity.name.scope-resolution', + settings: { + fontStyle: 'underline', + foreground: '#A6E22E' + } + }, ] }; @@ -72,18 +79,23 @@ suite('Themes - TokenStyleResolving', () => { let tokenStyle; - tokenStyle = themeData.findTokenStyleForScope('variable'); + tokenStyle = themeData.findTokenStyleForScope(['variable']); assertTokenStyle(tokenStyle, ts('#F8F8F2', 0), 'variable'); - tokenStyle = themeData.findTokenStyleForScope('keyword'); + tokenStyle = themeData.findTokenStyleForScope(['keyword']); assertTokenStyle(tokenStyle, ts('#F92672', TokenStyleBits.ITALIC | TokenStyleBits.BOLD | TokenStyleBits.UNDERLINE), 'keyword'); - tokenStyle = themeData.findTokenStyleForScope('storage'); + tokenStyle = themeData.findTokenStyleForScope(['storage']); assertTokenStyle(tokenStyle, ts('#F92672', TokenStyleBits.ITALIC), 'storage'); - tokenStyle = themeData.findTokenStyleForScope('storage.type'); + tokenStyle = themeData.findTokenStyleForScope(['storage.type']); assertTokenStyle(tokenStyle, ts('#66D9EF', TokenStyleBits.ITALIC), 'storage.type'); + tokenStyle = themeData.findTokenStyleForScope(['entity.name.class']); + assertTokenStyle(tokenStyle, ts('#A6E22E', TokenStyleBits.UNDERLINE), 'entity.name.class'); + + tokenStyle = themeData.findTokenStyleForScope(['meta.structure.dictionary.json', 'string.quoted.double.json']); + assertTokenStyle(tokenStyle, ts('#66D9EF', undefined), 'json property'); }); }); From f337499eb451e84d57a60a9ee9470c09e88d0f2d Mon Sep 17 00:00:00 2001 From: Martin Aeschlimann Date: Wed, 18 Sep 2019 13:46:56 +0200 Subject: [PATCH 003/352] monokai test --- .../theme/common/tokenStyleRegistry.ts | 2 +- .../services/themes/common/colorThemeData.ts | 15 ++----- .../tokenStyleResolving.test.ts | 45 +++++++++++++++++-- 3 files changed, 46 insertions(+), 16 deletions(-) diff --git a/src/vs/platform/theme/common/tokenStyleRegistry.ts b/src/vs/platform/theme/common/tokenStyleRegistry.ts index 5be9d6a650deb..1dbd13ff778f6 100644 --- a/src/vs/platform/theme/common/tokenStyleRegistry.ts +++ b/src/vs/platform/theme/common/tokenStyleRegistry.ts @@ -243,7 +243,7 @@ export function getTokenStyleRegistry(): ITokenStyleRegistry { export const comments = registerTokenStyle('comments', { scopesToProbe: ['comment'], dark: null, light: null, hc: null }, nls.localize('comments', "Token style for comments.")); -export const strings = registerTokenStyle('strings', { scopesToProbe: ['strings'], dark: null, light: null, hc: null }, nls.localize('strings', "Token style for strings.")); +export const strings = registerTokenStyle('strings', { scopesToProbe: ['string'], dark: null, light: null, hc: null }, nls.localize('strings', "Token style for strings.")); export const keywords = registerTokenStyle('keywords', { scopesToProbe: ['keyword.control', 'storage', 'storage.type'], dark: null, light: null, hc: null }, nls.localize('keywords', "Token style for keywords.")); export const numbers = registerTokenStyle('numbers', { scopesToProbe: ['constant.numeric'], dark: null, light: null, hc: null }, nls.localize('numbers', "Token style for numbers.")); export const types = registerTokenStyle('types', { scopesToProbe: ['entity.name.type', 'entity.name.class', 'support.type', 'support.class'], dark: null, light: null, hc: null }, nls.localize('types', "Token style for types.")); diff --git a/src/vs/workbench/services/themes/common/colorThemeData.ts b/src/vs/workbench/services/themes/common/colorThemeData.ts index 68281aaa572b8..9d2f319a34355 100644 --- a/src/vs/workbench/services/themes/common/colorThemeData.ts +++ b/src/vs/workbench/services/themes/common/colorThemeData.ts @@ -57,7 +57,7 @@ export class ColorThemeData implements IColorTheme { private colorMap: IColorMap = {}; private customColorMap: IColorMap = {}; - private tokenStyleMap: ITokenStyleMap | undefined; + private tokenStyleMap: ITokenStyleMap = {}; private themeTokenScopeMatchers: Matcher[] | undefined; private customTokenScopeMatchers: Matcher[] | undefined; @@ -116,24 +116,17 @@ export class ColorThemeData implements IColorTheme { return color; } - public getTokenStyle(tokenStyleId: TokenStyleIdentifier): TokenStyle | undefined { - if (!this.tokenStyleMap) { - this.tokenStyleMap = this.initTokenStyleMap(); - } + public getTokenStyle(tokenStyleId: TokenStyleIdentifier, useDefault?: boolean): TokenStyle | undefined { let style: TokenStyle | undefined = this.tokenStyleMap[tokenStyleId]; if (style) { return style; } - if (types.isUndefined(style)) { - style = this.getDefaultTokenStyle(style); + if (useDefault !== false && types.isUndefined(style)) { + style = this.getDefaultTokenStyle(tokenStyleId); } return style; } - private initTokenStyleMap(): ITokenStyleMap { - return {}; - } - public getDefault(colorId: ColorIdentifier): Color | undefined { return colorRegistry.resolveDefaultColor(colorId, this); } diff --git a/src/vs/workbench/services/themes/test/electron-browser/tokenStyleResolving.test.ts b/src/vs/workbench/services/themes/test/electron-browser/tokenStyleResolving.test.ts index c8c3ef86ccf81..adcb8dcd749f0 100644 --- a/src/vs/workbench/services/themes/test/electron-browser/tokenStyleResolving.test.ts +++ b/src/vs/workbench/services/themes/test/electron-browser/tokenStyleResolving.test.ts @@ -6,9 +6,15 @@ import { ColorThemeData } from 'vs/workbench/services/themes/common/colorThemeData'; import * as assert from 'assert'; import { ITokenColorCustomizations } from 'vs/workbench/services/themes/common/workbenchThemeService'; -import { TokenStyle, TokenStyleBits } from 'vs/platform/theme/common/tokenStyleRegistry'; +import { TokenStyle, TokenStyleBits, comments, variables, types, functions, keywords, numbers, strings } from 'vs/platform/theme/common/tokenStyleRegistry'; import { Color } from 'vs/base/common/color'; import { isString } from 'vs/base/common/types'; +import { FileService } from 'vs/platform/files/common/fileService'; +import { NullLogService } from 'vs/platform/log/common/log'; +import { DiskFileSystemProvider } from 'vs/platform/files/node/diskFileSystemProvider'; +import { Schemas } from 'vs/base/common/network'; +import { URI } from 'vs/base/common/uri'; +import { getPathFromAmdModule } from 'vs/base/common/amd'; function ts(foreground: string | undefined, styleFlags: number | undefined): TokenStyle { const foregroundColor = isString(foreground) ? Color.fromHex(foreground) : undefined; @@ -24,14 +30,45 @@ function assertTokenStyle(expected: TokenStyle | undefined | null, actual: Token } + suite('Themes - TokenStyleResolving', () => { + const fileService = new FileService(new NullLogService()); + const diskFileSystemProvider = new DiskFileSystemProvider(new NullLogService()); + fileService.registerProvider(Schemas.file, diskFileSystemProvider); + + + test('color defaults - monokai', async () => { + const themeData = ColorThemeData.createUnloadedTheme('foo'); + const themeLocation = getPathFromAmdModule(require, '../../../../../../../extensions/theme-monokai/themes/monokai-color-theme.json'); + themeData.location = URI.file(themeLocation); + await themeData.ensureLoaded(fileService); + + assert.equal(themeData.isLoaded, true); + + let tokenStyle; - // const fileService = new FileService(new NullLogService()); - // const diskFileSystemProvider = new DiskFileSystemProvider(new NullLogService()); - // fileService.registerProvider(Schemas.file, diskFileSystemProvider); + tokenStyle = themeData.getTokenStyle(comments); + assertTokenStyle(tokenStyle, ts('#75715E', 0)); + tokenStyle = themeData.getTokenStyle(variables); + assertTokenStyle(tokenStyle, ts('#F8F8F2', 0)); + tokenStyle = themeData.getTokenStyle(types); + assertTokenStyle(tokenStyle, ts('#A6E22E', TokenStyleBits.UNDERLINE)); + tokenStyle = themeData.getTokenStyle(functions); + assertTokenStyle(tokenStyle, ts('#A6E22E', 0)); + + tokenStyle = themeData.getTokenStyle(strings); + assertTokenStyle(tokenStyle, ts('#E6DB74', 0)); + + tokenStyle = themeData.getTokenStyle(numbers); + assertTokenStyle(tokenStyle, ts('#AE81FF', 0)); + + tokenStyle = themeData.getTokenStyle(keywords); + assertTokenStyle(tokenStyle, ts('#F92672', 0)); + + }); test('resolve resource', async () => { const themeData = ColorThemeData.createLoadedEmptyTheme('test', 'test'); From fa99aa5c34816ac20fa4c71652cf2b0fc477e99c Mon Sep 17 00:00:00 2001 From: Martin Aeschlimann Date: Wed, 18 Sep 2019 23:16:52 +0200 Subject: [PATCH 004/352] more tests --- .../theme/common/tokenStyleRegistry.ts | 4 + .../tokenStyleResolving.test.ts | 141 +++++++++++++++--- 2 files changed, 126 insertions(+), 19 deletions(-) diff --git a/src/vs/platform/theme/common/tokenStyleRegistry.ts b/src/vs/platform/theme/common/tokenStyleRegistry.ts index 1dbd13ff778f6..e212367d8730f 100644 --- a/src/vs/platform/theme/common/tokenStyleRegistry.ts +++ b/src/vs/platform/theme/common/tokenStyleRegistry.ts @@ -12,6 +12,7 @@ import * as nls from 'vs/nls'; import { Extensions as JSONExtensions, IJSONContributionRegistry } from 'vs/platform/jsonschemas/common/jsonContributionRegistry'; import { RunOnceScheduler } from 'vs/base/common/async'; +import { editorForeground } from 'vs/platform/theme/common/colorRegistry'; // ------ API types @@ -200,6 +201,9 @@ class TokenStyleRegistry implements ITokenStyleRegistry { } } const tokenStyleValue = tokenStyleDesc.defaults[theme.type]; + if (tokenStyleValue === null) { + return new TokenStyle(theme.getColor(editorForeground)); + } return resolveTokenStyleValue(tokenStyleValue, theme); } return undefined; diff --git a/src/vs/workbench/services/themes/test/electron-browser/tokenStyleResolving.test.ts b/src/vs/workbench/services/themes/test/electron-browser/tokenStyleResolving.test.ts index adcb8dcd749f0..ac70d63599980 100644 --- a/src/vs/workbench/services/themes/test/electron-browser/tokenStyleResolving.test.ts +++ b/src/vs/workbench/services/themes/test/electron-browser/tokenStyleResolving.test.ts @@ -25,8 +25,15 @@ function tokenStyleAsString(ts: TokenStyle | undefined | null) { return ts ? `${ts.foreground ? ts.foreground.toString() : 'no-foreground'}-${ts.styles ? ts.styles : 'no-styles'}` : 'tokenstyle-undefined'; } -function assertTokenStyle(expected: TokenStyle | undefined | null, actual: TokenStyle | undefined | null, message?: string) { - assert.equal(tokenStyleAsString(expected), tokenStyleAsString(actual), message); +function assertTokenStyle(actual: TokenStyle | undefined | null, expected: TokenStyle | undefined | null, message?: string) { + assert.equal(tokenStyleAsString(actual), tokenStyleAsString(expected), message); +} + +function assertTokenStyles(themeData: ColorThemeData, expected: { [tokenStyleId: string]: TokenStyle }) { + for (let tokenStyleId in expected) { + const tokenStyle = themeData.getTokenStyle(tokenStyleId); + assertTokenStyle(tokenStyle, expected[tokenStyleId], tokenStyleId); + } } @@ -45,28 +52,115 @@ suite('Themes - TokenStyleResolving', () => { assert.equal(themeData.isLoaded, true); - let tokenStyle; + assertTokenStyles(themeData, { + [comments]: ts('#75715E', 0), + [variables]: ts('#F8F8F2', 0), + [types]: ts('#A6E22E', TokenStyleBits.UNDERLINE), + [functions]: ts('#A6E22E', 0), + [strings]: ts('#E6DB74', 0), + [numbers]: ts('#AE81FF', 0), + [keywords]: ts('#F92672', 0) + }); + + }); + + test('color defaults - dark+', async () => { + const themeData = ColorThemeData.createUnloadedTheme('foo'); + const themeLocation = getPathFromAmdModule(require, '../../../../../../../extensions/theme-defaults/themes/dark_plus.json'); + themeData.location = URI.file(themeLocation); + await themeData.ensureLoaded(fileService); + + assert.equal(themeData.isLoaded, true); + + assertTokenStyles(themeData, { + [comments]: ts('#6A9955', 0), + [variables]: ts('#9CDCFE', 0), + [types]: ts('#4EC9B0', 0), + [functions]: ts('#DCDCAA', 0), + [strings]: ts('#CE9178', 0), + [numbers]: ts('#B5CEA8', 0), + [keywords]: ts('#C586C0', 0) + }); + + }); + + test('color defaults - light vs', async () => { + const themeData = ColorThemeData.createUnloadedTheme('foo'); + const themeLocation = getPathFromAmdModule(require, '../../../../../../../extensions/theme-defaults/themes/light_vs.json'); + themeData.location = URI.file(themeLocation); + await themeData.ensureLoaded(fileService); + + assert.equal(themeData.isLoaded, true); + + assertTokenStyles(themeData, { + [comments]: ts('#008000', 0), + [variables]: ts('#000000', 0), + [types]: ts('#000000', 0), + [functions]: ts('#000000', 0), + [strings]: ts('#a31515', 0), + [numbers]: ts('#09885a', 0), + [keywords]: ts('#0000ff', 0) + }); + + }); - tokenStyle = themeData.getTokenStyle(comments); - assertTokenStyle(tokenStyle, ts('#75715E', 0)); + test('color defaults - hc', async () => { + const themeData = ColorThemeData.createUnloadedTheme('foo'); + const themeLocation = getPathFromAmdModule(require, '../../../../../../../extensions/theme-defaults/themes/hc_black.json'); + themeData.location = URI.file(themeLocation); + await themeData.ensureLoaded(fileService); - tokenStyle = themeData.getTokenStyle(variables); - assertTokenStyle(tokenStyle, ts('#F8F8F2', 0)); + assert.equal(themeData.isLoaded, true); - tokenStyle = themeData.getTokenStyle(types); - assertTokenStyle(tokenStyle, ts('#A6E22E', TokenStyleBits.UNDERLINE)); + assertTokenStyles(themeData, { + [comments]: ts('#7ca668', 0), + [variables]: ts('#9CDCFE', 0), + [types]: ts('#4EC9B0', 0), + [functions]: ts('#DCDCAA', 0), + [strings]: ts('#ce9178', 0), + [numbers]: ts('#b5cea8', 0), + [keywords]: ts('#C586C0', 0) + }); - tokenStyle = themeData.getTokenStyle(functions); - assertTokenStyle(tokenStyle, ts('#A6E22E', 0)); + }); - tokenStyle = themeData.getTokenStyle(strings); - assertTokenStyle(tokenStyle, ts('#E6DB74', 0)); + test('color defaults - kimbie dark', async () => { + const themeData = ColorThemeData.createUnloadedTheme('foo'); + const themeLocation = getPathFromAmdModule(require, '../../../../../../../extensions/theme-kimbie-dark/themes/kimbie-dark-color-theme.json'); + themeData.location = URI.file(themeLocation); + await themeData.ensureLoaded(fileService); - tokenStyle = themeData.getTokenStyle(numbers); - assertTokenStyle(tokenStyle, ts('#AE81FF', 0)); + assert.equal(themeData.isLoaded, true); - tokenStyle = themeData.getTokenStyle(keywords); - assertTokenStyle(tokenStyle, ts('#F92672', 0)); + assertTokenStyles(themeData, { + [comments]: ts('#a57a4c', 0), + [variables]: ts('#dc3958', 0), + [types]: ts('#f06431', 0), + [functions]: ts('#8ab1b0', 0), + [strings]: ts('#889b4a', 0), + [numbers]: ts('#f79a32', 0), + [keywords]: ts('#98676a', 0) + }); + + }); + + test('color defaults - abyss', async () => { + const themeData = ColorThemeData.createUnloadedTheme('foo'); + const themeLocation = getPathFromAmdModule(require, '../../../../../../../extensions/theme-abyss/themes/abyss-color-theme.json'); + themeData.location = URI.file(themeLocation); + await themeData.ensureLoaded(fileService); + + assert.equal(themeData.isLoaded, true); + + assertTokenStyles(themeData, { + [comments]: ts('#384887', 0), + [variables]: ts('#9966b8', 0), + [types]: ts('#f06431', 0), + [functions]: ts('#8ab1b0', 0), + [strings]: ts('#22aa44', 0), + [numbers]: ts('#f280d0', 0), + [keywords]: ts('#98676a', 0) + }); }); @@ -83,7 +177,7 @@ suite('Themes - TokenStyleResolving', () => { } }, { - scope: 'keyword', + scope: 'keyword.operator', settings: { fontStyle: 'italic bold underline', foreground: '#F92672' @@ -119,9 +213,18 @@ suite('Themes - TokenStyleResolving', () => { tokenStyle = themeData.findTokenStyleForScope(['variable']); assertTokenStyle(tokenStyle, ts('#F8F8F2', 0), 'variable'); - tokenStyle = themeData.findTokenStyleForScope(['keyword']); + tokenStyle = themeData.findTokenStyleForScope(['keyword.operator']); assertTokenStyle(tokenStyle, ts('#F92672', TokenStyleBits.ITALIC | TokenStyleBits.BOLD | TokenStyleBits.UNDERLINE), 'keyword'); + tokenStyle = themeData.findTokenStyleForScope(['keyword']); + assertTokenStyle(tokenStyle, undefined, 'keyword'); + + tokenStyle = themeData.findTokenStyleForScope(['keyword.operator']); + assertTokenStyle(tokenStyle, ts('#F92672', TokenStyleBits.ITALIC | TokenStyleBits.BOLD | TokenStyleBits.UNDERLINE), 'keyword.operator'); + + tokenStyle = themeData.findTokenStyleForScope(['keyword.operators']); + assertTokenStyle(tokenStyle, undefined, 'keyword.operators'); + tokenStyle = themeData.findTokenStyleForScope(['storage']); assertTokenStyle(tokenStyle, ts('#F92672', TokenStyleBits.ITALIC), 'storage'); From 4a1614f80b78c92cf446d98e942846dbeacdf1de Mon Sep 17 00:00:00 2001 From: Martin Aeschlimann Date: Thu, 19 Sep 2019 09:13:12 +0200 Subject: [PATCH 005/352] match score --- .../services/themes/common/colorThemeData.ts | 93 +++++++++++-------- .../themes/common/textMateScopeMatcher.ts | 43 +++++++-- 2 files changed, 90 insertions(+), 46 deletions(-) diff --git a/src/vs/workbench/services/themes/common/colorThemeData.ts b/src/vs/workbench/services/themes/common/colorThemeData.ts index 9d2f319a34355..12079e669db02 100644 --- a/src/vs/workbench/services/themes/common/colorThemeData.ts +++ b/src/vs/workbench/services/themes/common/colorThemeData.ts @@ -138,44 +138,41 @@ export class ColorThemeData implements IColorTheme { /** Public for testing reasons */ public findTokenStyleForScope(scope: ProbeScope): TokenStyle | undefined { + let foreground: string | null = null; + let fontStyle: string | null = null; + let foregroundScore = -1; + let fontStyleScore = -1; + function findTokenStyleForScopeInScopes(scopeMatchers: Matcher[], tokenColors: ITokenColorizationRule[]) { - for (let i = scopeMatchers.length - 1; i >= 0; i--) { + for (let i = 0; i < scopeMatchers.length; i++) { + const settings = tokenColors[i].settings; + if (!settings) { + continue; + } let matcher = scopeMatchers[i]; if (!matcher) { scopeMatchers[i] = matcher = getScopeMatcher(tokenColors[i]); } - if (matcher(scope)) { - const settings = tokenColors[i].settings; - if (settings) { - if (foreground === null && settings.foreground) { - foreground = settings.foreground; - } - if (fontStyle === null && types.isString(settings.fontStyle)) { - fontStyle = settings.fontStyle; - } - if (foreground !== null && fontStyle !== null) { - break; - } - } + const score = matcher(scope); + if (score > foregroundScore && settings.foreground) { + foreground = settings.foreground; + } + if (score > fontStyleScore && types.isString(settings.fontStyle)) { + fontStyle = settings.fontStyle; } } } - let foreground: string | null = null; - let fontStyle: string | null = null; + if (!this.themeTokenScopeMatchers) { + this.themeTokenScopeMatchers = new Array(this.themeTokenColors.length); + } + findTokenStyleForScopeInScopes(this.themeTokenScopeMatchers, this.themeTokenColors); if (!this.customTokenScopeMatchers) { this.customTokenScopeMatchers = new Array(this.customTokenColors.length); } findTokenStyleForScopeInScopes(this.customTokenScopeMatchers, this.customTokenColors); - if (foreground === null || fontStyle === null) { - if (!this.themeTokenScopeMatchers) { - this.themeTokenScopeMatchers = new Array(this.themeTokenColors.length); - } - findTokenStyleForScopeInScopes(this.themeTokenScopeMatchers, this.themeTokenColors); - } - if (foreground !== null || fontStyle !== null) { return getTokenStyle(foreground, fontStyle); } @@ -462,27 +459,43 @@ let defaultThemeColors: { [baseTheme: string]: ITokenColorizationRule[] } = { ], }; -const noMatch = (_scope: ProbeScope) => false; +const noMatch = (_scope: ProbeScope) => -1; -function nameMatcher(identifers: string[], scope: ProbeScope) { +function nameMatcher(identifers: string[], scope: ProbeScope): number { + function findInIdents(s: string, lastIndent: number): number { + for (let i = lastIndent - 1; i >= 0; i--) { + if (scopesAreMatching(identifers[i], s)) { + return i; + } + } + return -1; + } if (!Array.isArray(scope)) { - scope = [scope]; + const idx = findInIdents(scope, identifers.length); + if (idx >= 0) { + return idx * 0x10000 + scope.length; + } + return -1; } if (scope.length < identifers.length) { - return false; - } - let lastIndex = 0; - return identifers.every(identifier => { - for (let i = lastIndex; i < scope.length; i++) { - if (scopesAreMatching(scope[i], identifier)) { - lastIndex = i + 1; - return true; + return -1; + } + let lastScopeIndex = scope.length - 1; + let lastIdentifierIndex = findInIdents(scope[lastScopeIndex--], identifers.length); + if (lastIdentifierIndex >= 0) { + const score = lastIdentifierIndex * 0x10000 + scope.length; + while (lastScopeIndex >= 0) { + lastIdentifierIndex = findInIdents(scope[lastScopeIndex--], lastIdentifierIndex); + if (lastIdentifierIndex === -1) { + return -1; } } - return false; - }); + return score; + } + return -1; } + function scopesAreMatching(thisScopeName: string, scopeName: string): boolean { if (!thisScopeName) { return false; @@ -507,7 +520,13 @@ function getScopeMatcher(rule: ITokenColorizationRule): Matcher { } else { matchers.push(...createMatchers(ruleScope, nameMatcher)); } - return (scope: ProbeScope) => matchers.some(m => m.matcher(scope)); + return (scope: ProbeScope) => { + let max = 0; + for (const m of matchers) { + max = Math.max(max, m.matcher(scope)); + } + return max; + }; } function getTokenStyle(foreground: string | null, fontStyle: string | null): TokenStyle | undefined { diff --git a/src/vs/workbench/services/themes/common/textMateScopeMatcher.ts b/src/vs/workbench/services/themes/common/textMateScopeMatcher.ts index 16263c9ac8938..701081bca4ca3 100644 --- a/src/vs/workbench/services/themes/common/textMateScopeMatcher.ts +++ b/src/vs/workbench/services/themes/common/textMateScopeMatcher.ts @@ -11,10 +11,10 @@ export interface MatcherWithPriority { } export interface Matcher { - (matcherInput: T): boolean; + (matcherInput: T): number; } -export function createMatchers(selector: string, matchesName: (names: string[], matcherInput: T) => boolean): MatcherWithPriority[] { +export function createMatchers(selector: string, matchesName: (names: string[], matcherInput: T) => number): MatcherWithPriority[] { const results = []>[]; const tokenizer = newTokenizer(selector); let token = tokenizer.next(); @@ -44,7 +44,13 @@ export function createMatchers(selector: string, matchesName: (names: string[ if (token === '-') { token = tokenizer.next(); const expressionToNegate = parseOperand(); - return matcherInput => !!expressionToNegate && !expressionToNegate(matcherInput); + if (!expressionToNegate) { + return null; + } + return matcherInput => { + const score = expressionToNegate(matcherInput); + return score < 0 ? 0 : -1; + }; } if (token === '(') { token = tokenizer.next(); @@ -64,18 +70,31 @@ export function createMatchers(selector: string, matchesName: (names: string[ } return null; } - function parseConjunction(): Matcher { - const matchers: Matcher[] = []; + function parseConjunction(): Matcher | null { let matcher = parseOperand(); + if (!matcher) { + return null; + } + + const matchers: Matcher[] = []; while (matcher) { matchers.push(matcher); matcher = parseOperand(); } - return matcherInput => matchers.every(matcher => matcher(matcherInput)); // and + return matcherInput => { // and + let min = matchers[0](matcherInput); + for (let i = 1; min >= 0 && i < matchers.length; i++) { + min = Math.min(min, matchers[i](matcherInput)); + } + return min; + }; } - function parseInnerExpression(): Matcher { - const matchers: Matcher[] = []; + function parseInnerExpression(): Matcher | null { let matcher = parseConjunction(); + if (!matcher) { + return null; + } + const matchers: Matcher[] = []; while (matcher) { matchers.push(matcher); if (token === '|' || token === ',') { @@ -87,7 +106,13 @@ export function createMatchers(selector: string, matchesName: (names: string[ } matcher = parseConjunction(); } - return matcherInput => matchers.some(matcher => matcher(matcherInput)); // or + return matcherInput => { // or + let max = matchers[0](matcherInput); + for (let i = 1; i < matchers.length; i++) { + max = Math.max(max, matchers[i](matcherInput)); + } + return max; + }; } } From 6dce52093c8a2fd178f86e4de8d4844a89c33297 Mon Sep 17 00:00:00 2001 From: Martin Aeschlimann Date: Thu, 19 Sep 2019 16:11:43 +0200 Subject: [PATCH 006/352] fix score based rule matching --- .../theme-abyss/themes/abyss-color-theme.json | 11 ++--- .../theme/common/tokenStyleRegistry.ts | 16 +++---- .../services/themes/common/colorThemeData.ts | 42 +++++++++---------- .../tokenStyleResolving.test.ts | 14 ++++--- 4 files changed, 39 insertions(+), 44 deletions(-) diff --git a/extensions/theme-abyss/themes/abyss-color-theme.json b/extensions/theme-abyss/themes/abyss-color-theme.json index 18c8235f79c68..775dc8614d0f2 100644 --- a/extensions/theme-abyss/themes/abyss-color-theme.json +++ b/extensions/theme-abyss/themes/abyss-color-theme.json @@ -1,12 +1,6 @@ { "name": "Abyss", "tokenColors": [ - { - "settings": { - "background": "#000c18", - "foreground": "#6688cc" - } - }, { "scope": ["meta.embedded", "source.groovy.embedded"], "settings": { @@ -260,6 +254,9 @@ ], "colors": { + "editor.background": "#000c18", + "editor.foreground": "#6688cc", + // Base // "foreground": "", "focusBorder": "#596F99", @@ -303,8 +300,6 @@ "scrollbarSlider.hoverBackground": "#3B3F5188", // Editor - "editor.background": "#000c18", - // "editor.foreground": "#6688cc", "editorWidget.background": "#262641", "editorCursor.foreground": "#ddbb88", "editorWhitespace.foreground": "#103050", diff --git a/src/vs/platform/theme/common/tokenStyleRegistry.ts b/src/vs/platform/theme/common/tokenStyleRegistry.ts index e212367d8730f..27f1a7ebc2972 100644 --- a/src/vs/platform/theme/common/tokenStyleRegistry.ts +++ b/src/vs/platform/theme/common/tokenStyleRegistry.ts @@ -71,7 +71,7 @@ export namespace TokenStyle { } } -export type ProbeScope = string[] | string; +export type ProbeScope = string[]; export interface TokenStyleFunction { (theme: ITheme): TokenStyle | undefined; @@ -246,13 +246,13 @@ export function getTokenStyleRegistry(): ITokenStyleRegistry { // colors -export const comments = registerTokenStyle('comments', { scopesToProbe: ['comment'], dark: null, light: null, hc: null }, nls.localize('comments', "Token style for comments.")); -export const strings = registerTokenStyle('strings', { scopesToProbe: ['string'], dark: null, light: null, hc: null }, nls.localize('strings', "Token style for strings.")); -export const keywords = registerTokenStyle('keywords', { scopesToProbe: ['keyword.control', 'storage', 'storage.type'], dark: null, light: null, hc: null }, nls.localize('keywords', "Token style for keywords.")); -export const numbers = registerTokenStyle('numbers', { scopesToProbe: ['constant.numeric'], dark: null, light: null, hc: null }, nls.localize('numbers', "Token style for numbers.")); -export const types = registerTokenStyle('types', { scopesToProbe: ['entity.name.type', 'entity.name.class', 'support.type', 'support.class'], dark: null, light: null, hc: null }, nls.localize('types', "Token style for types.")); -export const functions = registerTokenStyle('functions', { scopesToProbe: ['entity.name.function', 'support.function'], dark: null, light: null, hc: null }, nls.localize('functions', "Token style for functions.")); -export const variables = registerTokenStyle('variables', { scopesToProbe: ['variable', 'entity.name.variable'], dark: null, light: null, hc: null }, nls.localize('variables', "Token style for variables.")); +export const comments = registerTokenStyle('comments', { scopesToProbe: [['comment']], dark: null, light: null, hc: null }, nls.localize('comments', "Token style for comments.")); +export const strings = registerTokenStyle('strings', { scopesToProbe: [['string']], dark: null, light: null, hc: null }, nls.localize('strings', "Token style for strings.")); +export const keywords = registerTokenStyle('keywords', { scopesToProbe: [['keyword.control'], ['storage'], ['storage.type']], dark: null, light: null, hc: null }, nls.localize('keywords', "Token style for keywords.")); +export const numbers = registerTokenStyle('numbers', { scopesToProbe: [['constant.numeric']], dark: null, light: null, hc: null }, nls.localize('numbers', "Token style for numbers.")); +export const types = registerTokenStyle('types', { scopesToProbe: [['entity.name.type'], ['entity.name.class'], ['support.type'], ['support.class']], dark: null, light: null, hc: null }, nls.localize('types', "Token style for types.")); +export const functions = registerTokenStyle('functions', { scopesToProbe: [['entity.name.function'], ['support.function']], dark: null, light: null, hc: null }, nls.localize('functions', "Token style for functions.")); +export const variables = registerTokenStyle('variables', { scopesToProbe: [['variable'], ['entity.name.variable']], dark: null, light: null, hc: null }, nls.localize('variables', "Token style for variables.")); /** * @param colorValue Resolve a color value in the context of a theme diff --git a/src/vs/workbench/services/themes/common/colorThemeData.ts b/src/vs/workbench/services/themes/common/colorThemeData.ts index 12079e669db02..4dbdfcc2eff9f 100644 --- a/src/vs/workbench/services/themes/common/colorThemeData.ts +++ b/src/vs/workbench/services/themes/common/colorThemeData.ts @@ -138,7 +138,9 @@ export class ColorThemeData implements IColorTheme { /** Public for testing reasons */ public findTokenStyleForScope(scope: ProbeScope): TokenStyle | undefined { - let foreground: string | null = null; + let foregroundColor = this.getColor(editorForeground); + + let foreground = foregroundColor ? foregroundColor.toString() : null; let fontStyle: string | null = null; let foregroundScore = -1; let fontStyleScore = -1; @@ -154,12 +156,15 @@ export class ColorThemeData implements IColorTheme { scopeMatchers[i] = matcher = getScopeMatcher(tokenColors[i]); } const score = matcher(scope); - if (score > foregroundScore && settings.foreground) { - foreground = settings.foreground; - } - if (score > fontStyleScore && types.isString(settings.fontStyle)) { - fontStyle = settings.fontStyle; + if (score >= 0) { + if (score >= foregroundScore && settings.foreground) { + foreground = settings.foreground; + } + if (score >= fontStyleScore && types.isString(settings.fontStyle)) { + fontStyle = settings.fontStyle; + } } + } } @@ -173,10 +178,7 @@ export class ColorThemeData implements IColorTheme { } findTokenStyleForScopeInScopes(this.customTokenScopeMatchers, this.customTokenColors); - if (foreground !== null || fontStyle !== null) { - return getTokenStyle(foreground, fontStyle); - } - return undefined; + return getTokenStyle(foreground, fontStyle); } @@ -464,26 +466,19 @@ const noMatch = (_scope: ProbeScope) => -1; function nameMatcher(identifers: string[], scope: ProbeScope): number { function findInIdents(s: string, lastIndent: number): number { for (let i = lastIndent - 1; i >= 0; i--) { - if (scopesAreMatching(identifers[i], s)) { + if (scopesAreMatching(s, identifers[i])) { return i; } } return -1; } - if (!Array.isArray(scope)) { - const idx = findInIdents(scope, identifers.length); - if (idx >= 0) { - return idx * 0x10000 + scope.length; - } - return -1; - } if (scope.length < identifers.length) { return -1; } let lastScopeIndex = scope.length - 1; let lastIdentifierIndex = findInIdents(scope[lastScopeIndex--], identifers.length); if (lastIdentifierIndex >= 0) { - const score = lastIdentifierIndex * 0x10000 + scope.length; + const score = (lastIdentifierIndex + 1) * 0x10000 + scope.length; while (lastScopeIndex >= 0) { lastIdentifierIndex = findInIdents(scope[lastScopeIndex--], lastIdentifierIndex); if (lastIdentifierIndex === -1) { @@ -520,10 +515,13 @@ function getScopeMatcher(rule: ITokenColorizationRule): Matcher { } else { matchers.push(...createMatchers(ruleScope, nameMatcher)); } + if (matchers.length === 0) { + return noMatch; + } return (scope: ProbeScope) => { - let max = 0; - for (const m of matchers) { - max = Math.max(max, m.matcher(scope)); + let max = matchers[0].matcher(scope); + for (let i = 1; i < matchers.length; i++) { + max = Math.max(max, matchers[i].matcher(scope)); } return max; }; diff --git a/src/vs/workbench/services/themes/test/electron-browser/tokenStyleResolving.test.ts b/src/vs/workbench/services/themes/test/electron-browser/tokenStyleResolving.test.ts index ac70d63599980..12b9e9102dacc 100644 --- a/src/vs/workbench/services/themes/test/electron-browser/tokenStyleResolving.test.ts +++ b/src/vs/workbench/services/themes/test/electron-browser/tokenStyleResolving.test.ts @@ -15,6 +15,7 @@ import { DiskFileSystemProvider } from 'vs/platform/files/node/diskFileSystemPro import { Schemas } from 'vs/base/common/network'; import { URI } from 'vs/base/common/uri'; import { getPathFromAmdModule } from 'vs/base/common/amd'; +import { editorForeground } from 'vs/platform/theme/common/colorRegistry'; function ts(foreground: string | undefined, styleFlags: number | undefined): TokenStyle { const foregroundColor = isString(foreground) ? Color.fromHex(foreground) : undefined; @@ -154,12 +155,12 @@ suite('Themes - TokenStyleResolving', () => { assertTokenStyles(themeData, { [comments]: ts('#384887', 0), - [variables]: ts('#9966b8', 0), - [types]: ts('#f06431', 0), - [functions]: ts('#8ab1b0', 0), + [variables]: ts('#6688cc', 0), + [types]: ts('#ffeebb', TokenStyleBits.UNDERLINE), + [functions]: ts('#ddbb88', 0), [strings]: ts('#22aa44', 0), [numbers]: ts('#f280d0', 0), - [keywords]: ts('#98676a', 0) + [keywords]: ts('#225588', 0) }); }); @@ -209,6 +210,7 @@ suite('Themes - TokenStyleResolving', () => { themeData.setCustomTokenColors(customTokenColors); let tokenStyle; + let defaultTokenStyle = new TokenStyle(themeData.getColor(editorForeground)); tokenStyle = themeData.findTokenStyleForScope(['variable']); assertTokenStyle(tokenStyle, ts('#F8F8F2', 0), 'variable'); @@ -217,13 +219,13 @@ suite('Themes - TokenStyleResolving', () => { assertTokenStyle(tokenStyle, ts('#F92672', TokenStyleBits.ITALIC | TokenStyleBits.BOLD | TokenStyleBits.UNDERLINE), 'keyword'); tokenStyle = themeData.findTokenStyleForScope(['keyword']); - assertTokenStyle(tokenStyle, undefined, 'keyword'); + assertTokenStyle(tokenStyle, defaultTokenStyle, 'keyword'); tokenStyle = themeData.findTokenStyleForScope(['keyword.operator']); assertTokenStyle(tokenStyle, ts('#F92672', TokenStyleBits.ITALIC | TokenStyleBits.BOLD | TokenStyleBits.UNDERLINE), 'keyword.operator'); tokenStyle = themeData.findTokenStyleForScope(['keyword.operators']); - assertTokenStyle(tokenStyle, undefined, 'keyword.operators'); + assertTokenStyle(tokenStyle, defaultTokenStyle, 'keyword.operators'); tokenStyle = themeData.findTokenStyleForScope(['storage']); assertTokenStyle(tokenStyle, ts('#F92672', TokenStyleBits.ITALIC), 'storage'); From 3bc026d9b05346bdc126db6aa67cefce3158f735 Mon Sep 17 00:00:00 2001 From: Martin Aeschlimann Date: Thu, 19 Sep 2019 17:16:30 +0200 Subject: [PATCH 007/352] classifictions --- .../theme/common/tokenStyleRegistry.ts | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/src/vs/platform/theme/common/tokenStyleRegistry.ts b/src/vs/platform/theme/common/tokenStyleRegistry.ts index 27f1a7ebc2972..45f548b352078 100644 --- a/src/vs/platform/theme/common/tokenStyleRegistry.ts +++ b/src/vs/platform/theme/common/tokenStyleRegistry.ts @@ -253,7 +253,43 @@ export const numbers = registerTokenStyle('numbers', { scopesToProbe: [['constan export const types = registerTokenStyle('types', { scopesToProbe: [['entity.name.type'], ['entity.name.class'], ['support.type'], ['support.class']], dark: null, light: null, hc: null }, nls.localize('types', "Token style for types.")); export const functions = registerTokenStyle('functions', { scopesToProbe: [['entity.name.function'], ['support.function']], dark: null, light: null, hc: null }, nls.localize('functions', "Token style for functions.")); export const variables = registerTokenStyle('variables', { scopesToProbe: [['variable'], ['entity.name.variable']], dark: null, light: null, hc: null }, nls.localize('variables', "Token style for variables.")); +/* +Tags: local, param, reference, write, async, documentation, overloaded +Struct + +Type +Class : Type +Interface : Type + +Field : Property +Method : Property +Property + +Variable +Parameter +Const + +Function + +Macro +Operator + +Namespace +Label +Event + +(Emum) + +Operator +Keyword + +literal +string : literal +number : literal +regex: literal + +*/ /** * @param colorValue Resolve a color value in the context of a theme */ From b351673fac97975912bb1386eff213ebdc32d9e9 Mon Sep 17 00:00:00 2001 From: Martin Aeschlimann Date: Fri, 27 Sep 2019 16:54:45 +0200 Subject: [PATCH 008/352] TokenTypes & TokenModifiers --- .../browser/standaloneThemeServiceImpl.ts | 8 +- .../test/browser/standaloneLanguages.test.ts | 5 +- src/vs/platform/theme/common/themeService.ts | 6 +- .../common/tokenClassificationRegistry.ts | 345 ++++++++++++++++++ .../theme/common/tokenStyleRegistry.ts | 327 ----------------- .../theme/test/common/testThemeService.ts | 10 +- .../terminalColorRegistry.test.ts | 4 +- .../services/themes/common/colorThemeData.ts | 121 +++--- .../tokenStyleResolving.test.ts | 74 ++-- 9 files changed, 465 insertions(+), 435 deletions(-) create mode 100644 src/vs/platform/theme/common/tokenClassificationRegistry.ts delete mode 100644 src/vs/platform/theme/common/tokenStyleRegistry.ts diff --git a/src/vs/editor/standalone/browser/standaloneThemeServiceImpl.ts b/src/vs/editor/standalone/browser/standaloneThemeServiceImpl.ts index b26e44bf76c95..61cf4274a0d88 100644 --- a/src/vs/editor/standalone/browser/standaloneThemeServiceImpl.ts +++ b/src/vs/editor/standalone/browser/standaloneThemeServiceImpl.ts @@ -14,7 +14,7 @@ import { IEnvironmentService } from 'vs/platform/environment/common/environment' import { Registry } from 'vs/platform/registry/common/platform'; import { ColorIdentifier, Extensions, IColorRegistry } from 'vs/platform/theme/common/colorRegistry'; import { Extensions as ThemingExtensions, ICssStyleCollector, IIconTheme, IThemingRegistry } from 'vs/platform/theme/common/themeService'; -import { TokenStyle, TokenStyleIdentifier } from 'vs/platform/theme/common/tokenStyleRegistry'; +import { TokenStyle, TokenClassification, ProbeScope } from 'vs/platform/theme/common/tokenClassificationRegistry'; const VS_THEME_NAME = 'vs'; const VS_DARK_THEME_NAME = 'vs-dark'; @@ -131,7 +131,11 @@ class StandaloneTheme implements IStandaloneTheme { return this._tokenTheme; } - getTokenStyle(tokenStyle: TokenStyleIdentifier, useDefault?: boolean | undefined): TokenStyle | undefined { + getTokenStyle(classification: TokenClassification, useDefault?: boolean | undefined): TokenStyle | undefined { + return undefined; + } + + resolveScopes(scopes: ProbeScope[]): TokenStyle | undefined { return undefined; } } diff --git a/src/vs/editor/standalone/test/browser/standaloneLanguages.test.ts b/src/vs/editor/standalone/test/browser/standaloneLanguages.test.ts index 5dfa7d92149a3..4be6f23210767 100644 --- a/src/vs/editor/standalone/test/browser/standaloneLanguages.test.ts +++ b/src/vs/editor/standalone/test/browser/standaloneLanguages.test.ts @@ -13,7 +13,6 @@ import { ILineTokens, IToken, TokenizationSupport2Adapter, TokensProvider } from import { IStandaloneTheme, IStandaloneThemeData, IStandaloneThemeService } from 'vs/editor/standalone/common/standaloneThemeService'; import { ColorIdentifier } from 'vs/platform/theme/common/colorRegistry'; import { IIconTheme, ITheme, LIGHT } from 'vs/platform/theme/common/themeService'; -import { TokenStyleIdentifier } from 'vs/platform/theme/common/tokenStyleRegistry'; suite('TokenizationSupport2Adapter', () => { @@ -57,7 +56,9 @@ suite('TokenizationSupport2Adapter', () => { throw new Error('Not implemented'); }, - getTokenStyle: (tokenStyleId: TokenStyleIdentifier) => undefined + getTokenStyle: () => undefined, + + }; } public getIconTheme(): IIconTheme { diff --git a/src/vs/platform/theme/common/themeService.ts b/src/vs/platform/theme/common/themeService.ts index 7ac9788d1a736..8117fd486a377 100644 --- a/src/vs/platform/theme/common/themeService.ts +++ b/src/vs/platform/theme/common/themeService.ts @@ -10,7 +10,7 @@ import * as platform from 'vs/platform/registry/common/platform'; import { ColorIdentifier } from 'vs/platform/theme/common/colorRegistry'; import { Event, Emitter } from 'vs/base/common/event'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; -import { TokenStyleIdentifier, TokenStyle } from 'vs/platform/theme/common/tokenStyleRegistry'; +import { TokenStyle, TokenClassification, ProbeScope } from 'vs/platform/theme/common/tokenClassificationRegistry'; export const IThemeService = createDecorator('themeService'); @@ -61,7 +61,9 @@ export interface ITheme { */ defines(color: ColorIdentifier): boolean; - getTokenStyle(color: TokenStyleIdentifier, useDefault?: boolean): TokenStyle | undefined; + getTokenStyle(classification: TokenClassification, useDefault?: boolean): TokenStyle | undefined; + + resolveScopes(scopes: ProbeScope[]): TokenStyle | undefined; } export interface IIconTheme { diff --git a/src/vs/platform/theme/common/tokenClassificationRegistry.ts b/src/vs/platform/theme/common/tokenClassificationRegistry.ts new file mode 100644 index 0000000000000..d1778608f8f7b --- /dev/null +++ b/src/vs/platform/theme/common/tokenClassificationRegistry.ts @@ -0,0 +1,345 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as platform from 'vs/platform/registry/common/platform'; +import { Color } from 'vs/base/common/color'; +import { ITheme } from 'vs/platform/theme/common/themeService'; +import * as nls from 'vs/nls'; + +import { editorForeground } from 'vs/platform/theme/common/colorRegistry'; + +// ------ API types + +export const TOKEN_TYPE_WILDCARD = '*'; +export const TOKEN_TYPE_WILDCARD_NUM = -1; + +// qualified string [type|*](.modifier)* +export type TokenClassificationString = string; + +export interface TokenClassification { + type: number; + modifiers: number; +} + +export interface TokenTypeOrModifierContribution { + readonly num: number; + readonly id: string; + readonly description: string; + readonly deprecationMessage: string | undefined; +} + + +export interface TokenStyleData { + foreground?: Color; + bold?: boolean; + underline?: boolean; + italic?: boolean; +} + +export class TokenStyle implements Readonly { + constructor( + public readonly foreground?: Color, + public readonly bold?: boolean, + public readonly underline?: boolean, + public readonly italic?: boolean, + ) { + } +} + +export namespace TokenStyle { + export function fromData(data: { foreground?: Color, bold?: boolean, underline?: boolean, italic?: boolean }) { + return new TokenStyle(data.foreground, data.bold, data.underline, data.italic); + } +} + +export type ProbeScope = string[]; + +export interface TokenStyleFunction { + (theme: ITheme): TokenStyle | undefined; +} + +export interface TokenStyleDefaults { + scopesToProbe: ProbeScope[]; + light: TokenStyleValue | null; + dark: TokenStyleValue | null; + hc: TokenStyleValue | null; +} + +export interface TokenStylingDefaultRule { + classification: TokenClassification; + matchScore: number; + defaults: TokenStyleDefaults; +} + +export interface TokenStylingRule { + classification: TokenClassification; + matchScore: number; + value: TokenStyle; +} + +/** + * A TokenStyle Value is either a token style literal, or a TokenClassificationString + */ +export type TokenStyleValue = TokenStyle | TokenClassificationString; + +// TokenStyle registry +export const Extensions = { + TokenClassificationContribution: 'base.contributions.tokenClassification' +}; + +export interface ITokenClassificationRegistry { + + /** + * Register a token type to the registry. + * @param id The TokenType id as used in theme description files + * @description the description + */ + registerTokenType(id: string, description: string): void; + + /** + * Register a token modifier to the registry. + * @param id The TokenModifier id as used in theme description files + * @description the description + */ + registerTokenModifier(id: string, description: string): void; + + getTokenClassificationFromString(str: TokenClassificationString): TokenClassification | undefined; + getTokenClassification(type: string, modifiers: string[]): TokenClassification | undefined; + + /** + * Register a TokenStyle default to the registry. + * @param selector The rule selector + * @param defaults The default values + */ + registerTokenStyleDefault(selector: TokenClassification, defaults: TokenStyleDefaults): void; + + /** + * Deregister a TokenType from the registry. + */ + deregisterTokenType(id: string): void; + + /** + * Deregister a TokenModifier from the registry. + */ + deregisterTokenModifier(id: string): void; + + /** + * Get all TokenType contributions + */ + getTokenTypes(): TokenTypeOrModifierContribution[]; + + /** + * Get all TokenModifier contributions + */ + getTokenModifiers(): TokenTypeOrModifierContribution[]; + + /** + * Resolves a token classification against the given rules and default rules from the registry. + */ + resolveTokenStyle(classification: TokenClassification, themingRules: TokenStylingRule[], useDefault: boolean, theme: ITheme): TokenStyle | undefined; +} + + + +class TokenClassificationRegistry implements ITokenClassificationRegistry { + + private currentTypeNumber = 0; + private currentModifierBit = 1; + + private tokenTypeById: { [key: string]: TokenTypeOrModifierContribution }; + private tokenModifierById: { [key: string]: TokenTypeOrModifierContribution }; + + private tokenStylingDefaultRules: TokenStylingDefaultRule[] = []; + + constructor() { + this.tokenTypeById = {}; + this.tokenModifierById = {}; + + this.tokenTypeById[TOKEN_TYPE_WILDCARD] = { num: TOKEN_TYPE_WILDCARD_NUM, id: TOKEN_TYPE_WILDCARD, description: '', deprecationMessage: undefined }; + } + + public registerTokenType(id: string, description: string, deprecationMessage?: string): void { + const num = this.currentTypeNumber++; + let tokenStyleContribution: TokenTypeOrModifierContribution = { num, id, description, deprecationMessage }; + this.tokenTypeById[id] = tokenStyleContribution; + } + + public registerTokenModifier(id: string, description: string, deprecationMessage?: string): void { + const num = this.currentModifierBit; + this.currentModifierBit = this.currentModifierBit * 2; + let tokenStyleContribution: TokenTypeOrModifierContribution = { num, id, description, deprecationMessage }; + this.tokenModifierById[id] = tokenStyleContribution; + } + + public getTokenClassification(type: string, modifiers: string[]): TokenClassification | undefined { + const tokenTypeDesc = this.tokenTypeById[type]; + if (!tokenTypeDesc) { + return undefined; + } + let allModifierBits = 0; + for (const modifier of modifiers) { + const tokenModifierDesc = this.tokenModifierById[modifier]; + if (tokenModifierDesc) { + allModifierBits |= tokenModifierDesc.num; + } + } + return { type: tokenTypeDesc.num, modifiers: allModifierBits }; + } + + public getTokenClassificationFromString(str: TokenClassificationString): TokenClassification | undefined { + const parts = str.split('.'); + const type = parts.shift(); + if (type) { + return this.getTokenClassification(type, parts); + } + return undefined; + } + + public registerTokenStyleDefault(classification: TokenClassification, defaults: TokenStyleDefaults): void { + const matchScore = bitCount(classification.modifiers) + ((classification.type !== TOKEN_TYPE_WILDCARD_NUM) ? 1 : 0); + this.tokenStylingDefaultRules.push({ classification, matchScore, defaults }); + } + + public deregisterTokenType(id: string): void { + delete this.tokenTypeById[id]; + } + + public deregisterTokenModifier(id: string): void { + delete this.tokenModifierById[id]; + } + + public getTokenTypes(): TokenTypeOrModifierContribution[] { + return Object.keys(this.tokenTypeById).map(id => this.tokenTypeById[id]); + } + + public getTokenModifiers(): TokenTypeOrModifierContribution[] { + return Object.keys(this.tokenModifierById).map(id => this.tokenModifierById[id]); + } + + public resolveTokenStyle(classification: TokenClassification, themingRules: TokenStylingRule[], useDefault: boolean, theme: ITheme): TokenStyle | undefined { + let result: any = { + foreground: theme.getColor(editorForeground), + bold: false, + underline: false, + italic: false + }; + let score = { + foreground: -1, + bold: -1, + underline: -1, + italic: -1 + }; + + function _processStyle(matchScore: number, style: TokenStyle) { + for (let p in result) { + const property = p as keyof TokenStyle; + const info = style[property]; + if (info !== undefined && score[property] <= matchScore) { + score[property] = matchScore; + result[property] = info; + } + } + } + themingRules.forEach(rule => { + const matchScore = match(rule, classification); + if (matchScore >= 0) { + _processStyle(matchScore, rule.value); + } + }); + if (useDefault) { + this.tokenStylingDefaultRules.forEach(rule => { + const matchScore = match(rule, classification); + if (matchScore >= 0) { + let style = theme.resolveScopes(rule.defaults.scopesToProbe); + if (!style) { + style = this.resolveTokenStyleValue(rule.defaults[theme.type], theme); + } + if (style) { + _processStyle(matchScore, style); + } + } + }); + } + return TokenStyle.fromData(result); + } + + /** + * @param tokenStyleValue Resolve a tokenStyleValue in the context of a theme + */ + private resolveTokenStyleValue(tokenStyleValue: TokenStyleValue | null, theme: ITheme): TokenStyle | undefined { + if (tokenStyleValue === null) { + return undefined; + } else if (typeof tokenStyleValue === 'string') { + const classification = this.getTokenClassificationFromString(tokenStyleValue); + if (classification) { + return theme.getTokenStyle(classification); + } + } else if (typeof tokenStyleValue === 'object') { + return tokenStyleValue; + } + return undefined; + } + + + public toString() { + let sorter = (a: string, b: string) => { + let cat1 = a.indexOf('.') === -1 ? 0 : 1; + let cat2 = b.indexOf('.') === -1 ? 0 : 1; + if (cat1 !== cat2) { + return cat1 - cat2; + } + return a.localeCompare(b); + }; + + return Object.keys(this.tokenTypeById).sort(sorter).map(k => `- \`${k}\`: ${this.tokenTypeById[k].description}`).join('\n'); + } + +} + +function match(themeSelector: TokenStylingRule | TokenStylingDefaultRule, classification: TokenClassification): number { + const selectorType = themeSelector.classification.type; + if (selectorType !== TOKEN_TYPE_WILDCARD_NUM && selectorType === classification.type) { + return -1; + } + const selectorModifier = themeSelector.classification.modifiers; + if ((classification.modifiers & selectorModifier) !== selectorModifier) { + return -1; + } + return themeSelector.matchScore; +} + + +const tokenClassificationRegistry = new TokenClassificationRegistry(); +platform.Registry.add(Extensions.TokenClassificationContribution, tokenClassificationRegistry); + +export function registerTokenType(id: string, defaults: TokenStyleDefaults | null, description: string, deprecationMessage?: string): string { + tokenClassificationRegistry.registerTokenType(id, description, deprecationMessage); + + if (defaults) { + const classification = tokenClassificationRegistry.getTokenClassification(id, []); + tokenClassificationRegistry.registerTokenStyleDefault(classification!, defaults); + } + return id; +} + +export function getTokenClassificationRegistry(): ITokenClassificationRegistry { + return tokenClassificationRegistry; +} + +export const comments = registerTokenType('comments', { scopesToProbe: [['comment']], dark: null, light: null, hc: null }, nls.localize('comments', "Token style for comments.")); +export const strings = registerTokenType('strings', { scopesToProbe: [['string']], dark: null, light: null, hc: null }, nls.localize('strings', "Token style for strings.")); +export const keywords = registerTokenType('keywords', { scopesToProbe: [['keyword.control'], ['storage'], ['storage.type']], dark: null, light: null, hc: null }, nls.localize('keywords', "Token style for keywords.")); +export const numbers = registerTokenType('numbers', { scopesToProbe: [['constant.numeric']], dark: null, light: null, hc: null }, nls.localize('numbers', "Token style for numbers.")); +export const types = registerTokenType('types', { scopesToProbe: [['entity.name.type'], ['entity.name.class'], ['support.type'], ['support.class']], dark: null, light: null, hc: null }, nls.localize('types', "Token style for types.")); +export const functions = registerTokenType('functions', { scopesToProbe: [['entity.name.function'], ['support.function']], dark: null, light: null, hc: null }, nls.localize('functions', "Token style for functions.")); +export const variables = registerTokenType('variables', { scopesToProbe: [['variable'], ['entity.name.variable']], dark: null, light: null, hc: null }, nls.localize('variables', "Token style for variables.")); + + + +function bitCount(u: number) { + // https://blogs.msdn.microsoft.com/jeuge/2005/06/08/bit-fiddling-3/ + const uCount = u - ((u >> 1) & 0o33333333333) - ((u >> 2) & 0o11111111111); + return ((uCount + (uCount >> 3)) & 0o30707070707) % 63; +} diff --git a/src/vs/platform/theme/common/tokenStyleRegistry.ts b/src/vs/platform/theme/common/tokenStyleRegistry.ts deleted file mode 100644 index 45f548b352078..0000000000000 --- a/src/vs/platform/theme/common/tokenStyleRegistry.ts +++ /dev/null @@ -1,327 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import * as platform from 'vs/platform/registry/common/platform'; -import { IJSONSchema, IJSONSchemaMap } from 'vs/base/common/jsonSchema'; -import { Color } from 'vs/base/common/color'; -import { ITheme } from 'vs/platform/theme/common/themeService'; -import { Event, Emitter } from 'vs/base/common/event'; -import * as nls from 'vs/nls'; - -import { Extensions as JSONExtensions, IJSONContributionRegistry } from 'vs/platform/jsonschemas/common/jsonContributionRegistry'; -import { RunOnceScheduler } from 'vs/base/common/async'; -import { editorForeground } from 'vs/platform/theme/common/colorRegistry'; - -// ------ API types - -export type TokenStyleIdentifier = string; - -export interface TokenStyleContribution { - readonly id: TokenStyleIdentifier; - readonly description: string; - readonly defaults: TokenStyleDefaults | null; - readonly deprecationMessage: string | undefined; -} - -export const enum TokenStyleBits { - BOLD = 0x01, - UNDERLINE = 0x02, - ITALIC = 0x04 -} - -export class TokenStyle { - constructor( - public readonly foreground?: Color, - public readonly background?: Color, - public readonly styles?: number - ) { - - } - - hasStyle(style: number): boolean { - return !!this.styles && ((this.styles & style) === style); - } -} - -export namespace TokenStyle { - export function fromString(s: string) { - const parts = s.split('-'); - let part = parts.shift(); - if (part) { - const foreground = Color.fromHex(part); - let background = undefined; - let style = undefined; - part = parts.shift(); - if (part && part[0] === '#') { - background = Color.fromHex(part); - part = parts.shift(); - } - if (part) { - try { - style = parseInt(part); - } catch (e) { - // ignore - } - } - return new TokenStyle(foreground, background, style); - } - return new TokenStyle(Color.red); - } -} - -export type ProbeScope = string[]; - -export interface TokenStyleFunction { - (theme: ITheme): TokenStyle | undefined; -} - -export interface TokenStyleDefaults { - scopesToProbe?: ProbeScope[]; - light: TokenStyleValue | null; - dark: TokenStyleValue | null; - hc: TokenStyleValue | null; -} - -/** - * A TokenStyle Value is either a token style literal, a reference to other token style or a derived token style - */ -export type TokenStyleValue = TokenStyle | string | TokenStyleIdentifier | TokenStyleFunction; - -// TokenStyle registry -export const Extensions = { - TokenStyleContribution: 'base.contributions.tokenStyles' -}; - -export interface ITokenStyleRegistry { - - readonly onDidChangeSchema: Event; - - /** - * Register a TokenStyle to the registry. - * @param id The TokenStyle id as used in theme description files - * @param defaults The default values - * @description the description - */ - registerTokenStyle(id: string, defaults: TokenStyleDefaults, description: string): TokenStyleIdentifier; - - /** - * Register a TokenStyle to the registry. - */ - deregisterTokenStyle(id: string): void; - - /** - * Get all TokenStyle contributions - */ - getTokenStyles(): TokenStyleContribution[]; - - /** - * Gets the default TokenStyle of the given id - */ - resolveDefaultTokenStyle(id: TokenStyleIdentifier, theme: ITheme, findTokenStyleForScope: (scope: ProbeScope) => TokenStyle | undefined): TokenStyle | undefined; - - /** - * JSON schema for an object to assign TokenStyle values to one of the TokenStyle contributions. - */ - getTokenStyleSchema(): IJSONSchema; - - /** - * JSON schema to for a reference to a TokenStyle contribution. - */ - getTokenStyleReferenceSchema(): IJSONSchema; - -} - - - -class TokenStyleRegistry implements ITokenStyleRegistry { - - private readonly _onDidChangeSchema = new Emitter(); - readonly onDidChangeSchema: Event = this._onDidChangeSchema.event; - - private tokenStyleById: { [key: string]: TokenStyleContribution }; - private tokenStyleSchema: IJSONSchema & { properties: IJSONSchemaMap } = { type: 'object', properties: {} }; - private tokenStyleReferenceSchema: IJSONSchema & { enum: string[], enumDescriptions: string[] } = { type: 'string', enum: [], enumDescriptions: [] }; - - constructor() { - this.tokenStyleById = {}; - } - - public registerTokenStyle(id: string, defaults: TokenStyleDefaults | null, description: string, deprecationMessage?: string): TokenStyleIdentifier { - let tokenStyleContribution: TokenStyleContribution = { id, description, defaults, deprecationMessage }; - this.tokenStyleById[id] = tokenStyleContribution; - let propertySchema: IJSONSchema = { - type: 'object', - description, - properties: { - 'foreground': { type: 'string', format: 'color-hex', default: '#ff0000' }, - 'italic': { type: 'boolean' }, - 'bold': { type: 'boolean' }, - 'underline': { type: 'boolean' } - } - }; - if (deprecationMessage) { - propertySchema.deprecationMessage = deprecationMessage; - } - this.tokenStyleSchema.properties[id] = propertySchema; - this.tokenStyleReferenceSchema.enum.push(id); - this.tokenStyleReferenceSchema.enumDescriptions.push(description); - - this._onDidChangeSchema.fire(); - return id; - } - - - public deregisterTokenStyle(id: string): void { - delete this.tokenStyleById[id]; - delete this.tokenStyleSchema.properties[id]; - const index = this.tokenStyleReferenceSchema.enum.indexOf(id); - if (index !== -1) { - this.tokenStyleReferenceSchema.enum.splice(index, 1); - this.tokenStyleReferenceSchema.enumDescriptions.splice(index, 1); - } - this._onDidChangeSchema.fire(); - } - - public getTokenStyles(): TokenStyleContribution[] { - return Object.keys(this.tokenStyleById).map(id => this.tokenStyleById[id]); - } - - public resolveDefaultTokenStyle(id: TokenStyleIdentifier, theme: ITheme, findTokenStyleForScope: (scope: ProbeScope) => TokenStyle | undefined): TokenStyle | undefined { - const tokenStyleDesc = this.tokenStyleById[id]; - if (tokenStyleDesc && tokenStyleDesc.defaults) { - const scopesToProbe = tokenStyleDesc.defaults.scopesToProbe; - if (scopesToProbe) { - for (let scope of scopesToProbe) { - const style = findTokenStyleForScope(scope); - if (style) { - return style; - } - } - } - const tokenStyleValue = tokenStyleDesc.defaults[theme.type]; - if (tokenStyleValue === null) { - return new TokenStyle(theme.getColor(editorForeground)); - } - return resolveTokenStyleValue(tokenStyleValue, theme); - } - return undefined; - } - - public getTokenStyleSchema(): IJSONSchema { - return this.tokenStyleSchema; - } - - public getTokenStyleReferenceSchema(): IJSONSchema { - return this.tokenStyleReferenceSchema; - } - - public toString() { - let sorter = (a: string, b: string) => { - let cat1 = a.indexOf('.') === -1 ? 0 : 1; - let cat2 = b.indexOf('.') === -1 ? 0 : 1; - if (cat1 !== cat2) { - return cat1 - cat2; - } - return a.localeCompare(b); - }; - - return Object.keys(this.tokenStyleById).sort(sorter).map(k => `- \`${k}\`: ${this.tokenStyleById[k].description}`).join('\n'); - } - -} - -const tokenStyleRegistry = new TokenStyleRegistry(); -platform.Registry.add(Extensions.TokenStyleContribution, tokenStyleRegistry); - -export function registerTokenStyle(id: string, defaults: TokenStyleDefaults | null, description: string, deprecationMessage?: string): TokenStyleIdentifier { - return tokenStyleRegistry.registerTokenStyle(id, defaults, description, deprecationMessage); -} - -export function getTokenStyleRegistry(): ITokenStyleRegistry { - return tokenStyleRegistry; -} - -// colors - - -export const comments = registerTokenStyle('comments', { scopesToProbe: [['comment']], dark: null, light: null, hc: null }, nls.localize('comments', "Token style for comments.")); -export const strings = registerTokenStyle('strings', { scopesToProbe: [['string']], dark: null, light: null, hc: null }, nls.localize('strings', "Token style for strings.")); -export const keywords = registerTokenStyle('keywords', { scopesToProbe: [['keyword.control'], ['storage'], ['storage.type']], dark: null, light: null, hc: null }, nls.localize('keywords', "Token style for keywords.")); -export const numbers = registerTokenStyle('numbers', { scopesToProbe: [['constant.numeric']], dark: null, light: null, hc: null }, nls.localize('numbers', "Token style for numbers.")); -export const types = registerTokenStyle('types', { scopesToProbe: [['entity.name.type'], ['entity.name.class'], ['support.type'], ['support.class']], dark: null, light: null, hc: null }, nls.localize('types', "Token style for types.")); -export const functions = registerTokenStyle('functions', { scopesToProbe: [['entity.name.function'], ['support.function']], dark: null, light: null, hc: null }, nls.localize('functions', "Token style for functions.")); -export const variables = registerTokenStyle('variables', { scopesToProbe: [['variable'], ['entity.name.variable']], dark: null, light: null, hc: null }, nls.localize('variables', "Token style for variables.")); -/* -Tags: local, param, reference, write, async, documentation, overloaded - -Struct - -Type -Class : Type -Interface : Type - -Field : Property -Method : Property -Property - -Variable -Parameter -Const - -Function - -Macro -Operator - -Namespace -Label -Event - -(Emum) - -Operator -Keyword - -literal -string : literal -number : literal -regex: literal - -*/ -/** - * @param colorValue Resolve a color value in the context of a theme - */ -function resolveTokenStyleValue(tokenStyleValue: TokenStyleValue | null, theme: ITheme): TokenStyle | undefined { - if (tokenStyleValue === null) { - return undefined; - } else if (typeof tokenStyleValue === 'string') { - if (tokenStyleValue[0] === '#') { - return TokenStyle.fromString(tokenStyleValue); - } - return theme.getTokenStyle(tokenStyleValue); - } else if (typeof tokenStyleValue === 'object') { - return tokenStyleValue; - } else if (typeof tokenStyleValue === 'function') { - return tokenStyleValue(theme); - } - return undefined; -} - -export const tokenStyleColorsSchemaId = 'vscode://schemas/workbench-tokenstyles'; - -let schemaRegistry = platform.Registry.as(JSONExtensions.JSONContribution); -schemaRegistry.registerSchema(tokenStyleColorsSchemaId, tokenStyleRegistry.getTokenStyleSchema()); - -const delayer = new RunOnceScheduler(() => schemaRegistry.notifySchemaChanged(tokenStyleColorsSchemaId), 200); -tokenStyleRegistry.onDidChangeSchema(() => { - if (!delayer.isScheduled()) { - delayer.schedule(); - } -}); - -// setTimeout(_ => console.log(colorRegistry.toString()), 5000); - - - diff --git a/src/vs/platform/theme/test/common/testThemeService.ts b/src/vs/platform/theme/test/common/testThemeService.ts index e384b45738966..b9279dc39ee88 100644 --- a/src/vs/platform/theme/test/common/testThemeService.ts +++ b/src/vs/platform/theme/test/common/testThemeService.ts @@ -6,7 +6,7 @@ import { Event, Emitter } from 'vs/base/common/event'; import { IThemeService, ITheme, DARK, IIconTheme } from 'vs/platform/theme/common/themeService'; import { Color } from 'vs/base/common/color'; -import { TokenStyle, TokenStyleIdentifier } from 'vs/platform/theme/common/tokenStyleRegistry'; +import { TokenStyle, TokenClassification, ProbeScope } from 'vs/platform/theme/common/tokenClassificationRegistry'; export class TestTheme implements ITheme { @@ -25,8 +25,12 @@ export class TestTheme implements ITheme { throw new Error('Method not implemented.'); } - getTokenStyle(tokenStyleIdentifier: TokenStyleIdentifier, useDefault?: boolean | undefined): TokenStyle | undefined { - return undefined; + getTokenStyle(classification: TokenClassification, useDefault?: boolean | undefined): TokenStyle | undefined { + throw new Error('Method not implemented.'); + } + + resolveScopes(scopes: ProbeScope[]): TokenStyle | undefined { + throw new Error('Method not implemented.'); } } diff --git a/src/vs/workbench/contrib/terminal/test/electron-browser/terminalColorRegistry.test.ts b/src/vs/workbench/contrib/terminal/test/electron-browser/terminalColorRegistry.test.ts index d2d64fa1a2452..1026d3a91a1cb 100644 --- a/src/vs/workbench/contrib/terminal/test/electron-browser/terminalColorRegistry.test.ts +++ b/src/vs/workbench/contrib/terminal/test/electron-browser/terminalColorRegistry.test.ts @@ -9,7 +9,7 @@ import { Registry } from 'vs/platform/registry/common/platform'; import { ansiColorIdentifiers, registerColors } from 'vs/workbench/contrib/terminal/common/terminalColorRegistry'; import { ITheme, ThemeType } from 'vs/platform/theme/common/themeService'; import { Color } from 'vs/base/common/color'; -import { TokenStyleIdentifier } from 'vs/platform/theme/common/tokenStyleRegistry'; +import { TokenClassification } from 'vs/platform/theme/common/tokenClassificationRegistry'; registerColors(); @@ -21,7 +21,7 @@ function getMockTheme(type: ThemeType): ITheme { type: type, getColor: (colorId: ColorIdentifier): Color | undefined => themingRegistry.resolveDefaultColor(colorId, theme), defines: () => true, - getTokenStyle: (tokenStyleId: TokenStyleIdentifier) => undefined + getTokenStyle: (tokenStyleId: TokenClassification) => undefined }; return theme; } diff --git a/src/vs/workbench/services/themes/common/colorThemeData.ts b/src/vs/workbench/services/themes/common/colorThemeData.ts index 4dbdfcc2eff9f..53fa06ef14965 100644 --- a/src/vs/workbench/services/themes/common/colorThemeData.ts +++ b/src/vs/workbench/services/themes/common/colorThemeData.ts @@ -20,12 +20,12 @@ import { URI } from 'vs/base/common/uri'; import { IFileService } from 'vs/platform/files/common/files'; import { parse as parsePList } from 'vs/workbench/services/themes/common/plistParser'; import { startsWith } from 'vs/base/common/strings'; -import { Extensions as TokenStyleRegistryExtensions, TokenStyle, TokenStyleIdentifier, ITokenStyleRegistry, TokenStyleBits, ProbeScope } from 'vs/platform/theme/common/tokenStyleRegistry'; +import { Extensions as TokenStyleRegistryExtensions, TokenStyle, TokenClassification, ITokenClassificationRegistry, ProbeScope, TokenStylingRule } from 'vs/platform/theme/common/tokenClassificationRegistry'; import { MatcherWithPriority, Matcher, createMatchers } from 'vs/workbench/services/themes/common/textMateScopeMatcher'; let colorRegistry = Registry.as(ColorRegistryExtensions.ColorContribution); -let tokenStyleRegistry = Registry.as(TokenStyleRegistryExtensions.TokenStyleContribution); +let tokenClassificationRegistry = Registry.as(TokenStyleRegistryExtensions.TokenClassificationContribution); const tokenGroupToScopesMap = { comments: ['comment'], @@ -37,9 +37,6 @@ const tokenGroupToScopesMap = { variables: ['variable', 'entity.name.variable'] }; -interface ITokenStyleMap { - [id: string]: TokenStyle; -} export class ColorThemeData implements IColorTheme { @@ -57,7 +54,7 @@ export class ColorThemeData implements IColorTheme { private colorMap: IColorMap = {}; private customColorMap: IColorMap = {}; - private tokenStyleMap: ITokenStyleMap = {}; + private tokenStylingRules: TokenStylingRule[] = []; private themeTokenScopeMatchers: Matcher[] | undefined; private customTokenScopeMatchers: Matcher[] | undefined; @@ -116,73 +113,57 @@ export class ColorThemeData implements IColorTheme { return color; } - public getTokenStyle(tokenStyleId: TokenStyleIdentifier, useDefault?: boolean): TokenStyle | undefined { - let style: TokenStyle | undefined = this.tokenStyleMap[tokenStyleId]; - if (style) { - return style; - } - if (useDefault !== false && types.isUndefined(style)) { - style = this.getDefaultTokenStyle(tokenStyleId); - } - return style; + public getTokenStyle(tokenClassification: TokenClassification, useDefault?: boolean): TokenStyle | undefined { + // todo: cache results + return tokenClassificationRegistry.resolveTokenStyle(tokenClassification, this.tokenStylingRules, !!useDefault, this); } public getDefault(colorId: ColorIdentifier): Color | undefined { return colorRegistry.resolveDefaultColor(colorId, this); } - public getDefaultTokenStyle(tokenStyleId: TokenStyleIdentifier): TokenStyle | undefined { - return tokenStyleRegistry.resolveDefaultTokenStyle(tokenStyleId, this, this.findTokenStyleForScope.bind(this)); + public getDefaultTokenStyle(tokenClassification: TokenClassification): TokenStyle | undefined { + return tokenClassificationRegistry.resolveTokenStyle(tokenClassification, [], true, this); } - /** Public for testing reasons */ - public findTokenStyleForScope(scope: ProbeScope): TokenStyle | undefined { - - let foregroundColor = this.getColor(editorForeground); - - let foreground = foregroundColor ? foregroundColor.toString() : null; - let fontStyle: string | null = null; - let foregroundScore = -1; - let fontStyleScore = -1; - - function findTokenStyleForScopeInScopes(scopeMatchers: Matcher[], tokenColors: ITokenColorizationRule[]) { - for (let i = 0; i < scopeMatchers.length; i++) { - const settings = tokenColors[i].settings; - if (!settings) { - continue; - } - let matcher = scopeMatchers[i]; - if (!matcher) { - scopeMatchers[i] = matcher = getScopeMatcher(tokenColors[i]); - } - const score = matcher(scope); - if (score >= 0) { - if (score >= foregroundScore && settings.foreground) { - foreground = settings.foreground; - } - if (score >= fontStyleScore && types.isString(settings.fontStyle)) { - fontStyle = settings.fontStyle; - } - } - - } - } + public resolveScopes(scopes: ProbeScope[]): TokenStyle | undefined { if (!this.themeTokenScopeMatchers) { - this.themeTokenScopeMatchers = new Array(this.themeTokenColors.length); + this.themeTokenScopeMatchers = this.themeTokenColors.map(getScopeMatcher); } - findTokenStyleForScopeInScopes(this.themeTokenScopeMatchers, this.themeTokenColors); - if (!this.customTokenScopeMatchers) { - this.customTokenScopeMatchers = new Array(this.customTokenColors.length); + this.customTokenScopeMatchers = this.customTokenColors.map(getScopeMatcher); } - findTokenStyleForScopeInScopes(this.customTokenScopeMatchers, this.customTokenColors); - return getTokenStyle(foreground, fontStyle); + for (let scope of scopes) { + let foreground: string | null = null; + let fontStyle: string | null = null; + let foregroundScore = -1; + let fontStyleScore = -1; + + function findTokenStyleForScopeInScopes(scopeMatchers: Matcher[], tokenColors: ITokenColorizationRule[]) { + for (let i = 0; i < scopeMatchers.length; i++) { + const score = scopeMatchers[i](scope); + if (score >= 0) { + const settings = tokenColors[i].settings; + if (score >= foregroundScore && settings.foreground) { + foreground = settings.foreground; + } + if (score >= fontStyleScore && types.isString(settings.fontStyle)) { + fontStyle = settings.fontStyle; + } + } + } + } + findTokenStyleForScopeInScopes(this.themeTokenScopeMatchers, this.themeTokenColors); + findTokenStyleForScopeInScopes(this.customTokenScopeMatchers, this.customTokenColors); + if (foreground !== null || fontStyle !== null) { + return getTokenStyle(foreground, fontStyle); + } + } + return undefined; } - - public defines(colorId: ColorIdentifier): boolean { return this.customColorMap.hasOwnProperty(colorId) || this.colorMap.hasOwnProperty(colorId); } @@ -508,12 +489,8 @@ function getScopeMatcher(rule: ITokenColorizationRule): Matcher { return noMatch; } const matchers: MatcherWithPriority[] = []; - if (Array.isArray(ruleScope)) { - for (let rs of ruleScope) { - matchers.push(...createMatchers(rs, nameMatcher)); - } - } else { - matchers.push(...createMatchers(ruleScope, nameMatcher)); + for (let rs of ruleScope) { + matchers.push(...createMatchers(rs, nameMatcher)); } if (matchers.length === 0) { return noMatch; @@ -528,24 +505,16 @@ function getScopeMatcher(rule: ITokenColorizationRule): Matcher { } function getTokenStyle(foreground: string | null, fontStyle: string | null): TokenStyle | undefined { - let styles: number | undefined; let foregroundColor = undefined; if (foreground !== null) { foregroundColor = Color.fromHex(foreground); } - + let bold, underline, italic; if (fontStyle !== null) { - styles = 0; - if (fontStyle.indexOf('underline') !== -1) { - styles |= TokenStyleBits.UNDERLINE; - } - if (fontStyle.indexOf('italic') !== -1) { - styles |= TokenStyleBits.ITALIC; - } - if (fontStyle.indexOf('bold') !== -1) { - styles |= TokenStyleBits.BOLD; - } + bold = fontStyle.indexOf('bold') !== -1; + underline = fontStyle.indexOf('underline') !== -1; + italic = fontStyle.indexOf('italic') !== -1; } - return new TokenStyle(foregroundColor, undefined, styles); + return new TokenStyle(foregroundColor, bold, underline, italic); } diff --git a/src/vs/workbench/services/themes/test/electron-browser/tokenStyleResolving.test.ts b/src/vs/workbench/services/themes/test/electron-browser/tokenStyleResolving.test.ts index 12b9e9102dacc..324a9664a3c91 100644 --- a/src/vs/workbench/services/themes/test/electron-browser/tokenStyleResolving.test.ts +++ b/src/vs/workbench/services/themes/test/electron-browser/tokenStyleResolving.test.ts @@ -6,7 +6,7 @@ import { ColorThemeData } from 'vs/workbench/services/themes/common/colorThemeData'; import * as assert from 'assert'; import { ITokenColorCustomizations } from 'vs/workbench/services/themes/common/workbenchThemeService'; -import { TokenStyle, TokenStyleBits, comments, variables, types, functions, keywords, numbers, strings } from 'vs/platform/theme/common/tokenStyleRegistry'; +import { Extensions as TokenStyleRegistryExtensions, ITokenClassificationRegistry, TokenStyle, comments, variables, types, functions, keywords, numbers, strings } from 'vs/platform/theme/common/tokenClassificationRegistry'; import { Color } from 'vs/base/common/color'; import { isString } from 'vs/base/common/types'; import { FileService } from 'vs/platform/files/common/fileService'; @@ -15,30 +15,59 @@ import { DiskFileSystemProvider } from 'vs/platform/files/node/diskFileSystemPro import { Schemas } from 'vs/base/common/network'; import { URI } from 'vs/base/common/uri'; import { getPathFromAmdModule } from 'vs/base/common/amd'; -import { editorForeground } from 'vs/platform/theme/common/colorRegistry'; +import { Registry } from 'vs/platform/registry/common/platform'; + +let tokenClassificationRegistry = Registry.as(TokenStyleRegistryExtensions.TokenClassificationContribution); + +const enum TokenStyleBits { + BOLD = 0x01, + UNDERLINE = 0x02, + ITALIC = 0x04 +} + function ts(foreground: string | undefined, styleFlags: number | undefined): TokenStyle { const foregroundColor = isString(foreground) ? Color.fromHex(foreground) : undefined; - return new TokenStyle(foregroundColor, undefined, styleFlags); + let bold, underline, italic; + if (styleFlags !== undefined) { + bold = (styleFlags & TokenStyleBits.BOLD) !== 0; + underline = (styleFlags & TokenStyleBits.UNDERLINE) !== 0; + italic = (styleFlags & TokenStyleBits.ITALIC) !== 0; + } + return new TokenStyle(foregroundColor, bold, underline, italic); } function tokenStyleAsString(ts: TokenStyle | undefined | null) { - return ts ? `${ts.foreground ? ts.foreground.toString() : 'no-foreground'}-${ts.styles ? ts.styles : 'no-styles'}` : 'tokenstyle-undefined'; + if (!ts) { + return 'tokenstyle-undefined'; + } + let str = ts.foreground ? ts.foreground.toString() : 'no-foreground'; + if (ts.bold !== undefined) { + str = ts.bold ? '+B' : '-B'; + } + if (ts.underline !== undefined) { + str = ts.underline ? '+U' : '-U'; + } + if (ts.italic !== undefined) { + str = ts.italic ? '+I' : '-I'; + } + return str; } function assertTokenStyle(actual: TokenStyle | undefined | null, expected: TokenStyle | undefined | null, message?: string) { assert.equal(tokenStyleAsString(actual), tokenStyleAsString(expected), message); } -function assertTokenStyles(themeData: ColorThemeData, expected: { [tokenStyleId: string]: TokenStyle }) { - for (let tokenStyleId in expected) { - const tokenStyle = themeData.getTokenStyle(tokenStyleId); - assertTokenStyle(tokenStyle, expected[tokenStyleId], tokenStyleId); +function assertTokenStyles(themeData: ColorThemeData, expected: { [qualifiedClassifier: string]: TokenStyle }) { + for (let qualifiedClassifier in expected) { + const classification = tokenClassificationRegistry.getTokenClassificationFromString(qualifiedClassifier); + assert.ok(classification, 'Classification not found'); + + const tokenStyle = themeData.getTokenStyle(classification!); + assertTokenStyle(tokenStyle, expected[qualifiedClassifier], qualifiedClassifier); } } - - suite('Themes - TokenStyleResolving', () => { const fileService = new FileService(new NullLogService()); const diskFileSystemProvider = new DiskFileSystemProvider(new NullLogService()); @@ -165,7 +194,7 @@ suite('Themes - TokenStyleResolving', () => { }); - test('resolve resource', async () => { + test('resolveScopes', async () => { const themeData = ColorThemeData.createLoadedEmptyTheme('test', 'test'); const customTokenColors: ITokenColorCustomizations = { @@ -210,34 +239,37 @@ suite('Themes - TokenStyleResolving', () => { themeData.setCustomTokenColors(customTokenColors); let tokenStyle; - let defaultTokenStyle = new TokenStyle(themeData.getColor(editorForeground)); + let defaultTokenStyle = undefined; - tokenStyle = themeData.findTokenStyleForScope(['variable']); + tokenStyle = themeData.resolveScopes([['variable']]); assertTokenStyle(tokenStyle, ts('#F8F8F2', 0), 'variable'); - tokenStyle = themeData.findTokenStyleForScope(['keyword.operator']); + tokenStyle = themeData.resolveScopes([['keyword.operator']]); assertTokenStyle(tokenStyle, ts('#F92672', TokenStyleBits.ITALIC | TokenStyleBits.BOLD | TokenStyleBits.UNDERLINE), 'keyword'); - tokenStyle = themeData.findTokenStyleForScope(['keyword']); + tokenStyle = themeData.resolveScopes([['keyword']]); assertTokenStyle(tokenStyle, defaultTokenStyle, 'keyword'); - tokenStyle = themeData.findTokenStyleForScope(['keyword.operator']); + tokenStyle = themeData.resolveScopes([['keyword.operator']]); assertTokenStyle(tokenStyle, ts('#F92672', TokenStyleBits.ITALIC | TokenStyleBits.BOLD | TokenStyleBits.UNDERLINE), 'keyword.operator'); - tokenStyle = themeData.findTokenStyleForScope(['keyword.operators']); + tokenStyle = themeData.resolveScopes([['keyword.operators']]); assertTokenStyle(tokenStyle, defaultTokenStyle, 'keyword.operators'); - tokenStyle = themeData.findTokenStyleForScope(['storage']); + tokenStyle = themeData.resolveScopes([['storage']]); assertTokenStyle(tokenStyle, ts('#F92672', TokenStyleBits.ITALIC), 'storage'); - tokenStyle = themeData.findTokenStyleForScope(['storage.type']); + tokenStyle = themeData.resolveScopes([['storage.type']]); assertTokenStyle(tokenStyle, ts('#66D9EF', TokenStyleBits.ITALIC), 'storage.type'); - tokenStyle = themeData.findTokenStyleForScope(['entity.name.class']); + tokenStyle = themeData.resolveScopes([['entity.name.class']]); assertTokenStyle(tokenStyle, ts('#A6E22E', TokenStyleBits.UNDERLINE), 'entity.name.class'); - tokenStyle = themeData.findTokenStyleForScope(['meta.structure.dictionary.json', 'string.quoted.double.json']); + tokenStyle = themeData.resolveScopes([['meta.structure.dictionary.json', 'string.quoted.double.json']]); assertTokenStyle(tokenStyle, ts('#66D9EF', undefined), 'json property'); + tokenStyle = themeData.resolveScopes([['keyword'], ['storage.type'], ['entity.name.class']]); + assertTokenStyle(tokenStyle, ts('#66D9EF', TokenStyleBits.ITALIC), 'storage.type'); + }); }); From 3ec1475b14e277d5750ae145dc9ad0720c91e649 Mon Sep 17 00:00:00 2001 From: Martin Aeschlimann Date: Fri, 27 Sep 2019 17:22:30 +0200 Subject: [PATCH 009/352] fix missing resolveScopes --- .../standalone/test/browser/standaloneLanguages.test.ts | 2 +- .../test/electron-browser/terminalColorRegistry.test.ts | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/vs/editor/standalone/test/browser/standaloneLanguages.test.ts b/src/vs/editor/standalone/test/browser/standaloneLanguages.test.ts index 4be6f23210767..3cb4e474b1dfd 100644 --- a/src/vs/editor/standalone/test/browser/standaloneLanguages.test.ts +++ b/src/vs/editor/standalone/test/browser/standaloneLanguages.test.ts @@ -57,7 +57,7 @@ suite('TokenizationSupport2Adapter', () => { }, getTokenStyle: () => undefined, - + resolveScopes: () => undefined }; } diff --git a/src/vs/workbench/contrib/terminal/test/electron-browser/terminalColorRegistry.test.ts b/src/vs/workbench/contrib/terminal/test/electron-browser/terminalColorRegistry.test.ts index 1026d3a91a1cb..10cad170f83ec 100644 --- a/src/vs/workbench/contrib/terminal/test/electron-browser/terminalColorRegistry.test.ts +++ b/src/vs/workbench/contrib/terminal/test/electron-browser/terminalColorRegistry.test.ts @@ -9,7 +9,6 @@ import { Registry } from 'vs/platform/registry/common/platform'; import { ansiColorIdentifiers, registerColors } from 'vs/workbench/contrib/terminal/common/terminalColorRegistry'; import { ITheme, ThemeType } from 'vs/platform/theme/common/themeService'; import { Color } from 'vs/base/common/color'; -import { TokenClassification } from 'vs/platform/theme/common/tokenClassificationRegistry'; registerColors(); @@ -21,7 +20,9 @@ function getMockTheme(type: ThemeType): ITheme { type: type, getColor: (colorId: ColorIdentifier): Color | undefined => themingRegistry.resolveDefaultColor(colorId, theme), defines: () => true, - getTokenStyle: (tokenStyleId: TokenClassification) => undefined + getTokenStyle: () => undefined, + resolveScopes: () => undefined + }; return theme; } From 74c44d63a2595c31a6e95f88bf88cdbf0f98a622 Mon Sep 17 00:00:00 2001 From: Martin Aeschlimann Date: Mon, 7 Oct 2019 16:57:52 +0200 Subject: [PATCH 010/352] all types & modifiers --- .../common/tokenClassificationRegistry.ts | 54 ++++++++++++++----- 1 file changed, 42 insertions(+), 12 deletions(-) diff --git a/src/vs/platform/theme/common/tokenClassificationRegistry.ts b/src/vs/platform/theme/common/tokenClassificationRegistry.ts index d1778608f8f7b..9b46ae5cbe115 100644 --- a/src/vs/platform/theme/common/tokenClassificationRegistry.ts +++ b/src/vs/platform/theme/common/tokenClassificationRegistry.ts @@ -314,29 +314,59 @@ function match(themeSelector: TokenStylingRule | TokenStylingDefaultRule, classi const tokenClassificationRegistry = new TokenClassificationRegistry(); platform.Registry.add(Extensions.TokenClassificationContribution, tokenClassificationRegistry); -export function registerTokenType(id: string, defaults: TokenStyleDefaults | null, description: string, deprecationMessage?: string): string { +export function registerTokenType(id: string, description: string, scopesToProbe: ProbeScope[] = [], extendsTC: string | null = null, deprecationMessage?: string): string { tokenClassificationRegistry.registerTokenType(id, description, deprecationMessage); - if (defaults) { + if (scopesToProbe || extendsTC) { const classification = tokenClassificationRegistry.getTokenClassification(id, []); - tokenClassificationRegistry.registerTokenStyleDefault(classification!, defaults); + tokenClassificationRegistry.registerTokenStyleDefault(classification!, { scopesToProbe, light: extendsTC, dark: extendsTC, hc: extendsTC }); } return id; } +export function registerTokenModifier(id: string, description: string, deprecationMessage?: string): string { + tokenClassificationRegistry.registerTokenModifier(id, description, deprecationMessage); + return id; +} + export function getTokenClassificationRegistry(): ITokenClassificationRegistry { return tokenClassificationRegistry; } -export const comments = registerTokenType('comments', { scopesToProbe: [['comment']], dark: null, light: null, hc: null }, nls.localize('comments', "Token style for comments.")); -export const strings = registerTokenType('strings', { scopesToProbe: [['string']], dark: null, light: null, hc: null }, nls.localize('strings', "Token style for strings.")); -export const keywords = registerTokenType('keywords', { scopesToProbe: [['keyword.control'], ['storage'], ['storage.type']], dark: null, light: null, hc: null }, nls.localize('keywords', "Token style for keywords.")); -export const numbers = registerTokenType('numbers', { scopesToProbe: [['constant.numeric']], dark: null, light: null, hc: null }, nls.localize('numbers', "Token style for numbers.")); -export const types = registerTokenType('types', { scopesToProbe: [['entity.name.type'], ['entity.name.class'], ['support.type'], ['support.class']], dark: null, light: null, hc: null }, nls.localize('types', "Token style for types.")); -export const functions = registerTokenType('functions', { scopesToProbe: [['entity.name.function'], ['support.function']], dark: null, light: null, hc: null }, nls.localize('functions', "Token style for functions.")); -export const variables = registerTokenType('variables', { scopesToProbe: [['variable'], ['entity.name.variable']], dark: null, light: null, hc: null }, nls.localize('variables', "Token style for variables.")); - - +export const comments = registerTokenType('comments', nls.localize('comments', "Token style for comments."), [['comment']]); +export const strings = registerTokenType('strings', nls.localize('strings', "Token style for strings."), [['string']]); +export const keywords = registerTokenType('keywords', nls.localize('keywords', "Token style for keywords."), [['keyword.control']]); +export const numbers = registerTokenType('numbers', nls.localize('numbers', "Token style for numbers."), [['constant.numeric']]); +export const regexp = registerTokenType('regexp', nls.localize('regexp', "Token style for regular expressions."), [['constant.regexp']]); +export const operators = registerTokenType('operators', nls.localize('operator', "Token style for operators."), [['keyword.operator']]); + +export const namespaces = registerTokenType('namespaces', nls.localize('namespace', "Token style for namespaces."), [['entity.name.namespace']]); + +export const types = registerTokenType('types', nls.localize('types', "Token style for types."), [['entity.name.type'], ['entity.name.class'], ['support.type'], ['support.class']]); +export const structs = registerTokenType('structs', nls.localize('struct', "Token style for struct."), [['storage.type.struct']], types); +export const classes = registerTokenType('classes', nls.localize('class', "Token style for classes."), [['ntity.name.class']], types); +export const interfaces = registerTokenType('interfaces', nls.localize('interface', "Token style for interfaces."), undefined, types); +export const enums = registerTokenType('enums', nls.localize('enum', "Token style for enums."), undefined, types); +export const parameterTypes = registerTokenType('parameterTypes', nls.localize('parameterType', "Token style for parameterTypes."), undefined, types); + +export const functions = registerTokenType('functions', nls.localize('functions', "Token style for functions."), [['entity.name.function'], ['support.function']]); +export const macros = registerTokenType('macros', nls.localize('macro', "Token style for macros."), undefined, functions); + +export const variables = registerTokenType('variables', nls.localize('variables', "Token style for variables."), [['variable'], ['entity.name.variable']]); +export const constants = registerTokenType('constants', nls.localize('constants', "Token style for constants."), undefined, variables); +export const parameters = registerTokenType('parameters', nls.localize('parameters', "Token style for parameters."), undefined, variables); +export const property = registerTokenType('properties', nls.localize('properties', "Token style for properties."), undefined, variables); + +export const labels = registerTokenType('labels', nls.localize('labels', "Token style for labels."), undefined); + +export const m_declaration = registerTokenModifier('declaration', nls.localize('declaration', "Token modifier for declarations."), undefined); +export const m_documentation = registerTokenModifier('documentation', nls.localize('documentation', "Token modifier for documentation."), undefined); +export const m_member = registerTokenModifier('member', nls.localize('member', "Token modifier for member."), undefined); +export const m_static = registerTokenModifier('static', nls.localize('static', "Token modifier for statics."), undefined); +export const m_abstract = registerTokenModifier('abstract', nls.localize('abstract', "Token modifier for abstracts."), undefined); +export const m_deprecated = registerTokenModifier('deprecated', nls.localize('deprecated', "Token modifier for deprecated."), undefined); +export const m_modification = registerTokenModifier('modification', nls.localize('modification', "Token modifier for modification."), undefined); +export const m_async = registerTokenModifier('async', nls.localize('async', "Token modifier for async."), undefined); function bitCount(u: number) { // https://blogs.msdn.microsoft.com/jeuge/2005/06/08/bit-fiddling-3/ From 65bcaa88af7c244c3dd01572ac19c8d82ca7d99d Mon Sep 17 00:00:00 2001 From: Martin Aeschlimann Date: Mon, 7 Oct 2019 23:05:20 +0200 Subject: [PATCH 011/352] more tests --- .../common/tokenClassificationRegistry.ts | 37 ++++- .../services/themes/common/colorThemeData.ts | 19 ++- .../themes/common/textMateScopeMatcher.ts | 4 +- .../tokenStyleResolving.test.ts | 153 ++++++++++-------- 4 files changed, 130 insertions(+), 83 deletions(-) diff --git a/src/vs/platform/theme/common/tokenClassificationRegistry.ts b/src/vs/platform/theme/common/tokenClassificationRegistry.ts index 9b46ae5cbe115..205f8ba33f27d 100644 --- a/src/vs/platform/theme/common/tokenClassificationRegistry.ts +++ b/src/vs/platform/theme/common/tokenClassificationRegistry.ts @@ -108,6 +108,8 @@ export interface ITokenClassificationRegistry { getTokenClassificationFromString(str: TokenClassificationString): TokenClassification | undefined; getTokenClassification(type: string, modifiers: string[]): TokenClassification | undefined; + getTokenStylingRule(classification: TokenClassification | string | undefined, value: TokenStyle): TokenStylingRule | undefined; + /** * Register a TokenStyle default to the registry. * @param selector The rule selector @@ -197,9 +199,18 @@ class TokenClassificationRegistry implements ITokenClassificationRegistry { return undefined; } + public getTokenStylingRule(classification: TokenClassification | string | undefined, value: TokenStyle): TokenStylingRule | undefined { + if (typeof classification === 'string') { + classification = this.getTokenClassificationFromString(classification); + } + if (classification) { + return { classification, matchScore: getTokenStylingScore(classification), value }; + } + return undefined; + } + public registerTokenStyleDefault(classification: TokenClassification, defaults: TokenStyleDefaults): void { - const matchScore = bitCount(classification.modifiers) + ((classification.type !== TOKEN_TYPE_WILDCARD_NUM) ? 1 : 0); - this.tokenStylingDefaultRules.push({ classification, matchScore, defaults }); + this.tokenStylingDefaultRules.push({ classification, matchScore: getTokenStylingScore(classification), defaults }); } public deregisterTokenType(id: string): void { @@ -233,12 +244,20 @@ class TokenClassificationRegistry implements ITokenClassificationRegistry { }; function _processStyle(matchScore: number, style: TokenStyle) { - for (let p in result) { + if (style.foreground && score.foreground <= matchScore) { + score.foreground = matchScore; + result.foreground = style.foreground; + } + for (let p of ['bold', 'underline', 'italic']) { const property = p as keyof TokenStyle; const info = style[property]; - if (info !== undefined && score[property] <= matchScore) { - score[property] = matchScore; - result[property] = info; + if (info !== undefined) { + if (score[property] < matchScore) { + score[property] = matchScore; + result[property] = info; + } else if (score[property] === matchScore) { + result[property] = result[property] || info; + } } } } @@ -300,7 +319,7 @@ class TokenClassificationRegistry implements ITokenClassificationRegistry { function match(themeSelector: TokenStylingRule | TokenStylingDefaultRule, classification: TokenClassification): number { const selectorType = themeSelector.classification.type; - if (selectorType !== TOKEN_TYPE_WILDCARD_NUM && selectorType === classification.type) { + if (selectorType !== TOKEN_TYPE_WILDCARD_NUM && selectorType !== classification.type) { return -1; } const selectorModifier = themeSelector.classification.modifiers; @@ -373,3 +392,7 @@ function bitCount(u: number) { const uCount = u - ((u >> 1) & 0o33333333333) - ((u >> 2) & 0o11111111111); return ((uCount + (uCount >> 3)) & 0o30707070707) % 63; } + +function getTokenStylingScore(classification: TokenClassification) { + return bitCount(classification.modifiers) + ((classification.type !== TOKEN_TYPE_WILDCARD_NUM) ? 1 : 0); +} diff --git a/src/vs/workbench/services/themes/common/colorThemeData.ts b/src/vs/workbench/services/themes/common/colorThemeData.ts index 53fa06ef14965..7daee34388717 100644 --- a/src/vs/workbench/services/themes/common/colorThemeData.ts +++ b/src/vs/workbench/services/themes/common/colorThemeData.ts @@ -20,12 +20,12 @@ import { URI } from 'vs/base/common/uri'; import { IFileService } from 'vs/platform/files/common/files'; import { parse as parsePList } from 'vs/workbench/services/themes/common/plistParser'; import { startsWith } from 'vs/base/common/strings'; -import { Extensions as TokenStyleRegistryExtensions, TokenStyle, TokenClassification, ITokenClassificationRegistry, ProbeScope, TokenStylingRule } from 'vs/platform/theme/common/tokenClassificationRegistry'; +import { TokenStyle, TokenClassification, ProbeScope, TokenStylingRule, getTokenClassificationRegistry } from 'vs/platform/theme/common/tokenClassificationRegistry'; import { MatcherWithPriority, Matcher, createMatchers } from 'vs/workbench/services/themes/common/textMateScopeMatcher'; let colorRegistry = Registry.as(ColorRegistryExtensions.ColorContribution); -let tokenClassificationRegistry = Registry.as(TokenStyleRegistryExtensions.TokenClassificationContribution); +let tokenClassificationRegistry = getTokenClassificationRegistry(); const tokenGroupToScopesMap = { comments: ['comment'], @@ -115,7 +115,7 @@ export class ColorThemeData implements IColorTheme { public getTokenStyle(tokenClassification: TokenClassification, useDefault?: boolean): TokenStyle | undefined { // todo: cache results - return tokenClassificationRegistry.resolveTokenStyle(tokenClassification, this.tokenStylingRules, !!useDefault, this); + return tokenClassificationRegistry.resolveTokenStyle(tokenClassification, this.tokenStylingRules, useDefault !== false, this); } public getDefault(colorId: ColorIdentifier): Color | undefined { @@ -200,6 +200,10 @@ export class ColorThemeData implements IColorTheme { } } + public setTokenStyleRules(tokenStylingRules: TokenStylingRule[]) { + this.tokenStylingRules = tokenStylingRules; + } + private addCustomTokenColors(customTokenColors: ITokenColorCustomizations) { // Put the general customizations such as comments, strings, etc. first so that // they can be overridden by specific customizations like "string.interpolated" @@ -489,9 +493,14 @@ function getScopeMatcher(rule: ITokenColorizationRule): Matcher { return noMatch; } const matchers: MatcherWithPriority[] = []; - for (let rs of ruleScope) { - matchers.push(...createMatchers(rs, nameMatcher)); + if (Array.isArray(ruleScope)) { + for (let rs of ruleScope) { + createMatchers(rs, nameMatcher, matchers); + } + } else { + createMatchers(ruleScope, nameMatcher, matchers); } + if (matchers.length === 0) { return noMatch; } diff --git a/src/vs/workbench/services/themes/common/textMateScopeMatcher.ts b/src/vs/workbench/services/themes/common/textMateScopeMatcher.ts index 701081bca4ca3..4d1c66adf6fbd 100644 --- a/src/vs/workbench/services/themes/common/textMateScopeMatcher.ts +++ b/src/vs/workbench/services/themes/common/textMateScopeMatcher.ts @@ -14,8 +14,7 @@ export interface Matcher { (matcherInput: T): number; } -export function createMatchers(selector: string, matchesName: (names: string[], matcherInput: T) => number): MatcherWithPriority[] { - const results = []>[]; +export function createMatchers(selector: string, matchesName: (names: string[], matcherInput: T) => number, results: MatcherWithPriority[]): void { const tokenizer = newTokenizer(selector); let token = tokenizer.next(); while (token !== null) { @@ -38,7 +37,6 @@ export function createMatchers(selector: string, matchesName: (names: string[ } token = tokenizer.next(); } - return results; function parseOperand(): Matcher | null { if (token === '-') { diff --git a/src/vs/workbench/services/themes/test/electron-browser/tokenStyleResolving.test.ts b/src/vs/workbench/services/themes/test/electron-browser/tokenStyleResolving.test.ts index 324a9664a3c91..b8956caab0a3b 100644 --- a/src/vs/workbench/services/themes/test/electron-browser/tokenStyleResolving.test.ts +++ b/src/vs/workbench/services/themes/test/electron-browser/tokenStyleResolving.test.ts @@ -6,7 +6,7 @@ import { ColorThemeData } from 'vs/workbench/services/themes/common/colorThemeData'; import * as assert from 'assert'; import { ITokenColorCustomizations } from 'vs/workbench/services/themes/common/workbenchThemeService'; -import { Extensions as TokenStyleRegistryExtensions, ITokenClassificationRegistry, TokenStyle, comments, variables, types, functions, keywords, numbers, strings } from 'vs/platform/theme/common/tokenClassificationRegistry'; +import { TokenStyle, comments, variables, types, functions, keywords, numbers, strings, getTokenClassificationRegistry, TokenStylingRule } from 'vs/platform/theme/common/tokenClassificationRegistry'; import { Color } from 'vs/base/common/color'; import { isString } from 'vs/base/common/types'; import { FileService } from 'vs/platform/files/common/fileService'; @@ -15,26 +15,15 @@ import { DiskFileSystemProvider } from 'vs/platform/files/node/diskFileSystemPro import { Schemas } from 'vs/base/common/network'; import { URI } from 'vs/base/common/uri'; import { getPathFromAmdModule } from 'vs/base/common/amd'; -import { Registry } from 'vs/platform/registry/common/platform'; -let tokenClassificationRegistry = Registry.as(TokenStyleRegistryExtensions.TokenClassificationContribution); +let tokenClassificationRegistry = getTokenClassificationRegistry(); -const enum TokenStyleBits { - BOLD = 0x01, - UNDERLINE = 0x02, - ITALIC = 0x04 -} +const unsetStyle = { bold: false, underline: false, italic: false }; -function ts(foreground: string | undefined, styleFlags: number | undefined): TokenStyle { +function ts(foreground: string | undefined, styleFlags: { bold?: boolean; underline?: boolean; italic?: boolean } | undefined): TokenStyle { const foregroundColor = isString(foreground) ? Color.fromHex(foreground) : undefined; - let bold, underline, italic; - if (styleFlags !== undefined) { - bold = (styleFlags & TokenStyleBits.BOLD) !== 0; - underline = (styleFlags & TokenStyleBits.UNDERLINE) !== 0; - italic = (styleFlags & TokenStyleBits.ITALIC) !== 0; - } - return new TokenStyle(foregroundColor, bold, underline, italic); + return new TokenStyle(foregroundColor, styleFlags && styleFlags.bold, styleFlags && styleFlags.underline, styleFlags && styleFlags.italic); } function tokenStyleAsString(ts: TokenStyle | undefined | null) { @@ -43,17 +32,25 @@ function tokenStyleAsString(ts: TokenStyle | undefined | null) { } let str = ts.foreground ? ts.foreground.toString() : 'no-foreground'; if (ts.bold !== undefined) { - str = ts.bold ? '+B' : '-B'; + str += ts.bold ? '+B' : '-B'; } if (ts.underline !== undefined) { - str = ts.underline ? '+U' : '-U'; + str += ts.underline ? '+U' : '-U'; } if (ts.italic !== undefined) { - str = ts.italic ? '+I' : '-I'; + str += ts.italic ? '+I' : '-I'; } return str; } +function getTokenStyleRules(rules: [string, TokenStyle][]): TokenStylingRule[] { + return rules.map(e => { + const rule = tokenClassificationRegistry.getTokenStylingRule(e[0], e[1]); + assert.ok(rule); + return rule!; + }); +} + function assertTokenStyle(actual: TokenStyle | undefined | null, expected: TokenStyle | undefined | null, message?: string) { assert.equal(tokenStyleAsString(actual), tokenStyleAsString(expected), message); } @@ -69,6 +66,8 @@ function assertTokenStyles(themeData: ColorThemeData, expected: { [qualifiedClas } suite('Themes - TokenStyleResolving', () => { + + const fileService = new FileService(new NullLogService()); const diskFileSystemProvider = new DiskFileSystemProvider(new NullLogService()); fileService.registerProvider(Schemas.file, diskFileSystemProvider); @@ -83,13 +82,13 @@ suite('Themes - TokenStyleResolving', () => { assert.equal(themeData.isLoaded, true); assertTokenStyles(themeData, { - [comments]: ts('#75715E', 0), - [variables]: ts('#F8F8F2', 0), - [types]: ts('#A6E22E', TokenStyleBits.UNDERLINE), - [functions]: ts('#A6E22E', 0), - [strings]: ts('#E6DB74', 0), - [numbers]: ts('#AE81FF', 0), - [keywords]: ts('#F92672', 0) + [comments]: ts('#75715E', unsetStyle), + [variables]: ts('#F8F8F2', unsetStyle), + [types]: ts('#A6E22E', { underline: true, bold: false, italic: false }), + [functions]: ts('#A6E22E', unsetStyle), + [strings]: ts('#E6DB74', unsetStyle), + [numbers]: ts('#AE81FF', unsetStyle), + [keywords]: ts('#F92672', unsetStyle) }); }); @@ -103,13 +102,13 @@ suite('Themes - TokenStyleResolving', () => { assert.equal(themeData.isLoaded, true); assertTokenStyles(themeData, { - [comments]: ts('#6A9955', 0), - [variables]: ts('#9CDCFE', 0), - [types]: ts('#4EC9B0', 0), - [functions]: ts('#DCDCAA', 0), - [strings]: ts('#CE9178', 0), - [numbers]: ts('#B5CEA8', 0), - [keywords]: ts('#C586C0', 0) + [comments]: ts('#6A9955', unsetStyle), + [variables]: ts('#9CDCFE', unsetStyle), + [types]: ts('#4EC9B0', unsetStyle), + [functions]: ts('#DCDCAA', unsetStyle), + [strings]: ts('#CE9178', unsetStyle), + [numbers]: ts('#B5CEA8', unsetStyle), + [keywords]: ts('#C586C0', unsetStyle) }); }); @@ -123,13 +122,13 @@ suite('Themes - TokenStyleResolving', () => { assert.equal(themeData.isLoaded, true); assertTokenStyles(themeData, { - [comments]: ts('#008000', 0), - [variables]: ts('#000000', 0), - [types]: ts('#000000', 0), - [functions]: ts('#000000', 0), - [strings]: ts('#a31515', 0), - [numbers]: ts('#09885a', 0), - [keywords]: ts('#0000ff', 0) + [comments]: ts('#008000', unsetStyle), + [variables]: ts('#000000', unsetStyle), + [types]: ts('#000000', unsetStyle), + [functions]: ts('#000000', unsetStyle), + [strings]: ts('#a31515', unsetStyle), + [numbers]: ts('#09885a', unsetStyle), + [keywords]: ts('#0000ff', unsetStyle) }); }); @@ -143,13 +142,13 @@ suite('Themes - TokenStyleResolving', () => { assert.equal(themeData.isLoaded, true); assertTokenStyles(themeData, { - [comments]: ts('#7ca668', 0), - [variables]: ts('#9CDCFE', 0), - [types]: ts('#4EC9B0', 0), - [functions]: ts('#DCDCAA', 0), - [strings]: ts('#ce9178', 0), - [numbers]: ts('#b5cea8', 0), - [keywords]: ts('#C586C0', 0) + [comments]: ts('#7ca668', unsetStyle), + [variables]: ts('#9CDCFE', unsetStyle), + [types]: ts('#4EC9B0', unsetStyle), + [functions]: ts('#DCDCAA', unsetStyle), + [strings]: ts('#ce9178', unsetStyle), + [numbers]: ts('#b5cea8', unsetStyle), + [keywords]: ts('#C586C0', unsetStyle) }); }); @@ -163,13 +162,13 @@ suite('Themes - TokenStyleResolving', () => { assert.equal(themeData.isLoaded, true); assertTokenStyles(themeData, { - [comments]: ts('#a57a4c', 0), - [variables]: ts('#dc3958', 0), - [types]: ts('#f06431', 0), - [functions]: ts('#8ab1b0', 0), - [strings]: ts('#889b4a', 0), - [numbers]: ts('#f79a32', 0), - [keywords]: ts('#98676a', 0) + [comments]: ts('#a57a4c', unsetStyle), + [variables]: ts('#dc3958', unsetStyle), + [types]: ts('#f06431', unsetStyle), + [functions]: ts('#8ab1b0', unsetStyle), + [strings]: ts('#889b4a', unsetStyle), + [numbers]: ts('#f79a32', unsetStyle), + [keywords]: ts('#98676a', unsetStyle) }); }); @@ -183,13 +182,13 @@ suite('Themes - TokenStyleResolving', () => { assert.equal(themeData.isLoaded, true); assertTokenStyles(themeData, { - [comments]: ts('#384887', 0), - [variables]: ts('#6688cc', 0), - [types]: ts('#ffeebb', TokenStyleBits.UNDERLINE), - [functions]: ts('#ddbb88', 0), - [strings]: ts('#22aa44', 0), - [numbers]: ts('#f280d0', 0), - [keywords]: ts('#225588', 0) + [comments]: ts('#384887', unsetStyle), + [variables]: ts('#6688cc', unsetStyle), + [types]: ts('#ffeebb', { underline: true, bold: false, italic: false }), + [functions]: ts('#ddbb88', unsetStyle), + [strings]: ts('#22aa44', unsetStyle), + [numbers]: ts('#f280d0', unsetStyle), + [keywords]: ts('#225588', unsetStyle) }); }); @@ -242,34 +241,52 @@ suite('Themes - TokenStyleResolving', () => { let defaultTokenStyle = undefined; tokenStyle = themeData.resolveScopes([['variable']]); - assertTokenStyle(tokenStyle, ts('#F8F8F2', 0), 'variable'); + assertTokenStyle(tokenStyle, ts('#F8F8F2', unsetStyle), 'variable'); tokenStyle = themeData.resolveScopes([['keyword.operator']]); - assertTokenStyle(tokenStyle, ts('#F92672', TokenStyleBits.ITALIC | TokenStyleBits.BOLD | TokenStyleBits.UNDERLINE), 'keyword'); + assertTokenStyle(tokenStyle, ts('#F92672', { italic: true, bold: true, underline: true }), 'keyword'); tokenStyle = themeData.resolveScopes([['keyword']]); assertTokenStyle(tokenStyle, defaultTokenStyle, 'keyword'); tokenStyle = themeData.resolveScopes([['keyword.operator']]); - assertTokenStyle(tokenStyle, ts('#F92672', TokenStyleBits.ITALIC | TokenStyleBits.BOLD | TokenStyleBits.UNDERLINE), 'keyword.operator'); + assertTokenStyle(tokenStyle, ts('#F92672', { italic: true, bold: true, underline: true }), 'keyword.operator'); tokenStyle = themeData.resolveScopes([['keyword.operators']]); assertTokenStyle(tokenStyle, defaultTokenStyle, 'keyword.operators'); tokenStyle = themeData.resolveScopes([['storage']]); - assertTokenStyle(tokenStyle, ts('#F92672', TokenStyleBits.ITALIC), 'storage'); + assertTokenStyle(tokenStyle, ts('#F92672', { italic: true, underline: false, bold: false }), 'storage'); tokenStyle = themeData.resolveScopes([['storage.type']]); - assertTokenStyle(tokenStyle, ts('#66D9EF', TokenStyleBits.ITALIC), 'storage.type'); + assertTokenStyle(tokenStyle, ts('#66D9EF', { italic: true, underline: false, bold: false }), 'storage.type'); tokenStyle = themeData.resolveScopes([['entity.name.class']]); - assertTokenStyle(tokenStyle, ts('#A6E22E', TokenStyleBits.UNDERLINE), 'entity.name.class'); + assertTokenStyle(tokenStyle, ts('#A6E22E', { underline: true, italic: false, bold: false }), 'entity.name.class'); tokenStyle = themeData.resolveScopes([['meta.structure.dictionary.json', 'string.quoted.double.json']]); assertTokenStyle(tokenStyle, ts('#66D9EF', undefined), 'json property'); tokenStyle = themeData.resolveScopes([['keyword'], ['storage.type'], ['entity.name.class']]); - assertTokenStyle(tokenStyle, ts('#66D9EF', TokenStyleBits.ITALIC), 'storage.type'); + assertTokenStyle(tokenStyle, ts('#66D9EF', { italic: true, underline: false, bold: false }), 'storage.type'); + + }); + + test('rule matching', async () => { + const themeData = ColorThemeData.createLoadedEmptyTheme('test', 'test'); + themeData.setCustomColors({ 'editor.foreground': '#000000' }); + themeData.setTokenStyleRules(getTokenStyleRules([ + ['types', ts('#ff0000', undefined)], + ['classes', ts('#0000ff', undefined)], + ['*.static', ts(undefined, { bold: true })], + ['*.declaration', ts(undefined, { italic: true })] + ])); + + assertTokenStyles(themeData, { + 'types': ts('#ff0000', unsetStyle), + 'types.static': ts('#ff0000', { bold: true, italic: false, underline: false }), + 'types.static.declaration': ts('#ff0000', { bold: true, italic: true, underline: false }) + }); }); }); From 4003b647509dc1921c944697efef2c6ac157ba6e Mon Sep 17 00:00:00 2001 From: gjsjohnmurray Date: Mon, 28 Oct 2019 10:27:38 +0000 Subject: [PATCH 012/352] Resolve https://github.com/microsoft/vscode/issues/83139 --- src/vs/workbench/contrib/search/browser/search.contribution.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/search/browser/search.contribution.ts b/src/vs/workbench/contrib/search/browser/search.contribution.ts index 697ceeb031ad2..0ff6040727190 100644 --- a/src/vs/workbench/contrib/search/browser/search.contribution.ts +++ b/src/vs/workbench/contrib/search/browser/search.contribution.ts @@ -333,7 +333,7 @@ CommandsRegistry.registerCommand({ const RevealInSideBarForSearchResultsCommand: ICommandAction = { id: Constants.RevealInSideBarForSearchResults, - title: nls.localize('revealInSideBar', "Reveal in Explorer") + title: nls.localize('revealInSideBar', "Reveal in Side Bar") }; MenuRegistry.appendMenuItem(MenuId.SearchContext, { From 18f1aea54c10efcc6ae7ab65bb6b7b74da10142b Mon Sep 17 00:00:00 2001 From: jeanp413 Date: Mon, 4 Nov 2019 20:58:19 -0500 Subject: [PATCH 013/352] Fixes #83264 --- src/vs/workbench/contrib/debug/browser/linkDetector.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/debug/browser/linkDetector.ts b/src/vs/workbench/contrib/debug/browser/linkDetector.ts index baca730b769b1..0d1152234200e 100644 --- a/src/vs/workbench/contrib/debug/browser/linkDetector.ts +++ b/src/vs/workbench/contrib/debug/browser/linkDetector.ts @@ -142,7 +142,7 @@ export class LinkDetector { private decorateLink(link: HTMLElement, onclick: () => void) { link.classList.add('link'); link.title = platform.isMacintosh ? nls.localize('fileLinkMac', "Cmd + click to follow link") : nls.localize('fileLink', "Ctrl + click to follow link"); - link.onmousemove = (event) => link.classList.toggle('pointer', platform.isMacintosh ? event.metaKey : event.ctrlKey); + link.onmousemove = (event) => { link.classList.toggle('pointer', platform.isMacintosh ? event.metaKey : event.ctrlKey); }; link.onmouseleave = () => link.classList.remove('pointer'); link.onclick = (event) => { const selection = window.getSelection(); From 5b6f03e8c69e04c8e3cf823eba563f73f1f65107 Mon Sep 17 00:00:00 2001 From: Martin Aeschlimann Date: Wed, 6 Nov 2019 11:56:05 +0100 Subject: [PATCH 014/352] adopt merge --- .../extensionResourceLoaderService.ts | 2 +- .../tokenStyleResolving.test.ts | 17 ++++++++++------- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/src/vs/workbench/services/extensionResourceLoader/electron-browser/extensionResourceLoaderService.ts b/src/vs/workbench/services/extensionResourceLoader/electron-browser/extensionResourceLoaderService.ts index 2acf10e0b5353..744f2860788e6 100644 --- a/src/vs/workbench/services/extensionResourceLoader/electron-browser/extensionResourceLoaderService.ts +++ b/src/vs/workbench/services/extensionResourceLoader/electron-browser/extensionResourceLoaderService.ts @@ -8,7 +8,7 @@ import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { IFileService } from 'vs/platform/files/common/files'; import { IExtensionResourceLoaderService } from 'vs/workbench/services/extensionResourceLoader/common/extensionResourceLoader'; -class ExtensionResourceLoaderService implements IExtensionResourceLoaderService { +export class ExtensionResourceLoaderService implements IExtensionResourceLoaderService { _serviceBrand: undefined; diff --git a/src/vs/workbench/services/themes/test/electron-browser/tokenStyleResolving.test.ts b/src/vs/workbench/services/themes/test/electron-browser/tokenStyleResolving.test.ts index b8956caab0a3b..6c0d9af598c3e 100644 --- a/src/vs/workbench/services/themes/test/electron-browser/tokenStyleResolving.test.ts +++ b/src/vs/workbench/services/themes/test/electron-browser/tokenStyleResolving.test.ts @@ -15,6 +15,7 @@ import { DiskFileSystemProvider } from 'vs/platform/files/node/diskFileSystemPro import { Schemas } from 'vs/base/common/network'; import { URI } from 'vs/base/common/uri'; import { getPathFromAmdModule } from 'vs/base/common/amd'; +import { ExtensionResourceLoaderService } from 'vs/workbench/services/extensionResourceLoader/electron-browser/extensionResourceLoaderService'; let tokenClassificationRegistry = getTokenClassificationRegistry(); @@ -69,6 +70,8 @@ suite('Themes - TokenStyleResolving', () => { const fileService = new FileService(new NullLogService()); + const extensionResourceLoaderService = new ExtensionResourceLoaderService(fileService); + const diskFileSystemProvider = new DiskFileSystemProvider(new NullLogService()); fileService.registerProvider(Schemas.file, diskFileSystemProvider); @@ -77,12 +80,12 @@ suite('Themes - TokenStyleResolving', () => { const themeData = ColorThemeData.createUnloadedTheme('foo'); const themeLocation = getPathFromAmdModule(require, '../../../../../../../extensions/theme-monokai/themes/monokai-color-theme.json'); themeData.location = URI.file(themeLocation); - await themeData.ensureLoaded(fileService); + await themeData.ensureLoaded(extensionResourceLoaderService); assert.equal(themeData.isLoaded, true); assertTokenStyles(themeData, { - [comments]: ts('#75715E', unsetStyle), + [comments]: ts('#88846f', unsetStyle), [variables]: ts('#F8F8F2', unsetStyle), [types]: ts('#A6E22E', { underline: true, bold: false, italic: false }), [functions]: ts('#A6E22E', unsetStyle), @@ -97,7 +100,7 @@ suite('Themes - TokenStyleResolving', () => { const themeData = ColorThemeData.createUnloadedTheme('foo'); const themeLocation = getPathFromAmdModule(require, '../../../../../../../extensions/theme-defaults/themes/dark_plus.json'); themeData.location = URI.file(themeLocation); - await themeData.ensureLoaded(fileService); + await themeData.ensureLoaded(extensionResourceLoaderService); assert.equal(themeData.isLoaded, true); @@ -117,7 +120,7 @@ suite('Themes - TokenStyleResolving', () => { const themeData = ColorThemeData.createUnloadedTheme('foo'); const themeLocation = getPathFromAmdModule(require, '../../../../../../../extensions/theme-defaults/themes/light_vs.json'); themeData.location = URI.file(themeLocation); - await themeData.ensureLoaded(fileService); + await themeData.ensureLoaded(extensionResourceLoaderService); assert.equal(themeData.isLoaded, true); @@ -137,7 +140,7 @@ suite('Themes - TokenStyleResolving', () => { const themeData = ColorThemeData.createUnloadedTheme('foo'); const themeLocation = getPathFromAmdModule(require, '../../../../../../../extensions/theme-defaults/themes/hc_black.json'); themeData.location = URI.file(themeLocation); - await themeData.ensureLoaded(fileService); + await themeData.ensureLoaded(extensionResourceLoaderService); assert.equal(themeData.isLoaded, true); @@ -157,7 +160,7 @@ suite('Themes - TokenStyleResolving', () => { const themeData = ColorThemeData.createUnloadedTheme('foo'); const themeLocation = getPathFromAmdModule(require, '../../../../../../../extensions/theme-kimbie-dark/themes/kimbie-dark-color-theme.json'); themeData.location = URI.file(themeLocation); - await themeData.ensureLoaded(fileService); + await themeData.ensureLoaded(extensionResourceLoaderService); assert.equal(themeData.isLoaded, true); @@ -177,7 +180,7 @@ suite('Themes - TokenStyleResolving', () => { const themeData = ColorThemeData.createUnloadedTheme('foo'); const themeLocation = getPathFromAmdModule(require, '../../../../../../../extensions/theme-abyss/themes/abyss-color-theme.json'); themeData.location = URI.file(themeLocation); - await themeData.ensureLoaded(fileService); + await themeData.ensureLoaded(extensionResourceLoaderService); assert.equal(themeData.isLoaded, true); From a9de2f33c3c8b44c6b4dc74e18c5dcff81e16653 Mon Sep 17 00:00:00 2001 From: Martin Aeschlimann Date: Thu, 7 Nov 2019 17:10:45 +0100 Subject: [PATCH 015/352] keep unset attributes as undefined --- .../common/tokenClassificationRegistry.ts | 30 +++--- .../tokenStyleResolving.test.ts | 93 ++++++++++--------- 2 files changed, 63 insertions(+), 60 deletions(-) diff --git a/src/vs/platform/theme/common/tokenClassificationRegistry.ts b/src/vs/platform/theme/common/tokenClassificationRegistry.ts index 205f8ba33f27d..7817b7a577832 100644 --- a/src/vs/platform/theme/common/tokenClassificationRegistry.ts +++ b/src/vs/platform/theme/common/tokenClassificationRegistry.ts @@ -8,8 +8,6 @@ import { Color } from 'vs/base/common/color'; import { ITheme } from 'vs/platform/theme/common/themeService'; import * as nls from 'vs/nls'; -import { editorForeground } from 'vs/platform/theme/common/colorRegistry'; - // ------ API types export const TOKEN_TYPE_WILDCARD = '*'; @@ -231,10 +229,10 @@ class TokenClassificationRegistry implements ITokenClassificationRegistry { public resolveTokenStyle(classification: TokenClassification, themingRules: TokenStylingRule[], useDefault: boolean, theme: ITheme): TokenStyle | undefined { let result: any = { - foreground: theme.getColor(editorForeground), - bold: false, - underline: false, - italic: false + foreground: undefined, + bold: undefined, + underline: undefined, + italic: undefined }; let score = { foreground: -1, @@ -252,23 +250,15 @@ class TokenClassificationRegistry implements ITokenClassificationRegistry { const property = p as keyof TokenStyle; const info = style[property]; if (info !== undefined) { - if (score[property] < matchScore) { + if (score[property] <= matchScore) { score[property] = matchScore; result[property] = info; - } else if (score[property] === matchScore) { - result[property] = result[property] || info; } } } } - themingRules.forEach(rule => { - const matchScore = match(rule, classification); - if (matchScore >= 0) { - _processStyle(matchScore, rule.value); - } - }); if (useDefault) { - this.tokenStylingDefaultRules.forEach(rule => { + for (const rule of this.tokenStylingDefaultRules) { const matchScore = match(rule, classification); if (matchScore >= 0) { let style = theme.resolveScopes(rule.defaults.scopesToProbe); @@ -279,7 +269,13 @@ class TokenClassificationRegistry implements ITokenClassificationRegistry { _processStyle(matchScore, style); } } - }); + } + } + for (const rule of themingRules) { + const matchScore = match(rule, classification); + if (matchScore >= 0) { + _processStyle(matchScore, rule.value); + } } return TokenStyle.fromData(result); } diff --git a/src/vs/workbench/services/themes/test/electron-browser/tokenStyleResolving.test.ts b/src/vs/workbench/services/themes/test/electron-browser/tokenStyleResolving.test.ts index 6c0d9af598c3e..a0fe30b868356 100644 --- a/src/vs/workbench/services/themes/test/electron-browser/tokenStyleResolving.test.ts +++ b/src/vs/workbench/services/themes/test/electron-browser/tokenStyleResolving.test.ts @@ -19,9 +19,9 @@ import { ExtensionResourceLoaderService } from 'vs/workbench/services/extensionR let tokenClassificationRegistry = getTokenClassificationRegistry(); +const undefinedStyle = { bold: undefined, underline: undefined, italic: undefined }; const unsetStyle = { bold: false, underline: false, italic: false }; - function ts(foreground: string | undefined, styleFlags: { bold?: boolean; underline?: boolean; italic?: boolean } | undefined): TokenStyle { const foregroundColor = isString(foreground) ? Color.fromHex(foreground) : undefined; return new TokenStyle(foregroundColor, styleFlags && styleFlags.bold, styleFlags && styleFlags.underline, styleFlags && styleFlags.italic); @@ -85,13 +85,13 @@ suite('Themes - TokenStyleResolving', () => { assert.equal(themeData.isLoaded, true); assertTokenStyles(themeData, { - [comments]: ts('#88846f', unsetStyle), + [comments]: ts('#88846f', undefinedStyle), [variables]: ts('#F8F8F2', unsetStyle), [types]: ts('#A6E22E', { underline: true, bold: false, italic: false }), [functions]: ts('#A6E22E', unsetStyle), - [strings]: ts('#E6DB74', unsetStyle), - [numbers]: ts('#AE81FF', unsetStyle), - [keywords]: ts('#F92672', unsetStyle) + [strings]: ts('#E6DB74', undefinedStyle), + [numbers]: ts('#AE81FF', undefinedStyle), + [keywords]: ts('#F92672', undefinedStyle) }); }); @@ -105,13 +105,13 @@ suite('Themes - TokenStyleResolving', () => { assert.equal(themeData.isLoaded, true); assertTokenStyles(themeData, { - [comments]: ts('#6A9955', unsetStyle), - [variables]: ts('#9CDCFE', unsetStyle), - [types]: ts('#4EC9B0', unsetStyle), - [functions]: ts('#DCDCAA', unsetStyle), - [strings]: ts('#CE9178', unsetStyle), - [numbers]: ts('#B5CEA8', unsetStyle), - [keywords]: ts('#C586C0', unsetStyle) + [comments]: ts('#6A9955', undefinedStyle), + [variables]: ts('#9CDCFE', undefinedStyle), + [types]: ts('#4EC9B0', undefinedStyle), + [functions]: ts('#DCDCAA', undefinedStyle), + [strings]: ts('#CE9178', undefinedStyle), + [numbers]: ts('#B5CEA8', undefinedStyle), + [keywords]: ts('#C586C0', undefinedStyle) }); }); @@ -125,13 +125,13 @@ suite('Themes - TokenStyleResolving', () => { assert.equal(themeData.isLoaded, true); assertTokenStyles(themeData, { - [comments]: ts('#008000', unsetStyle), - [variables]: ts('#000000', unsetStyle), - [types]: ts('#000000', unsetStyle), - [functions]: ts('#000000', unsetStyle), - [strings]: ts('#a31515', unsetStyle), - [numbers]: ts('#09885a', unsetStyle), - [keywords]: ts('#0000ff', unsetStyle) + [comments]: ts('#008000', undefinedStyle), + [variables]: ts(undefined, undefinedStyle), + [types]: ts(undefined, undefinedStyle), + [functions]: ts(undefined, undefinedStyle), + [strings]: ts('#a31515', undefinedStyle), + [numbers]: ts('#09885a', undefinedStyle), + [keywords]: ts('#0000ff', undefinedStyle) }); }); @@ -145,13 +145,13 @@ suite('Themes - TokenStyleResolving', () => { assert.equal(themeData.isLoaded, true); assertTokenStyles(themeData, { - [comments]: ts('#7ca668', unsetStyle), - [variables]: ts('#9CDCFE', unsetStyle), - [types]: ts('#4EC9B0', unsetStyle), - [functions]: ts('#DCDCAA', unsetStyle), - [strings]: ts('#ce9178', unsetStyle), - [numbers]: ts('#b5cea8', unsetStyle), - [keywords]: ts('#C586C0', unsetStyle) + [comments]: ts('#7ca668', undefinedStyle), + [variables]: ts('#9CDCFE', undefinedStyle), + [types]: ts('#4EC9B0', undefinedStyle), + [functions]: ts('#DCDCAA', undefinedStyle), + [strings]: ts('#ce9178', undefinedStyle), + [numbers]: ts('#b5cea8', undefinedStyle), + [keywords]: ts('#C586C0', undefinedStyle) }); }); @@ -165,13 +165,13 @@ suite('Themes - TokenStyleResolving', () => { assert.equal(themeData.isLoaded, true); assertTokenStyles(themeData, { - [comments]: ts('#a57a4c', unsetStyle), - [variables]: ts('#dc3958', unsetStyle), - [types]: ts('#f06431', unsetStyle), - [functions]: ts('#8ab1b0', unsetStyle), - [strings]: ts('#889b4a', unsetStyle), - [numbers]: ts('#f79a32', unsetStyle), - [keywords]: ts('#98676a', unsetStyle) + [comments]: ts('#a57a4c', undefinedStyle), + [variables]: ts('#dc3958', undefinedStyle), + [types]: ts('#f06431', undefinedStyle), + [functions]: ts('#8ab1b0', undefinedStyle), + [strings]: ts('#889b4a', undefinedStyle), + [numbers]: ts('#f79a32', undefinedStyle), + [keywords]: ts('#98676a', undefinedStyle) }); }); @@ -185,13 +185,13 @@ suite('Themes - TokenStyleResolving', () => { assert.equal(themeData.isLoaded, true); assertTokenStyles(themeData, { - [comments]: ts('#384887', unsetStyle), - [variables]: ts('#6688cc', unsetStyle), + [comments]: ts('#384887', undefinedStyle), + [variables]: ts(undefined, unsetStyle), [types]: ts('#ffeebb', { underline: true, bold: false, italic: false }), [functions]: ts('#ddbb88', unsetStyle), - [strings]: ts('#22aa44', unsetStyle), - [numbers]: ts('#f280d0', unsetStyle), - [keywords]: ts('#225588', unsetStyle) + [strings]: ts('#22aa44', undefinedStyle), + [numbers]: ts('#f280d0', undefinedStyle), + [keywords]: ts('#225588', undefinedStyle) }); }); @@ -280,15 +280,22 @@ suite('Themes - TokenStyleResolving', () => { themeData.setCustomColors({ 'editor.foreground': '#000000' }); themeData.setTokenStyleRules(getTokenStyleRules([ ['types', ts('#ff0000', undefined)], - ['classes', ts('#0000ff', undefined)], + ['classes', ts('#0000ff', { italic: true })], ['*.static', ts(undefined, { bold: true })], - ['*.declaration', ts(undefined, { italic: true })] + ['*.declaration', ts(undefined, { italic: true })], + ['*.async.static', ts('#00ffff', { bold: false, underline: true })], + ['*.async', ts('#000fff', { italic: false, underline: true })] ])); assertTokenStyles(themeData, { - 'types': ts('#ff0000', unsetStyle), - 'types.static': ts('#ff0000', { bold: true, italic: false, underline: false }), - 'types.static.declaration': ts('#ff0000', { bold: true, italic: true, underline: false }) + 'types': ts('#ff0000', undefinedStyle), + 'types.static': ts('#ff0000', { bold: true, italic: undefined, underline: undefined }), + 'types.static.declaration': ts('#ff0000', { bold: true, italic: true, underline: undefined }), + 'classes': ts('#0000ff', { bold: undefined, italic: true, underline: undefined }), + 'classes.static.declaration': ts('#0000ff', { bold: true, italic: true, underline: undefined }), + 'classes.declaration': ts('#0000ff', { bold: undefined, italic: true, underline: undefined }), + 'classes.declaration.async': ts('#000fff', { bold: undefined, italic: false, underline: true }), + 'classes.declaration.async.static': ts('#00ffff', { bold: false, italic: false, underline: true }), }); }); From a5fe35b780b9ed7356f54c5fe14e447a0cf1833c Mon Sep 17 00:00:00 2001 From: Martin Aeschlimann Date: Fri, 8 Nov 2019 11:27:51 +0100 Subject: [PATCH 016/352] No longer preselected color in colorCustomizations. Fixes #84152 --- src/vs/platform/theme/common/colorRegistry.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/platform/theme/common/colorRegistry.ts b/src/vs/platform/theme/common/colorRegistry.ts index 89c695d2deee7..4c3093b823dcd 100644 --- a/src/vs/platform/theme/common/colorRegistry.ts +++ b/src/vs/platform/theme/common/colorRegistry.ts @@ -103,7 +103,7 @@ class ColorRegistry implements IColorRegistry { public registerColor(id: string, defaults: ColorDefaults | null, description: string, needsTransparency = false, deprecationMessage?: string): ColorIdentifier { let colorContribution: ColorContribution = { id, description, defaults, needsTransparency, deprecationMessage }; this.colorsById[id] = colorContribution; - let propertySchema: IJSONSchema = { type: 'string', description, format: 'color-hex', defaultSnippets: [{ body: '#ff0000' }] }; + let propertySchema: IJSONSchema = { type: 'string', description, format: 'color-hex', defaultSnippets: [{ body: '${1:#ff0000}' }] }; if (deprecationMessage) { propertySchema.deprecationMessage = deprecationMessage; } From 6b43b2cb5e5118a5246e8fd29feb1976fbeea264 Mon Sep 17 00:00:00 2001 From: Miguel Solorio Date: Fri, 8 Nov 2019 14:43:12 -0800 Subject: [PATCH 017/352] Update breakpoints to codicons --- .../editor/browser/viewParts/glyphMargin/glyphMargin.ts | 2 +- src/vs/workbench/contrib/debug/browser/breakpointsView.ts | 8 ++++---- .../extensions/browser/media/extensionsViewlet.css | 1 + test/automation/src/debug.ts | 2 +- 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/vs/editor/browser/viewParts/glyphMargin/glyphMargin.ts b/src/vs/editor/browser/viewParts/glyphMargin/glyphMargin.ts index 494b7d7ca233e..0cdd9c61cc2ed 100644 --- a/src/vs/editor/browser/viewParts/glyphMargin/glyphMargin.ts +++ b/src/vs/editor/browser/viewParts/glyphMargin/glyphMargin.ts @@ -177,7 +177,7 @@ export class GlyphMarginOverlay extends DedupOverlay { output[lineIndex] = ''; } else { output[lineIndex] = ( - '
.extensions .extension > .details > .header-container > .header .codicon { font-size: 120%; margin-right: 2px; + -webkit-mask: inherit; } .extensions-viewlet > .extensions .extension > .details > .header-container > .header > .ratings { diff --git a/test/automation/src/debug.ts b/test/automation/src/debug.ts index 2dc548e5cb32f..ec6678bb780ab 100644 --- a/test/automation/src/debug.ts +++ b/test/automation/src/debug.ts @@ -19,7 +19,7 @@ const STEP_IN = `.debug-toolbar .action-label[title*="Step Into"]`; const STEP_OUT = `.debug-toolbar .action-label[title*="Step Out"]`; const CONTINUE = `.debug-toolbar .action-label[title*="Continue"]`; const GLYPH_AREA = '.margin-view-overlays>:nth-child'; -const BREAKPOINT_GLYPH = '.debug-breakpoint'; +const BREAKPOINT_GLYPH = '.codicon-circle-filled'; const PAUSE = `.debug-toolbar .action-label[title*="Pause"]`; const DEBUG_STATUS_BAR = `.statusbar.debugging`; const NOT_DEBUG_STATUS_BAR = `.statusbar:not(debugging)`; From d0bc95278143374d10c5a10151a78e1cb5d9b52a Mon Sep 17 00:00:00 2001 From: okmttdhr <10101114fin@gmail.com> Date: Wed, 6 Nov 2019 21:29:15 +0900 Subject: [PATCH 018/352] Add builder-method for snippet choice --- src/vs/workbench/api/common/extHostTypes.ts | 6 ++++++ .../test/electron-browser/api/extHostTypes.test.ts | 7 +++++++ 2 files changed, 13 insertions(+) diff --git a/src/vs/workbench/api/common/extHostTypes.ts b/src/vs/workbench/api/common/extHostTypes.ts index 158fe11fda7e7..68cd2ab3ce125 100644 --- a/src/vs/workbench/api/common/extHostTypes.ts +++ b/src/vs/workbench/api/common/extHostTypes.ts @@ -740,6 +740,12 @@ export class SnippetString { return this; } + appendChoice(values: string[], number?: number): SnippetString { + this.appendPlaceholder(values.toString(), number) + this.value = this.value.replace(/:/g, '|').replace(/}/g, '|}') + return this; + } + appendVariable(name: string, defaultValue?: string | ((snippet: SnippetString) => any)): SnippetString { if (typeof defaultValue === 'function') { diff --git a/src/vs/workbench/test/electron-browser/api/extHostTypes.test.ts b/src/vs/workbench/test/electron-browser/api/extHostTypes.test.ts index f33a4d5f6e68e..f4b734b886351 100644 --- a/src/vs/workbench/test/electron-browser/api/extHostTypes.test.ts +++ b/src/vs/workbench/test/electron-browser/api/extHostTypes.test.ts @@ -527,6 +527,13 @@ suite('ExtHostTypes', function () { string.appendVariable('BAR', b => { }); assert.equal(string.value, '${BAR}'); + string = new types.SnippetString(); + string.appendChoice(['b', 'a', 'r']) + assert.equal(string.value, '${1|b,a,r|}'); + + string = new types.SnippetString(); + string.appendChoice(['b', 'a', 'r'], 0) + assert.equal(string.value, '${0|b,a,r|}'); }); test('instanceof doesn\'t work for FileSystemError #49386', function () { From 6378c89efd01858c94ef1a6371b5f4ef99c97edd Mon Sep 17 00:00:00 2001 From: okmttdhr <10101114fin@gmail.com> Date: Wed, 6 Nov 2019 22:08:09 +0900 Subject: [PATCH 019/352] Fix lint warnings --- src/vs/workbench/api/common/extHostTypes.ts | 4 ++-- .../workbench/test/electron-browser/api/extHostTypes.test.ts | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/vs/workbench/api/common/extHostTypes.ts b/src/vs/workbench/api/common/extHostTypes.ts index 68cd2ab3ce125..ed3c22a07abd2 100644 --- a/src/vs/workbench/api/common/extHostTypes.ts +++ b/src/vs/workbench/api/common/extHostTypes.ts @@ -741,8 +741,8 @@ export class SnippetString { } appendChoice(values: string[], number?: number): SnippetString { - this.appendPlaceholder(values.toString(), number) - this.value = this.value.replace(/:/g, '|').replace(/}/g, '|}') + this.appendPlaceholder(values.toString(), number); + this.value = this.value.replace(/:/g, '|').replace(/}/g, '|}'); return this; } diff --git a/src/vs/workbench/test/electron-browser/api/extHostTypes.test.ts b/src/vs/workbench/test/electron-browser/api/extHostTypes.test.ts index f4b734b886351..7a37f9fccdab7 100644 --- a/src/vs/workbench/test/electron-browser/api/extHostTypes.test.ts +++ b/src/vs/workbench/test/electron-browser/api/extHostTypes.test.ts @@ -528,11 +528,11 @@ suite('ExtHostTypes', function () { assert.equal(string.value, '${BAR}'); string = new types.SnippetString(); - string.appendChoice(['b', 'a', 'r']) + string.appendChoice(['b', 'a', 'r']); assert.equal(string.value, '${1|b,a,r|}'); string = new types.SnippetString(); - string.appendChoice(['b', 'a', 'r'], 0) + string.appendChoice(['b', 'a', 'r'], 0); assert.equal(string.value, '${0|b,a,r|}'); }); From 92b36ffc78bfbb78535f0383c6429b6de6f9dcfa Mon Sep 17 00:00:00 2001 From: okmttdhr <10101114fin@gmail.com> Date: Sat, 9 Nov 2019 21:12:44 +0900 Subject: [PATCH 020/352] Avoid unexpected value changes --- src/vs/workbench/api/common/extHostTypes.ts | 12 +++++++++--- .../test/electron-browser/api/extHostTypes.test.ts | 12 ++++++++++++ 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/src/vs/workbench/api/common/extHostTypes.ts b/src/vs/workbench/api/common/extHostTypes.ts index ed3c22a07abd2..7ef77a5d2591e 100644 --- a/src/vs/workbench/api/common/extHostTypes.ts +++ b/src/vs/workbench/api/common/extHostTypes.ts @@ -740,9 +740,15 @@ export class SnippetString { return this; } - appendChoice(values: string[], number?: number): SnippetString { - this.appendPlaceholder(values.toString(), number); - this.value = this.value.replace(/:/g, '|').replace(/}/g, '|}'); + appendChoice(values: string[], number: number = this._tabstop++): SnippetString { + const value = SnippetString._escape(values.toString()); + + this.value += '${'; + this.value += number; + this.value += '|'; + this.value += value; + this.value += '|}'; + return this; } diff --git a/src/vs/workbench/test/electron-browser/api/extHostTypes.test.ts b/src/vs/workbench/test/electron-browser/api/extHostTypes.test.ts index 7a37f9fccdab7..e372fcffa8d15 100644 --- a/src/vs/workbench/test/electron-browser/api/extHostTypes.test.ts +++ b/src/vs/workbench/test/electron-browser/api/extHostTypes.test.ts @@ -534,6 +534,18 @@ suite('ExtHostTypes', function () { string = new types.SnippetString(); string.appendChoice(['b', 'a', 'r'], 0); assert.equal(string.value, '${0|b,a,r|}'); + + string = new types.SnippetString(); + string.appendText('foo').appendChoice(['far', 'boo']).appendText('bar'); + assert.equal(string.value, 'foo${1|far,boo|}bar'); + + string = new types.SnippetString(); + string.appendText('foo').appendChoice(['far', '$boo']).appendText('bar'); + assert.equal(string.value, 'foo${1|far,\\$boo|}bar'); + + string = new types.SnippetString(); + string.appendText('foo').appendPlaceholder('farboo').appendChoice(['far', 'boo']).appendText('bar'); + assert.equal(string.value, 'foo${1:farboo}${2|far,boo|}bar'); }); test('instanceof doesn\'t work for FileSystemError #49386', function () { From 68f6d23ddef9b918a8ef0f5359e2f39279bf5aa0 Mon Sep 17 00:00:00 2001 From: okmttdhr <10101114fin@gmail.com> Date: Sun, 10 Nov 2019 09:40:51 +0900 Subject: [PATCH 021/352] Add the signature to the type --- src/vs/vscode.d.ts | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/vs/vscode.d.ts b/src/vs/vscode.d.ts index 25d57792ec326..22e9578157769 100644 --- a/src/vs/vscode.d.ts +++ b/src/vs/vscode.d.ts @@ -2967,6 +2967,17 @@ declare module 'vscode' { */ appendPlaceholder(value: string | ((snippet: SnippetString) => any), number?: number): SnippetString; + /** + * Builder-function that appends a choice (`${1|a,b,c}`) to + * the [`value`](#SnippetString.value) of this snippet string. + * + * @param values The values for choices - the array of strings + * @param number The number of this tabstop, defaults to an auto-increment + * value starting at 1. + * @return This snippet string. + */ + appendChoice(values: string[], number?: number): SnippetString; + /** * Builder-function that appends a variable (`${VAR}`) to * the [`value`](#SnippetString.value) of this snippet string. From 213bdddb72ff7a6c8eed071420de8ddac4293cb1 Mon Sep 17 00:00:00 2001 From: Miguel Solorio Date: Sun, 10 Nov 2019 13:28:43 -0800 Subject: [PATCH 022/352] Fix #84387 --- .../parts/panel/media/ellipsis-dark.svg | 5 ----- .../browser/parts/panel/media/ellipsis-hc.svg | 5 ----- .../parts/panel/media/ellipsis-light.svg | 5 ----- .../browser/parts/panel/media/panelpart.css | 22 +++++-------------- 4 files changed, 5 insertions(+), 32 deletions(-) delete mode 100644 src/vs/workbench/browser/parts/panel/media/ellipsis-dark.svg delete mode 100644 src/vs/workbench/browser/parts/panel/media/ellipsis-hc.svg delete mode 100644 src/vs/workbench/browser/parts/panel/media/ellipsis-light.svg diff --git a/src/vs/workbench/browser/parts/panel/media/ellipsis-dark.svg b/src/vs/workbench/browser/parts/panel/media/ellipsis-dark.svg deleted file mode 100644 index 2c52e359f610d..0000000000000 --- a/src/vs/workbench/browser/parts/panel/media/ellipsis-dark.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/src/vs/workbench/browser/parts/panel/media/ellipsis-hc.svg b/src/vs/workbench/browser/parts/panel/media/ellipsis-hc.svg deleted file mode 100644 index 3d7068f6b4cd1..0000000000000 --- a/src/vs/workbench/browser/parts/panel/media/ellipsis-hc.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/src/vs/workbench/browser/parts/panel/media/ellipsis-light.svg b/src/vs/workbench/browser/parts/panel/media/ellipsis-light.svg deleted file mode 100644 index 883d2722ce306..0000000000000 --- a/src/vs/workbench/browser/parts/panel/media/ellipsis-light.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/src/vs/workbench/browser/parts/panel/media/panelpart.css b/src/vs/workbench/browser/parts/panel/media/panelpart.css index 8de6bf60eaf51..64af1d2101147 100644 --- a/src/vs/workbench/browser/parts/panel/media/panelpart.css +++ b/src/vs/workbench/browser/parts/panel/media/panelpart.css @@ -43,24 +43,14 @@ /** Panel Switcher */ -.monaco-workbench .part.panel > .title > .panel-switcher-container.composite-bar > .monaco-action-bar .action-label.toggle-more { - background-image: url('ellipsis-light.svg'); - display: block; - height: 28px; - min-width: 28px; +.monaco-workbench .part.panel > .title > .panel-switcher-container.composite-bar > .monaco-action-bar .action-label.codicon-more { + display: flex; + align-items: center; + justify-content: center; margin-left: 0px; margin-right: 0px; - background-size: 16px; - background-repeat: no-repeat; - background-position: center center; -} + color: inherit !important; -.vs-dark .monaco-workbench .part.panel > .title > .panel-switcher-container.composite-bar > .monaco-action-bar .action-label.toggle-more { - background-image: url('ellipsis-dark.svg'); -} - -.hc-black .monaco-workbench .part.panel > .title > .panel-switcher-container.composite-bar > .monaco-action-bar .action-label.toggle-more { - background-image: url('ellipsis-hc.svg'); } .monaco-workbench .part.panel > .title > .panel-switcher-container > .monaco-action-bar { @@ -84,8 +74,6 @@ .monaco-workbench .part.panel > .title > .panel-switcher-container > .monaco-action-bar .action-item .action-label{ margin-right: 0; - display: flex; - align-items: center; } .monaco-workbench .part.panel > .title > .panel-switcher-container > .monaco-action-bar .action-item:last-child { From b8bb1770a5897e1dcbc9608d2280a3e765777ae5 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Mon, 11 Nov 2019 07:52:18 +0100 Subject: [PATCH 023/352] :up: jschardet (for #83421) --- extensions/git/package.json | 2 +- extensions/git/src/encoding.ts | 2 -- extensions/git/src/typings/jschardet.d.ts | 11 ----------- extensions/git/yarn.lock | 8 ++++---- package.json | 2 +- src/typings/jschardet.d.ts | 11 ----------- src/vs/base/node/encoding.ts | 3 --- yarn.lock | 8 ++++---- 8 files changed, 10 insertions(+), 37 deletions(-) delete mode 100644 extensions/git/src/typings/jschardet.d.ts delete mode 100644 src/typings/jschardet.d.ts diff --git a/extensions/git/package.json b/extensions/git/package.json index 060b6af554e83..eff48607109d1 100644 --- a/extensions/git/package.json +++ b/extensions/git/package.json @@ -1765,7 +1765,7 @@ "byline": "^5.0.0", "file-type": "^7.2.0", "iconv-lite": "^0.4.24", - "jschardet": "^1.6.0", + "jschardet": "2.1.1", "vscode-extension-telemetry": "0.1.1", "vscode-nls": "^4.0.0", "vscode-uri": "^2.0.0", diff --git a/extensions/git/src/encoding.ts b/extensions/git/src/encoding.ts index 92f6edc12a8f3..ff3eddd8413e9 100644 --- a/extensions/git/src/encoding.ts +++ b/extensions/git/src/encoding.ts @@ -5,8 +5,6 @@ import * as jschardet from 'jschardet'; -jschardet.Constants.MINIMUM_THRESHOLD = 0.2; - function detectEncodingByBOM(buffer: Buffer): string | null { if (!buffer || buffer.length < 2) { return null; diff --git a/extensions/git/src/typings/jschardet.d.ts b/extensions/git/src/typings/jschardet.d.ts deleted file mode 100644 index f252a47fd094a..0000000000000 --- a/extensions/git/src/typings/jschardet.d.ts +++ /dev/null @@ -1,11 +0,0 @@ -declare module 'jschardet' { - export interface IDetectedMap { - encoding: string, - confidence: number - } - export function detect(buffer: Buffer): IDetectedMap; - - export const Constants: { - MINIMUM_THRESHOLD: number, - } -} \ No newline at end of file diff --git a/extensions/git/yarn.lock b/extensions/git/yarn.lock index 2bfd883067da0..58a82bbe41c81 100644 --- a/extensions/git/yarn.lock +++ b/extensions/git/yarn.lock @@ -176,10 +176,10 @@ isexe@^2.0.0: resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= -jschardet@^1.6.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/jschardet/-/jschardet-1.6.0.tgz#c7d1a71edcff2839db2f9ec30fc5d5ebd3c1a678" - integrity sha512-xYuhvQ7I9PDJIGBWev9xm0+SMSed3ZDBAmvVjbFR1ZRLAF+vlXcQu6cRI9uAlj81rzikElRVteehwV7DuX2ZmQ== +jschardet@2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/jschardet/-/jschardet-2.1.1.tgz#af6f8fd0b3b0f5d46a8fd9614a4fce490575c184" + integrity sha512-pA5qG9Zwm8CBpGlK/lo2GE9jPxwqRgMV7Lzc/1iaPccw6v4Rhj8Zg2BTyrdmHmxlJojnbLupLeRnaPLsq03x6Q== json3@3.3.2: version "3.3.2" diff --git a/package.json b/package.json index 0d027ad75391b..ab2174a9025e5 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "http-proxy-agent": "^2.1.0", "https-proxy-agent": "^2.2.3", "iconv-lite": "0.5.0", - "jschardet": "1.6.0", + "jschardet": "2.1.1", "keytar": "^4.11.0", "native-is-elevated": "0.4.1", "native-keymap": "2.0.0", diff --git a/src/typings/jschardet.d.ts b/src/typings/jschardet.d.ts deleted file mode 100644 index f252a47fd094a..0000000000000 --- a/src/typings/jschardet.d.ts +++ /dev/null @@ -1,11 +0,0 @@ -declare module 'jschardet' { - export interface IDetectedMap { - encoding: string, - confidence: number - } - export function detect(buffer: Buffer): IDetectedMap; - - export const Constants: { - MINIMUM_THRESHOLD: number, - } -} \ No newline at end of file diff --git a/src/vs/base/node/encoding.ts b/src/vs/base/node/encoding.ts index 0df9dbd26c2da..d0501c2fd6d54 100644 --- a/src/vs/base/node/encoding.ts +++ b/src/vs/base/node/encoding.ts @@ -199,7 +199,6 @@ export function detectEncodingByBOMFromBuffer(buffer: Buffer | VSBuffer | null, return null; } -const MINIMUM_THRESHOLD = 0.2; const IGNORE_ENCODINGS = ['ascii', 'utf-8', 'utf-16', 'utf-32']; /** @@ -208,8 +207,6 @@ const IGNORE_ENCODINGS = ['ascii', 'utf-8', 'utf-16', 'utf-32']; async function guessEncodingByBuffer(buffer: Buffer): Promise { const jschardet = await import('jschardet'); - jschardet.Constants.MINIMUM_THRESHOLD = MINIMUM_THRESHOLD; - const guessed = jschardet.detect(buffer); if (!guessed || !guessed.encoding) { return null; diff --git a/yarn.lock b/yarn.lock index 95a0c8221dfce..e3aff8c82d8fd 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4806,10 +4806,10 @@ jsbn@~0.1.0: resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" integrity sha1-peZUwuWi3rXyAdls77yoDA7y9RM= -jschardet@1.6.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/jschardet/-/jschardet-1.6.0.tgz#c7d1a71edcff2839db2f9ec30fc5d5ebd3c1a678" - integrity sha512-xYuhvQ7I9PDJIGBWev9xm0+SMSed3ZDBAmvVjbFR1ZRLAF+vlXcQu6cRI9uAlj81rzikElRVteehwV7DuX2ZmQ== +jschardet@2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/jschardet/-/jschardet-2.1.1.tgz#af6f8fd0b3b0f5d46a8fd9614a4fce490575c184" + integrity sha512-pA5qG9Zwm8CBpGlK/lo2GE9jPxwqRgMV7Lzc/1iaPccw6v4Rhj8Zg2BTyrdmHmxlJojnbLupLeRnaPLsq03x6Q== jsdom-no-contextify@^3.1.0: version "3.1.0" From f6df7ed73834eb47c1d2321d512aad970e9e5af7 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Mon, 11 Nov 2019 08:32:06 +0100 Subject: [PATCH 024/352] fix build --- remote/package.json | 2 +- remote/yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/remote/package.json b/remote/package.json index 081fe4bdd585e..439fd388f8c0e 100644 --- a/remote/package.json +++ b/remote/package.json @@ -9,7 +9,7 @@ "http-proxy-agent": "^2.1.0", "https-proxy-agent": "^2.2.3", "iconv-lite": "0.5.0", - "jschardet": "1.6.0", + "jschardet": "2.1.1", "native-watchdog": "1.2.0", "node-pty": "^0.10.0-beta2", "onigasm-umd": "^2.2.2", diff --git a/remote/yarn.lock b/remote/yarn.lock index d62fcb1f2ad36..c6e5ac0c6b6d4 100644 --- a/remote/yarn.lock +++ b/remote/yarn.lock @@ -217,10 +217,10 @@ is-number@^7.0.0: resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== -jschardet@1.6.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/jschardet/-/jschardet-1.6.0.tgz#c7d1a71edcff2839db2f9ec30fc5d5ebd3c1a678" - integrity sha512-xYuhvQ7I9PDJIGBWev9xm0+SMSed3ZDBAmvVjbFR1ZRLAF+vlXcQu6cRI9uAlj81rzikElRVteehwV7DuX2ZmQ== +jschardet@2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/jschardet/-/jschardet-2.1.1.tgz#af6f8fd0b3b0f5d46a8fd9614a4fce490575c184" + integrity sha512-pA5qG9Zwm8CBpGlK/lo2GE9jPxwqRgMV7Lzc/1iaPccw6v4Rhj8Zg2BTyrdmHmxlJojnbLupLeRnaPLsq03x6Q== jsonfile@^4.0.0: version "4.0.0" From bd08b319d3099ce2e77c3382721fa13d0670843d Mon Sep 17 00:00:00 2001 From: Christof Marti Date: Mon, 11 Nov 2019 09:23:23 +0100 Subject: [PATCH 025/352] Update commands.yml --- .github/commands.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.github/commands.yml b/.github/commands.yml index 0e78ac749fafa..c7c5c902cdfd9 100644 --- a/.github/commands.yml +++ b/.github/commands.yml @@ -123,5 +123,12 @@ action: 'updateLabels', addLabel: 'a11ymas' }, + { + type: 'label', + name: '*needs more info', + action: 'updateLabels', + addLabel: 'needs more info', + removeLabel: '*needs more info' + }, ] } From 7417a299b4debfbb9222fc17bc9dbdc587ce4091 Mon Sep 17 00:00:00 2001 From: Christof Marti Date: Mon, 11 Nov 2019 09:26:15 +0100 Subject: [PATCH 026/352] Update commands.yml --- .github/commands.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.github/commands.yml b/.github/commands.yml index c7c5c902cdfd9..ca4b782002fdb 100644 --- a/.github/commands.yml +++ b/.github/commands.yml @@ -116,6 +116,14 @@ addLabel: 'needs more info', comment: "Thanks for creating this issue! We figured it's missing some basic information or in some other way doesn't follow our [issue reporting](https://aka.ms/vscodeissuereporting) guidelines. Please take the time to review these and update the issue.\n\nHappy Coding!" }, + { + type: 'label', + name: '*needs more info', + action: 'updateLabels', + addLabel: 'needs more info', + removeLabel: '*needs more info', + comment: "Thanks for creating this issue! We figured it's missing some basic information or in some other way doesn't follow our [issue reporting](https://aka.ms/vscodeissuereporting) guidelines. Please take the time to review these and update the issue.\n\nHappy Coding!" + }, { type: 'comment', name: 'a11ymas', From 296d7eb378e802588155a8636162c6b0160edd4a Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Mon, 11 Nov 2019 09:35:56 +0100 Subject: [PATCH 027/352] user LogService in extHostDecorations, #84283 --- src/vs/workbench/api/common/extHostDecorations.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/api/common/extHostDecorations.ts b/src/vs/workbench/api/common/extHostDecorations.ts index a0b0612706a10..1888766e31feb 100644 --- a/src/vs/workbench/api/common/extHostDecorations.ts +++ b/src/vs/workbench/api/common/extHostDecorations.ts @@ -12,6 +12,7 @@ import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions'; import { asArray } from 'vs/base/common/arrays'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { IExtHostRpcService } from 'vs/workbench/api/common/extHostRpcService'; +import { ILogService } from 'vs/platform/log/common/log'; interface ProviderData { provider: vscode.DecorationProvider; @@ -28,6 +29,7 @@ export class ExtHostDecorations implements IExtHostDecorations { constructor( @IExtHostRpcService extHostRpc: IExtHostRpcService, + @ILogService private readonly _logService: ILogService, ) { this._proxy = extHostRpc.getProxy(MainContext.MainThreadDecorations); } @@ -66,10 +68,10 @@ export class ExtHostDecorations implements IExtHostDecorations { Decoration.validate(data); result[id] = [data.priority, data.bubble, data.title, data.letter, data.color]; } catch (e) { - console.warn(`INVALID decoration from extension '${extensionId.value}': ${e}`); + this._logService.warn(`INVALID decoration from extension '${extensionId.value}': ${e}`); } }, err => { - console.error(err); + this._logService.error(err); }); })).then(() => { From 41dd402156939894c0a72d3bc76132109544e257 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Mon, 11 Nov 2019 09:38:21 +0100 Subject: [PATCH 028/352] use LogService in extHost.api.impl, #84283 --- src/vs/workbench/api/common/extHost.api.impl.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/vs/workbench/api/common/extHost.api.impl.ts b/src/vs/workbench/api/common/extHost.api.impl.ts index e578e636d4461..ac216e9263834 100644 --- a/src/vs/workbench/api/common/extHost.api.impl.ts +++ b/src/vs/workbench/api/common/extHost.api.impl.ts @@ -149,7 +149,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I let done = (!extension.isUnderDevelopment); function informOnce(selector: vscode.DocumentSelector) { if (!done) { - console.info(`Extension '${extension.identifier.value}' uses a document selector without scheme. Learn more about this: https://go.microsoft.com/fwlink/?linkid=872305`); + extHostLogService.info(`Extension '${extension.identifier.value}' uses a document selector without scheme. Learn more about this: https://go.microsoft.com/fwlink/?linkid=872305`); done = true; } } @@ -180,7 +180,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I return extHostCommands.registerCommand(true, id, (...args: any[]): any => { const activeTextEditor = extHostEditors.getActiveTextEditor(); if (!activeTextEditor) { - console.warn('Cannot execute ' + id + ' because there is no active text editor.'); + extHostLogService.warn('Cannot execute ' + id + ' because there is no active text editor.'); return undefined; } @@ -190,10 +190,10 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I }).then((result) => { if (!result) { - console.warn('Edits from command ' + id + ' were not applied.'); + extHostLogService.warn('Edits from command ' + id + ' were not applied.'); } }, (err) => { - console.warn('An error occurred while running command ' + id, err); + extHostLogService.warn('An error occurred while running command ' + id, err); }); }); }, @@ -202,7 +202,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I return extHostCommands.registerCommand(true, id, async (...args: any[]): Promise => { const activeTextEditor = extHostEditors.getActiveTextEditor(); if (!activeTextEditor) { - console.warn('Cannot execute ' + id + ' because there is no active text editor.'); + extHostLogService.warn('Cannot execute ' + id + ' because there is no active text editor.'); return undefined; } From 34bf3d97eb6ced716fa60d974f4e55b694bd1e0b Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Mon, 11 Nov 2019 09:50:05 +0100 Subject: [PATCH 029/352] use LogService in extHostDiagnostics, #84283 --- src/vs/workbench/api/common/extHost.api.impl.ts | 2 +- src/vs/workbench/api/common/extHostDiagnostics.ts | 5 +++-- .../test/electron-browser/api/extHostApiCommands.test.ts | 2 +- .../test/electron-browser/api/extHostDiagnostics.test.ts | 5 +++-- .../electron-browser/api/extHostLanguageFeatures.test.ts | 2 +- 5 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/vs/workbench/api/common/extHost.api.impl.ts b/src/vs/workbench/api/common/extHost.api.impl.ts index ac216e9263834..178d54dd3e05d 100644 --- a/src/vs/workbench/api/common/extHost.api.impl.ts +++ b/src/vs/workbench/api/common/extHost.api.impl.ts @@ -113,7 +113,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I const extHostEditors = rpcProtocol.set(ExtHostContext.ExtHostEditors, new ExtHostEditors(rpcProtocol, extHostDocumentsAndEditors)); const extHostTreeViews = rpcProtocol.set(ExtHostContext.ExtHostTreeViews, new ExtHostTreeViews(rpcProtocol.getProxy(MainContext.MainThreadTreeViews), extHostCommands, extHostLogService)); const extHostEditorInsets = rpcProtocol.set(ExtHostContext.ExtHostEditorInsets, new ExtHostEditorInsets(rpcProtocol.getProxy(MainContext.MainThreadEditorInsets), extHostEditors, initData.environment)); - const extHostDiagnostics = rpcProtocol.set(ExtHostContext.ExtHostDiagnostics, new ExtHostDiagnostics(rpcProtocol)); + const extHostDiagnostics = rpcProtocol.set(ExtHostContext.ExtHostDiagnostics, new ExtHostDiagnostics(rpcProtocol, extHostLogService)); const extHostLanguageFeatures = rpcProtocol.set(ExtHostContext.ExtHostLanguageFeatures, new ExtHostLanguageFeatures(rpcProtocol, uriTransformer, extHostDocuments, extHostCommands, extHostDiagnostics, extHostLogService)); const extHostFileSystem = rpcProtocol.set(ExtHostContext.ExtHostFileSystem, new ExtHostFileSystem(rpcProtocol, extHostLanguageFeatures)); const extHostFileSystemEvent = rpcProtocol.set(ExtHostContext.ExtHostFileSystemEventService, new ExtHostFileSystemEventService(rpcProtocol, extHostDocumentsAndEditors)); diff --git a/src/vs/workbench/api/common/extHostDiagnostics.ts b/src/vs/workbench/api/common/extHostDiagnostics.ts index 1455bb030d8ab..e0b6831c5522d 100644 --- a/src/vs/workbench/api/common/extHostDiagnostics.ts +++ b/src/vs/workbench/api/common/extHostDiagnostics.ts @@ -13,6 +13,7 @@ import * as converter from './extHostTypeConverters'; import { mergeSort } from 'vs/base/common/arrays'; import { Event, Emitter } from 'vs/base/common/event'; import { keys } from 'vs/base/common/map'; +import { ILogService } from 'vs/platform/log/common/log'; export class DiagnosticCollection implements vscode.DiagnosticCollection { @@ -253,7 +254,7 @@ export class ExtHostDiagnostics implements ExtHostDiagnosticsShape { readonly onDidChangeDiagnostics: Event = Event.map(Event.debounce(this._onDidChangeDiagnostics.event, ExtHostDiagnostics._debouncer, 50), ExtHostDiagnostics._mapper); - constructor(mainContext: IMainContext) { + constructor(mainContext: IMainContext, @ILogService private readonly _logService: ILogService) { this._proxy = mainContext.getProxy(MainContext.MainThreadDiagnostics); } @@ -266,7 +267,7 @@ export class ExtHostDiagnostics implements ExtHostDiagnosticsShape { } else if (!_collections.has(name)) { owner = name; } else { - console.warn(`DiagnosticCollection with name '${name}' does already exist.`); + this._logService.warn(`DiagnosticCollection with name '${name}' does already exist.`); do { owner = name + ExtHostDiagnostics._idPool++; } while (_collections.has(owner)); diff --git a/src/vs/workbench/test/electron-browser/api/extHostApiCommands.test.ts b/src/vs/workbench/test/electron-browser/api/extHostApiCommands.test.ts index 20bb18053aeb5..99d627ed5592d 100644 --- a/src/vs/workbench/test/electron-browser/api/extHostApiCommands.test.ts +++ b/src/vs/workbench/test/electron-browser/api/extHostApiCommands.test.ts @@ -112,7 +112,7 @@ suite('ExtHostLanguageFeatureCommands', function () { rpcProtocol.set(MainContext.MainThreadCommands, inst.createInstance(MainThreadCommands, rpcProtocol)); ExtHostApiCommands.register(commands); - const diagnostics = new ExtHostDiagnostics(rpcProtocol); + const diagnostics = new ExtHostDiagnostics(rpcProtocol, new NullLogService()); rpcProtocol.set(ExtHostContext.ExtHostDiagnostics, diagnostics); extHost = new ExtHostLanguageFeatures(rpcProtocol, null, extHostDocuments, commands, diagnostics, new NullLogService()); diff --git a/src/vs/workbench/test/electron-browser/api/extHostDiagnostics.test.ts b/src/vs/workbench/test/electron-browser/api/extHostDiagnostics.test.ts index 60181c415f256..43e7087b3be95 100644 --- a/src/vs/workbench/test/electron-browser/api/extHostDiagnostics.test.ts +++ b/src/vs/workbench/test/electron-browser/api/extHostDiagnostics.test.ts @@ -11,6 +11,7 @@ import { MainThreadDiagnosticsShape, IMainContext } from 'vs/workbench/api/commo import { IMarkerData, MarkerSeverity } from 'vs/platform/markers/common/markers'; import { mock } from 'vs/workbench/test/electron-browser/api/mock'; import { Emitter, Event } from 'vs/base/common/event'; +import { NullLogService } from 'vs/platform/log/common/log'; suite('ExtHostDiagnostics', () => { @@ -387,7 +388,7 @@ suite('ExtHostDiagnostics', () => { assertRegistered(): void { } - }); + }, new NullLogService()); let collection1 = diags.createDiagnosticCollection('foo'); let collection2 = diags.createDiagnosticCollection('foo'); // warns, uses a different owner @@ -436,7 +437,7 @@ suite('ExtHostDiagnostics', () => { assertRegistered(): void { } - }); + }, new NullLogService()); // diff --git a/src/vs/workbench/test/electron-browser/api/extHostLanguageFeatures.test.ts b/src/vs/workbench/test/electron-browser/api/extHostLanguageFeatures.test.ts index 68cd2940255d8..3793608226f30 100644 --- a/src/vs/workbench/test/electron-browser/api/extHostLanguageFeatures.test.ts +++ b/src/vs/workbench/test/electron-browser/api/extHostLanguageFeatures.test.ts @@ -102,7 +102,7 @@ suite('ExtHostLanguageFeatures', function () { rpcProtocol.set(ExtHostContext.ExtHostCommands, commands); rpcProtocol.set(MainContext.MainThreadCommands, inst.createInstance(MainThreadCommands, rpcProtocol)); - const diagnostics = new ExtHostDiagnostics(rpcProtocol); + const diagnostics = new ExtHostDiagnostics(rpcProtocol, new NullLogService()); rpcProtocol.set(ExtHostContext.ExtHostDiagnostics, diagnostics); extHost = new ExtHostLanguageFeatures(rpcProtocol, null, extHostDocuments, commands, diagnostics, new NullLogService()); From cb6f3e55e7b8f3fbe5dfd91a630d642c7758cc87 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Mon, 11 Nov 2019 09:54:33 +0100 Subject: [PATCH 030/352] throw error when calling getWordRange with invalid regex --- src/vs/workbench/api/common/extHostDocumentData.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/vs/workbench/api/common/extHostDocumentData.ts b/src/vs/workbench/api/common/extHostDocumentData.ts index 3a166503923e6..064cbbb0426db 100644 --- a/src/vs/workbench/api/common/extHostDocumentData.ts +++ b/src/vs/workbench/api/common/extHostDocumentData.ts @@ -239,8 +239,7 @@ export class ExtHostDocumentData extends MirrorTextModel { } else if (regExpLeadsToEndlessLoop(regexp)) { // use default when custom-regexp is bad - console.warn(`[getWordRangeAtPosition]: ignoring custom regexp '${regexp.source}' because it matches the empty string.`); - regexp = getWordDefinitionFor(this._languageId); + throw new Error(`[getWordRangeAtPosition]: ignoring custom regexp '${regexp.source}' because it matches the empty string.`); } const wordAtText = getWordAtText( From b272a9e0013e141de30fafb5108fa56d2402caaa Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Mon, 11 Nov 2019 09:58:20 +0100 Subject: [PATCH 031/352] fix typo --- src/vs/vscode.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/vscode.d.ts b/src/vs/vscode.d.ts index 25d57792ec326..7bc4e66bfef46 100644 --- a/src/vs/vscode.d.ts +++ b/src/vs/vscode.d.ts @@ -128,7 +128,7 @@ declare module 'vscode' { readonly isDirty: boolean; /** - * `true` if the document have been closed. A closed document isn't synchronized anymore + * `true` if the document has been closed. A closed document isn't synchronized anymore * and won't be re-used when the same resource is opened again. */ readonly isClosed: boolean; From d1778110df0bb7aa8f030ad4a95600cb8093f07d Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Mon, 11 Nov 2019 10:07:17 +0100 Subject: [PATCH 032/352] explorer: enable compressed folders by default --- src/vs/workbench/contrib/files/browser/files.contribution.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/files/browser/files.contribution.ts b/src/vs/workbench/contrib/files/browser/files.contribution.ts index 4e4375262cac5..25f5a95c4e318 100644 --- a/src/vs/workbench/contrib/files/browser/files.contribution.ts +++ b/src/vs/workbench/contrib/files/browser/files.contribution.ts @@ -427,7 +427,7 @@ configurationRegistry.registerConfiguration({ 'explorer.compressSingleChildFolders': { 'type': 'boolean', 'description': nls.localize('compressSingleChildFolders', "Controls whether the explorer should compress single child folders in a combined tree element. Useful for Java project folder structures, for example."), - 'default': false + 'default': true }, } }); From eb2af02d5e04af7d3a4b6302a3a109fed015e5b8 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Mon, 11 Nov 2019 10:17:16 +0100 Subject: [PATCH 033/352] fix tests --- .../test/electron-browser/api/extHostDocumentData.test.ts | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/vs/workbench/test/electron-browser/api/extHostDocumentData.test.ts b/src/vs/workbench/test/electron-browser/api/extHostDocumentData.test.ts index 7fbbf671196f0..2610d0241bb6c 100644 --- a/src/vs/workbench/test/electron-browser/api/extHostDocumentData.test.ts +++ b/src/vs/workbench/test/electron-browser/api/extHostDocumentData.test.ts @@ -251,11 +251,7 @@ suite('ExtHostDocumentData', () => { assert.equal(range.end.character, 4); // ignore bad regular expresson /.*/ - range = data.document.getWordRangeAtPosition(new Position(0, 2), /.*/)!; - assert.equal(range.start.line, 0); - assert.equal(range.start.character, 0); - assert.equal(range.end.line, 0); - assert.equal(range.end.character, 4); + assert.throws(() => data.document.getWordRangeAtPosition(new Position(0, 2), /.*/)!); range = data.document.getWordRangeAtPosition(new Position(0, 5), /[a-z+]+/)!; assert.equal(range.start.line, 0); From dd4f9d1a73cb74c3e384ab30e3711aaacecffc13 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Mon, 11 Nov 2019 10:31:53 +0100 Subject: [PATCH 034/352] - wrap only right items. hide left items on overflow --- .../browser/parts/statusbar/media/statusbarpart.css | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/browser/parts/statusbar/media/statusbarpart.css b/src/vs/workbench/browser/parts/statusbar/media/statusbarpart.css index a1c0c07debdd2..b859f25c71fb6 100644 --- a/src/vs/workbench/browser/parts/statusbar/media/statusbarpart.css +++ b/src/vs/workbench/browser/parts/statusbar/media/statusbarpart.css @@ -28,15 +28,16 @@ .monaco-workbench .part.statusbar > .left-items, .monaco-workbench .part.statusbar > .right-items { display: flex; - flex-wrap: wrap; /* individual entries should not shrink since we do not control their content */ } .monaco-workbench .part.statusbar > .right-items { - flex-direction: row-reverse; /* ensures that the most right elements wrap last when space is little */ + flex-direction: row-reverse; + flex-wrap: wrap /* ensures that the most right elements wrap last when space is little */; } .monaco-workbench .part.statusbar > .left-items { flex-grow: 1; /* left items push right items to the far right end */ + overflow: hidden; /* Hide the overflowing entries */ } .monaco-workbench .part.statusbar > .items-container > .statusbar-item { From 599864aeb01d4e7892d5a69ad3de8144883a5675 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Mon, 11 Nov 2019 10:47:56 +0100 Subject: [PATCH 035/352] peek - fix open to side --- .../contrib/gotoSymbol/peek/referencesController.ts | 12 ++++++------ .../contrib/gotoSymbol/peek/referencesWidget.ts | 4 ---- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/src/vs/editor/contrib/gotoSymbol/peek/referencesController.ts b/src/vs/editor/contrib/gotoSymbol/peek/referencesController.ts index 1b5389383e452..aaaede8378e8b 100644 --- a/src/vs/editor/contrib/gotoSymbol/peek/referencesController.ts +++ b/src/vs/editor/contrib/gotoSymbol/peek/referencesController.ts @@ -14,14 +14,14 @@ import { IStorageService, StorageScope } from 'vs/platform/storage/common/storag import * as editorCommon from 'vs/editor/common/editorCommon'; import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; import { ReferencesModel, OneReference } from '../referencesModel'; -import { ReferenceWidget, LayoutData, ctxReferenceWidgetSearchTreeFocused } from './referencesWidget'; +import { ReferenceWidget, LayoutData } from './referencesWidget'; import { Range } from 'vs/editor/common/core/range'; import { Position } from 'vs/editor/common/core/position'; import { Location } from 'vs/editor/common/modes'; import { INotificationService } from 'vs/platform/notification/common/notification'; import { CancelablePromise, createCancelablePromise } from 'vs/base/common/async'; import { getOuterEditor, PeekContext } from 'vs/editor/contrib/peekView/peekView'; -import { IListService } from 'vs/platform/list/browser/listService'; +import { IListService, WorkbenchListFocusContextKey } from 'vs/platform/list/browser/listService'; import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; import { KeyCode, KeyMod } from 'vs/base/common/keyCodes'; @@ -361,12 +361,12 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({ mac: { primary: KeyMod.WinCtrl | KeyCode.Enter }, - when: ContextKeyExpr.and(ctxReferenceSearchVisible, ctxReferenceWidgetSearchTreeFocused), + when: ContextKeyExpr.and(ctxReferenceSearchVisible, WorkbenchListFocusContextKey), handler(accessor: ServicesAccessor) { const listService = accessor.get(IListService); - const focus = listService.lastFocusedList && listService.lastFocusedList.getFocus(); - if (focus instanceof OneReference) { - withController(accessor, controller => controller.openReference(focus, true)); + const focus = listService.lastFocusedList?.getFocus(); + if (Array.isArray(focus) && focus[0] instanceof OneReference) { + withController(accessor, controller => controller.openReference(focus[0], true)); } } }); diff --git a/src/vs/editor/contrib/gotoSymbol/peek/referencesWidget.ts b/src/vs/editor/contrib/gotoSymbol/peek/referencesWidget.ts index 00130718f260f..82f86384de484 100644 --- a/src/vs/editor/contrib/gotoSymbol/peek/referencesWidget.ts +++ b/src/vs/editor/contrib/gotoSymbol/peek/referencesWidget.ts @@ -23,7 +23,6 @@ import { Location } from 'vs/editor/common/modes'; import { ITextEditorModel, ITextModelService } from 'vs/editor/common/services/resolverService'; import { AriaProvider, DataSource, Delegate, FileReferencesRenderer, OneReferenceRenderer, TreeElement, StringRepresentationProvider, IdentityProvider } from 'vs/editor/contrib/gotoSymbol/peek/referencesTree'; import * as nls from 'vs/nls'; -import { RawContextKey } from 'vs/platform/contextkey/common/contextkey'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { ILabelService } from 'vs/platform/label/common/label'; import { WorkbenchAsyncDataTree } from 'vs/platform/list/browser/listService'; @@ -182,8 +181,6 @@ export interface SelectionEvent { readonly element?: Location; } -export const ctxReferenceWidgetSearchTreeFocused = new RawContextKey('referenceSearchTreeFocused', true); - /** * ZoneWidget that is shown inside the editor */ @@ -319,7 +316,6 @@ export class ReferenceWidget extends peekView.PeekViewWidget { this._instantiationService.createInstance(DataSource), treeOptions ); - ctxReferenceWidgetSearchTreeFocused.bindTo(this._tree.contextKeyService); // split stuff this._splitView.addView({ From 1a644f628cba4dd63b4f7655f69795fb55b57f55 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Mon, 11 Nov 2019 10:52:59 +0100 Subject: [PATCH 036/352] #84283 Use log service --- .../workbench/api/common/extHostConfiguration.ts | 16 +++++++++++----- .../api/extHostConfiguration.test.ts | 14 +++++++++----- 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/src/vs/workbench/api/common/extHostConfiguration.ts b/src/vs/workbench/api/common/extHostConfiguration.ts index 44b064059fad0..9acade4b04c46 100644 --- a/src/vs/workbench/api/common/extHostConfiguration.ts +++ b/src/vs/workbench/api/common/extHostConfiguration.ts @@ -20,6 +20,7 @@ import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions'; import { Barrier } from 'vs/base/common/async'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { IExtHostRpcService } from 'vs/workbench/api/common/extHostRpcService'; +import { ILogService } from 'vs/platform/log/common/log'; function lookUp(tree: any, key: string) { if (key) { @@ -45,16 +46,19 @@ export class ExtHostConfiguration implements ExtHostConfigurationShape { readonly _serviceBrand: undefined; private readonly _proxy: MainThreadConfigurationShape; + private readonly _logService: ILogService; private readonly _extHostWorkspace: ExtHostWorkspace; private readonly _barrier: Barrier; private _actual: ExtHostConfigProvider | null; constructor( @IExtHostRpcService extHostRpc: IExtHostRpcService, - @IExtHostWorkspace extHostWorkspace: IExtHostWorkspace + @IExtHostWorkspace extHostWorkspace: IExtHostWorkspace, + @ILogService logService: ILogService, ) { this._proxy = extHostRpc.getProxy(MainContext.MainThreadConfiguration); this._extHostWorkspace = extHostWorkspace; + this._logService = logService; this._barrier = new Barrier(); this._actual = null; } @@ -64,7 +68,7 @@ export class ExtHostConfiguration implements ExtHostConfigurationShape { } $initializeConfiguration(data: IConfigurationInitData): void { - this._actual = new ExtHostConfigProvider(this._proxy, this._extHostWorkspace, data); + this._actual = new ExtHostConfigProvider(this._proxy, this._extHostWorkspace, data, this._logService); this._barrier.open(); } @@ -80,9 +84,11 @@ export class ExtHostConfigProvider { private readonly _extHostWorkspace: ExtHostWorkspace; private _configurationScopes: Map; private _configuration: Configuration; + private _logService: ILogService; - constructor(proxy: MainThreadConfigurationShape, extHostWorkspace: ExtHostWorkspace, data: IConfigurationInitData) { + constructor(proxy: MainThreadConfigurationShape, extHostWorkspace: ExtHostWorkspace, data: IConfigurationInitData, logService: ILogService) { this._proxy = proxy; + this._logService = logService; this._extHostWorkspace = extHostWorkspace; this._configuration = ExtHostConfigProvider.parse(data); this._configurationScopes = this._toMap(data.configurationScopes); @@ -236,13 +242,13 @@ export class ExtHostConfigProvider { const extensionIdText = extensionId ? `[${extensionId.value}] ` : ''; if (ConfigurationScope.RESOURCE === scope) { if (resource === undefined) { - console.warn(`${extensionIdText}Accessing a resource scoped configuration without providing a resource is not expected. To get the effective value for '${key}', provide the URI of a resource or 'null' for any resource.`); + this._logService.warn(`${extensionIdText}Accessing a resource scoped configuration without providing a resource is not expected. To get the effective value for '${key}', provide the URI of a resource or 'null' for any resource.`); } return; } if (ConfigurationScope.WINDOW === scope) { if (resource) { - console.warn(`${extensionIdText}Accessing a window scoped configuration for a resource is not expected. To associate '${key}' to a resource, define its scope to 'resource' in configuration contributions in 'package.json'.`); + this._logService.warn(`${extensionIdText}Accessing a window scoped configuration for a resource is not expected. To associate '${key}' to a resource, define its scope to 'resource' in configuration contributions in 'package.json'.`); } return; } diff --git a/src/vs/workbench/test/electron-browser/api/extHostConfiguration.test.ts b/src/vs/workbench/test/electron-browser/api/extHostConfiguration.test.ts index f319881a1032d..672c28dd63702 100644 --- a/src/vs/workbench/test/electron-browser/api/extHostConfiguration.test.ts +++ b/src/vs/workbench/test/electron-browser/api/extHostConfiguration.test.ts @@ -35,7 +35,7 @@ suite('ExtHostConfiguration', function () { if (!shape) { shape = new class extends mock() { }; } - return new ExtHostConfigProvider(shape, createExtHostWorkspace(), createConfigurationData(contents)); + return new ExtHostConfigProvider(shape, createExtHostWorkspace(), createConfigurationData(contents), new NullLogService()); } function createConfigurationData(contents: any): IConfigurationInitData { @@ -283,7 +283,8 @@ suite('ExtHostConfiguration', function () { workspace: new ConfigurationModel({}, []), folders: [], configurationScopes: [] - } + }, + new NullLogService() ); let actual = testObject.getConfiguration().inspect('editor.wordWrap')!; @@ -331,7 +332,8 @@ suite('ExtHostConfiguration', function () { workspace, folders, configurationScopes: [] - } + }, + new NullLogService() ); let actual1 = testObject.getConfiguration().inspect('editor.wordWrap')!; @@ -407,7 +409,8 @@ suite('ExtHostConfiguration', function () { workspace, folders, configurationScopes: [] - } + }, + new NullLogService() ); let actual1 = testObject.getConfiguration().inspect('editor.wordWrap')!; @@ -607,7 +610,8 @@ suite('ExtHostConfiguration', function () { 'config': false, 'updatedconfig': false } - }) + }), + new NullLogService() ); const newConfigData = createConfigurationData({ From 67ac10ad2879cab015ded52f9e57d96e8a3b471b Mon Sep 17 00:00:00 2001 From: Andre Weinand Date: Mon, 11 Nov 2019 10:55:58 +0100 Subject: [PATCH 037/352] #84283 use log service --- .../contrib/debug/browser/extensionHostDebugService.ts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/vs/workbench/contrib/debug/browser/extensionHostDebugService.ts b/src/vs/workbench/contrib/debug/browser/extensionHostDebugService.ts index 6283cda2f7859..d9b5232c0eb94 100644 --- a/src/vs/workbench/contrib/debug/browser/extensionHostDebugService.ts +++ b/src/vs/workbench/contrib/debug/browser/extensionHostDebugService.ts @@ -18,6 +18,7 @@ import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/ import { IWorkspaceProvider, IWorkspace } from 'vs/workbench/services/host/browser/browserHostService'; import { IProcessEnvironment } from 'vs/base/common/platform'; import { hasWorkspaceFileExtension } from 'vs/platform/workspaces/common/workspaces'; +import { ILogService } from 'vs/platform/log/common/log'; class BrowserExtensionHostDebugService extends ExtensionHostDebugChannelClient implements IExtensionHostDebugService { @@ -25,7 +26,8 @@ class BrowserExtensionHostDebugService extends ExtensionHostDebugChannelClient i constructor( @IRemoteAgentService remoteAgentService: IRemoteAgentService, - @IWorkbenchEnvironmentService environmentService: IWorkbenchEnvironmentService + @IWorkbenchEnvironmentService environmentService: IWorkbenchEnvironmentService, + @ILogService logService: ILogService ) { const connection = remoteAgentService.getConnection(); let channel: IChannel; @@ -34,7 +36,7 @@ class BrowserExtensionHostDebugService extends ExtensionHostDebugChannelClient i } else { channel = { call: async () => undefined, listen: () => Event.None } as any; // TODO@weinand TODO@isidorn fallback? - console.warn('Extension Host Debugging not available due to missing connection.'); + logService.warn('Extension Host Debugging not available due to missing connection.'); } super(channel); @@ -43,7 +45,7 @@ class BrowserExtensionHostDebugService extends ExtensionHostDebugChannelClient i this.workspaceProvider = environmentService.options.workspaceProvider; } else { this.workspaceProvider = { open: async () => undefined, workspace: undefined }; - console.warn('Extension Host Debugging not available due to missing workspace provider.'); + logService.warn('Extension Host Debugging not available due to missing workspace provider.'); } // Reload window on reload request From dae6ded35d9e64ddb0589b50d6b30923cefb5a79 Mon Sep 17 00:00:00 2001 From: Christof Marti Date: Mon, 11 Nov 2019 11:00:17 +0100 Subject: [PATCH 038/352] Update commands.yml --- .github/commands.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/commands.yml b/.github/commands.yml index ca4b782002fdb..c649e6c4d8915 100644 --- a/.github/commands.yml +++ b/.github/commands.yml @@ -96,7 +96,7 @@ { type: 'comment', name: 'confirmationPending', - allowUsers: ['cleidigh', 'usernamehw'], + allowUsers: ['cleidigh', 'usernamehw', 'gjsjohnmurray', 'IllusionMH'], action: 'updateLabels', addLabel: 'confirmation-pending', removeLabel: 'confirmed' From 2a3f65c54f2992c114916e8c1af51f23c3d732c5 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Mon, 11 Nov 2019 11:06:50 +0100 Subject: [PATCH 039/352] peek - fix bad ident provider --- src/vs/editor/contrib/gotoSymbol/peek/referencesTree.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/editor/contrib/gotoSymbol/peek/referencesTree.ts b/src/vs/editor/contrib/gotoSymbol/peek/referencesTree.ts index 0db277b7cf1f8..1b93c77febb10 100644 --- a/src/vs/editor/contrib/gotoSymbol/peek/referencesTree.ts +++ b/src/vs/editor/contrib/gotoSymbol/peek/referencesTree.ts @@ -101,7 +101,7 @@ export class StringRepresentationProvider implements IKeyboardNavigationLabelPro export class IdentityProvider implements IIdentityProvider { getId(element: TreeElement): { toString(): string; } { - return element.uri; + return element instanceof OneReference ? element.id : element.uri; } } From 69f2f05a37f2ddcbc93d5739373015a821a105b4 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Mon, 11 Nov 2019 11:09:54 +0100 Subject: [PATCH 040/352] Fix #84436 --- .../workbench/services/keybinding/common/keybindingEditing.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/services/keybinding/common/keybindingEditing.ts b/src/vs/workbench/services/keybinding/common/keybindingEditing.ts index 8e6059322b1ec..98c4d011305e8 100644 --- a/src/vs/workbench/services/keybinding/common/keybindingEditing.ts +++ b/src/vs/workbench/services/keybinding/common/keybindingEditing.ts @@ -250,7 +250,7 @@ export class KeybindingsEditingService extends Disposable implements IKeybinding private parse(model: ITextModel): { result: IUserFriendlyKeybinding[], parseErrors: json.ParseError[] } { const parseErrors: json.ParseError[] = []; - const result = json.parse(model.getValue(), parseErrors, { allowEmptyContent: true }); + const result = json.parse(model.getValue(), parseErrors, { allowTrailingComma: true, allowEmptyContent: true }); return { result, parseErrors }; } From 5b40229334bacac925a8cd71fe4a5f1b09803855 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Mon, 11 Nov 2019 11:29:21 +0100 Subject: [PATCH 041/352] Fix #84457 --- .../test/electron-browser/extensionsTipsService.test.ts | 5 +++-- .../electron-browser/extensionEnablementService.test.ts | 8 +++++--- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsTipsService.test.ts b/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsTipsService.test.ts index 6a381ae512786..3324f94e0824e 100644 --- a/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsTipsService.test.ts +++ b/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsTipsService.test.ts @@ -501,6 +501,7 @@ suite('ExtensionsTipsService Test', () => { const ignoredExtensionId = 'Some.Extension'; instantiationService.stub(IStorageService, >{ get: (a: string, b: StorageScope, c?: boolean) => a === 'extensionsAssistant/ignored_recommendations' ? '["ms-vscode.vscode"]' : c, + getBoolean: (a: string, b: StorageScope, c: boolean) => c, store: (...args: any[]) => { storageSetterTarget(...args); } @@ -519,7 +520,7 @@ suite('ExtensionsTipsService Test', () => { test('ExtensionTipsService: Get file based recommendations from storage (old format)', () => { const storedRecommendations = '["ms-vscode.csharp", "ms-python.python", "ms-vscode.vscode-typescript-tslint-plugin"]'; - instantiationService.stub(IStorageService, >{ get: (a: string, b: StorageScope, c?: string) => a === 'extensionsAssistant/recommendations' ? storedRecommendations : c }); + instantiationService.stub(IStorageService, >{ get: (a: string, b: StorageScope, c?: string) => a === 'extensionsAssistant/recommendations' ? storedRecommendations : c, getBoolean: (a: string, b: StorageScope, c: boolean) => c }); return setUpFolderWorkspace('myFolder', []).then(() => { testObject = instantiationService.createInstance(ExtensionTipsService); @@ -538,7 +539,7 @@ suite('ExtensionsTipsService Test', () => { const now = Date.now(); const tenDaysOld = 10 * milliSecondsInADay; const storedRecommendations = `{"ms-vscode.csharp": ${now}, "ms-python.python": ${now}, "ms-vscode.vscode-typescript-tslint-plugin": ${now}, "lukehoban.Go": ${tenDaysOld}}`; - instantiationService.stub(IStorageService, >{ get: (a: string, b: StorageScope, c?: string) => a === 'extensionsAssistant/recommendations' ? storedRecommendations : c }); + instantiationService.stub(IStorageService, >{ get: (a: string, b: StorageScope, c?: string) => a === 'extensionsAssistant/recommendations' ? storedRecommendations : c, getBoolean: (a: string, b: StorageScope, c: boolean) => c }); return setUpFolderWorkspace('myFolder', []).then(() => { testObject = instantiationService.createInstance(ExtensionTipsService); diff --git a/src/vs/workbench/services/extensionManagement/test/electron-browser/extensionEnablementService.test.ts b/src/vs/workbench/services/extensionManagement/test/electron-browser/extensionEnablementService.test.ts index 93bc95313b81e..0e4e725ae649a 100644 --- a/src/vs/workbench/services/extensionManagement/test/electron-browser/extensionEnablementService.test.ts +++ b/src/vs/workbench/services/extensionManagement/test/electron-browser/extensionEnablementService.test.ts @@ -39,13 +39,15 @@ function storageService(instantiationService: TestInstantiationService): IStorag export class TestExtensionEnablementService extends ExtensionEnablementService { constructor(instantiationService: TestInstantiationService) { + const extensionManagementService = instantiationService.get(IExtensionManagementService) || instantiationService.stub(IExtensionManagementService, { onDidInstallExtension: new Emitter().event, onDidUninstallExtension: new Emitter().event } as IExtensionManagementService); + const extensionManagementServerService = instantiationService.get(IExtensionManagementServerService) || instantiationService.stub(IExtensionManagementServerService, { localExtensionManagementServer: { extensionManagementService } }); super( storageService(instantiationService), instantiationService.get(IWorkspaceContextService), instantiationService.get(IWorkbenchEnvironmentService) || instantiationService.stub(IWorkbenchEnvironmentService, { configuration: Object.create(null) } as IWorkbenchEnvironmentService), - instantiationService.get(IExtensionManagementService) || instantiationService.stub(IExtensionManagementService, - { onDidInstallExtension: new Emitter().event, onDidUninstallExtension: new Emitter().event } as IExtensionManagementService), - instantiationService.get(IConfigurationService), instantiationService.get(IExtensionManagementServerService), + extensionManagementService, + instantiationService.get(IConfigurationService), + extensionManagementServerService, productService ); } From 545e066ccdd0f083dfb6841c0ec1151f19ec4954 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Mon, 11 Nov 2019 11:55:04 +0100 Subject: [PATCH 042/352] fixes #83998 --- src/bootstrap.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/bootstrap.js b/src/bootstrap.js index c3815b745cc56..b035adc9f4113 100644 --- a/src/bootstrap.js +++ b/src/bootstrap.js @@ -263,7 +263,12 @@ exports.configurePortable = function () { } if (isTempPortable) { - process.env[process.platform === 'win32' ? 'TEMP' : 'TMPDIR'] = portableTempPath; + if (process.platform === 'win32') { + process.env['TMP'] = portableTempPath; + process.env['TEMP'] = portableTempPath; + } else { + process.env['TMPDIR'] = portableTempPath; + } } return { From 8879cf69cd6f363c3f14c917976cad02246943b7 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Mon, 11 Nov 2019 11:56:06 +0100 Subject: [PATCH 043/352] fix #84352 --- .../contrib/outline/browser/outlinePanel.ts | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/vs/workbench/contrib/outline/browser/outlinePanel.ts b/src/vs/workbench/contrib/outline/browser/outlinePanel.ts index bf6ab98899a8c..75777a0e8e7e9 100644 --- a/src/vs/workbench/contrib/outline/browser/outlinePanel.ts +++ b/src/vs/workbench/contrib/outline/browser/outlinePanel.ts @@ -466,10 +466,14 @@ export class OutlinePanel extends ViewletPanel { } const textModel = editor.getModel(); - const loadingMessage = oldModel && new TimeoutTimer( - () => this._showMessage(localize('loading', "Loading document symbols for '{0}'...", basename(textModel.uri))), - 100 - ); + + let loadingMessage: IDisposable | undefined; + if (!oldModel) { + loadingMessage = new TimeoutTimer( + () => this._showMessage(localize('loading', "Loading document symbols for '{0}'...", basename(textModel.uri))), + 100 + ); + } const requestDelay = OutlineModel.getRequestDelay(textModel); this._progressBar.infinite().show(requestDelay); From 8e64adbbde644b623cf147763caa7ff8471396d0 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Mon, 11 Nov 2019 12:22:55 +0100 Subject: [PATCH 044/352] use LogService in extHostLanguageFeatures and extHostMessageService, #84283 --- .../workbench/api/common/extHost.api.impl.ts | 2 +- .../api/common/extHostLanguageFeatures.ts | 49 +++++++++---------- .../api/common/extHostMessageService.ts | 8 ++- 3 files changed, 31 insertions(+), 28 deletions(-) diff --git a/src/vs/workbench/api/common/extHost.api.impl.ts b/src/vs/workbench/api/common/extHost.api.impl.ts index 178d54dd3e05d..26ef1db530a95 100644 --- a/src/vs/workbench/api/common/extHost.api.impl.ts +++ b/src/vs/workbench/api/common/extHost.api.impl.ts @@ -130,7 +130,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I // Other instances const extHostClipboard = new ExtHostClipboard(rpcProtocol); - const extHostMessageService = new ExtHostMessageService(rpcProtocol); + const extHostMessageService = new ExtHostMessageService(rpcProtocol, extHostLogService); const extHostDialogs = new ExtHostDialogs(rpcProtocol); const extHostStatusBar = new ExtHostStatusBar(rpcProtocol); const extHostLanguages = new ExtHostLanguages(rpcProtocol, extHostDocuments); diff --git a/src/vs/workbench/api/common/extHostLanguageFeatures.ts b/src/vs/workbench/api/common/extHostLanguageFeatures.ts index ee4043d7860bd..fb15773114e7f 100644 --- a/src/vs/workbench/api/common/extHostLanguageFeatures.ts +++ b/src/vs/workbench/api/common/extHostLanguageFeatures.ts @@ -474,11 +474,11 @@ class NavigateTypeAdapter { private readonly _symbolCache = new Map(); private readonly _resultCache = new Map(); - private readonly _provider: vscode.WorkspaceSymbolProvider; - constructor(provider: vscode.WorkspaceSymbolProvider) { - this._provider = provider; - } + constructor( + private readonly _provider: vscode.WorkspaceSymbolProvider, + private readonly _logService: ILogService + ) { } provideWorkspaceSymbols(search: string, token: CancellationToken): Promise { const result: extHostProtocol.IWorkspaceSymbolsDto = extHostProtocol.IdObject.mixin({ symbols: [] }); @@ -490,7 +490,7 @@ class NavigateTypeAdapter { continue; } if (!item.name) { - console.warn('INVALID SymbolInformation, lacks name', item); + this._logService.warn('INVALID SymbolInformation, lacks name', item); continue; } const symbol = extHostProtocol.IdObject.mixin(typeConvert.WorkspaceSymbol.from(item)); @@ -538,7 +538,8 @@ class RenameAdapter { constructor( private readonly _documents: ExtHostDocuments, - private readonly _provider: vscode.RenameProvider + private readonly _provider: vscode.RenameProvider, + private readonly _logService: ILogService ) { } provideRenameEdits(resource: URI, position: IPosition, newName: string, token: CancellationToken): Promise { @@ -587,7 +588,7 @@ class RenameAdapter { return undefined; } if (range.start.line > pos.line || range.end.line < pos.line) { - console.warn('INVALID rename location: position line must be within range start/end lines'); + this._logService.warn('INVALID rename location: position line must be within range start/end lines'); return undefined; } return { range: typeConvert.Range.from(range), text }; @@ -618,18 +619,15 @@ class SuggestAdapter { return typeof provider.resolveCompletionItem === 'function'; } - private _documents: ExtHostDocuments; - private _commands: CommandsConverter; - private _provider: vscode.CompletionItemProvider; - private _cache = new Cache('CompletionItem'); private _disposables = new Map(); - constructor(documents: ExtHostDocuments, commands: CommandsConverter, provider: vscode.CompletionItemProvider) { - this._documents = documents; - this._commands = commands; - this._provider = provider; - } + constructor( + private readonly _documents: ExtHostDocuments, + private readonly _commands: CommandsConverter, + private readonly _provider: vscode.CompletionItemProvider, + private readonly _logService: ILogService + ) { } provideCompletionItems(resource: URI, position: IPosition, context: modes.CompletionContext, token: CancellationToken): Promise { @@ -712,7 +710,7 @@ class SuggestAdapter { private _convertCompletionItem(item: vscode.CompletionItem, position: vscode.Position, id: extHostProtocol.ChainedCacheId): extHostProtocol.ISuggestDataDto | undefined { if (typeof item.label !== 'string' || item.label.length === 0) { - console.warn('INVALID text edit -> must have at least a label'); + this._logService.warn('INVALID text edit -> must have at least a label'); return undefined; } @@ -764,7 +762,7 @@ class SuggestAdapter { if (range) { if (Range.isRange(range)) { if (!SuggestAdapter._isValidRangeForCompletion(range, position)) { - console.trace('INVALID range -> must be single line and on the same line'); + this._logService.trace('INVALID range -> must be single line and on the same line'); return undefined; } result[extHostProtocol.ISuggestDataDtoField.range] = typeConvert.Range.from(range); @@ -776,7 +774,7 @@ class SuggestAdapter { || !range.inserting.start.isEqual(range.replacing.start) || !range.replacing.contains(range.inserting) ) { - console.trace('INVALID range -> must be single line, on the same line, insert range must be a prefix of replace range'); + this._logService.trace('INVALID range -> must be single line, on the same line, insert range must be a prefix of replace range'); return undefined; } result[extHostProtocol.ISuggestDataDtoField.range] = { @@ -992,7 +990,8 @@ class SelectionRangeAdapter { constructor( private readonly _documents: ExtHostDocuments, - private readonly _provider: vscode.SelectionRangeProvider + private readonly _provider: vscode.SelectionRangeProvider, + private readonly _logService: ILogService ) { } provideSelectionRanges(resource: URI, pos: IPosition[], token: CancellationToken): Promise { @@ -1004,7 +1003,7 @@ class SelectionRangeAdapter { return []; } if (allProviderRanges.length !== positions.length) { - console.warn('BAD selection ranges, provider must return ranges for each position'); + this._logService.warn('BAD selection ranges, provider must return ranges for each position'); return []; } @@ -1413,7 +1412,7 @@ export class ExtHostLanguageFeatures implements extHostProtocol.ExtHostLanguageF // --- navigate types registerWorkspaceSymbolProvider(extension: IExtensionDescription, provider: vscode.WorkspaceSymbolProvider): vscode.Disposable { - const handle = this._addNewAdapter(new NavigateTypeAdapter(provider), extension); + const handle = this._addNewAdapter(new NavigateTypeAdapter(provider, this._logService), extension); this._proxy.$registerNavigateTypeSupport(handle); return this._createDisposable(handle); } @@ -1433,7 +1432,7 @@ export class ExtHostLanguageFeatures implements extHostProtocol.ExtHostLanguageF // --- rename registerRenameProvider(extension: IExtensionDescription, selector: vscode.DocumentSelector, provider: vscode.RenameProvider): vscode.Disposable { - const handle = this._addNewAdapter(new RenameAdapter(this._documents, provider), extension); + const handle = this._addNewAdapter(new RenameAdapter(this._documents, provider, this._logService), extension); this._proxy.$registerRenameSupport(handle, this._transformDocumentSelector(selector), RenameAdapter.supportsResolving(provider)); return this._createDisposable(handle); } @@ -1449,7 +1448,7 @@ export class ExtHostLanguageFeatures implements extHostProtocol.ExtHostLanguageF // --- suggestion registerCompletionItemProvider(extension: IExtensionDescription, selector: vscode.DocumentSelector, provider: vscode.CompletionItemProvider, triggerCharacters: string[]): vscode.Disposable { - const handle = this._addNewAdapter(new SuggestAdapter(this._documents, this._commands.converter, provider), extension); + const handle = this._addNewAdapter(new SuggestAdapter(this._documents, this._commands.converter, provider, this._logService), extension); this._proxy.$registerSuggestSupport(handle, this._transformDocumentSelector(selector), triggerCharacters, SuggestAdapter.supportsResolving(provider), extension.identifier); return this._createDisposable(handle); } @@ -1533,7 +1532,7 @@ export class ExtHostLanguageFeatures implements extHostProtocol.ExtHostLanguageF // --- smart select registerSelectionRangeProvider(extension: IExtensionDescription, selector: vscode.DocumentSelector, provider: vscode.SelectionRangeProvider): vscode.Disposable { - const handle = this._addNewAdapter(new SelectionRangeAdapter(this._documents, provider), extension); + const handle = this._addNewAdapter(new SelectionRangeAdapter(this._documents, provider, this._logService), extension); this._proxy.$registerSelectionRangeProvider(handle, this._transformDocumentSelector(selector)); return this._createDisposable(handle); } diff --git a/src/vs/workbench/api/common/extHostMessageService.ts b/src/vs/workbench/api/common/extHostMessageService.ts index 997ca16271ff3..31154ab1de9d0 100644 --- a/src/vs/workbench/api/common/extHostMessageService.ts +++ b/src/vs/workbench/api/common/extHostMessageService.ts @@ -7,6 +7,7 @@ import Severity from 'vs/base/common/severity'; import * as vscode from 'vscode'; import { MainContext, MainThreadMessageServiceShape, MainThreadMessageOptions, IMainContext } from './extHost.protocol'; import { IExtensionDescription } from 'vs/platform/extensions/common/extensions'; +import { ILogService } from 'vs/platform/log/common/log'; function isMessageItem(item: any): item is vscode.MessageItem { return item && item.title; @@ -16,7 +17,10 @@ export class ExtHostMessageService { private _proxy: MainThreadMessageServiceShape; - constructor(mainContext: IMainContext) { + constructor( + mainContext: IMainContext, + @ILogService private readonly _logService: ILogService + ) { this._proxy = mainContext.getProxy(MainContext.MainThreadMessageService); } @@ -45,7 +49,7 @@ export class ExtHostMessageService { let { title, isCloseAffordance } = command; commands.push({ title, isCloseAffordance: !!isCloseAffordance, handle }); } else { - console.warn('Invalid message item:', command); + this._logService.warn('Invalid message item:', command); } } From 336ff850c455c6182cdc7b63a45a79043c8264c0 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Mon, 11 Nov 2019 12:26:53 +0100 Subject: [PATCH 045/352] Fix #82714 --- .../workbench/contrib/preferences/browser/keybindingWidgets.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/preferences/browser/keybindingWidgets.ts b/src/vs/workbench/contrib/preferences/browser/keybindingWidgets.ts index 4002fe6e3772f..0bfccbd8acaaa 100644 --- a/src/vs/workbench/contrib/preferences/browser/keybindingWidgets.ts +++ b/src/vs/workbench/contrib/preferences/browser/keybindingWidgets.ts @@ -82,7 +82,7 @@ export class KeybindingsSearchWidget extends SearchWidget { stopRecordingKeys(): void { this._reset(); - this.recordDisposables.dispose(); + this.recordDisposables.clear(); } setInputValue(value: string): void { From e74086a39bd14b2a770b56383c3d4be88f4cf428 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Mon, 11 Nov 2019 12:33:02 +0100 Subject: [PATCH 046/352] peek - use meta title to classify contents --- .../editor/contrib/gotoSymbol/goToCommands.ts | 43 +++---------------- .../gotoSymbol/peek/referencesController.ts | 6 +-- .../contrib/gotoSymbol/referencesModel.ts | 10 ++++- .../gotoSymbol/test/referencesModel.test.ts | 2 +- 4 files changed, 18 insertions(+), 43 deletions(-) diff --git a/src/vs/editor/contrib/gotoSymbol/goToCommands.ts b/src/vs/editor/contrib/gotoSymbol/goToCommands.ts index 8fab75a9709b8..5ec0555a5efbe 100644 --- a/src/vs/editor/contrib/gotoSymbol/goToCommands.ts +++ b/src/vs/editor/contrib/gotoSymbol/goToCommands.ts @@ -107,8 +107,6 @@ abstract class SymbolNavigationAction extends EditorAction { protected abstract _getNoResultFoundMessage(info: IWordAtPosition | null): string; - protected abstract _getMetaTitle(model: ReferencesModel): string; - protected abstract _getAlternativeCommand(): string; protected abstract _getGoToPreference(editor: IActiveCodeEditor): GoToLocationValues; @@ -171,7 +169,7 @@ abstract class SymbolNavigationAction extends EditorAction { export class DefinitionAction extends SymbolNavigationAction { protected async _getLocationModel(model: ITextModel, position: corePosition.Position, token: CancellationToken): Promise { - return new ReferencesModel(await getDefinitionsAtPosition(model, position, token)); + return new ReferencesModel(await getDefinitionsAtPosition(model, position, token), nls.localize('def.title', 'Definitions')); } protected _getNoResultFoundMessage(info: IWordAtPosition | null): string { @@ -180,10 +178,6 @@ export class DefinitionAction extends SymbolNavigationAction { : nls.localize('generic.noResults', "No definition found"); } - protected _getMetaTitle(model: ReferencesModel): string { - return model.references.length > 1 ? nls.localize('meta.title', " – {0} definitions", model.references.length) : ''; - } - protected _getAlternativeCommand(): string { return 'editor.action.goToReferences'; } @@ -295,7 +289,7 @@ registerEditorAction(class PeekDefinitionAction extends DefinitionAction { class DeclarationAction extends SymbolNavigationAction { protected async _getLocationModel(model: ITextModel, position: corePosition.Position, token: CancellationToken): Promise { - return new ReferencesModel(await getDeclarationsAtPosition(model, position, token)); + return new ReferencesModel(await getDeclarationsAtPosition(model, position, token), nls.localize('decl.title', 'Declarations')); } protected _getNoResultFoundMessage(info: IWordAtPosition | null): string { @@ -304,10 +298,6 @@ class DeclarationAction extends SymbolNavigationAction { : nls.localize('decl.generic.noResults', "No declaration found"); } - protected _getMetaTitle(model: ReferencesModel): string { - return model.references.length > 1 ? nls.localize('decl.meta.title', " – {0} declarations", model.references.length) : ''; - } - protected _getAlternativeCommand(): string { return 'editor.action.goToReferences'; } @@ -352,10 +342,6 @@ registerEditorAction(class GoToDeclarationAction extends DeclarationAction { ? nls.localize('decl.noResultWord', "No declaration found for '{0}'", info.word) : nls.localize('decl.generic.noResults', "No declaration found"); } - - protected _getMetaTitle(model: ReferencesModel): string { - return model.references.length > 1 ? nls.localize('decl.meta.title', " – {0} declarations", model.references.length) : ''; - } }); registerEditorAction(class PeekDeclarationAction extends DeclarationAction { @@ -384,7 +370,7 @@ registerEditorAction(class PeekDeclarationAction extends DeclarationAction { class TypeDefinitionAction extends SymbolNavigationAction { protected async _getLocationModel(model: ITextModel, position: corePosition.Position, token: CancellationToken): Promise { - return new ReferencesModel(await getTypeDefinitionsAtPosition(model, position, token)); + return new ReferencesModel(await getTypeDefinitionsAtPosition(model, position, token), nls.localize('typedef.title', 'Type Definitions')); } protected _getNoResultFoundMessage(info: IWordAtPosition | null): string { @@ -393,10 +379,6 @@ class TypeDefinitionAction extends SymbolNavigationAction { : nls.localize('goToTypeDefinition.generic.noResults', "No type definition found"); } - protected _getMetaTitle(model: ReferencesModel): string { - return model.references.length > 1 ? nls.localize('meta.typeDefinitions.title', " – {0} type definitions", model.references.length) : ''; - } - protected _getAlternativeCommand(): string { return 'editor.action.goToReferences'; } @@ -470,7 +452,7 @@ registerEditorAction(class PeekTypeDefinitionAction extends TypeDefinitionAction class ImplementationAction extends SymbolNavigationAction { protected async _getLocationModel(model: ITextModel, position: corePosition.Position, token: CancellationToken): Promise { - return new ReferencesModel(await getImplementationsAtPosition(model, position, token)); + return new ReferencesModel(await getImplementationsAtPosition(model, position, token), nls.localize('impl.title', 'Implementations')); } protected _getNoResultFoundMessage(info: IWordAtPosition | null): string { @@ -479,10 +461,6 @@ class ImplementationAction extends SymbolNavigationAction { : nls.localize('goToImplementation.generic.noResults', "No implementation found"); } - protected _getMetaTitle(model: ReferencesModel): string { - return model.references.length > 1 ? nls.localize('meta.implementations.title', " – {0} implementations", model.references.length) : ''; - } - protected _getAlternativeCommand(): string { return ''; } @@ -561,7 +539,7 @@ registerEditorAction(class PeekImplementationAction extends ImplementationAction class ReferencesAction extends SymbolNavigationAction { protected async _getLocationModel(model: ITextModel, position: corePosition.Position, token: CancellationToken): Promise { - return new ReferencesModel(await getReferencesAtPosition(model, position, token)); + return new ReferencesModel(await getReferencesAtPosition(model, position, token), nls.localize('ref.title', 'References')); } protected _getNoResultFoundMessage(info: IWordAtPosition | null): string { @@ -570,12 +548,6 @@ class ReferencesAction extends SymbolNavigationAction { : nls.localize('references.noGeneric', "No references found"); } - protected _getMetaTitle(model: ReferencesModel): string { - return model.references.length > 1 - ? nls.localize('meta.titleReference', " – {0} references", model.references.length) - : ''; - } - protected _getAlternativeCommand(): string { return ''; } @@ -667,7 +639,7 @@ class GenericGoToLocationAction extends SymbolNavigationAction { } protected async _getLocationModel(_model: ITextModel, _position: corePosition.Position, _token: CancellationToken): Promise { - return new ReferencesModel(this._references); + return new ReferencesModel(this._references, nls.localize('generic.title', 'Locations')); } protected _getNoResultFoundMessage(info: IWordAtPosition | null): string { @@ -678,7 +650,6 @@ class GenericGoToLocationAction extends SymbolNavigationAction { return this._gotoMultipleBehaviour ?? editor.getOption(EditorOption.gotoLocation).multipleReferences; } - protected _getMetaTitle() { return ''; } protected _getAlternativeCommand() { return ''; } } @@ -736,7 +707,7 @@ CommandsRegistry.registerCommand({ return undefined; } - const references = createCancelablePromise(token => getReferencesAtPosition(control.getModel(), corePosition.Position.lift(position), token).then(references => new ReferencesModel(references))); + const references = createCancelablePromise(token => getReferencesAtPosition(control.getModel(), corePosition.Position.lift(position), token).then(references => new ReferencesModel(references, nls.localize('ref.title', 'References')))); const range = new Range(position.lineNumber, position.column, position.lineNumber, position.column); return Promise.resolve(controller.toggleWidget(range, references, false)); }); diff --git a/src/vs/editor/contrib/gotoSymbol/peek/referencesController.ts b/src/vs/editor/contrib/gotoSymbol/peek/referencesController.ts index aaaede8378e8b..4d22101b994b4 100644 --- a/src/vs/editor/contrib/gotoSymbol/peek/referencesController.ts +++ b/src/vs/editor/contrib/gotoSymbol/peek/referencesController.ts @@ -151,10 +151,8 @@ export abstract class ReferencesController implements editorCommon.IEditorContri if (this._widget && this._model && this._editor.hasModel()) { // might have been closed // set title - if (this._model.references.length === 1) { - this._widget.setMetaTitle(nls.localize('metaTitle.1', "1 result")); - } else if (!this._model.isEmpty) { - this._widget.setMetaTitle(nls.localize('metaTitle.N', "{0} results", this._model.references.length)); + if (!this._model.isEmpty) { + this._widget.setMetaTitle(nls.localize('metaTitle.N', "{0} ({1})", this._model.title, this._model.references.length)); } else { this._widget.setMetaTitle(''); } diff --git a/src/vs/editor/contrib/gotoSymbol/referencesModel.ts b/src/vs/editor/contrib/gotoSymbol/referencesModel.ts index 77b09ed7b0f8a..fa0f2c14db2bc 100644 --- a/src/vs/editor/contrib/gotoSymbol/referencesModel.ts +++ b/src/vs/editor/contrib/gotoSymbol/referencesModel.ts @@ -149,6 +149,7 @@ export class ReferencesModel implements IDisposable { private readonly _disposables = new DisposableStore(); private readonly _links: LocationLink[]; + private readonly _title: string; readonly groups: FileReferences[] = []; readonly references: OneReference[] = []; @@ -156,8 +157,9 @@ export class ReferencesModel implements IDisposable { readonly _onDidChangeReferenceRange = new Emitter(); readonly onDidChangeReferenceRange: Event = this._onDidChangeReferenceRange.event; - constructor(links: LocationLink[]) { + constructor(links: LocationLink[], title: string) { this._links = links; + this._title = title; // grouping and sorting const [providersFirst] = links; @@ -192,7 +194,11 @@ export class ReferencesModel implements IDisposable { } clone(): ReferencesModel { - return new ReferencesModel(this._links); + return new ReferencesModel(this._links, this._title); + } + + get title(): string { + return this._title; } get isEmpty(): boolean { diff --git a/src/vs/editor/contrib/gotoSymbol/test/referencesModel.test.ts b/src/vs/editor/contrib/gotoSymbol/test/referencesModel.test.ts index f3a0d01191412..c2a1b95246a99 100644 --- a/src/vs/editor/contrib/gotoSymbol/test/referencesModel.test.ts +++ b/src/vs/editor/contrib/gotoSymbol/test/referencesModel.test.ts @@ -21,7 +21,7 @@ suite('references', function () { }, { uri: URI.file('/src/can'), range: new Range(1, 1, 1, 1) - }]); + }], 'FOO'); let ref = model.nearestReference(URI.file('/src/can'), new Position(1, 1)); assert.equal(ref!.uri.path, '/src/can'); From 5207eade914ccec12c75a6a16d36adb54d132b66 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Mon, 11 Nov 2019 12:37:22 +0100 Subject: [PATCH 047/352] use LogService in extHostStoragePaths and extHostRequireInterceptor, #84283 --- .../workbench/api/common/extHostRequireInterceptor.ts | 11 +++++++---- src/vs/workbench/api/node/extHostStoragePaths.ts | 8 ++++++-- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/src/vs/workbench/api/common/extHostRequireInterceptor.ts b/src/vs/workbench/api/common/extHostRequireInterceptor.ts index 158239df61612..b6f94048fbd3b 100644 --- a/src/vs/workbench/api/common/extHostRequireInterceptor.ts +++ b/src/vs/workbench/api/common/extHostRequireInterceptor.ts @@ -18,6 +18,7 @@ import { IExtHostInitDataService } from 'vs/workbench/api/common/extHostInitData import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IExtHostExtensionService } from 'vs/workbench/api/common/extHostExtensionService'; import { platform } from 'vs/base/common/process'; +import { ILogService } from 'vs/platform/log/common/log'; interface LoadFunction { @@ -41,7 +42,8 @@ export abstract class RequireInterceptor { @IInstantiationService private readonly _instaService: IInstantiationService, @IExtHostConfiguration private readonly _extHostConfiguration: IExtHostConfiguration, @IExtHostExtensionService private readonly _extHostExtensionService: IExtHostExtensionService, - @IExtHostInitDataService private readonly _initData: IExtHostInitDataService + @IExtHostInitDataService private readonly _initData: IExtHostInitDataService, + @ILogService private readonly _logService: ILogService, ) { this._factories = new Map(); this._alternatives = []; @@ -54,7 +56,7 @@ export abstract class RequireInterceptor { const configProvider = await this._extHostConfiguration.getConfigProvider(); const extensionPaths = await this._extHostExtensionService.getExtensionPathIndex(); - this.register(new VSCodeNodeModuleFactory(this._apiFactory, extensionPaths, this._extensionRegistry, configProvider)); + this.register(new VSCodeNodeModuleFactory(this._apiFactory, extensionPaths, this._extensionRegistry, configProvider, this._logService)); this.register(this._instaService.createInstance(KeytarNodeModuleFactory)); if (this._initData.remote.isRemote) { this.register(this._instaService.createInstance(OpenNodeModuleFactory, extensionPaths, this._initData.environment.appUriScheme)); @@ -91,7 +93,8 @@ class VSCodeNodeModuleFactory implements INodeModuleFactory { private readonly _apiFactory: IExtensionApiFactory, private readonly _extensionPaths: TernarySearchTree, private readonly _extensionRegistry: ExtensionDescriptionRegistry, - private readonly _configProvider: ExtHostConfigProvider + private readonly _configProvider: ExtHostConfigProvider, + private readonly _logService: ILogService, ) { } @@ -112,7 +115,7 @@ class VSCodeNodeModuleFactory implements INodeModuleFactory { if (!this._defaultApiImpl) { let extensionPathsPretty = ''; this._extensionPaths.forEach((value, index) => extensionPathsPretty += `\t${index} -> ${value.identifier.value}\n`); - console.warn(`Could not identify extension for 'vscode' require call from ${parent.fsPath}. These are the extension path mappings: \n${extensionPathsPretty}`); + this._logService.warn(`Could not identify extension for 'vscode' require call from ${parent.fsPath}. These are the extension path mappings: \n${extensionPathsPretty}`); this._defaultApiImpl = this._apiFactory(nullExtensionDescription, this._extensionRegistry, this._configProvider); } return this._defaultApiImpl; diff --git a/src/vs/workbench/api/node/extHostStoragePaths.ts b/src/vs/workbench/api/node/extHostStoragePaths.ts index 5a301ad857ca4..afdd6bf3984c9 100644 --- a/src/vs/workbench/api/node/extHostStoragePaths.ts +++ b/src/vs/workbench/api/node/extHostStoragePaths.ts @@ -11,6 +11,7 @@ import { IExtensionDescription } from 'vs/platform/extensions/common/extensions' import { IExtensionStoragePaths } from 'vs/workbench/api/common/extHostStoragePaths'; import { IExtHostInitDataService } from 'vs/workbench/api/common/extHostInitDataService'; import { withNullAsUndefined } from 'vs/base/common/types'; +import { ILogService } from 'vs/platform/log/common/log'; export class ExtensionStoragePaths implements IExtensionStoragePaths { @@ -22,7 +23,10 @@ export class ExtensionStoragePaths implements IExtensionStoragePaths { readonly whenReady: Promise; private _value?: string; - constructor(@IExtHostInitDataService initData: IExtHostInitDataService) { + constructor( + @IExtHostInitDataService initData: IExtHostInitDataService, + @ILogService private readonly _logService: ILogService, + ) { this._workspace = withNullAsUndefined(initData.workspace); this._environment = initData.environment; this.whenReady = this._getOrCreateWorkspaceStoragePath().then(value => this._value = value); @@ -69,7 +73,7 @@ export class ExtensionStoragePaths implements IExtensionStoragePaths { return storagePath; } catch (e) { - console.error(e); + this._logService.error(e); return undefined; } } From 3c610a66d6551b35dda11877ed5d7d037d2d8a55 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Mon, 11 Nov 2019 13:57:52 +0100 Subject: [PATCH 048/352] disable test custom editor for now --- .../browser/testCustomEditors.ts | 56 ++++++++++--------- 1 file changed, 30 insertions(+), 26 deletions(-) diff --git a/src/vs/workbench/contrib/testCustomEditors/browser/testCustomEditors.ts b/src/vs/workbench/contrib/testCustomEditors/browser/testCustomEditors.ts index 6bb83b86b553a..6f25031e1dbdc 100644 --- a/src/vs/workbench/contrib/testCustomEditors/browser/testCustomEditors.ts +++ b/src/vs/workbench/contrib/testCustomEditors/browser/testCustomEditors.ts @@ -25,7 +25,9 @@ import { generateUuid } from 'vs/base/common/uuid'; import { CancellationToken } from 'vs/base/common/cancellation'; import { editorBackground, editorForeground } from 'vs/platform/theme/common/colorRegistry'; -export class TestCustomEditorsAction extends Action { +const ENABLE = false; + +class TestCustomEditorsAction extends Action { static readonly ID = 'workbench.action.openCustomEditor'; static readonly LABEL = nls.localize('openCustomEditor', "Test Open Custom Editor"); @@ -45,7 +47,7 @@ export class TestCustomEditorsAction extends Action { } } -export class TestCustomEditor extends BaseEditor { +class TestCustomEditor extends BaseEditor { static ID = 'testCustomEditor'; @@ -109,7 +111,7 @@ export class TestCustomEditor extends BaseEditor { layout(dimension: Dimension): void { } } -export class TestCustomEditorInput extends EditorInput { +class TestCustomEditorInput extends EditorInput { private model: TestCustomEditorModel | undefined = undefined; private dirty = false; @@ -176,7 +178,7 @@ export class TestCustomEditorInput extends EditorInput { } } -export class TestCustomEditorModel extends EditorModel { +class TestCustomEditorModel extends EditorModel { public value: string = ''; @@ -185,32 +187,34 @@ export class TestCustomEditorModel extends EditorModel { } } -Registry.as(EditorExtensions.Editors).registerEditor( - new EditorDescriptor( - TestCustomEditor, - TestCustomEditor.ID, - nls.localize('testCustomEditor', "Test Custom Editor") - ), - [ - new SyncDescriptor(TestCustomEditorInput), - ] -); +if (ENABLE) { + Registry.as(EditorExtensions.Editors).registerEditor( + new EditorDescriptor( + TestCustomEditor, + TestCustomEditor.ID, + nls.localize('testCustomEditor', "Test Custom Editor") + ), + [ + new SyncDescriptor(TestCustomEditorInput), + ] + ); -const registry = Registry.as(Extensions.WorkbenchActions); + const registry = Registry.as(Extensions.WorkbenchActions); -registry.registerWorkbenchAction(new SyncActionDescriptor(TestCustomEditorsAction, TestCustomEditorsAction.ID, TestCustomEditorsAction.LABEL), 'Test Open Custom Editor'); + registry.registerWorkbenchAction(new SyncActionDescriptor(TestCustomEditorsAction, TestCustomEditorsAction.ID, TestCustomEditorsAction.LABEL), 'Test Open Custom Editor'); -class TestCustomEditorInputFactory implements IEditorInputFactory { + class TestCustomEditorInputFactory implements IEditorInputFactory { - serialize(editorInput: TestCustomEditorInput): string { - return JSON.stringify({ - resource: editorInput.resource.toString() - }); - } + serialize(editorInput: TestCustomEditorInput): string { + return JSON.stringify({ + resource: editorInput.resource.toString() + }); + } - deserialize(instantiationService: IInstantiationService, serializedEditorInput: string): TestCustomEditorInput { - return new TestCustomEditorInput(URI.parse(JSON.parse(serializedEditorInput).resource)); + deserialize(instantiationService: IInstantiationService, serializedEditorInput: string): TestCustomEditorInput { + return new TestCustomEditorInput(URI.parse(JSON.parse(serializedEditorInput).resource)); + } } -} -Registry.as(EditorInputExtensions.EditorInputFactories).registerEditorInputFactory(TestCustomEditor.ID, TestCustomEditorInputFactory); + Registry.as(EditorInputExtensions.EditorInputFactories).registerEditorInputFactory(TestCustomEditor.ID, TestCustomEditorInputFactory); +} From 9cb1cb506fd8e2b52898b3110cc6a36e2eb1ff9e Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Mon, 11 Nov 2019 14:22:24 +0100 Subject: [PATCH 049/352] #78168 Fix strict null checks --- .../extensions/browser/extensionEditor.ts | 6 +- .../extensions/browser/extensionsActions.ts | 147 +++++++++++------- 2 files changed, 91 insertions(+), 62 deletions(-) diff --git a/src/vs/workbench/contrib/extensions/browser/extensionEditor.ts b/src/vs/workbench/contrib/extensions/browser/extensionEditor.ts index 7c0193db0ec0c..e6681ffe074e7 100644 --- a/src/vs/workbench/contrib/extensions/browser/extensionEditor.ts +++ b/src/vs/workbench/contrib/extensions/browser/extensionEditor.ts @@ -452,10 +452,8 @@ export class ExtensionEditor extends BaseEditor { private setSubText(extension: IExtension, reloadAction: ReloadAction, template: IExtensionEditorTemplate): void { hide(template.subtextContainer); - const ignoreAction = this.instantiationService.createInstance(IgnoreExtensionRecommendationAction); - const undoIgnoreAction = this.instantiationService.createInstance(UndoIgnoreExtensionRecommendationAction); - ignoreAction.extension = extension; - undoIgnoreAction.extension = extension; + const ignoreAction = this.instantiationService.createInstance(IgnoreExtensionRecommendationAction, extension); + const undoIgnoreAction = this.instantiationService.createInstance(UndoIgnoreExtensionRecommendationAction, extension); ignoreAction.enabled = false; undoIgnoreAction.enabled = false; diff --git a/src/vs/workbench/contrib/extensions/browser/extensionsActions.ts b/src/vs/workbench/contrib/extensions/browser/extensionsActions.ts index 1d8099e1d2f09..2b847bf7ab540 100644 --- a/src/vs/workbench/contrib/extensions/browser/extensionsActions.ts +++ b/src/vs/workbench/contrib/extensions/browser/extensionsActions.ts @@ -135,9 +135,9 @@ function getRelativeDateLabel(date: Date): string { } export abstract class ExtensionAction extends Action implements IExtensionContainer { - private _extension: IExtension; - get extension(): IExtension { return this._extension; } - set extension(extension: IExtension) { this._extension = extension; this.update(); } + private _extension: IExtension | null = null; + get extension(): IExtension | null { return this._extension; } + set extension(extension: IExtension | null) { this._extension = extension; this.update(); } abstract update(): void; } @@ -150,7 +150,7 @@ export class InstallAction extends ExtensionAction { private static readonly InstallingClass = 'extension-action install installing'; - private _manifest: IExtensionManifest | null; + private _manifest: IExtensionManifest | null = null; set manifest(manifest: IExtensionManifest) { this._manifest = manifest; this.updateLabel(); @@ -193,6 +193,9 @@ export class InstallAction extends ExtensionAction { } private updateLabel(): void { + if (!this.extension) { + return; + } if (this.extension.state === ExtensionState.Installing) { this.label = InstallAction.INSTALLING_LABEL; this.tooltip = InstallAction.INSTALLING_LABEL; @@ -214,6 +217,9 @@ export class InstallAction extends ExtensionAction { } async run(): Promise { + if (!this.extension) { + return; + } this.extensionsWorkbenchService.open(this.extension); alert(localize('installExtensionStart', "Installing extension {0} started. An editor is now open with more details on this extension", this.extension.displayName)); @@ -303,7 +309,7 @@ export abstract class InstallInOtherServerAction extends ExtensionAction { // disabled by extension kind or it is a language pack extension && (this.extension.enablementState === EnablementState.DisabledByExtensionKind || isLanguagePackExtension(this.extension.local.manifest)) ) { - const extensionInOtherServer = this.extensionsWorkbenchService.installed.filter(e => areSameExtensions(e.identifier, this.extension.identifier) && e.server === this.server)[0]; + const extensionInOtherServer = this.extensionsWorkbenchService.installed.filter(e => areSameExtensions(e.identifier, this.extension!.identifier) && e.server === this.server)[0]; if (extensionInOtherServer) { // Getting installed in other server if (extensionInOtherServer.state === ExtensionState.Installing && !extensionInOtherServer.local) { @@ -320,6 +326,9 @@ export abstract class InstallInOtherServerAction extends ExtensionAction { } async run(): Promise { + if (!this.extension) { + return; + } if (this.server) { this.extensionsWorkbenchService.open(this.extension); alert(localize('installExtensionStart', "Installing extension {0} started. An editor is now open with more details on this extension", this.extension.displayName)); @@ -412,11 +421,14 @@ export class UninstallAction extends ExtensionAction { this.enabled = true; } - run(): Promise { + async run(): Promise { + if (!this.extension) { + return; + } alert(localize('uninstallExtensionStart', "Uninstalling extension {0} started.", this.extension.displayName)); return this.extensionsWorkbenchService.uninstall(this.extension).then(() => { - alert(localize('uninstallExtensionComplete', "Please reload Visual Studio Code to complete the uninstallation of the extension {0}.", this.extension.displayName)); + alert(localize('uninstallExtensionComplete', "Please reload Visual Studio Code to complete the uninstallation of the extension {0}.", this.extension!.displayName)); }); } } @@ -527,14 +539,17 @@ export class UpdateAction extends ExtensionAction { this.label = this.extension.outdated ? this.getUpdateLabel(this.extension.latestVersion) : this.getUpdateLabel(); } - run(): Promise { + async run(): Promise { + if (!this.extension) { + return; + } alert(localize('updateExtensionStart', "Updating extension {0} to version {1} started.", this.extension.displayName, this.extension.latestVersion)); return this.install(this.extension); } private install(extension: IExtension): Promise { return this.extensionsWorkbenchService.install(extension).then(() => { - alert(localize('updateExtensionComplete', "Updating extension {0} to version {1} completed.", this.extension.displayName, this.extension.latestVersion)); + alert(localize('updateExtensionComplete', "Updating extension {0} to version {1} completed.", extension.displayName, extension.latestVersion)); }, err => { if (!extension.gallery) { return this.notificationService.error(err); @@ -557,8 +572,6 @@ interface IExtensionActionViewItemOptions extends IActionViewItemOptions { export class ExtensionActionViewItem extends ActionViewItem { - protected options: IExtensionActionViewItemOptions; - constructor(context: any, action: IAction, options: IExtensionActionViewItemOptions = {}) { super(context, action, options); } @@ -566,14 +579,14 @@ export class ExtensionActionViewItem extends ActionViewItem { updateEnabled(): void { super.updateEnabled(); - if (this.label && this.options.tabOnlyOnFocus && this.getAction().enabled && !this._hasFocus) { + if (this.label && (this.options).tabOnlyOnFocus && this.getAction().enabled && !this._hasFocus) { DOM.removeTabIndexAndUpdateFocus(this.label); } } - private _hasFocus: boolean; + private _hasFocus: boolean = false; setFocus(value: boolean): void { - if (!this.options.tabOnlyOnFocus || this._hasFocus === value) { + if (!(this.options).tabOnlyOnFocus || this._hasFocus === value) { return; } this._hasFocus = value; @@ -600,7 +613,7 @@ export abstract class ExtensionDropDownAction extends ExtensionAction { super(id, label, cssClass, enabled); } - private _actionViewItem: DropDownMenuActionViewItem; + private _actionViewItem: DropDownMenuActionViewItem | null = null; createActionViewItem(): DropDownMenuActionViewItem { this._actionViewItem = this.instantiationService.createInstance(DropDownMenuActionViewItem, this, this.tabOnlyOnFocus); return this._actionViewItem; @@ -692,13 +705,14 @@ export class ManageExtensionAction extends ExtensionDropDownAction { groups.push([this.instantiationService.createInstance(UninstallAction)]); groups.push([this.instantiationService.createInstance(InstallAnotherVersionAction)]); - const extensionActions: ExtensionAction[] = [this.instantiationService.createInstance(ExtensionInfoAction)]; - if (this.extension.local && this.extension.local.manifest.contributes && this.extension.local.manifest.contributes.configuration) { - extensionActions.push(this.instantiationService.createInstance(ExtensionSettingsAction)); + if (this.extension) { + const extensionActions: ExtensionAction[] = [this.instantiationService.createInstance(ExtensionInfoAction)]; + if (this.extension.local && this.extension.local.manifest.contributes && this.extension.local.manifest.contributes.configuration) { + extensionActions.push(this.instantiationService.createInstance(ExtensionSettingsAction)); + } + groups.push(extensionActions); } - groups.push(extensionActions); - groups.forEach(group => group.forEach(extensionAction => extensionAction.extension = this.extension)); return groups; @@ -742,7 +756,7 @@ export class InstallAnotherVersionAction extends ExtensionAction { } update(): void { - this.enabled = this.extension && !!this.extension.gallery; + this.enabled = !!this.extension && !!this.extension.gallery; } run(): Promise { @@ -752,19 +766,19 @@ export class InstallAnotherVersionAction extends ExtensionAction { return this.quickInputService.pick(this.getVersionEntries(), { placeHolder: localize('selectVersion', "Select Version to Install"), matchOnDetail: true }) .then(pick => { if (pick) { - if (this.extension.version === pick.id) { + if (this.extension!.version === pick.id) { return Promise.resolve(); } - const promise: Promise = pick.latest ? this.extensionsWorkbenchService.install(this.extension) : this.extensionsWorkbenchService.installVersion(this.extension, pick.id); + const promise: Promise = pick.latest ? this.extensionsWorkbenchService.install(this.extension!) : this.extensionsWorkbenchService.installVersion(this.extension!, pick.id); return promise .then(null, err => { - if (!this.extension.gallery) { + if (!this.extension!.gallery) { return this.notificationService.error(err); } console.error(err); - return promptDownloadManually(this.extension.gallery, localize('failedToInstall', "Failed to install \'{0}\'.", this.extension.identifier.id), err, this.instantiationService, this.notificationService, this.openerService, this.productService); + return promptDownloadManually(this.extension!.gallery, localize('failedToInstall', "Failed to install \'{0}\'.", this.extension!.identifier.id), err, this.instantiationService, this.notificationService, this.openerService, this.productService); }); } return null; @@ -772,8 +786,8 @@ export class InstallAnotherVersionAction extends ExtensionAction { } private getVersionEntries(): Promise<(IQuickPickItem & { latest: boolean, id: string })[]> { - return this.extensionGalleryService.getAllVersions(this.extension.gallery!, true) - .then(allVersions => allVersions.map((v, i) => ({ id: v.version, label: v.version, description: `${getRelativeDateLabel(new Date(Date.parse(v.date)))}${v.version === this.extension.version ? ` (${localize('current', "Current")})` : ''}`, latest: i === 0 }))); + return this.extensionGalleryService.getAllVersions(this.extension!.gallery!, true) + .then(allVersions => allVersions.map((v, i) => ({ id: v.version, label: v.version, description: `${getRelativeDateLabel(new Date(Date.parse(v.date)))}${v.version === this.extension!.version ? ` (${localize('current', "Current")})` : ''}`, latest: i === 0 }))); } } @@ -793,7 +807,10 @@ export class ExtensionInfoAction extends ExtensionAction { this.enabled = !!this.extension; } - run(): Promise { + async run(): Promise { + if (!this.extension) { + return; + } const name = localize('extensionInfoName', 'Name: {0}', this.extension.displayName); const id = localize('extensionInfoId', 'Id: {0}', this.extension.identifier.id); @@ -823,7 +840,11 @@ export class ExtensionSettingsAction extends ExtensionAction { update(): void { this.enabled = !!this.extension; } - run(): Promise { + + async run(): Promise { + if (!this.extension) { + return; + } this.preferencesService.openSettings(false, `@ext:${this.extension.identifier.id}`); return Promise.resolve(); } @@ -851,7 +872,10 @@ export class EnableForWorkspaceAction extends ExtensionAction { } } - run(): Promise { + async run(): Promise { + if (!this.extension) { + return; + } return this.extensionsWorkbenchService.setEnablement(this.extension, EnablementState.EnabledWorkspace); } } @@ -878,7 +902,10 @@ export class EnableGloballyAction extends ExtensionAction { } } - run(): Promise { + async run(): Promise { + if (!this.extension) { + return; + } return this.extensionsWorkbenchService.setEnablement(this.extension, EnablementState.EnabledGlobally); } } @@ -899,14 +926,17 @@ export class DisableForWorkspaceAction extends ExtensionAction { update(): void { this.enabled = false; - if (this.extension && this.extension.local && this.runningExtensions.some(e => areSameExtensions({ id: e.identifier.value, uuid: e.uuid }, this.extension.identifier) && this.workspaceContextService.getWorkbenchState() !== WorkbenchState.EMPTY)) { + if (this.extension && this.extension.local && this.runningExtensions.some(e => areSameExtensions({ id: e.identifier.value, uuid: e.uuid }, this.extension!.identifier) && this.workspaceContextService.getWorkbenchState() !== WorkbenchState.EMPTY)) { this.enabled = this.extension.state === ExtensionState.Installed && (this.extension.enablementState === EnablementState.EnabledGlobally || this.extension.enablementState === EnablementState.EnabledWorkspace) && this.extensionEnablementService.canChangeEnablement(this.extension.local); } } - run(): Promise { + async run(): Promise { + if (!this.extension) { + return; + } return this.extensionsWorkbenchService.setEnablement(this.extension, EnablementState.DisabledWorkspace); } } @@ -926,14 +956,17 @@ export class DisableGloballyAction extends ExtensionAction { update(): void { this.enabled = false; - if (this.extension && this.extension.local && this.runningExtensions.some(e => areSameExtensions({ id: e.identifier.value, uuid: e.uuid }, this.extension.identifier))) { + if (this.extension && this.extension.local && this.runningExtensions.some(e => areSameExtensions({ id: e.identifier.value, uuid: e.uuid }, this.extension!.identifier))) { this.enabled = this.extension.state === ExtensionState.Installed && (this.extension.enablementState === EnablementState.EnabledGlobally || this.extension.enablementState === EnablementState.EnabledWorkspace) && this.extensionEnablementService.canChangeEnablement(this.extension.local); } } - run(): Promise { + async run(): Promise { + if (!this.extension) { + return; + } return this.extensionsWorkbenchService.setEnablement(this.extension, EnablementState.DisabledGlobally); } } @@ -1190,11 +1223,11 @@ export class ReloadAction extends ExtensionAction { } private computeReloadState(): void { - if (!this._runningExtensions) { + if (!this._runningExtensions || !this.extension) { return; } const isUninstalled = this.extension.state === ExtensionState.Uninstalled; - const runningExtension = this._runningExtensions.filter(e => areSameExtensions({ id: e.identifier.value, uuid: e.uuid }, this.extension.identifier))[0]; + const runningExtension = this._runningExtensions.filter(e => areSameExtensions({ id: e.identifier.value, uuid: e.uuid }, this.extension!.identifier))[0]; const isSameExtensionRunning = runningExtension && this.extension.server === this.extensionManagementServerService.getExtensionManagementServer(runningExtension.extensionLocation); if (isUninstalled) { @@ -1242,7 +1275,7 @@ export class ReloadAction extends ExtensionAction { const otherServer = this.extension.server ? this.extension.server === this.extensionManagementServerService.localExtensionManagementServer ? this.extensionManagementServerService.remoteExtensionManagementServer : this.extensionManagementServerService.localExtensionManagementServer : null; if (otherServer && this.extension.enablementState === EnablementState.DisabledByExtensionKind) { - const extensionInOtherServer = this.extensionsWorkbenchService.local.filter(e => areSameExtensions(e.identifier, this.extension.identifier) && e.server === otherServer)[0]; + const extensionInOtherServer = this.extensionsWorkbenchService.local.filter(e => areSameExtensions(e.identifier, this.extension!.identifier) && e.server === otherServer)[0]; // Same extension in other server exists and if (extensionInOtherServer && extensionInOtherServer.local && this.extensionEnablementService.isEnabled(extensionInOtherServer.local)) { this.enabled = true; @@ -1300,7 +1333,7 @@ export class SetColorThemeAction extends ExtensionAction { if (!this.enabled) { return; } - let extensionThemes = SetColorThemeAction.getColorThemes(this.colorThemes, this.extension); + let extensionThemes = SetColorThemeAction.getColorThemes(this.colorThemes, this.extension!); const currentTheme = this.colorThemes.filter(t => t.settingsId === this.configurationService.getValue(COLOR_THEME_SETTING))[0]; showCurrentTheme = showCurrentTheme || extensionThemes.some(t => t.id === currentTheme.id); if (showCurrentTheme) { @@ -1366,7 +1399,7 @@ export class SetFileIconThemeAction extends ExtensionAction { if (!this.enabled) { return; } - let extensionThemes = SetFileIconThemeAction.getFileIconThemes(this.fileIconThemes, this.extension); + let extensionThemes = SetFileIconThemeAction.getFileIconThemes(this.fileIconThemes, this.extension!); const currentTheme = this.fileIconThemes.filter(t => t.settingsId === this.configurationService.getValue(ICON_THEME_SETTING))[0] || this.workbenchThemeService.getFileIconTheme(); showCurrentTheme = showCurrentTheme || extensionThemes.some(t => t.id === currentTheme.id); if (showCurrentTheme) { @@ -1719,9 +1752,8 @@ export class IgnoreExtensionRecommendationAction extends Action { private static readonly Class = 'extension-action ignore'; - extension: IExtension; - constructor( + private readonly extension: IExtension, @IExtensionTipsService private readonly extensionsTipsService: IExtensionTipsService, ) { super(IgnoreExtensionRecommendationAction.ID, 'Ignore Recommendation'); @@ -1743,9 +1775,8 @@ export class UndoIgnoreExtensionRecommendationAction extends Action { private static readonly Class = 'extension-action undo-ignore'; - extension: IExtension; - constructor( + private readonly extension: IExtension, @IExtensionTipsService private readonly extensionsTipsService: IExtensionTipsService, ) { super(UndoIgnoreExtensionRecommendationAction.ID, 'Undo'); @@ -2389,9 +2420,9 @@ export class StatusLabelAction extends Action implements IExtensionContainer { private status: ExtensionState | null = null; private enablementState: EnablementState | null = null; - private _extension: IExtension; - get extension(): IExtension { return this._extension; } - set extension(extension: IExtension) { + private _extension: IExtension | null = null; + get extension(): IExtension | null { return this._extension; } + set extension(extension: IExtension | null) { if (!(this._extension && extension && areSameExtensions(this._extension.identifier, extension.identifier))) { // Different extension. Reset this.initialStatus = null; @@ -2432,21 +2463,21 @@ export class StatusLabelAction extends Action implements IExtensionContainer { const runningExtensions = await this.extensionService.getExtensions(); const canAddExtension = () => { - const runningExtension = runningExtensions.filter(e => areSameExtensions({ id: e.identifier.value, uuid: e.uuid }, this.extension.identifier))[0]; - if (this.extension.local) { - if (runningExtension && this.extension.version === runningExtension.version) { + const runningExtension = runningExtensions.filter(e => areSameExtensions({ id: e.identifier.value, uuid: e.uuid }, this.extension!.identifier))[0]; + if (this.extension!.local) { + if (runningExtension && this.extension!.version === runningExtension.version) { return true; } - return this.extensionService.canAddExtension(toExtensionDescription(this.extension.local)); + return this.extensionService.canAddExtension(toExtensionDescription(this.extension!.local)); } return false; }; const canRemoveExtension = () => { - if (this.extension.local) { - if (runningExtensions.every(e => !(areSameExtensions({ id: e.identifier.value, uuid: e.uuid }, this.extension.identifier) && this.extension.server === this.extensionManagementServerService.getExtensionManagementServer(e.extensionLocation)))) { + if (this.extension!.local) { + if (runningExtensions.every(e => !(areSameExtensions({ id: e.identifier.value, uuid: e.uuid }, this.extension!.identifier) && this.extension!.server === this.extensionManagementServerService.getExtensionManagementServer(e.extensionLocation)))) { return true; } - return this.extensionService.canRemoveExtension(toExtensionDescription(this.extension.local)); + return this.extensionService.canRemoveExtension(toExtensionDescription(this.extension!.local)); } return false; }; @@ -2549,7 +2580,7 @@ export class ExtensionToolTipAction extends ExtensionAction { return this.warningAction.tooltip; } if (this.extension && this.extension.local && this.extension.state === ExtensionState.Installed && this._runningExtensions) { - const isRunning = this._runningExtensions.some(e => areSameExtensions({ id: e.identifier.value, uuid: e.uuid }, this.extension.identifier)); + const isRunning = this._runningExtensions.some(e => areSameExtensions({ id: e.identifier.value, uuid: e.uuid }, this.extension!.identifier)); const isEnabled = this.extensionEnablementService.isEnabled(this.extension.local); if (isEnabled && isRunning) { @@ -2623,7 +2654,7 @@ export class SystemDisabledWarningAction extends ExtensionAction { return; } if (isLanguagePackExtension(this.extension.local.manifest)) { - if (!this.extensionsWorkbenchService.installed.some(e => areSameExtensions(e.identifier, this.extension.identifier) && e.server !== this.extension.server)) { + if (!this.extensionsWorkbenchService.installed.some(e => areSameExtensions(e.identifier, this.extension!.identifier) && e.server !== this.extension!.server)) { this.class = `${SystemDisabledWarningAction.INFO_CLASS}`; this.tooltip = this.extension.server === this.extensionManagementServerService.localExtensionManagementServer ? localize('Install language pack also in remote server', "Install the language pack extension on '{0}' to enable it also there.", this.extensionManagementServerService.remoteExtensionManagementServer.label) @@ -2632,13 +2663,13 @@ export class SystemDisabledWarningAction extends ExtensionAction { return; } if (this.extension.enablementState === EnablementState.DisabledByExtensionKind) { - if (!this.extensionsWorkbenchService.installed.some(e => areSameExtensions(e.identifier, this.extension.identifier) && e.server !== this.extension.server)) { + if (!this.extensionsWorkbenchService.installed.some(e => areSameExtensions(e.identifier, this.extension!.identifier) && e.server !== this.extension!.server)) { this.class = `${SystemDisabledWarningAction.WARNING_CLASS}`; const server = this.extensionManagementServerService.localExtensionManagementServer === this.extension.server ? this.extensionManagementServerService.remoteExtensionManagementServer : this.extensionManagementServerService.localExtensionManagementServer; this.tooltip = localize('Install in other server to enable', "Install the extension on '{0}' to enable.", server.label); return; } - const runningExtension = this._runningExtensions.filter(e => areSameExtensions({ id: e.identifier.value, uuid: e.uuid }, this.extension.identifier))[0]; + const runningExtension = this._runningExtensions.filter(e => areSameExtensions({ id: e.identifier.value, uuid: e.uuid }, this.extension!.identifier))[0]; const runningExtensionServer = runningExtension ? this.extensionManagementServerService.getExtensionManagementServer(runningExtension.extensionLocation) : null; if (this.extension.server === this.extensionManagementServerService.localExtensionManagementServer && runningExtensionServer === this.extensionManagementServerService.remoteExtensionManagementServer) { this.class = `${SystemDisabledWarningAction.INFO_CLASS}`; From 3c39263275858211a4c2cb7a8dd9af901a7e976d Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Mon, 11 Nov 2019 14:37:28 +0100 Subject: [PATCH 050/352] #78168 Strict null check --- .../preferences/browser/keybindingsEditor.ts | 110 +++++++----------- 1 file changed, 45 insertions(+), 65 deletions(-) diff --git a/src/vs/workbench/contrib/preferences/browser/keybindingsEditor.ts b/src/vs/workbench/contrib/preferences/browser/keybindingsEditor.ts index 4169b1d34bb25..e4b845e14a7c9 100644 --- a/src/vs/workbench/contrib/preferences/browser/keybindingsEditor.ts +++ b/src/vs/workbench/contrib/preferences/browser/keybindingsEditor.ts @@ -65,22 +65,22 @@ export class KeybindingsEditor extends BaseEditor implements IKeybindingsEditor private _onLayout: Emitter = this._register(new Emitter()); readonly onLayout: Event = this._onLayout.event; - private keybindingsEditorModel: KeybindingsEditorModel; + private keybindingsEditorModel: KeybindingsEditorModel | null = null; - private headerContainer: HTMLElement; - private actionsContainer: HTMLElement; - private searchWidget: KeybindingsSearchWidget; + private headerContainer!: HTMLElement; + private actionsContainer!: HTMLElement; + private searchWidget!: KeybindingsSearchWidget; - private overlayContainer: HTMLElement; - private defineKeybindingWidget: DefineKeybindingWidget; + private overlayContainer!: HTMLElement; + private defineKeybindingWidget!: DefineKeybindingWidget; private columnItems: ColumnItem[] = []; - private keybindingsListContainer: HTMLElement; - private unAssignedKeybindingItemToRevealAndFocus: IKeybindingItemEntry | null; - private listEntries: IListEntry[]; - private keybindingsList: WorkbenchList; + private keybindingsListContainer!: HTMLElement; + private unAssignedKeybindingItemToRevealAndFocus: IKeybindingItemEntry | null = null; + private listEntries: IListEntry[] = []; + private keybindingsList!: WorkbenchList; - private dimension: DOM.Dimension; + private dimension: DOM.Dimension | null = null; private delayedFiltering: Delayer; private latestEmptyFilters: string[] = []; private delayedFilterLogging: Delayer; @@ -88,11 +88,10 @@ export class KeybindingsEditor extends BaseEditor implements IKeybindingsEditor private keybindingFocusContextKey: IContextKey; private searchFocusContextKey: IContextKey; - private actionBar: ActionBar; - private sortByPrecedenceAction: Action; - private recordKeysAction: Action; + private readonly sortByPrecedenceAction: Action; + private readonly recordKeysAction: Action; - private ariaLabelElement: HTMLElement; + private ariaLabelElement!: HTMLElement; constructor( @ITelemetryService telemetryService: ITelemetryService, @@ -115,6 +114,16 @@ export class KeybindingsEditor extends BaseEditor implements IKeybindingsEditor this.searchFocusContextKey = CONTEXT_KEYBINDINGS_SEARCH_FOCUS.bindTo(this.contextKeyService); this.keybindingFocusContextKey = CONTEXT_KEYBINDING_FOCUS.bindTo(this.contextKeyService); this.delayedFilterLogging = new Delayer(1000); + + const recordKeysActionKeybinding = this.keybindingsService.lookupKeybinding(KEYBINDINGS_EDITOR_COMMAND_RECORD_SEARCH_KEYS); + const recordKeysActionLabel = localize('recordKeysLabel', "Record Keys"); + this.recordKeysAction = new Action(KEYBINDINGS_EDITOR_COMMAND_RECORD_SEARCH_KEYS, recordKeysActionKeybinding ? localize('recordKeysLabelWithKeybinding', "{0} ({1})", recordKeysActionLabel, recordKeysActionKeybinding.getLabel()) : recordKeysActionLabel, 'codicon-record-keys'); + this.recordKeysAction.checked = false; + + const sortByPrecedenceActionKeybinding = this.keybindingsService.lookupKeybinding(KEYBINDINGS_EDITOR_COMMAND_SORTBY_PRECEDENCE); + const sortByPrecedenceActionLabel = localize('sortByPrecedeneLabel', "Sort by Precedence"); + this.sortByPrecedenceAction = new Action('keybindings.editor.sortByPrecedence', sortByPrecedenceActionKeybinding ? localize('sortByPrecedeneLabelWithKeybinding', "{0} ({1})", sortByPrecedenceActionLabel, sortByPrecedenceActionKeybinding.getLabel()) : sortByPrecedenceActionLabel, 'codicon-sort-precedence'); + this.sortByPrecedenceAction.checked = false; } createEditor(parent: HTMLElement): void { @@ -298,7 +307,7 @@ export class KeybindingsEditor extends BaseEditor implements IKeybindingsEditor this.overlayContainer.style.position = 'absolute'; this.overlayContainer.style.zIndex = '10'; this.defineKeybindingWidget = this._register(this.instantiationService.createInstance(DefineKeybindingWidget, this.overlayContainer)); - this._register(this.defineKeybindingWidget.onDidChange(keybindingStr => this.defineKeybindingWidget.printExisting(this.keybindingsEditorModel.fetch(`"${keybindingStr}"`).length))); + this._register(this.defineKeybindingWidget.onDidChange(keybindingStr => this.defineKeybindingWidget.printExisting(this.keybindingsEditorModel!.fetch(`"${keybindingStr}"`).length))); this._register(this.defineKeybindingWidget.onShowExistingKeybidings(keybindingStr => this.searchWidget.setValue(`"${keybindingStr}"`))); this.hideOverlayContainer(); } @@ -337,10 +346,6 @@ export class KeybindingsEditor extends BaseEditor implements IKeybindingsEditor this.actionsContainer = DOM.append(searchContainer, DOM.$('.keybindings-search-actions-container')); const recordingBadge = this.createRecordingBadge(this.actionsContainer); - const sortByPrecedenceActionKeybinding = this.keybindingsService.lookupKeybinding(KEYBINDINGS_EDITOR_COMMAND_SORTBY_PRECEDENCE); - const sortByPrecedenceActionLabel = localize('sortByPrecedeneLabel', "Sort by Precedence"); - this.sortByPrecedenceAction = new Action('keybindings.editor.sortByPrecedence', sortByPrecedenceActionKeybinding ? localize('sortByPrecedeneLabelWithKeybinding', "{0} ({1})", sortByPrecedenceActionLabel, sortByPrecedenceActionKeybinding.getLabel()) : sortByPrecedenceActionLabel, 'codicon-sort-precedence'); - this.sortByPrecedenceAction.checked = false; this._register(this.sortByPrecedenceAction.onDidChange(e => { if (e.checked !== undefined) { this.renderKeybindingsEntries(false); @@ -348,10 +353,6 @@ export class KeybindingsEditor extends BaseEditor implements IKeybindingsEditor this.updateSearchOptions(); })); - const recordKeysActionKeybinding = this.keybindingsService.lookupKeybinding(KEYBINDINGS_EDITOR_COMMAND_RECORD_SEARCH_KEYS); - const recordKeysActionLabel = localize('recordKeysLabel', "Record Keys"); - this.recordKeysAction = new Action(KEYBINDINGS_EDITOR_COMMAND_RECORD_SEARCH_KEYS, recordKeysActionKeybinding ? localize('recordKeysLabelWithKeybinding', "{0} ({1})", recordKeysActionLabel, recordKeysActionKeybinding.getLabel()) : recordKeysActionLabel, 'codicon-record-keys'); - this.recordKeysAction.checked = false; this._register(this.recordKeysAction.onDidChange(e => { if (e.checked !== undefined) { DOM.toggleClass(recordingBadge, 'disabled', !e.checked); @@ -370,7 +371,7 @@ export class KeybindingsEditor extends BaseEditor implements IKeybindingsEditor } })); - this.actionBar = this._register(new ActionBar(this.actionsContainer, { + const actionBar = this._register(new ActionBar(this.actionsContainer, { animated: false, actionViewItemProvider: (action: Action) => { if (action.id === this.sortByPrecedenceAction.id) { @@ -383,7 +384,7 @@ export class KeybindingsEditor extends BaseEditor implements IKeybindingsEditor } })); - this.actionBar.push([this.recordKeysAction, this.sortByPrecedenceAction, clearInputAction], { label: false, icon: true }); + actionBar.push([this.recordKeysAction, this.sortByPrecedenceAction, clearInputAction], { label: false, icon: true }); } private updateSearchOptions(): void { @@ -563,6 +564,9 @@ export class KeybindingsEditor extends BaseEditor implements IKeybindingsEditor } private layoutKeybindingsList(): void { + if (!this.dimension) { + return; + } let width = this.dimension.width - 27; for (const columnItem of this.columnItems) { if (columnItem.width && !columnItem.proportion) { @@ -855,7 +859,7 @@ abstract class Column extends Disposable { class ActionsColumn extends Column { - private actionBar: ActionBar; + private readonly actionBar: ActionBar; readonly element: HTMLElement; constructor( @@ -864,13 +868,8 @@ class ActionsColumn extends Column { @IKeybindingService private keybindingsService: IKeybindingService ) { super(keybindingsEditor); - this.element = this.create(parent); - } - - create(parent: HTMLElement): HTMLElement { - const actionsContainer = DOM.append(parent, $('.column.actions', { id: 'actions_' + ++Column.COUNTER })); - this.actionBar = new ActionBar(actionsContainer, { animated: false }); - return actionsContainer; + this.element = DOM.append(parent, $('.column.actions', { id: 'actions_' + ++Column.COUNTER })); + this.actionBar = new ActionBar(this.element, { animated: false }); } render(keybindingItemEntry: IKeybindingItemEntry): void { @@ -914,7 +913,7 @@ class ActionsColumn extends Column { class CommandColumn extends Column { - private commandColumn: HTMLElement; + private readonly commandColumn: HTMLElement; readonly element: HTMLElement; constructor( @@ -922,12 +921,7 @@ class CommandColumn extends Column { keybindingsEditor: IKeybindingsEditor, ) { super(keybindingsEditor); - this.element = this.create(parent); - } - - private create(parent: HTMLElement): HTMLElement { - this.commandColumn = DOM.append(parent, $('.column.command', { id: 'command_' + ++Column.COUNTER })); - return this.commandColumn; + this.element = this.commandColumn = DOM.append(parent, $('.column.command', { id: 'command_' + ++Column.COUNTER })); } render(keybindingItemEntry: IKeybindingItemEntry): void { @@ -962,7 +956,7 @@ class CommandColumn extends Column { class KeybindingColumn extends Column { - private keybindingLabel: HTMLElement; + private readonly keybindingLabel: HTMLElement; readonly element: HTMLElement; constructor( @@ -970,13 +964,9 @@ class KeybindingColumn extends Column { keybindingsEditor: IKeybindingsEditor, ) { super(keybindingsEditor); - this.element = this.create(parent); - } - private create(parent: HTMLElement): HTMLElement { - const column = DOM.append(parent, $('.column.keybinding', { id: 'keybinding_' + ++Column.COUNTER })); - this.keybindingLabel = DOM.append(column, $('div.keybinding-label')); - return column; + this.element = DOM.append(parent, $('.column.keybinding', { id: 'keybinding_' + ++Column.COUNTER })); + this.keybindingLabel = DOM.append(this.element, $('div.keybinding-label')); } render(keybindingItemEntry: IKeybindingItemEntry): void { @@ -994,7 +984,7 @@ class KeybindingColumn extends Column { class SourceColumn extends Column { - private sourceColumn: HTMLElement; + private readonly sourceColumn: HTMLElement; readonly element: HTMLElement; constructor( @@ -1002,12 +992,7 @@ class SourceColumn extends Column { keybindingsEditor: IKeybindingsEditor, ) { super(keybindingsEditor); - this.element = this.create(parent); - } - - create(parent: HTMLElement): HTMLElement { - this.sourceColumn = DOM.append(parent, $('.column.source', { id: 'source_' + ++Column.COUNTER })); - return this.sourceColumn; + this.element = this.sourceColumn = DOM.append(parent, $('.column.source', { id: 'source_' + ++Column.COUNTER })); } render(keybindingItemEntry: IKeybindingItemEntry): void { @@ -1024,8 +1009,8 @@ class SourceColumn extends Column { class WhenColumn extends Column { readonly element: HTMLElement; - private whenLabel: HTMLElement; - private whenInput: InputBox; + private readonly whenLabel: HTMLElement; + private readonly whenInput: InputBox; private readonly renderDisposables = this._register(new DisposableStore()); private _onDidAccept: Emitter = this._register(new Emitter()); @@ -1041,14 +1026,11 @@ class WhenColumn extends Column { @IThemeService private readonly themeService: IThemeService ) { super(keybindingsEditor); - this.element = this.create(parent); - } - private create(parent: HTMLElement): HTMLElement { - const column = DOM.append(parent, $('.column.when', { id: 'when_' + ++Column.COUNTER })); + this.element = DOM.append(parent, $('.column.when', { id: 'when_' + ++Column.COUNTER })); - this.whenLabel = DOM.append(column, $('div.when-label')); - this.whenInput = new InputBox(column, this.contextViewService, { + this.whenLabel = DOM.append(this.element, $('div.when-label')); + this.whenInput = new InputBox(this.element, this.contextViewService, { validationOptions: { validation: (value) => { try { @@ -1068,8 +1050,6 @@ class WhenColumn extends Column { this._register(attachInputBoxStyler(this.whenInput, this.themeService)); this._register(DOM.addStandardDisposableListener(this.whenInput.inputElement, DOM.EventType.KEY_DOWN, e => this.onInputKeyDown(e))); this._register(DOM.addDisposableListener(this.whenInput.inputElement, DOM.EventType.BLUR, () => this.cancelEditing())); - - return column; } private onInputKeyDown(e: IKeyboardEvent): void { From f54691d1b329a1d48ff95af7ef37056d48dbe07f Mon Sep 17 00:00:00 2001 From: isidor Date: Mon, 11 Nov 2019 15:43:47 +0100 Subject: [PATCH 051/352] debug: enabling breakpoints should set them to activated fixes #83323 --- src/vs/workbench/contrib/debug/common/debugModel.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/vs/workbench/contrib/debug/common/debugModel.ts b/src/vs/workbench/contrib/debug/common/debugModel.ts index 2dc46ce56f910..0e647c09b2338 100644 --- a/src/vs/workbench/contrib/debug/common/debugModel.ts +++ b/src/vs/workbench/contrib/debug/common/debugModel.ts @@ -1093,6 +1093,9 @@ export class DebugModel implements IDebugModel { } element.enabled = enable; + if (enable) { + this.breakpointsActivated = true; + } this._onDidChangeBreakpoints.fire({ changed: changed }); } @@ -1119,6 +1122,9 @@ export class DebugModel implements IDebugModel { } dbp.enabled = enable; }); + if (enable) { + this.breakpointsActivated = true; + } this._onDidChangeBreakpoints.fire({ changed: changed }); } From ba26877c62bf529842da8bb889a04873f1c28e17 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Mon, 11 Nov 2019 15:47:38 +0100 Subject: [PATCH 052/352] add controller, add navigation functions, add commands --- .../contrib/documentSymbols/outlineModel.ts | 20 +++ .../documentSymbols/outlineNavigation.ts | 114 ++++++++++++++++++ src/vs/editor/editor.all.ts | 1 + 3 files changed, 135 insertions(+) create mode 100644 src/vs/editor/contrib/documentSymbols/outlineNavigation.ts diff --git a/src/vs/editor/contrib/documentSymbols/outlineModel.ts b/src/vs/editor/contrib/documentSymbols/outlineModel.ts index 8059fdbdcfd40..947d99f0f1bbc 100644 --- a/src/vs/editor/contrib/documentSymbols/outlineModel.ts +++ b/src/vs/editor/contrib/documentSymbols/outlineModel.ts @@ -29,6 +29,26 @@ export abstract class TreeElement { } } + // todo@joh sort by position! + firstChild(): TreeElement | undefined { + const [first] = Object.keys(this.children); + return this.children[first]; + } + + lastChild(): TreeElement | undefined { + const [last] = Object.keys(this.children).slice(-1); + return this.children[last]; + } + + sibling(next: boolean): TreeElement | undefined { + if (!this.parent) { + return undefined; + } + const all = Object.keys(this.parent.children); + const index = all.indexOf(this.id) + (next ? +1 : -1); + return this.parent.children[all[index]]; + } + static findId(candidate: DocumentSymbol | string, container: TreeElement): string { // complex id-computation which contains the origin/extension, // the parent path, and some dedupe logic when names collide diff --git a/src/vs/editor/contrib/documentSymbols/outlineNavigation.ts b/src/vs/editor/contrib/documentSymbols/outlineNavigation.ts new file mode 100644 index 0000000000000..8a4477e55b069 --- /dev/null +++ b/src/vs/editor/contrib/documentSymbols/outlineNavigation.ts @@ -0,0 +1,114 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import 'vs/css!./media/outlineTree'; +import 'vs/css!./media/symbol-icons'; +import { Range } from 'vs/editor/common/core/range'; +import { OutlineElement, OutlineModel } from 'vs/editor/contrib/documentSymbols/outlineModel'; +import { localize } from 'vs/nls'; +import { IEditorContribution } from 'vs/editor/common/editorCommon'; +import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; +import { CancellationTokenSource } from 'vs/base/common/cancellation'; +import { EditorStateCancellationTokenSource, CodeEditorStateFlag } from 'vs/editor/browser/core/editorState'; +import { EditorAction, registerEditorAction, registerEditorContribution } from 'vs/editor/browser/editorExtensions'; +import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; +import { EditorContextKeys } from 'vs/editor/common/editorContextKeys'; + +export class OutlineNavigation implements IEditorContribution { + + public static readonly ID = 'editor.contrib.OutlineNavigation'; + + public static get(editor: ICodeEditor): OutlineNavigation { + return editor.getContribution(OutlineNavigation.ID); + } + + private readonly _editor: ICodeEditor; + + private _cts?: CancellationTokenSource; + + constructor( + editor: ICodeEditor, + ) { + this._editor = editor; + } + + dispose(): void { + if (this._cts) { + this._cts.dispose(true); + } + } + + async goto(next: boolean) { + + if (this._cts) { + this._cts.cancel(); + } + + if (!this._editor.hasModel()) { + return; + } + + const textModel = this._editor.getModel(); + const position = this._editor.getPosition(); + + this._cts = new EditorStateCancellationTokenSource(this._editor, CodeEditorStateFlag.Position | CodeEditorStateFlag.Value | CodeEditorStateFlag.Scroll); + + const outlineModel = await OutlineModel.create(textModel, this._cts.token); + const element = outlineModel.getItemEnclosingPosition(position); + + if (!element) { + return; + } + + let nextElement = element.sibling(next); + if (!nextElement && element.parent) { + let nextParent = element.parent.sibling(next); + if (nextParent) { + nextElement = next ? nextParent.firstChild() : nextParent.lastChild(); + } + } + + if (!(nextElement instanceof OutlineElement)) { + return; + } + + this._editor.setPosition(Range.lift(nextElement.symbol.selectionRange).getStartPosition()); + } + +} + +registerEditorContribution(OutlineNavigation.ID, OutlineNavigation); + +registerEditorAction(class extends EditorAction { + + constructor() { + super({ + id: 'editor.action.gotoNextSymbol', + label: localize('label.next', "Go to Next Symbol"), + alias: 'Go to Next Symbol', + precondition: EditorContextKeys.hasDocumentSymbolProvider, + }); + } + + run(_accessor: ServicesAccessor, editor: ICodeEditor): void | Promise { + OutlineNavigation.get(editor).goto(true); + } +}); + +registerEditorAction(class extends EditorAction { + + constructor() { + super({ + id: 'editor.action.gotoPrevSymbol', + label: localize('label.prev', "Go to Previous Symbol"), + alias: 'Go to Previous Symbol', + precondition: EditorContextKeys.hasDocumentSymbolProvider, + }); + } + + run(_accessor: ServicesAccessor, editor: ICodeEditor): void | Promise { + OutlineNavigation.get(editor).goto(false); + } +}); diff --git a/src/vs/editor/editor.all.ts b/src/vs/editor/editor.all.ts index 31a6ad0497b5b..a862f9accbc3f 100644 --- a/src/vs/editor/editor.all.ts +++ b/src/vs/editor/editor.all.ts @@ -18,6 +18,7 @@ import 'vs/editor/contrib/comment/comment'; import 'vs/editor/contrib/contextmenu/contextmenu'; import 'vs/editor/contrib/cursorUndo/cursorUndo'; import 'vs/editor/contrib/dnd/dnd'; +import 'vs/editor/contrib/documentSymbols/outlineNavigation'; import 'vs/editor/contrib/find/findController'; import 'vs/editor/contrib/folding/folding'; import 'vs/editor/contrib/fontZoom/fontZoom'; From f9285ac2b58a0bf385a229542f8b025e6baf8b07 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Mon, 11 Nov 2019 12:37:22 +0100 Subject: [PATCH 053/352] use LogService in extHostStoragePaths and extHostRequireInterceptor, #84283 --- .../workbench/api/common/extHostRequireInterceptor.ts | 11 +++++++---- src/vs/workbench/api/node/extHostStoragePaths.ts | 8 ++++++-- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/src/vs/workbench/api/common/extHostRequireInterceptor.ts b/src/vs/workbench/api/common/extHostRequireInterceptor.ts index 158239df61612..b6f94048fbd3b 100644 --- a/src/vs/workbench/api/common/extHostRequireInterceptor.ts +++ b/src/vs/workbench/api/common/extHostRequireInterceptor.ts @@ -18,6 +18,7 @@ import { IExtHostInitDataService } from 'vs/workbench/api/common/extHostInitData import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IExtHostExtensionService } from 'vs/workbench/api/common/extHostExtensionService'; import { platform } from 'vs/base/common/process'; +import { ILogService } from 'vs/platform/log/common/log'; interface LoadFunction { @@ -41,7 +42,8 @@ export abstract class RequireInterceptor { @IInstantiationService private readonly _instaService: IInstantiationService, @IExtHostConfiguration private readonly _extHostConfiguration: IExtHostConfiguration, @IExtHostExtensionService private readonly _extHostExtensionService: IExtHostExtensionService, - @IExtHostInitDataService private readonly _initData: IExtHostInitDataService + @IExtHostInitDataService private readonly _initData: IExtHostInitDataService, + @ILogService private readonly _logService: ILogService, ) { this._factories = new Map(); this._alternatives = []; @@ -54,7 +56,7 @@ export abstract class RequireInterceptor { const configProvider = await this._extHostConfiguration.getConfigProvider(); const extensionPaths = await this._extHostExtensionService.getExtensionPathIndex(); - this.register(new VSCodeNodeModuleFactory(this._apiFactory, extensionPaths, this._extensionRegistry, configProvider)); + this.register(new VSCodeNodeModuleFactory(this._apiFactory, extensionPaths, this._extensionRegistry, configProvider, this._logService)); this.register(this._instaService.createInstance(KeytarNodeModuleFactory)); if (this._initData.remote.isRemote) { this.register(this._instaService.createInstance(OpenNodeModuleFactory, extensionPaths, this._initData.environment.appUriScheme)); @@ -91,7 +93,8 @@ class VSCodeNodeModuleFactory implements INodeModuleFactory { private readonly _apiFactory: IExtensionApiFactory, private readonly _extensionPaths: TernarySearchTree, private readonly _extensionRegistry: ExtensionDescriptionRegistry, - private readonly _configProvider: ExtHostConfigProvider + private readonly _configProvider: ExtHostConfigProvider, + private readonly _logService: ILogService, ) { } @@ -112,7 +115,7 @@ class VSCodeNodeModuleFactory implements INodeModuleFactory { if (!this._defaultApiImpl) { let extensionPathsPretty = ''; this._extensionPaths.forEach((value, index) => extensionPathsPretty += `\t${index} -> ${value.identifier.value}\n`); - console.warn(`Could not identify extension for 'vscode' require call from ${parent.fsPath}. These are the extension path mappings: \n${extensionPathsPretty}`); + this._logService.warn(`Could not identify extension for 'vscode' require call from ${parent.fsPath}. These are the extension path mappings: \n${extensionPathsPretty}`); this._defaultApiImpl = this._apiFactory(nullExtensionDescription, this._extensionRegistry, this._configProvider); } return this._defaultApiImpl; diff --git a/src/vs/workbench/api/node/extHostStoragePaths.ts b/src/vs/workbench/api/node/extHostStoragePaths.ts index 5a301ad857ca4..afdd6bf3984c9 100644 --- a/src/vs/workbench/api/node/extHostStoragePaths.ts +++ b/src/vs/workbench/api/node/extHostStoragePaths.ts @@ -11,6 +11,7 @@ import { IExtensionDescription } from 'vs/platform/extensions/common/extensions' import { IExtensionStoragePaths } from 'vs/workbench/api/common/extHostStoragePaths'; import { IExtHostInitDataService } from 'vs/workbench/api/common/extHostInitDataService'; import { withNullAsUndefined } from 'vs/base/common/types'; +import { ILogService } from 'vs/platform/log/common/log'; export class ExtensionStoragePaths implements IExtensionStoragePaths { @@ -22,7 +23,10 @@ export class ExtensionStoragePaths implements IExtensionStoragePaths { readonly whenReady: Promise; private _value?: string; - constructor(@IExtHostInitDataService initData: IExtHostInitDataService) { + constructor( + @IExtHostInitDataService initData: IExtHostInitDataService, + @ILogService private readonly _logService: ILogService, + ) { this._workspace = withNullAsUndefined(initData.workspace); this._environment = initData.environment; this.whenReady = this._getOrCreateWorkspaceStoragePath().then(value => this._value = value); @@ -69,7 +73,7 @@ export class ExtensionStoragePaths implements IExtensionStoragePaths { return storagePath; } catch (e) { - console.error(e); + this._logService.error(e); return undefined; } } From 100318a63e2af38b5a442362d25742d732fc0d94 Mon Sep 17 00:00:00 2001 From: Martin Aeschlimann Date: Mon, 11 Nov 2019 16:04:09 +0100 Subject: [PATCH 054/352] styling in settings and themes --- .../common/tokenClassificationRegistry.ts | 182 +++++++++++++----- .../browser/abstractTextMateService.ts | 4 +- .../themes/browser/workbenchThemeService.ts | 24 ++- .../services/themes/common/colorThemeData.ts | 128 ++++++++---- .../themes/common/themeCompatibility.ts | 8 +- .../themes/common/workbenchThemeService.ts | 17 +- .../tokenStyleResolving.test.ts | 52 +++-- 7 files changed, 287 insertions(+), 128 deletions(-) diff --git a/src/vs/platform/theme/common/tokenClassificationRegistry.ts b/src/vs/platform/theme/common/tokenClassificationRegistry.ts index 7817b7a577832..2ec489ae46f4e 100644 --- a/src/vs/platform/theme/common/tokenClassificationRegistry.ts +++ b/src/vs/platform/theme/common/tokenClassificationRegistry.ts @@ -7,6 +7,10 @@ import * as platform from 'vs/platform/registry/common/platform'; import { Color } from 'vs/base/common/color'; import { ITheme } from 'vs/platform/theme/common/themeService'; import * as nls from 'vs/nls'; +import { Extensions as JSONExtensions, IJSONContributionRegistry } from 'vs/platform/jsonschemas/common/jsonContributionRegistry'; +import { RunOnceScheduler } from 'vs/base/common/async'; +import { Event, Emitter } from 'vs/base/common/event'; +import { IJSONSchema, IJSONSchemaMap } from 'vs/base/common/jsonSchema'; // ------ API types @@ -89,6 +93,8 @@ export const Extensions = { export interface ITokenClassificationRegistry { + readonly onDidChangeSchema: Event; + /** * Register a token type to the registry. * @param id The TokenType id as used in theme description files @@ -106,7 +112,7 @@ export interface ITokenClassificationRegistry { getTokenClassificationFromString(str: TokenClassificationString): TokenClassification | undefined; getTokenClassification(type: string, modifiers: string[]): TokenClassification | undefined; - getTokenStylingRule(classification: TokenClassification | string | undefined, value: TokenStyle): TokenStylingRule | undefined; + getTokenStylingRule(classification: TokenClassification, value: TokenStyle): TokenStylingRule; /** * Register a TokenStyle default to the registry. @@ -138,13 +144,19 @@ export interface ITokenClassificationRegistry { /** * Resolves a token classification against the given rules and default rules from the registry. */ - resolveTokenStyle(classification: TokenClassification, themingRules: TokenStylingRule[], useDefault: boolean, theme: ITheme): TokenStyle | undefined; -} - + resolveTokenStyle(classification: TokenClassification, themingRules: TokenStylingRule[] | undefined, customThemingRules: TokenStylingRule[], theme: ITheme): TokenStyle | undefined; + /** + * JSON schema for an object to assign styling to token classifications + */ + getTokenStylingSchema(): IJSONSchema; +} class TokenClassificationRegistry implements ITokenClassificationRegistry { + private readonly _onDidChangeSchema = new Emitter(); + readonly onDidChangeSchema: Event = this._onDidChangeSchema.event; + private currentTypeNumber = 0; private currentModifierBit = 1; @@ -153,6 +165,38 @@ class TokenClassificationRegistry implements ITokenClassificationRegistry { private tokenStylingDefaultRules: TokenStylingDefaultRule[] = []; + private tokenStylingSchema: IJSONSchema & { properties: IJSONSchemaMap } = { + type: 'object', + properties: {}, + definitions: { + style: { + type: 'object', + description: nls.localize('schema.token.settings', 'Colors and styles for the token.'), + properties: { + foreground: { + type: 'string', + description: nls.localize('schema.token.foreground', 'Foreground color for the token.'), + format: 'color-hex', + default: '#ff0000' + }, + background: { + type: 'string', + deprecationMessage: nls.localize('schema.token.background.warning', 'Token background colors are currently not supported.') + }, + fontStyle: { + type: 'string', + description: nls.localize('schema.token.fontStyle', 'Font style of the rule: \'italic\', \'bold\' or \'underline\', \'-italic\', \'-bold\' or \'-underline\'or a combination. The empty string unsets inherited settings.'), + pattern: '^(\\s*(-?italic|-?bold|-?underline))*\\s*$', + patternErrorMessage: nls.localize('schema.fontStyle.error', 'Font style must be \'italic\', \'bold\' or \'underline\' to set a style or \'-italic\', \'-bold\' or \'-underline\' to unset or a combination. The empty string unsets all styles.'), + defaultSnippets: [{ label: nls.localize('schema.token.fontStyle.none', 'None (clear inherited style)'), bodyText: '""' }, { body: 'italic' }, { body: 'bold' }, { body: 'underline' }, { body: '-italic' }, { body: '-bold' }, { body: '-underline' }, { body: 'italic bold' }, { body: 'italic underline' }, { body: 'bold underline' }, { body: 'italic bold underline' }] + } + }, + additionalProperties: false, + defaultSnippets: [{ body: { foreground: '${1:#FF0000}', fontStyle: '${2:bold}' } }] + } + } + }; + constructor() { this.tokenTypeById = {}; this.tokenModifierById = {}; @@ -164,6 +208,8 @@ class TokenClassificationRegistry implements ITokenClassificationRegistry { const num = this.currentTypeNumber++; let tokenStyleContribution: TokenTypeOrModifierContribution = { num, id, description, deprecationMessage }; this.tokenTypeById[id] = tokenStyleContribution; + + this.tokenStylingSchema.properties[id] = getStylingSchemeEntry(description, deprecationMessage); } public registerTokenModifier(id: string, description: string, deprecationMessage?: string): void { @@ -171,6 +217,8 @@ class TokenClassificationRegistry implements ITokenClassificationRegistry { this.currentModifierBit = this.currentModifierBit * 2; let tokenStyleContribution: TokenTypeOrModifierContribution = { num, id, description, deprecationMessage }; this.tokenModifierById[id] = tokenStyleContribution; + + this.tokenStylingSchema.properties[`*.${id}`] = getStylingSchemeEntry(description, deprecationMessage); } public getTokenClassification(type: string, modifiers: string[]): TokenClassification | undefined { @@ -197,14 +245,8 @@ class TokenClassificationRegistry implements ITokenClassificationRegistry { return undefined; } - public getTokenStylingRule(classification: TokenClassification | string | undefined, value: TokenStyle): TokenStylingRule | undefined { - if (typeof classification === 'string') { - classification = this.getTokenClassificationFromString(classification); - } - if (classification) { - return { classification, matchScore: getTokenStylingScore(classification), value }; - } - return undefined; + public getTokenStylingRule(classification: TokenClassification, value: TokenStyle): TokenStylingRule { + return { classification, matchScore: getTokenStylingScore(classification), value }; } public registerTokenStyleDefault(classification: TokenClassification, defaults: TokenStyleDefaults): void { @@ -213,10 +255,12 @@ class TokenClassificationRegistry implements ITokenClassificationRegistry { public deregisterTokenType(id: string): void { delete this.tokenTypeById[id]; + delete this.tokenStylingSchema.properties[id]; } public deregisterTokenModifier(id: string): void { delete this.tokenModifierById[id]; + delete this.tokenStylingSchema.properties[`*.${id}`]; } public getTokenTypes(): TokenTypeOrModifierContribution[] { @@ -227,7 +271,7 @@ class TokenClassificationRegistry implements ITokenClassificationRegistry { return Object.keys(this.tokenModifierById).map(id => this.tokenModifierById[id]); } - public resolveTokenStyle(classification: TokenClassification, themingRules: TokenStylingRule[], useDefault: boolean, theme: ITheme): TokenStyle | undefined { + public resolveTokenStyle(classification: TokenClassification, themingRules: TokenStylingRule[] | undefined, customThemingRules: TokenStylingRule[], theme: ITheme): TokenStyle | undefined { let result: any = { foreground: undefined, bold: undefined, @@ -257,7 +301,7 @@ class TokenClassificationRegistry implements ITokenClassificationRegistry { } } } - if (useDefault) { + if (themingRules === undefined) { for (const rule of this.tokenStylingDefaultRules) { const matchScore = match(rule, classification); if (matchScore >= 0) { @@ -270,8 +314,15 @@ class TokenClassificationRegistry implements ITokenClassificationRegistry { } } } + } else { + for (const rule of themingRules) { + const matchScore = match(rule, classification); + if (matchScore >= 0) { + _processStyle(matchScore, rule.value); + } + } } - for (const rule of themingRules) { + for (const rule of customThemingRules) { const matchScore = match(rule, classification); if (matchScore >= 0) { _processStyle(matchScore, rule.value); @@ -297,6 +348,10 @@ class TokenClassificationRegistry implements ITokenClassificationRegistry { return undefined; } + public getTokenStylingSchema(): IJSONSchema { + return this.tokenStylingSchema; + } + public toString() { let sorter = (a: string, b: string) => { @@ -348,40 +403,40 @@ export function getTokenClassificationRegistry(): ITokenClassificationRegistry { return tokenClassificationRegistry; } -export const comments = registerTokenType('comments', nls.localize('comments', "Token style for comments."), [['comment']]); -export const strings = registerTokenType('strings', nls.localize('strings', "Token style for strings."), [['string']]); -export const keywords = registerTokenType('keywords', nls.localize('keywords', "Token style for keywords."), [['keyword.control']]); -export const numbers = registerTokenType('numbers', nls.localize('numbers', "Token style for numbers."), [['constant.numeric']]); -export const regexp = registerTokenType('regexp', nls.localize('regexp', "Token style for regular expressions."), [['constant.regexp']]); -export const operators = registerTokenType('operators', nls.localize('operator', "Token style for operators."), [['keyword.operator']]); - -export const namespaces = registerTokenType('namespaces', nls.localize('namespace', "Token style for namespaces."), [['entity.name.namespace']]); - -export const types = registerTokenType('types', nls.localize('types', "Token style for types."), [['entity.name.type'], ['entity.name.class'], ['support.type'], ['support.class']]); -export const structs = registerTokenType('structs', nls.localize('struct', "Token style for struct."), [['storage.type.struct']], types); -export const classes = registerTokenType('classes', nls.localize('class', "Token style for classes."), [['ntity.name.class']], types); -export const interfaces = registerTokenType('interfaces', nls.localize('interface', "Token style for interfaces."), undefined, types); -export const enums = registerTokenType('enums', nls.localize('enum', "Token style for enums."), undefined, types); -export const parameterTypes = registerTokenType('parameterTypes', nls.localize('parameterType', "Token style for parameterTypes."), undefined, types); - -export const functions = registerTokenType('functions', nls.localize('functions', "Token style for functions."), [['entity.name.function'], ['support.function']]); -export const macros = registerTokenType('macros', nls.localize('macro', "Token style for macros."), undefined, functions); - -export const variables = registerTokenType('variables', nls.localize('variables', "Token style for variables."), [['variable'], ['entity.name.variable']]); -export const constants = registerTokenType('constants', nls.localize('constants', "Token style for constants."), undefined, variables); -export const parameters = registerTokenType('parameters', nls.localize('parameters', "Token style for parameters."), undefined, variables); -export const property = registerTokenType('properties', nls.localize('properties', "Token style for properties."), undefined, variables); - -export const labels = registerTokenType('labels', nls.localize('labels', "Token style for labels."), undefined); - -export const m_declaration = registerTokenModifier('declaration', nls.localize('declaration', "Token modifier for declarations."), undefined); -export const m_documentation = registerTokenModifier('documentation', nls.localize('documentation', "Token modifier for documentation."), undefined); -export const m_member = registerTokenModifier('member', nls.localize('member', "Token modifier for member."), undefined); -export const m_static = registerTokenModifier('static', nls.localize('static', "Token modifier for statics."), undefined); -export const m_abstract = registerTokenModifier('abstract', nls.localize('abstract', "Token modifier for abstracts."), undefined); -export const m_deprecated = registerTokenModifier('deprecated', nls.localize('deprecated', "Token modifier for deprecated."), undefined); -export const m_modification = registerTokenModifier('modification', nls.localize('modification', "Token modifier for modification."), undefined); -export const m_async = registerTokenModifier('async', nls.localize('async', "Token modifier for async."), undefined); +export const comments = registerTokenType('comments', nls.localize('comments', "Style for comments."), [['comment']]); +export const strings = registerTokenType('strings', nls.localize('strings', "Style for strings."), [['string']]); +export const keywords = registerTokenType('keywords', nls.localize('keywords', "Style for keywords."), [['keyword.control']]); +export const numbers = registerTokenType('numbers', nls.localize('numbers', "Style for numbers."), [['constant.numeric']]); +export const regexp = registerTokenType('regexp', nls.localize('regexp', "Style for expressions."), [['constant.regexp']]); +export const operators = registerTokenType('operators', nls.localize('operator', "Style for operators."), [['keyword.operator']]); + +export const namespaces = registerTokenType('namespaces', nls.localize('namespace', "Style for namespaces."), [['entity.name.namespace']]); + +export const types = registerTokenType('types', nls.localize('types', "Style for types."), [['entity.name.type'], ['entity.name.class'], ['support.type'], ['support.class']]); +export const structs = registerTokenType('structs', nls.localize('struct', "Style for structs."), [['storage.type.struct']], types); +export const classes = registerTokenType('classes', nls.localize('class', "Style for classes."), [['entity.name.class']], types); +export const interfaces = registerTokenType('interfaces', nls.localize('interface', "Style for interfaces."), undefined, types); +export const enums = registerTokenType('enums', nls.localize('enum', "Style for enums."), undefined, types); +export const parameterTypes = registerTokenType('parameterTypes', nls.localize('parameterType', "Style for parameter types."), undefined, types); + +export const functions = registerTokenType('functions', nls.localize('functions', "Style for functions"), [['entity.name.function'], ['support.function']]); +export const macros = registerTokenType('macros', nls.localize('macro', "Style for macros."), undefined, functions); + +export const variables = registerTokenType('variables', nls.localize('variables', "Style for variables."), [['variable'], ['entity.name.variable']]); +export const constants = registerTokenType('constants', nls.localize('constants', "Style for constants."), undefined, variables); +export const parameters = registerTokenType('parameters', nls.localize('parameters', "Style for parameters."), undefined, variables); +export const property = registerTokenType('properties', nls.localize('properties', "Style for properties."), undefined, variables); + +export const labels = registerTokenType('labels', nls.localize('labels', "Style for labels. "), undefined); + +export const m_declaration = registerTokenModifier('declaration', nls.localize('declaration', "Style for all symbol declarations."), undefined); +export const m_documentation = registerTokenModifier('documentation', nls.localize('documentation', "Style to use for references in documentation."), undefined); +export const m_member = registerTokenModifier('member', nls.localize('member', "Style to use for member functions, variables (fields) and types."), undefined); +export const m_static = registerTokenModifier('static', nls.localize('static', "Style to use for symbols that are static."), undefined); +export const m_abstract = registerTokenModifier('abstract', nls.localize('abstract', "Style to use for symbols that are abstract."), undefined); +export const m_deprecated = registerTokenModifier('deprecated', nls.localize('deprecated', "Style to use for symbols that are deprecated."), undefined); +export const m_modification = registerTokenModifier('modification', nls.localize('modification', "Style to use for write accesses."), undefined); +export const m_async = registerTokenModifier('async', nls.localize('async', "Style to use for symbols that are async."), undefined); function bitCount(u: number) { // https://blogs.msdn.microsoft.com/jeuge/2005/06/08/bit-fiddling-3/ @@ -392,3 +447,32 @@ function bitCount(u: number) { function getTokenStylingScore(classification: TokenClassification) { return bitCount(classification.modifiers) + ((classification.type !== TOKEN_TYPE_WILDCARD_NUM) ? 1 : 0); } + +function getStylingSchemeEntry(description: string, deprecationMessage?: string): IJSONSchema { + return { + description, + deprecationMessage, + defaultSnippets: [{ body: '${1:#ff0000}' }], + anyOf: [ + { + type: 'string', + format: 'color-hex' + }, + { + $ref: '#definitions/style' + } + ] + }; +} + +export const tokenStylingSchemaId = 'vscode://schemas/token-styling'; + +let schemaRegistry = platform.Registry.as(JSONExtensions.JSONContribution); +schemaRegistry.registerSchema(tokenStylingSchemaId, tokenClassificationRegistry.getTokenStylingSchema()); + +const delayer = new RunOnceScheduler(() => schemaRegistry.notifySchemaChanged(tokenStylingSchemaId), 200); +tokenClassificationRegistry.onDidChangeSchema(() => { + if (!delayer.isScheduled()) { + delayer.schedule(); + } +}); diff --git a/src/vs/workbench/services/textMate/browser/abstractTextMateService.ts b/src/vs/workbench/services/textMate/browser/abstractTextMateService.ts index cb553b6fcc875..dc9222e4b02c1 100644 --- a/src/vs/workbench/services/textMate/browser/abstractTextMateService.ts +++ b/src/vs/workbench/services/textMate/browser/abstractTextMateService.ts @@ -22,7 +22,7 @@ import { IStorageService, StorageScope } from 'vs/platform/storage/common/storag import { ExtensionMessageCollector } from 'vs/workbench/services/extensions/common/extensionsRegistry'; import { ITMSyntaxExtensionPoint, grammarsExtPoint } from 'vs/workbench/services/textMate/common/TMGrammars'; import { ITextMateService } from 'vs/workbench/services/textMate/common/textMateService'; -import { ITokenColorizationRule, IWorkbenchThemeService, IColorTheme } from 'vs/workbench/services/themes/common/workbenchThemeService'; +import { ITextMateThemingRule, IWorkbenchThemeService, IColorTheme } from 'vs/workbench/services/themes/common/workbenchThemeService'; import { IGrammar, StackElement, IOnigLib, IRawTheme } from 'vscode-textmate'; import { Disposable, IDisposable, dispose } from 'vs/base/common/lifecycle'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; @@ -257,7 +257,7 @@ export abstract class AbstractTextMateService extends Disposable implements ITex TokenizationRegistry.setColorMap(colorMap); } - private static equalsTokenRules(a: ITokenColorizationRule[] | null, b: ITokenColorizationRule[] | null): boolean { + private static equalsTokenRules(a: ITextMateThemingRule[] | null, b: ITextMateThemingRule[] | null): boolean { if (!b || !a || b.length !== a.length) { return false; } diff --git a/src/vs/workbench/services/themes/browser/workbenchThemeService.ts b/src/vs/workbench/services/themes/browser/workbenchThemeService.ts index 85b09406b2c59..91e4c86fe5397 100644 --- a/src/vs/workbench/services/themes/browser/workbenchThemeService.ts +++ b/src/vs/workbench/services/themes/browser/workbenchThemeService.ts @@ -6,7 +6,7 @@ import * as nls from 'vs/nls'; import * as types from 'vs/base/common/types'; import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; -import { IWorkbenchThemeService, IColorTheme, ITokenColorCustomizations, IFileIconTheme, ExtensionData, VS_LIGHT_THEME, VS_DARK_THEME, VS_HC_THEME, COLOR_THEME_SETTING, ICON_THEME_SETTING, CUSTOM_WORKBENCH_COLORS_SETTING, CUSTOM_EDITOR_COLORS_SETTING, DETECT_HC_SETTING, HC_THEME_ID, IColorCustomizations } from 'vs/workbench/services/themes/common/workbenchThemeService'; +import { IWorkbenchThemeService, IColorTheme, ITokenColorCustomizations, IFileIconTheme, ExtensionData, VS_LIGHT_THEME, VS_DARK_THEME, VS_HC_THEME, COLOR_THEME_SETTING, ICON_THEME_SETTING, CUSTOM_WORKBENCH_COLORS_SETTING, CUSTOM_EDITOR_COLORS_SETTING, DETECT_HC_SETTING, HC_THEME_ID, IColorCustomizations, CUSTOM_EDITOR_TOKENSTYLES_SETTING, IExperimentalTokenStyleCustomizations } from 'vs/workbench/services/themes/common/workbenchThemeService'; import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { Registry } from 'vs/platform/registry/common/platform'; @@ -29,6 +29,7 @@ import * as resources from 'vs/base/common/resources'; import { IJSONSchema } from 'vs/base/common/jsonSchema'; import { textmateColorsSchemaId, registerColorThemeSchemas, textmateColorSettingsSchemaId } from 'vs/workbench/services/themes/common/colorThemeSchema'; import { workbenchColorsSchemaId } from 'vs/platform/theme/common/colorRegistry'; +import { tokenStylingSchemaId } from 'vs/platform/theme/common/tokenClassificationRegistry'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { getRemoteAuthority } from 'vs/platform/remote/common/remoteHosts'; import { IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService'; @@ -92,6 +93,10 @@ export class WorkbenchThemeService implements IWorkbenchThemeService { return this.configurationService.getValue(CUSTOM_EDITOR_COLORS_SETTING) || {}; } + private get tokenStylesCustomizations(): IExperimentalTokenStyleCustomizations { + return this.configurationService.getValue(CUSTOM_EDITOR_TOKENSTYLES_SETTING) || {}; + } + constructor( @IExtensionService extensionService: IExtensionService, @IStorageService private readonly storageService: IStorageService, @@ -126,6 +131,7 @@ export class WorkbenchThemeService implements IWorkbenchThemeService { } themeData.setCustomColors(this.colorCustomizations); themeData.setCustomTokenColors(this.tokenColorCustomizations); + themeData.setCustomTokenStyleRules(this.tokenStylesCustomizations); this.updateDynamicCSSRules(themeData); this.applyTheme(themeData, undefined, true); @@ -154,18 +160,22 @@ export class WorkbenchThemeService implements IWorkbenchThemeService { const themeSpecificWorkbenchColors: IJSONSchema = { properties: {} }; const themeSpecificTokenColors: IJSONSchema = { properties: {} }; + const themeSpecificTokenStyling: IJSONSchema = { properties: {} }; const workbenchColors = { $ref: workbenchColorsSchemaId, additionalProperties: false }; const tokenColors = { properties: tokenColorSchema.properties, additionalProperties: false }; + const tokenStyling = { $ref: tokenStylingSchemaId, additionalProperties: false }; for (let t of event.themes) { // add theme specific color customization ("[Abyss]":{ ... }) const themeId = `[${t.settingsId}]`; themeSpecificWorkbenchColors.properties![themeId] = workbenchColors; themeSpecificTokenColors.properties![themeId] = tokenColors; + themeSpecificTokenStyling.properties![themeId] = tokenStyling; } colorCustomizationsSchema.allOf![1] = themeSpecificWorkbenchColors; tokenColorCustomizationSchema.allOf![1] = themeSpecificTokenColors; + experimentalTokenStylingCustomizationSchema.allOf![1] = themeSpecificTokenStyling; configurationRegistry.notifyConfigurationSchemaUpdated(themeSettingsConfiguration, tokenColorCustomizationConfiguration); @@ -308,6 +318,10 @@ export class WorkbenchThemeService implements IWorkbenchThemeService { this.currentColorTheme.setCustomTokenColors(this.tokenColorCustomizations); hasColorChanges = true; } + if (e.affectsConfiguration(CUSTOM_EDITOR_TOKENSTYLES_SETTING)) { + this.currentColorTheme.setCustomTokenStyleRules(this.tokenStylesCustomizations); + hasColorChanges = true; + } if (hasColorChanges) { this.updateDynamicCSSRules(this.currentColorTheme); this.onColorThemeChange.fire(this.currentColorTheme); @@ -698,12 +712,18 @@ const tokenColorCustomizationSchema: IConfigurationPropertySchema = { default: {}, allOf: [tokenColorSchema] }; +const experimentalTokenStylingCustomizationSchema: IConfigurationPropertySchema = { + description: nls.localize('editorColorsTokenStyles', "Overrides token color and styles from the currently selected color theme."), + default: {}, + allOf: [{ $ref: tokenStylingSchemaId }] +}; const tokenColorCustomizationConfiguration: IConfigurationNode = { id: 'editor', order: 7.2, type: 'object', properties: { - [CUSTOM_EDITOR_COLORS_SETTING]: tokenColorCustomizationSchema + [CUSTOM_EDITOR_COLORS_SETTING]: tokenColorCustomizationSchema, + [CUSTOM_EDITOR_TOKENSTYLES_SETTING]: experimentalTokenStylingCustomizationSchema } }; configurationRegistry.registerConfiguration(tokenColorCustomizationConfiguration); diff --git a/src/vs/workbench/services/themes/common/colorThemeData.ts b/src/vs/workbench/services/themes/common/colorThemeData.ts index e417676fc2e60..4a1b760b4e226 100644 --- a/src/vs/workbench/services/themes/common/colorThemeData.ts +++ b/src/vs/workbench/services/themes/common/colorThemeData.ts @@ -6,7 +6,7 @@ import { basename } from 'vs/base/common/path'; import * as Json from 'vs/base/common/json'; import { Color } from 'vs/base/common/color'; -import { ExtensionData, ITokenColorCustomizations, ITokenColorizationRule, IColorTheme, IColorMap, IThemeExtensionPoint, VS_LIGHT_THEME, VS_HC_THEME, IColorCustomizations } from 'vs/workbench/services/themes/common/workbenchThemeService'; +import { ExtensionData, ITokenColorCustomizations, ITextMateThemingRule, IColorTheme, IColorMap, IThemeExtensionPoint, VS_LIGHT_THEME, VS_HC_THEME, IColorCustomizations, IExperimentalTokenStyleCustomizations, ITokenColorizationSetting } from 'vs/workbench/services/themes/common/workbenchThemeService'; import { convertSettings } from 'vs/workbench/services/themes/common/themeCompatibility'; import * as nls from 'vs/nls'; import * as types from 'vs/base/common/types'; @@ -49,12 +49,13 @@ export class ColorThemeData implements IColorTheme { watch?: boolean; extensionData?: ExtensionData; - private themeTokenColors: ITokenColorizationRule[] = []; - private customTokenColors: ITokenColorizationRule[] = []; + private themeTokenColors: ITextMateThemingRule[] = []; + private customTokenColors: ITextMateThemingRule[] = []; private colorMap: IColorMap = {}; private customColorMap: IColorMap = {}; - private tokenStylingRules: TokenStylingRule[] = []; + private tokenStylingRules: TokenStylingRule[] | undefined = undefined; + private customTokenStylingRules: TokenStylingRule[] = []; private themeTokenScopeMatchers: Matcher[] | undefined; private customTokenScopeMatchers: Matcher[] | undefined; @@ -66,8 +67,8 @@ export class ColorThemeData implements IColorTheme { this.isLoaded = false; } - get tokenColors(): ITokenColorizationRule[] { - const result: ITokenColorizationRule[] = []; + get tokenColors(): ITextMateThemingRule[] { + const result: ITextMateThemingRule[] = []; // the default rule (scope empty) is always the first rule. Ignore all other default rules. const foreground = this.getColor(editorForeground) || this.getDefault(editorForeground)!; @@ -81,7 +82,7 @@ export class ColorThemeData implements IColorTheme { let hasDefaultTokens = false; - function addRule(rule: ITokenColorizationRule) { + function addRule(rule: ITextMateThemingRule) { if (rule.scope && rule.settings) { if (rule.scope === 'token.info-token') { hasDefaultTokens = true; @@ -115,7 +116,7 @@ export class ColorThemeData implements IColorTheme { public getTokenStyle(tokenClassification: TokenClassification, useDefault?: boolean): TokenStyle | undefined { // todo: cache results - return tokenClassificationRegistry.resolveTokenStyle(tokenClassification, this.tokenStylingRules, useDefault !== false, this); + return tokenClassificationRegistry.resolveTokenStyle(tokenClassification, this.tokenStylingRules, this.customTokenStylingRules, this); } public getDefault(colorId: ColorIdentifier): Color | undefined { @@ -123,7 +124,7 @@ export class ColorThemeData implements IColorTheme { } public getDefaultTokenStyle(tokenClassification: TokenClassification): TokenStyle | undefined { - return tokenClassificationRegistry.resolveTokenStyle(tokenClassification, [], true, this); + return tokenClassificationRegistry.resolveTokenStyle(tokenClassification, undefined, [], this); } public resolveScopes(scopes: ProbeScope[]): TokenStyle | undefined { @@ -136,12 +137,12 @@ export class ColorThemeData implements IColorTheme { } for (let scope of scopes) { - let foreground: string | null = null; - let fontStyle: string | null = null; + let foreground: string | undefined = undefined; + let fontStyle: string | undefined = undefined; let foregroundScore = -1; let fontStyleScore = -1; - function findTokenStyleForScopeInScopes(scopeMatchers: Matcher[], tokenColors: ITokenColorizationRule[]) { + function findTokenStyleForScopeInScopes(scopeMatchers: Matcher[], tokenColors: ITextMateThemingRule[]) { for (let i = 0; i < scopeMatchers.length; i++) { const score = scopeMatchers[i](scope); if (score >= 0) { @@ -157,7 +158,7 @@ export class ColorThemeData implements IColorTheme { } findTokenStyleForScopeInScopes(this.themeTokenScopeMatchers, this.themeTokenColors); findTokenStyleForScopeInScopes(this.customTokenScopeMatchers, this.customTokenColors); - if (foreground !== null || fontStyle !== null) { + if (foreground !== undefined || fontStyle !== undefined) { return getTokenStyle(foreground, fontStyle); } } @@ -200,8 +201,14 @@ export class ColorThemeData implements IColorTheme { } } - public setTokenStyleRules(tokenStylingRules: TokenStylingRule[]) { - this.tokenStylingRules = tokenStylingRules; + public setCustomTokenStyleRules(tokenStylingRules: IExperimentalTokenStyleCustomizations) { + this.tokenStylingRules = []; + readCustomTokenStyleRules(tokenStylingRules, this.tokenStylingRules); + + const themeSpecificColors = tokenStylingRules[`[${this.settingsId}]`] as IExperimentalTokenStyleCustomizations; + if (types.isObject(themeSpecificColors)) { + readCustomTokenStyleRules(themeSpecificColors, this.tokenStylingRules); + } } private addCustomTokenColors(customTokenColors: ITokenColorCustomizations) { @@ -243,9 +250,17 @@ export class ColorThemeData implements IColorTheme { } this.themeTokenColors = []; this.themeTokenScopeMatchers = undefined; - this.colorMap = {}; - return _loadColorTheme(extensionResourceLoaderService, this.location, this.themeTokenColors, this.colorMap).then(_ => { + + const result = { + colors: {}, + textMateRules: [], + stylingRules: undefined + }; + return _loadColorTheme(extensionResourceLoaderService, this.location, result).then(_ => { this.isLoaded = true; + this.tokenStylingRules = result.stylingRules; + this.colorMap = result.colors; + this.themeTokenColors = result.textMateRules; }); } @@ -358,7 +373,7 @@ function toCSSSelector(extensionId: string, path: string) { return str; } -function _loadColorTheme(extensionResourceLoaderService: IExtensionResourceLoaderService, themeLocation: URI, resultRules: ITokenColorizationRule[], resultColors: IColorMap): Promise { +function _loadColorTheme(extensionResourceLoaderService: IExtensionResourceLoaderService, themeLocation: URI, result: { textMateRules: ITextMateThemingRule[], colors: IColorMap, stylingRules: TokenStylingRule[] | undefined }): Promise { if (resources.extname(themeLocation) === '.json') { return extensionResourceLoaderService.readExtensionResource(themeLocation).then(content => { let errors: Json.ParseError[] = []; @@ -370,11 +385,11 @@ function _loadColorTheme(extensionResourceLoaderService: IExtensionResourceLoade } let includeCompletes: Promise = Promise.resolve(null); if (contentValue.include) { - includeCompletes = _loadColorTheme(extensionResourceLoaderService, resources.joinPath(resources.dirname(themeLocation), contentValue.include), resultRules, resultColors); + includeCompletes = _loadColorTheme(extensionResourceLoaderService, resources.joinPath(resources.dirname(themeLocation), contentValue.include), result); } return includeCompletes.then(_ => { if (Array.isArray(contentValue.settings)) { - convertSettings(contentValue.settings, resultRules, resultColors); + convertSettings(contentValue.settings, result); return null; } let colors = contentValue.colors; @@ -386,38 +401,42 @@ function _loadColorTheme(extensionResourceLoaderService: IExtensionResourceLoade for (let colorId in colors) { let colorHex = colors[colorId]; if (typeof colorHex === 'string') { // ignore colors tht are null - resultColors[colorId] = Color.fromHex(colors[colorId]); + result.colors[colorId] = Color.fromHex(colors[colorId]); } } } let tokenColors = contentValue.tokenColors; if (tokenColors) { if (Array.isArray(tokenColors)) { - resultRules.push(...tokenColors); + result.textMateRules.push(...tokenColors); return null; } else if (typeof tokenColors === 'string') { - return _loadSyntaxTokens(extensionResourceLoaderService, resources.joinPath(resources.dirname(themeLocation), tokenColors), resultRules, {}); + return _loadSyntaxTokens(extensionResourceLoaderService, resources.joinPath(resources.dirname(themeLocation), tokenColors), result); } else { return Promise.reject(new Error(nls.localize({ key: 'error.invalidformat.tokenColors', comment: ['{0} will be replaced by a path. Values in quotes should not be translated.'] }, "Problem parsing color theme file: {0}. Property 'tokenColors' should be either an array specifying colors or a path to a TextMate theme file", themeLocation.toString()))); } } + let tokenStylingRules = contentValue.tokenStylingRules; + if (tokenStylingRules && typeof tokenStylingRules === 'object') { + result.stylingRules = readCustomTokenStyleRules(tokenStylingRules, result.stylingRules); + } return null; }); }); } else { - return _loadSyntaxTokens(extensionResourceLoaderService, themeLocation, resultRules, resultColors); + return _loadSyntaxTokens(extensionResourceLoaderService, themeLocation, result); } } -function _loadSyntaxTokens(extensionResourceLoaderService: IExtensionResourceLoaderService, themeLocation: URI, resultRules: ITokenColorizationRule[], resultColors: IColorMap): Promise { +function _loadSyntaxTokens(extensionResourceLoaderService: IExtensionResourceLoaderService, themeLocation: URI, result: { textMateRules: ITextMateThemingRule[], colors: IColorMap }): Promise { return extensionResourceLoaderService.readExtensionResource(themeLocation).then(content => { try { let contentValue = parsePList(content); - let settings: ITokenColorizationRule[] = contentValue.settings; + let settings: ITextMateThemingRule[] = contentValue.settings; if (!Array.isArray(settings)) { return Promise.reject(new Error(nls.localize('error.plist.invalidformat', "Problem parsing tmTheme file: {0}. 'settings' is not array."))); } - convertSettings(settings, resultRules, resultColors); + convertSettings(settings, result); return Promise.resolve(null); } catch (e) { return Promise.reject(new Error(nls.localize('error.cannotparse', "Problems parsing tmTheme file: {0}", e.message))); @@ -427,7 +446,7 @@ function _loadSyntaxTokens(extensionResourceLoaderService: IExtensionResourceLoa }); } -let defaultThemeColors: { [baseTheme: string]: ITokenColorizationRule[] } = { +let defaultThemeColors: { [baseTheme: string]: ITextMateThemingRule[] } = { 'light': [ { scope: 'token.info-token', settings: { foreground: '#316bcd' } }, { scope: 'token.warn-token', settings: { foreground: '#cd9731' } }, @@ -489,7 +508,7 @@ function scopesAreMatching(thisScopeName: string, scopeName: string): boolean { return thisScopeName.length > len && thisScopeName.substr(0, len) === scopeName && thisScopeName[len] === '.'; } -function getScopeMatcher(rule: ITokenColorizationRule): Matcher { +function getScopeMatcher(rule: ITextMateThemingRule): Matcher { const ruleScope = rule.scope; if (!ruleScope || !rule.settings) { return noMatch; @@ -515,17 +534,56 @@ function getScopeMatcher(rule: ITokenColorizationRule): Matcher { }; } -function getTokenStyle(foreground: string | null, fontStyle: string | null): TokenStyle | undefined { +function getTokenStyle(foreground: string | undefined, fontStyle: string | undefined): TokenStyle { let foregroundColor = undefined; - if (foreground !== null) { + if (foreground !== undefined) { foregroundColor = Color.fromHex(foreground); } let bold, underline, italic; - if (fontStyle !== null) { - bold = fontStyle.indexOf('bold') !== -1; - underline = fontStyle.indexOf('underline') !== -1; - italic = fontStyle.indexOf('italic') !== -1; + if (fontStyle !== undefined) { + fontStyle = fontStyle.trim(); + if (fontStyle.length === 0) { + bold = italic = underline = false; + } else { + const expression = /-?italic|-?bold|-?underline/g; + let match; + while ((match = expression.exec(fontStyle))) { + switch (match[0]) { + case 'bold': bold = true; break; + case '-bold': bold = false; break; + case 'italic': italic = true; break; + case '-italic': italic = false; break; + case 'underline': underline = true; break; + case '-underline': underline = false; break; + } + } + } } return new TokenStyle(foregroundColor, bold, underline, italic); } + +function readCustomTokenStyleRules(tokenStylingRuleSection: IExperimentalTokenStyleCustomizations, result: TokenStylingRule[] = []) { + for (let key in tokenStylingRuleSection) { + if (key[0] !== '[') { + const classification = tokenClassificationRegistry.getTokenClassificationFromString(key); + if (classification) { + const settings = tokenStylingRuleSection[key]; + let style: TokenStyle | undefined; + if (typeof settings === 'string') { + style = getTokenStyle(settings, undefined); + } else if (isTokenColorizationSetting(settings)) { + style = getTokenStyle(settings.foreground, settings.fontStyle); + } + if (style) { + result.push(tokenClassificationRegistry.getTokenStylingRule(classification, style)); + } + } + } + } + return result; +} + +function isTokenColorizationSetting(style: any): style is ITokenColorizationSetting { + return style && (style.foreground || style.fontStyle); +} diff --git a/src/vs/workbench/services/themes/common/themeCompatibility.ts b/src/vs/workbench/services/themes/common/themeCompatibility.ts index 6518ff4a4acbf..7af65c955ad47 100644 --- a/src/vs/workbench/services/themes/common/themeCompatibility.ts +++ b/src/vs/workbench/services/themes/common/themeCompatibility.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { ITokenColorizationRule, IColorMap } from 'vs/workbench/services/themes/common/workbenchThemeService'; +import { ITextMateThemingRule, IColorMap } from 'vs/workbench/services/themes/common/workbenchThemeService'; import { Color } from 'vs/base/common/color'; import * as colorRegistry from 'vs/platform/theme/common/colorRegistry'; @@ -18,9 +18,9 @@ function addSettingMapping(settingId: string, colorId: string) { colorIds.push(colorId); } -export function convertSettings(oldSettings: ITokenColorizationRule[], resultRules: ITokenColorizationRule[], resultColors: IColorMap): void { +export function convertSettings(oldSettings: ITextMateThemingRule[], result: { textMateRules: ITextMateThemingRule[], colors: IColorMap }): void { for (let rule of oldSettings) { - resultRules.push(rule); + result.textMateRules.push(rule); if (!rule.scope) { let settings = rule.settings; if (!settings) { @@ -34,7 +34,7 @@ export function convertSettings(oldSettings: ITokenColorizationRule[], resultRul if (typeof colorHex === 'string') { let color = Color.fromHex(colorHex); for (let colorId of mappings) { - resultColors[colorId] = color; + result.colors[colorId] = color; } } } diff --git a/src/vs/workbench/services/themes/common/workbenchThemeService.ts b/src/vs/workbench/services/themes/common/workbenchThemeService.ts index 8684b54a80403..9937ca11be921 100644 --- a/src/vs/workbench/services/themes/common/workbenchThemeService.ts +++ b/src/vs/workbench/services/themes/common/workbenchThemeService.ts @@ -22,6 +22,7 @@ export const DETECT_HC_SETTING = 'window.autoDetectHighContrast'; export const ICON_THEME_SETTING = 'workbench.iconTheme'; export const CUSTOM_WORKBENCH_COLORS_SETTING = 'workbench.colorCustomizations'; export const CUSTOM_EDITOR_COLORS_SETTING = 'editor.tokenColorCustomizations'; +export const CUSTOM_EDITOR_TOKENSTYLES_SETTING = 'editor.tokenColorCustomizationsExperimental'; export interface IColorTheme extends ITheme { readonly id: string; @@ -30,7 +31,7 @@ export interface IColorTheme extends ITheme { readonly extensionData?: ExtensionData; readonly description?: string; readonly isLoaded: boolean; - readonly tokenColors: ITokenColorizationRule[]; + readonly tokenColors: ITextMateThemingRule[]; } export interface IColorMap { @@ -69,7 +70,7 @@ export interface IColorCustomizations { } export interface ITokenColorCustomizations { - [groupIdOrThemeSettingsId: string]: string | ITokenColorizationSetting | ITokenColorCustomizations | undefined | ITokenColorizationRule[]; + [groupIdOrThemeSettingsId: string]: string | ITokenColorizationSetting | ITokenColorCustomizations | undefined | ITextMateThemingRule[]; comments?: string | ITokenColorizationSetting; strings?: string | ITokenColorizationSetting; numbers?: string | ITokenColorizationSetting; @@ -77,10 +78,14 @@ export interface ITokenColorCustomizations { types?: string | ITokenColorizationSetting; functions?: string | ITokenColorizationSetting; variables?: string | ITokenColorizationSetting; - textMateRules?: ITokenColorizationRule[]; + textMateRules?: ITextMateThemingRule[]; } -export interface ITokenColorizationRule { +export interface IExperimentalTokenStyleCustomizations { + [styleRuleOrThemeSettingsId: string]: string | ITokenColorizationSetting | IExperimentalTokenStyleCustomizations | undefined; +} + +export interface ITextMateThemingRule { name?: string; scope?: string | string[]; settings: ITokenColorizationSetting; @@ -89,7 +94,7 @@ export interface ITokenColorizationRule { export interface ITokenColorizationSetting { foreground?: string; background?: string; - fontStyle?: string; // italic, underline, bold + fontStyle?: string; /* [italic|underline|bold] */ } export interface ExtensionData { @@ -106,4 +111,4 @@ export interface IThemeExtensionPoint { path: string; uiTheme?: typeof VS_LIGHT_THEME | typeof VS_DARK_THEME | typeof VS_HC_THEME; _watch: boolean; // unsupported options to watch location -} \ No newline at end of file +} diff --git a/src/vs/workbench/services/themes/test/electron-browser/tokenStyleResolving.test.ts b/src/vs/workbench/services/themes/test/electron-browser/tokenStyleResolving.test.ts index a0fe30b868356..ab41c917cb8ac 100644 --- a/src/vs/workbench/services/themes/test/electron-browser/tokenStyleResolving.test.ts +++ b/src/vs/workbench/services/themes/test/electron-browser/tokenStyleResolving.test.ts @@ -6,7 +6,7 @@ import { ColorThemeData } from 'vs/workbench/services/themes/common/colorThemeData'; import * as assert from 'assert'; import { ITokenColorCustomizations } from 'vs/workbench/services/themes/common/workbenchThemeService'; -import { TokenStyle, comments, variables, types, functions, keywords, numbers, strings, getTokenClassificationRegistry, TokenStylingRule } from 'vs/platform/theme/common/tokenClassificationRegistry'; +import { TokenStyle, comments, variables, types, functions, keywords, numbers, strings, getTokenClassificationRegistry } from 'vs/platform/theme/common/tokenClassificationRegistry'; import { Color } from 'vs/base/common/color'; import { isString } from 'vs/base/common/types'; import { FileService } from 'vs/platform/files/common/fileService'; @@ -44,14 +44,6 @@ function tokenStyleAsString(ts: TokenStyle | undefined | null) { return str; } -function getTokenStyleRules(rules: [string, TokenStyle][]): TokenStylingRule[] { - return rules.map(e => { - const rule = tokenClassificationRegistry.getTokenStylingRule(e[0], e[1]); - assert.ok(rule); - return rule!; - }); -} - function assertTokenStyle(actual: TokenStyle | undefined | null, expected: TokenStyle | undefined | null, message?: string) { assert.equal(tokenStyleAsString(actual), tokenStyleAsString(expected), message); } @@ -87,7 +79,7 @@ suite('Themes - TokenStyleResolving', () => { assertTokenStyles(themeData, { [comments]: ts('#88846f', undefinedStyle), [variables]: ts('#F8F8F2', unsetStyle), - [types]: ts('#A6E22E', { underline: true, bold: false, italic: false }), + [types]: ts('#A6E22E', { underline: true }), [functions]: ts('#A6E22E', unsetStyle), [strings]: ts('#E6DB74', undefinedStyle), [numbers]: ts('#AE81FF', undefinedStyle), @@ -187,7 +179,7 @@ suite('Themes - TokenStyleResolving', () => { assertTokenStyles(themeData, { [comments]: ts('#384887', undefinedStyle), [variables]: ts(undefined, unsetStyle), - [types]: ts('#ffeebb', { underline: true, bold: false, italic: false }), + [types]: ts('#ffeebb', { underline: true }), [functions]: ts('#ddbb88', unsetStyle), [strings]: ts('#22aa44', undefinedStyle), [numbers]: ts('#f280d0', undefinedStyle), @@ -259,43 +251,43 @@ suite('Themes - TokenStyleResolving', () => { assertTokenStyle(tokenStyle, defaultTokenStyle, 'keyword.operators'); tokenStyle = themeData.resolveScopes([['storage']]); - assertTokenStyle(tokenStyle, ts('#F92672', { italic: true, underline: false, bold: false }), 'storage'); + assertTokenStyle(tokenStyle, ts('#F92672', { italic: true }), 'storage'); tokenStyle = themeData.resolveScopes([['storage.type']]); - assertTokenStyle(tokenStyle, ts('#66D9EF', { italic: true, underline: false, bold: false }), 'storage.type'); + assertTokenStyle(tokenStyle, ts('#66D9EF', { italic: true }), 'storage.type'); tokenStyle = themeData.resolveScopes([['entity.name.class']]); - assertTokenStyle(tokenStyle, ts('#A6E22E', { underline: true, italic: false, bold: false }), 'entity.name.class'); + assertTokenStyle(tokenStyle, ts('#A6E22E', { underline: true }), 'entity.name.class'); tokenStyle = themeData.resolveScopes([['meta.structure.dictionary.json', 'string.quoted.double.json']]); assertTokenStyle(tokenStyle, ts('#66D9EF', undefined), 'json property'); tokenStyle = themeData.resolveScopes([['keyword'], ['storage.type'], ['entity.name.class']]); - assertTokenStyle(tokenStyle, ts('#66D9EF', { italic: true, underline: false, bold: false }), 'storage.type'); + assertTokenStyle(tokenStyle, ts('#66D9EF', { italic: true }), 'storage.type'); }); test('rule matching', async () => { const themeData = ColorThemeData.createLoadedEmptyTheme('test', 'test'); themeData.setCustomColors({ 'editor.foreground': '#000000' }); - themeData.setTokenStyleRules(getTokenStyleRules([ - ['types', ts('#ff0000', undefined)], - ['classes', ts('#0000ff', { italic: true })], - ['*.static', ts(undefined, { bold: true })], - ['*.declaration', ts(undefined, { italic: true })], - ['*.async.static', ts('#00ffff', { bold: false, underline: true })], - ['*.async', ts('#000fff', { italic: false, underline: true })] - ])); + themeData.setCustomTokenStyleRules({ + 'types': '#ff0000', + 'classes': { foreground: '#0000ff', fontStyle: 'italic' }, + '*.static': { fontStyle: 'bold' }, + '*.declaration': { fontStyle: 'italic' }, + '*.async.static': { fontStyle: 'italic underline' }, + '*.async': { foreground: '#000fff', fontStyle: '-italic underline' } + }); assertTokenStyles(themeData, { 'types': ts('#ff0000', undefinedStyle), - 'types.static': ts('#ff0000', { bold: true, italic: undefined, underline: undefined }), - 'types.static.declaration': ts('#ff0000', { bold: true, italic: true, underline: undefined }), - 'classes': ts('#0000ff', { bold: undefined, italic: true, underline: undefined }), - 'classes.static.declaration': ts('#0000ff', { bold: true, italic: true, underline: undefined }), - 'classes.declaration': ts('#0000ff', { bold: undefined, italic: true, underline: undefined }), - 'classes.declaration.async': ts('#000fff', { bold: undefined, italic: false, underline: true }), - 'classes.declaration.async.static': ts('#00ffff', { bold: false, italic: false, underline: true }), + 'types.static': ts('#ff0000', { bold: true }), + 'types.static.declaration': ts('#ff0000', { bold: true, italic: true }), + 'classes': ts('#0000ff', { italic: true }), + 'classes.static.declaration': ts('#0000ff', { bold: true, italic: true }), + 'classes.declaration': ts('#0000ff', { italic: true }), + 'classes.declaration.async': ts('#000fff', { underline: true, italic: false }), + 'classes.declaration.async.static': ts('#000fff', { italic: true, underline: true, bold: true }), }); }); From dfe469fb985ae8e6686125039994983e815f7d28 Mon Sep 17 00:00:00 2001 From: isidor Date: Mon, 11 Nov 2019 16:05:00 +0100 Subject: [PATCH 055/352] fixes #83396 --- .../workbench/contrib/files/browser/views/explorerViewer.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/contrib/files/browser/views/explorerViewer.ts b/src/vs/workbench/contrib/files/browser/views/explorerViewer.ts index af298d30f03bb..054a39beafe57 100644 --- a/src/vs/workbench/contrib/files/browser/views/explorerViewer.ts +++ b/src/vs/workbench/contrib/files/browser/views/explorerViewer.ts @@ -751,9 +751,9 @@ export class FileDragAndDrop implements ITreeDragAndDrop { if (confirmDragAndDrop) { const confirmation = await this.dialogService.confirm({ message: items.length > 1 && items.every(s => s.isRoot) ? localize('confirmRootsMove', "Are you sure you want to change the order of multiple root folders in your workspace?") - : items.length > 1 ? getConfirmMessage(localize('confirmMultiMove', "Are you sure you want to move the following {0} files?", items.length), items.map(s => s.resource)) + : items.length > 1 ? getConfirmMessage(localize('confirmMultiMove', "Are you sure you want to move the following {0} files into '{1}'?", items.length, target.name), items.map(s => s.resource)) : items[0].isRoot ? localize('confirmRootMove', "Are you sure you want to change the order of root folder '{0}' in your workspace?", items[0].name) - : localize('confirmMove', "Are you sure you want to move '{0}'?", items[0].name), + : localize('confirmMove', "Are you sure you want to move '{0}' into '{1}'?", items[0].name, target.name), checkbox: { label: localize('doNotAskAgain', "Do not ask me again") }, From b5f471572b7ef619dc29cec08c26606613304393 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Mon, 11 Nov 2019 16:13:23 +0100 Subject: [PATCH 056/352] move navigator logic --- .../contrib/documentSymbols/outlineModel.ts | 20 ---- .../documentSymbols/outlineNavigation.ts | 93 ++++++++++++++++--- 2 files changed, 81 insertions(+), 32 deletions(-) diff --git a/src/vs/editor/contrib/documentSymbols/outlineModel.ts b/src/vs/editor/contrib/documentSymbols/outlineModel.ts index 947d99f0f1bbc..8059fdbdcfd40 100644 --- a/src/vs/editor/contrib/documentSymbols/outlineModel.ts +++ b/src/vs/editor/contrib/documentSymbols/outlineModel.ts @@ -29,26 +29,6 @@ export abstract class TreeElement { } } - // todo@joh sort by position! - firstChild(): TreeElement | undefined { - const [first] = Object.keys(this.children); - return this.children[first]; - } - - lastChild(): TreeElement | undefined { - const [last] = Object.keys(this.children).slice(-1); - return this.children[last]; - } - - sibling(next: boolean): TreeElement | undefined { - if (!this.parent) { - return undefined; - } - const all = Object.keys(this.parent.children); - const index = all.indexOf(this.id) + (next ? +1 : -1); - return this.parent.children[all[index]]; - } - static findId(candidate: DocumentSymbol | string, container: TreeElement): string { // complex id-computation which contains the origin/extension, // the parent path, and some dedupe logic when names collide diff --git a/src/vs/editor/contrib/documentSymbols/outlineNavigation.ts b/src/vs/editor/contrib/documentSymbols/outlineNavigation.ts index 8a4477e55b069..dd13a75eed3ed 100644 --- a/src/vs/editor/contrib/documentSymbols/outlineNavigation.ts +++ b/src/vs/editor/contrib/documentSymbols/outlineNavigation.ts @@ -15,6 +15,82 @@ import { EditorStateCancellationTokenSource, CodeEditorStateFlag } from 'vs/edit import { EditorAction, registerEditorAction, registerEditorContribution } from 'vs/editor/browser/editorExtensions'; import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { EditorContextKeys } from 'vs/editor/common/editorContextKeys'; +import { values } from 'vs/base/common/collections'; + +class Navigator { + + private static readonly _instances = new WeakMap(); + + static for(element: OutlineElement): Navigator { + let res = this._instances.get(element); + if (!res) { + res = new Navigator(element); + this._instances.set(element, res); + } + return res; + } + + private readonly _children: OutlineElement[] = []; + + private constructor(readonly element: OutlineElement) { + this._children = values(element.children).sort(Navigator._compare); + } + + parent(): OutlineElement | undefined { + const { parent } = this.element; + return parent instanceof OutlineElement ? parent : undefined; + } + + firstChild(): OutlineElement | undefined { + return this._children[0]; + } + + lastChild(): OutlineElement | undefined { + return this._children[this._children.length - 1]; + } + + nextSibling(): OutlineElement | undefined { + const parent = this.parent(); + if (!parent) { + return undefined; + } + const parentNav = Navigator.for(parent); + const idx = parentNav._children.indexOf(this.element); + if (idx < 0 || idx + 1 >= parentNav._children.length) { + return undefined; + } + return parentNav._children[idx + 1]; + } + + previousSibling(): OutlineElement | undefined { + const parent = this.parent(); + if (!parent) { + return undefined; + } + const parentNav = Navigator.for(parent); + const idx = parentNav._children.indexOf(this.element); + if (idx - 1 < 0) { + return undefined; + } + return parentNav._children[idx - 1]; + } + + navigate(next: boolean): OutlineElement | undefined { + return next ? this._navNext() : this._navPrev(); + } + + private _navNext(): OutlineElement | undefined { + return undefined; + } + + private _navPrev(): OutlineElement | undefined { + return undefined; + } + + private static _compare(a: OutlineElement, b: OutlineElement): number { + return Range.compareRangesUsingStarts(a.symbol.range, b.symbol.range); + } +} export class OutlineNavigation implements IEditorContribution { @@ -58,23 +134,16 @@ export class OutlineNavigation implements IEditorContribution { const outlineModel = await OutlineModel.create(textModel, this._cts.token); const element = outlineModel.getItemEnclosingPosition(position); - if (!element) { + if (!element || this._cts.token.isCancellationRequested) { return; } - let nextElement = element.sibling(next); - if (!nextElement && element.parent) { - let nextParent = element.parent.sibling(next); - if (nextParent) { - nextElement = next ? nextParent.firstChild() : nextParent.lastChild(); - } - } + let nav = Navigator.for(element); + let nextElement = nav.navigate(next); - if (!(nextElement instanceof OutlineElement)) { - return; + if (nextElement) { + this._editor.setPosition(Range.lift(nextElement.symbol.selectionRange).getStartPosition()); } - - this._editor.setPosition(Range.lift(nextElement.symbol.selectionRange).getStartPosition()); } } From c27fe98afec4d5d7ff23ba076e2cdb39eab93f38 Mon Sep 17 00:00:00 2001 From: Christof Marti Date: Mon, 11 Nov 2019 16:22:56 +0100 Subject: [PATCH 057/352] Reduce typings files (#83421) --- package.json | 3 ++- remote/package.json | 4 ++-- remote/yarn.lock | 16 +++++++-------- src/typings/http-proxy-agent.d.ts | 20 ------------------- src/typings/vscode-proxy-agent.d.ts | 6 ------ src/vs/platform/request/node/proxy.ts | 2 +- .../services/extensions/node/proxyResolver.ts | 10 +++++++--- yarn.lock | 15 ++++++++++---- 8 files changed, 31 insertions(+), 45 deletions(-) delete mode 100644 src/typings/http-proxy-agent.d.ts delete mode 100644 src/typings/vscode-proxy-agent.d.ts diff --git a/package.json b/package.json index ab2174a9025e5..d4bf37ca9ae26 100644 --- a/package.json +++ b/package.json @@ -49,7 +49,7 @@ "v8-inspect-profiler": "^0.0.20", "vscode-minimist": "^1.2.1", "vscode-nsfw": "1.2.8", - "vscode-proxy-agent": "^0.5.1", + "vscode-proxy-agent": "^0.5.2", "vscode-ripgrep": "^1.5.7", "vscode-sqlite3": "4.0.9", "vscode-textmate": "^4.3.0", @@ -65,6 +65,7 @@ "@types/chokidar": "2.1.3", "@types/cookie": "^0.3.3", "@types/graceful-fs": "4.1.2", + "@types/http-proxy-agent": "^2.0.1", "@types/iconv-lite": "0.0.1", "@types/keytar": "^4.4.0", "@types/mocha": "2.2.39", diff --git a/remote/package.json b/remote/package.json index 439fd388f8c0e..ec299bfed0cdf 100644 --- a/remote/package.json +++ b/remote/package.json @@ -17,7 +17,7 @@ "spdlog": "^0.11.1", "vscode-minimist": "^1.2.1", "vscode-nsfw": "1.2.8", - "vscode-proxy-agent": "^0.5.1", + "vscode-proxy-agent": "^0.5.2", "vscode-ripgrep": "^1.5.7", "vscode-textmate": "^4.3.0", "xterm": "4.3.0-beta17", @@ -27,7 +27,7 @@ "yazl": "^2.4.3" }, "optionalDependencies": { - "vscode-windows-ca-certs": "0.1.0", + "vscode-windows-ca-certs": "0.2.0", "vscode-windows-registry": "1.0.2" } } diff --git a/remote/yarn.lock b/remote/yarn.lock index c6e5ac0c6b6d4..1aab9f6a9c0ef 100644 --- a/remote/yarn.lock +++ b/remote/yarn.lock @@ -384,10 +384,10 @@ vscode-nsfw@1.2.8: lodash.isundefined "^3.0.1" nan "^2.10.0" -vscode-proxy-agent@^0.5.1: - version "0.5.1" - resolved "https://registry.yarnpkg.com/vscode-proxy-agent/-/vscode-proxy-agent-0.5.1.tgz#7fd15e157c02176a0dca9f87840ad0991a62ca57" - integrity sha512-Nnkc7gBk9iAbbZURYZm3p/wvDvRVwDvdzEvDqF1Jh40p6przwQU/JTlV1XLrmd4cCwh6TOAWD81Z3cq+K7Xdmw== +vscode-proxy-agent@^0.5.2: + version "0.5.2" + resolved "https://registry.yarnpkg.com/vscode-proxy-agent/-/vscode-proxy-agent-0.5.2.tgz#0c90d24d353957b841d741da7b2701e3f0a044c4" + integrity sha512-1cCNPxrWIrmUwS+1XGaXxkh3G1y7z2fpXl1sT74OZvELaryQWYb3NMxMLJJ4Q/CpPLEyuhp/bAN7nzHxxFcQ5Q== dependencies: debug "^3.1.0" http-proxy-agent "^2.1.0" @@ -406,10 +406,10 @@ vscode-textmate@^4.3.0: dependencies: oniguruma "^7.2.0" -vscode-windows-ca-certs@0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/vscode-windows-ca-certs/-/vscode-windows-ca-certs-0.1.0.tgz#d58eeb40b536130918cfde2b01e6dc7e5c1bd757" - integrity sha512-ZfZbfJIE09Q0dwGqmqTj7kuAq4g6lul9WPJvo0DkKjln8/FL+dY3wUKIKbYwWQp4x56SBTLBq3tJkD72xQ9Gqw== +vscode-windows-ca-certs@0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/vscode-windows-ca-certs/-/vscode-windows-ca-certs-0.2.0.tgz#086f0f4de57e2760a35ac6920831bff246237115" + integrity sha512-YBrJRT0zos+Yb1Qdn73GD8QZr7pa2IE96b5Y1hmmp6XeR8aYB7Iiq5gDAF/+/AxL+caSR9KPZQ6jiYWh5biD7w== dependencies: node-addon-api "1.6.2" diff --git a/src/typings/http-proxy-agent.d.ts b/src/typings/http-proxy-agent.d.ts deleted file mode 100644 index 3d0071543b488..0000000000000 --- a/src/typings/http-proxy-agent.d.ts +++ /dev/null @@ -1,20 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -declare module 'http-proxy-agent' { - - interface IHttpProxyAgentOptions { - host: string; - port: number; - auth?: string; - } - - class HttpProxyAgent { - constructor(proxy: string); - constructor(opts: IHttpProxyAgentOptions); - } - - export = HttpProxyAgent; -} \ No newline at end of file diff --git a/src/typings/vscode-proxy-agent.d.ts b/src/typings/vscode-proxy-agent.d.ts deleted file mode 100644 index a997fa97801c6..0000000000000 --- a/src/typings/vscode-proxy-agent.d.ts +++ /dev/null @@ -1,6 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -declare module 'vscode-proxy-agent'; diff --git a/src/vs/platform/request/node/proxy.ts b/src/vs/platform/request/node/proxy.ts index 116f7e0c428ac..30b5bc29a9a5c 100644 --- a/src/vs/platform/request/node/proxy.ts +++ b/src/vs/platform/request/node/proxy.ts @@ -39,7 +39,7 @@ export async function getProxyAgent(rawRequestURL: string, options: IOptions = { const opts = { host: proxyEndpoint.hostname || '', - port: Number(proxyEndpoint.port), + port: proxyEndpoint.port || (proxyEndpoint.protocol === 'https' ? '443' : '80'), auth: proxyEndpoint.auth, rejectUnauthorized: isBoolean(options.strictSSL) ? options.strictSSL : true }; diff --git a/src/vs/workbench/services/extensions/node/proxyResolver.ts b/src/vs/workbench/services/extensions/node/proxyResolver.ts index 64c2e0a526e59..af9bcd2721cc2 100644 --- a/src/vs/workbench/services/extensions/node/proxyResolver.ts +++ b/src/vs/workbench/services/extensions/node/proxyResolver.ts @@ -343,9 +343,13 @@ function patches(originals: typeof http | typeof https, resolveProxy: ReturnType return original.apply(null, arguments as unknown as any[]); } - const optionsPatched = options.agent instanceof ProxyAgent; + const originalAgent = options.agent; + if (originalAgent === true) { + throw new Error('Unexpected agent option: true'); + } + const optionsPatched = originalAgent instanceof ProxyAgent; const config = onRequest && ((options)._vscodeProxySupport || /* LS */ (options)._vscodeSystemProxy) || proxySetting.config; - const useProxySettings = !optionsPatched && (config === 'override' || config === 'on' && !options.agent); + const useProxySettings = !optionsPatched && (config === 'override' || config === 'on' && originalAgent === undefined); const useSystemCertificates = !optionsPatched && certSetting.config && originals === https && !(options as https.RequestOptions).ca; if (useProxySettings || useSystemCertificates) { @@ -367,7 +371,7 @@ function patches(originals: typeof http | typeof https, resolveProxy: ReturnType options.agent = new ProxyAgent({ resolveProxy: resolveProxy.bind(undefined, { useProxySettings, useSystemCertificates }), defaultPort: originals === https ? 443 : 80, - originalAgent: options.agent + originalAgent }); return original(options, callback); } diff --git a/yarn.lock b/yarn.lock index e3aff8c82d8fd..5e44523b3f780 100644 --- a/yarn.lock +++ b/yarn.lock @@ -133,6 +133,13 @@ dependencies: "@types/node" "*" +"@types/http-proxy-agent@^2.0.1": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@types/http-proxy-agent/-/http-proxy-agent-2.0.1.tgz#2f95077f6bfe7adc39cc0f0042da85997ae77fc7" + integrity sha512-dgsgbsgI3t+ZkdzF9H19uBaLsurIZJJjJsVpj4mCLp8B6YghQ7jVwyqhaL0PcVtuC3nOi0ZBhAi2Dd9jCUwdFA== + dependencies: + "@types/node" "*" + "@types/iconv-lite@0.0.1": version "0.0.1" resolved "https://registry.yarnpkg.com/@types/iconv-lite/-/iconv-lite-0.0.1.tgz#aa3b8bda2be512b1ae0a057b942e869c370a5569" @@ -9033,10 +9040,10 @@ vscode-nsfw@1.2.8: lodash.isundefined "^3.0.1" nan "^2.10.0" -vscode-proxy-agent@^0.5.1: - version "0.5.1" - resolved "https://registry.yarnpkg.com/vscode-proxy-agent/-/vscode-proxy-agent-0.5.1.tgz#7fd15e157c02176a0dca9f87840ad0991a62ca57" - integrity sha512-Nnkc7gBk9iAbbZURYZm3p/wvDvRVwDvdzEvDqF1Jh40p6przwQU/JTlV1XLrmd4cCwh6TOAWD81Z3cq+K7Xdmw== +vscode-proxy-agent@^0.5.2: + version "0.5.2" + resolved "https://registry.yarnpkg.com/vscode-proxy-agent/-/vscode-proxy-agent-0.5.2.tgz#0c90d24d353957b841d741da7b2701e3f0a044c4" + integrity sha512-1cCNPxrWIrmUwS+1XGaXxkh3G1y7z2fpXl1sT74OZvELaryQWYb3NMxMLJJ4Q/CpPLEyuhp/bAN7nzHxxFcQ5Q== dependencies: debug "^3.1.0" http-proxy-agent "^2.1.0" From a95e14d1cf88ffb8571966a39b30f35d887e0ac6 Mon Sep 17 00:00:00 2001 From: Christof Marti Date: Mon, 11 Nov 2019 17:05:27 +0100 Subject: [PATCH 058/352] Reduce typings files (#83421) --- src/typings/vscode-windows-ca-certs.d.ts | 6 ------ src/vs/workbench/services/extensions/node/proxyResolver.ts | 4 +++- 2 files changed, 3 insertions(+), 7 deletions(-) delete mode 100644 src/typings/vscode-windows-ca-certs.d.ts diff --git a/src/typings/vscode-windows-ca-certs.d.ts b/src/typings/vscode-windows-ca-certs.d.ts deleted file mode 100644 index f923eb8a8aca5..0000000000000 --- a/src/typings/vscode-windows-ca-certs.d.ts +++ /dev/null @@ -1,6 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -declare module 'vscode-windows-ca-certs'; diff --git a/src/vs/workbench/services/extensions/node/proxyResolver.ts b/src/vs/workbench/services/extensions/node/proxyResolver.ts index af9bcd2721cc2..1bb31127b8cbc 100644 --- a/src/vs/workbench/services/extensions/node/proxyResolver.ts +++ b/src/vs/workbench/services/extensions/node/proxyResolver.ts @@ -473,7 +473,9 @@ async function readCaCertificates() { } async function readWindowsCaCertificates() { - const winCA = await import('vscode-windows-ca-certs'); + const winCA = await new Promise((resolve, reject) => { + require(['vscode-windows-ca-certs'], resolve, reject); + }); let ders: any[] = []; const store = winCA(); From cec8079c59d66374e1b20d97a4ad7a1743d74008 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Mon, 11 Nov 2019 17:26:19 +0100 Subject: [PATCH 059/352] opener - encapsulate external opening --- .../editor/browser/services/openerService.ts | 32 ++++++++++++------- src/vs/platform/opener/common/opener.ts | 24 ++++++++++++-- src/vs/workbench/electron-browser/window.ts | 32 ++++++------------- 3 files changed, 53 insertions(+), 35 deletions(-) diff --git a/src/vs/editor/browser/services/openerService.ts b/src/vs/editor/browser/services/openerService.ts index 9902634b3e2f5..48175adfb4272 100644 --- a/src/vs/editor/browser/services/openerService.ts +++ b/src/vs/editor/browser/services/openerService.ts @@ -13,7 +13,7 @@ import { equalsIgnoreCase } from 'vs/base/common/strings'; import { URI } from 'vs/base/common/uri'; import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService'; import { CommandsRegistry, ICommandService } from 'vs/platform/commands/common/commands'; -import { IOpener, IOpenerService, IValidator, IExternalUriResolver, OpenOptions } from 'vs/platform/opener/common/opener'; +import { IOpener, IOpenerService, IValidator, IExternalUriResolver, OpenOptions, ResolveExternalUriOptions, IResolvedExternalUri, IExternalOpener } from 'vs/platform/opener/common/opener'; import { EditorOpenContext } from 'vs/platform/editor/common/editor'; export class OpenerService extends Disposable implements IOpenerService { @@ -23,12 +23,22 @@ export class OpenerService extends Disposable implements IOpenerService { private readonly _openers = new LinkedList(); private readonly _validators = new LinkedList(); private readonly _resolvers = new LinkedList(); + private _externalOpener: IExternalOpener; constructor( @ICodeEditorService private readonly _editorService: ICodeEditorService, @ICommandService private readonly _commandService: ICommandService, ) { super(); + + // Default external opener is going through window.open() + this._externalOpener = { + openExternal: href => { + dom.windowOpenNoOpener(href); + + return Promise.resolve(true); + } + }; } registerOpener(opener: IOpener): IDisposable { @@ -49,6 +59,10 @@ export class OpenerService extends Disposable implements IOpenerService { return { dispose: remove }; } + setExternalOpener(externalOpener: IExternalOpener): void { + this._externalOpener = externalOpener; + } + async open(resource: URI, options?: OpenOptions): Promise { // no scheme ?!? @@ -75,7 +89,7 @@ export class OpenerService extends Disposable implements IOpenerService { return this._doOpen(resource, options); } - async resolveExternalUri(resource: URI, options?: { readonly allowTunneling?: boolean }): Promise<{ resolved: URI, dispose(): void }> { + async resolveExternalUri(resource: URI, options?: ResolveExternalUriOptions): Promise { for (const resolver of this._resolvers.toArray()) { const result = await resolver.resolveExternalUri(resource, options); if (result) { @@ -89,13 +103,8 @@ export class OpenerService extends Disposable implements IOpenerService { private async _doOpen(resource: URI, options: OpenOptions | undefined): Promise { const { scheme, path, query, fragment } = resource; - if (equalsIgnoreCase(scheme, Schemas.mailto) || options?.openExternal) { - // open default mail application - return this._doOpenExternal(resource, options); - } - - if (equalsIgnoreCase(scheme, Schemas.http) || equalsIgnoreCase(scheme, Schemas.https)) { - // open link in default browser + if (options?.openExternal || equalsIgnoreCase(scheme, Schemas.mailto) || equalsIgnoreCase(scheme, Schemas.http) || equalsIgnoreCase(scheme, Schemas.https)) { + // open externally return this._doOpenExternal(resource, options); } @@ -149,9 +158,10 @@ export class OpenerService extends Disposable implements IOpenerService { private async _doOpenExternal(resource: URI, options: OpenOptions | undefined): Promise { const { resolved } = await this.resolveExternalUri(resource, options); - dom.windowOpenNoOpener(encodeURI(resolved.toString(true))); - return true; + // TODO@Jo neither encodeURI nor toString(true) should be needed + // once we go with URL and not URI + return this._externalOpener.openExternal(encodeURI(resolved.toString(true))); } dispose() { diff --git a/src/vs/platform/opener/common/opener.ts b/src/vs/platform/opener/common/opener.ts index 70377fcb3dacc..3b60521677a04 100644 --- a/src/vs/platform/opener/common/opener.ts +++ b/src/vs/platform/opener/common/opener.ts @@ -28,11 +28,21 @@ type OpenExternalOptions = { readonly openExternal?: boolean; readonly allowTunn export type OpenOptions = OpenInternalOptions & OpenExternalOptions; +export type ResolveExternalUriOptions = { readonly allowTunneling?: boolean }; + +export interface IResolvedExternalUri extends IDisposable { + resolved: URI; +} + export interface IOpener { open(resource: URI, options?: OpenInternalOptions): Promise; open(resource: URI, options?: OpenExternalOptions): Promise; } +export interface IExternalOpener { + openExternal(href: string): Promise; +} + export interface IValidator { shouldOpen(resource: URI): Promise; } @@ -61,6 +71,12 @@ export interface IOpenerService { */ registerExternalUriResolver(resolver: IExternalUriResolver): IDisposable; + /** + * Sets the handler for opening externally. If not provided, + * a default handler will be used. + */ + setExternalOpener(opener: IExternalOpener): void; + /** * Opens a resource, like a webaddress, a document uri, or executes command. * @@ -70,7 +86,10 @@ export interface IOpenerService { open(resource: URI, options?: OpenInternalOptions): Promise; open(resource: URI, options?: OpenExternalOptions): Promise; - resolveExternalUri(resource: URI, options?: { readonly allowTunneling?: boolean }): Promise<{ resolved: URI, dispose(): void }>; + /** + * Resolve a resource to its external form. + */ + resolveExternalUri(resource: URI, options?: ResolveExternalUriOptions): Promise; } export const NullOpenerService: IOpenerService = Object.freeze({ @@ -78,6 +97,7 @@ export const NullOpenerService: IOpenerService = Object.freeze({ registerOpener() { return Disposable.None; }, registerValidator() { return Disposable.None; }, registerExternalUriResolver() { return Disposable.None; }, - open() { return Promise.resolve(false); }, + setExternalOpener() { }, + async open() { return false; }, async resolveExternalUri(uri: URI) { return { resolved: uri, dispose() { } }; }, }); diff --git a/src/vs/workbench/electron-browser/window.ts b/src/vs/workbench/electron-browser/window.ts index d5933e7105788..9f58a3e460125 100644 --- a/src/vs/workbench/electron-browser/window.ts +++ b/src/vs/workbench/electron-browser/window.ts @@ -398,29 +398,23 @@ export class ElectronWindow extends Disposable { throw new Error('Prevented call to window.open(). Use IOpenerService instead!'); }; - // Handle internal open() calls - this.openerService.registerOpener({ - open: async (resource: URI, options?: OpenOptions): Promise => { - - // If either the caller wants to open externally or the - // scheme is one where we prefer to open externally - // we handle this resource by delegating the opening to - // the main process to prevent window focus issues. - if (this.shouldOpenExternal(resource, options)) { - const { resolved } = await this.openerService.resolveExternalUri(resource, options); - const success = await this.electronService.openExternal(encodeURI(resolved.toString(true))); - if (!success && resolved.scheme === Schemas.file) { + // Handle external open() calls + this.openerService.setExternalOpener({ + openExternal: async (href: string) => { + const success = await this.electronService.openExternal(href); + if (!success) { + const fileCandidate = URI.parse(href); + if (fileCandidate.scheme === Schemas.file) { // if opening failed, and this is a file, we can still try to reveal it - await this.electronService.showItemInFolder(resolved.fsPath); + await this.electronService.showItemInFolder(fileCandidate.fsPath); } - - return true; } - return false; // not handled by us + return true; } }); + // Register external URI resolver this.openerService.registerExternalUriResolver({ resolveExternalUri: async (uri: URI, options?: OpenOptions) => { if (options?.allowTunneling) { @@ -440,12 +434,6 @@ export class ElectronWindow extends Disposable { }); } - private shouldOpenExternal(resource: URI, options?: OpenOptions) { - const scheme = resource.scheme.toLowerCase(); - const preferOpenExternal = (scheme === Schemas.mailto || scheme === Schemas.http || scheme === Schemas.https); - return options?.openExternal || preferOpenExternal; - } - private updateTouchbarMenu(): void { if (!isMacintosh) { return; // macOS only From 33e5678363c20a7ac6665cc88752ee00fc83cc0d Mon Sep 17 00:00:00 2001 From: Alex Ross Date: Mon, 11 Nov 2019 17:28:26 +0100 Subject: [PATCH 060/352] Change remote explorer to use drop-down UI. (#84482) Part of https://github.com/microsoft/vscode-remote-release/issues/1778 --- src/vs/workbench/browser/parts/views/views.ts | 5 + .../browser/parts/views/viewsViewlet.ts | 113 +++++++++++++++++- .../remote/browser/explorerViewItems.ts | 106 ++++++++++++++++ .../contrib/remote/browser/remote.ts | 79 ++++++------ .../contrib/remote/browser/remoteViewlet.css | 19 +++ .../remote/common/remote.contribution.ts | 2 +- .../remote/common/remoteExplorerService.ts | 36 ++++++ src/vs/workbench/workbench.common.main.ts | 1 + 8 files changed, 316 insertions(+), 45 deletions(-) create mode 100644 src/vs/workbench/contrib/remote/browser/explorerViewItems.ts create mode 100644 src/vs/workbench/services/remote/common/remoteExplorerService.ts diff --git a/src/vs/workbench/browser/parts/views/views.ts b/src/vs/workbench/browser/parts/views/views.ts index 9a0a307dd5c67..a0981c5c296b4 100644 --- a/src/vs/workbench/browser/parts/views/views.ts +++ b/src/vs/workbench/browser/parts/views/views.ts @@ -240,6 +240,9 @@ export class ContributableViewsModel extends Disposable { private _onDidChangeViewState = this._register(new Emitter()); protected readonly onDidChangeViewState: Event = this._onDidChangeViewState.event; + private _onDidChangeActiveViews = this._register(new Emitter()); + readonly onDidChangeActiveViews: Event = this._onDidChangeActiveViews.event; + constructor( container: ViewContainer, viewsService: IViewsService, @@ -469,6 +472,8 @@ export class ContributableViewsModel extends Disposable { if (toAdd.length) { this._onDidAdd.fire(toAdd); } + + this._onDidChangeActiveViews.fire(this.viewDescriptors); } } diff --git a/src/vs/workbench/browser/parts/views/viewsViewlet.ts b/src/vs/workbench/browser/parts/views/viewsViewlet.ts index 239514051a285..aa4e7f432ed58 100644 --- a/src/vs/workbench/browser/parts/views/viewsViewlet.ts +++ b/src/vs/workbench/browser/parts/views/viewsViewlet.ts @@ -23,7 +23,7 @@ import { DefaultPanelDndController } from 'vs/base/browser/ui/splitview/panelvie import { WorkbenchTree, IListService } from 'vs/platform/list/browser/listService'; import { IWorkbenchThemeService, IFileIconTheme } from 'vs/workbench/services/themes/common/workbenchThemeService'; import { ITreeConfiguration, ITreeOptions } from 'vs/base/parts/tree/browser/tree'; -import { Event } from 'vs/base/common/event'; +import { Event, Emitter } from 'vs/base/common/event'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService'; import { localize } from 'vs/nls'; @@ -112,7 +112,7 @@ export abstract class ViewContainerViewlet extends PanelViewlet implements IView })); result.push(...viewToggleActions); - const parentActions = super.getContextMenuActions(); + const parentActions = this.getViewletContextMenuActions(); if (viewToggleActions.length && parentActions.length) { result.push(new Separator()); } @@ -121,6 +121,10 @@ export abstract class ViewContainerViewlet extends PanelViewlet implements IView return result; } + protected getViewletContextMenuActions() { + return super.getContextMenuActions(); + } + setVisible(visible: boolean): void { super.setVisible(visible); this.panels.filter(view => view.isVisible() !== visible) @@ -264,7 +268,7 @@ export abstract class ViewContainerViewlet extends PanelViewlet implements IView }); } - private toggleViewVisibility(viewId: string): void { + protected toggleViewVisibility(viewId: string): void { const visible = !this.viewsModel.isVisible(viewId); type ViewsToggleVisibilityClassification = { viewId: { classification: 'SystemMetaData', purpose: 'FeatureInsight' }; @@ -321,6 +325,109 @@ export abstract class ViewContainerViewlet extends PanelViewlet implements IView } } +export abstract class FilterViewContainerViewlet extends ViewContainerViewlet { + private constantViewDescriptors: Map = new Map(); + private allViews: Map> = new Map(); + private filterValue: string; + + protected onDidChangeFilterValue: Emitter = new Emitter(); + + constructor( + viewletId: string, + @IConfigurationService configurationService: IConfigurationService, + @IWorkbenchLayoutService layoutService: IWorkbenchLayoutService, + @ITelemetryService telemetryService: ITelemetryService, + @IStorageService storageService: IStorageService, + @IInstantiationService instantiationService: IInstantiationService, + @IThemeService themeService: IThemeService, + @IContextMenuService contextMenuService: IContextMenuService, + @IExtensionService extensionService: IExtensionService, + @IWorkspaceContextService contextService: IWorkspaceContextService + ) { + super(viewletId, `${viewletId}.state`, false, configurationService, layoutService, telemetryService, storageService, instantiationService, themeService, contextMenuService, extensionService, contextService); + this._register(this.onDidChangeFilterValue.event(newFilterValue => { + this.filterValue = newFilterValue; + this.onFilterChanged(newFilterValue); + })); + + this._register(this.viewsModel.onDidChangeActiveViews((viewDescriptors) => { + viewDescriptors.forEach(descriptor => { + let filterOnValue = this.getFilterOn(descriptor); + if (!filterOnValue) { + return; + } + if (!this.allViews.has(filterOnValue)) { + this.allViews.set(filterOnValue, new Map()); + } + this.allViews.get(filterOnValue)!.set(descriptor.id, descriptor); + if (filterOnValue !== this.filterValue) { + this.viewsModel.setVisible(descriptor.id, false); + } + }); + })); + } + + protected addConstantViewDescriptors(constantViewDescriptors: IViewDescriptor[]) { + constantViewDescriptors.forEach(viewDescriptor => this.constantViewDescriptors.set(viewDescriptor.id, viewDescriptor)); + } + + protected abstract getFilterOn(viewDescriptor: IViewDescriptor): string | undefined; + + private onFilterChanged(newFilterValue: string) { + this.getViewsNotForTarget(newFilterValue).forEach(item => this.viewsModel.setVisible(item.id, false)); + this.getViewsForTarget(newFilterValue).forEach(item => this.viewsModel.setVisible(item.id, true)); + } + + getContextMenuActions(): IAction[] { + const result: IAction[] = []; + let viewToggleActions: IAction[] = Array.from(this.constantViewDescriptors.values()).map(viewDescriptor => ({ + id: `${viewDescriptor.id}.toggleVisibility`, + label: viewDescriptor.name, + checked: this.viewsModel.isVisible(viewDescriptor.id), + enabled: viewDescriptor.canToggleVisibility, + run: () => this.toggleViewVisibility(viewDescriptor.id) + })); + + result.push(...viewToggleActions); + const parentActions = this.getViewletContextMenuActions(); + if (viewToggleActions.length && parentActions.length) { + result.push(new Separator()); + } + + result.push(...parentActions); + return result; + } + + private getViewsForTarget(target: string): IViewDescriptor[] { + return this.allViews.has(target) ? Array.from(this.allViews.get(target)!.values()) : []; + } + + private getViewsNotForTarget(target: string): IViewDescriptor[] { + const iterable = this.allViews.keys(); + let key = iterable.next(); + let views: IViewDescriptor[] = []; + while (!key.done) { + if (key.value !== target) { + views = views.concat(this.getViewsForTarget(key.value)); + } + key = iterable.next(); + } + return views; + } + + onDidAddViews(added: IAddedViewDescriptorRef[]): ViewletPanel[] { + const panels: ViewletPanel[] = super.onDidAddViews(added); + for (let i = 0; i < added.length; i++) { + if (this.constantViewDescriptors.has(added[i].viewDescriptor.id)) { + panels[i].setExpanded(false); + } + } + return panels; + } + + abstract getTitle(): string; +} + export class FileIconThemableWorkbenchTree extends WorkbenchTree { constructor( diff --git a/src/vs/workbench/contrib/remote/browser/explorerViewItems.ts b/src/vs/workbench/contrib/remote/browser/explorerViewItems.ts new file mode 100644 index 0000000000000..f57014a69b5c4 --- /dev/null +++ b/src/vs/workbench/contrib/remote/browser/explorerViewItems.ts @@ -0,0 +1,106 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as nls from 'vs/nls'; +import * as dom from 'vs/base/browser/dom'; + +import { IActionRunner, IAction, Action } from 'vs/base/common/actions'; +import { SelectActionViewItem } from 'vs/base/browser/ui/actionbar/actionbar'; +import { IThemeService } from 'vs/platform/theme/common/themeService'; +import { attachSelectBoxStyler, attachStylerCallback } from 'vs/platform/theme/common/styler'; +import { IContextViewService } from 'vs/platform/contextview/browser/contextView'; +import { SIDE_BAR_BACKGROUND } from 'vs/workbench/common/theme'; +import { selectBorder } from 'vs/platform/theme/common/colorRegistry'; +import { IRemoteExplorerService } from 'vs/workbench/services/remote/common/remoteExplorerService'; +import { ISelectOptionItem } from 'vs/base/browser/ui/selectBox/selectBox'; +import { IViewDescriptor } from 'vs/workbench/common/views'; +import { startsWith } from 'vs/base/common/strings'; +import { isStringArray } from 'vs/base/common/types'; +import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; + +export interface IRemoteSelectItem extends ISelectOptionItem { + authority: string[]; +} + +export class SwitchRemoteViewItem extends SelectActionViewItem { + + actionRunner!: IActionRunner; + + constructor( + action: IAction, + private readonly optionsItems: IRemoteSelectItem[], + @IThemeService private readonly themeService: IThemeService, + @IContextViewService contextViewService: IContextViewService, + @IRemoteExplorerService remoteExplorerService: IRemoteExplorerService, + @IWorkbenchEnvironmentService environmentService: IWorkbenchEnvironmentService + ) { + super(null, action, optionsItems, 0, contextViewService, { ariaLabel: nls.localize('remotes', 'Switch Remote') }); + this._register(attachSelectBoxStyler(this.selectBox, themeService, { + selectBackground: SIDE_BAR_BACKGROUND + })); + + this.setSelectionForConnection(optionsItems, environmentService, remoteExplorerService); + } + + private setSelectionForConnection(optionsItems: IRemoteSelectItem[], environmentService: IWorkbenchEnvironmentService, remoteExplorerService: IRemoteExplorerService) { + // TODO: set from saved state + if (this.optionsItems.length > 0) { + const remoteAuthority = environmentService.configuration.remoteAuthority; + let index = 0; + if (remoteAuthority) { + const actualRemoteAuthority = remoteAuthority.split('+')[0]; + for (let optionIterator = 0; (optionIterator < this.optionsItems.length) && (index === 0); optionIterator++) { + for (let authorityIterator = 0; authorityIterator < optionsItems[optionIterator].authority.length; authorityIterator++) { + if (optionsItems[optionIterator].authority[authorityIterator] === actualRemoteAuthority) { + index = optionIterator; + break; + } + } + } + } + this.select(index); + remoteExplorerService.targetType = optionsItems[index].authority[0]; + } + } + + render(container: HTMLElement) { + super.render(container); + dom.addClass(container, 'switch-remote'); + this._register(attachStylerCallback(this.themeService, { selectBorder }, colors => { + container.style.border = colors.selectBorder ? `1px solid ${colors.selectBorder}` : ''; + })); + } + + protected getActionContext(_: string, index: number): any { + return this.optionsItems[index]; + } + + static createOptionItems(views: IViewDescriptor[]): IRemoteSelectItem[] { + let options: IRemoteSelectItem[] = []; + views.forEach(view => { + if (view.group && startsWith(view.group, 'targets') && view.remoteAuthority) { + options.push({ text: view.name, authority: isStringArray(view.remoteAuthority) ? view.remoteAuthority : [view.remoteAuthority] }); + } + }); + return options; + } +} + +export class SwitchRemoteAction extends Action { + + public static readonly ID = 'remote.explorer.switch'; + public static readonly LABEL = nls.localize('remote.explorer.switch', "Switch Remote"); + + constructor( + id: string, label: string, + @IRemoteExplorerService private readonly remoteExplorerService: IRemoteExplorerService + ) { + super(id, label); + } + + public async run(item: IRemoteSelectItem): Promise { + this.remoteExplorerService.targetType = item.authority[0]; + } +} diff --git a/src/vs/workbench/contrib/remote/browser/remote.ts b/src/vs/workbench/contrib/remote/browser/remote.ts index 4d17af30bd3e2..f87cdc9515a17 100644 --- a/src/vs/workbench/contrib/remote/browser/remote.ts +++ b/src/vs/workbench/contrib/remote/browser/remote.ts @@ -16,10 +16,9 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti import { IThemeService } from 'vs/platform/theme/common/themeService'; import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; -import { ViewContainerViewlet } from 'vs/workbench/browser/parts/views/viewsViewlet'; +import { FilterViewContainerViewlet } from 'vs/workbench/browser/parts/views/viewsViewlet'; import { VIEWLET_ID, VIEW_CONTAINER } from 'vs/workbench/contrib/remote/common/remote.contribution'; import { ViewletPanel, IViewletPanelOptions } from 'vs/workbench/browser/parts/views/panelViewlet'; -import { IAddedViewDescriptorRef } from 'vs/workbench/browser/parts/views/views'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { IViewDescriptor, IViewsRegistry, Extensions } from 'vs/workbench/common/views'; @@ -47,7 +46,10 @@ import Severity from 'vs/base/common/severity'; import { ReloadWindowAction } from 'vs/workbench/browser/actions/windowActions'; import { IDisposable } from 'vs/base/common/lifecycle'; import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle'; -import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; +import { SwitchRemoteViewItem, SwitchRemoteAction } from 'vs/workbench/contrib/remote/browser/explorerViewItems'; +import { Action, IActionViewItem, IAction } from 'vs/base/common/actions'; +import { isStringArray } from 'vs/base/common/types'; +import { IRemoteExplorerService } from 'vs/workbench/services/remote/common/remoteExplorerService'; interface HelpInformation { extensionDescription: IExtensionDescription; @@ -364,10 +366,9 @@ class HelpPanelDescriptor implements IViewDescriptor { } } - -export class RemoteViewlet extends ViewContainerViewlet implements IViewModel { +export class RemoteViewlet extends FilterViewContainerViewlet implements IViewModel { private helpPanelDescriptor = new HelpPanelDescriptor(this); - + private actions: IAction[] | undefined; helpInformations: HelpInformation[] = []; constructor( @@ -380,10 +381,10 @@ export class RemoteViewlet extends ViewContainerViewlet implements IViewModel { @IThemeService themeService: IThemeService, @IContextMenuService contextMenuService: IContextMenuService, @IExtensionService extensionService: IExtensionService, - @IWorkbenchEnvironmentService private environmentService: IWorkbenchEnvironmentService, + @IRemoteExplorerService private readonly remoteExplorerService: IRemoteExplorerService ) { - super(VIEWLET_ID, `${VIEWLET_ID}.state`, true, configurationService, layoutService, telemetryService, storageService, instantiationService, themeService, contextMenuService, extensionService, contextService); - + super(VIEWLET_ID, configurationService, layoutService, telemetryService, storageService, instantiationService, themeService, contextMenuService, extensionService, contextService); + this.addConstantViewDescriptors([this.helpPanelDescriptor]); remoteHelpExtPoint.setHandler((extensions) => { let helpInformation: HelpInformation[] = []; for (let extension of extensions) { @@ -399,6 +400,34 @@ export class RemoteViewlet extends ViewContainerViewlet implements IViewModel { viewsRegistry.deregisterViews([this.helpPanelDescriptor], VIEW_CONTAINER); } }); + + this._register(this.remoteExplorerService.onDidChangeTargetType(() => { + this.onDidChangeFilterValue.fire(this.remoteExplorerService.targetType); + })); + } + + protected getFilterOn(viewDescriptor: IViewDescriptor): string | undefined { + return isStringArray(viewDescriptor.remoteAuthority) ? viewDescriptor.remoteAuthority[0] : viewDescriptor.remoteAuthority; + } + + public getActionViewItem(action: Action): IActionViewItem | undefined { + if (action.id === SwitchRemoteAction.ID) { + return this.instantiationService.createInstance(SwitchRemoteViewItem, action, SwitchRemoteViewItem.createOptionItems(Registry.as(Extensions.ViewsRegistry).getViews(VIEW_CONTAINER))); + } + + return super.getActionViewItem(action); + } + + public getActions(): IAction[] { + if (!this.actions) { + this.actions = [ + this.instantiationService.createInstance(SwitchRemoteAction, SwitchRemoteAction.ID, SwitchRemoteAction.LABEL), + ]; + this.actions.forEach(a => { + this._register(a); + }); + } + return this.actions; } private _handleRemoteInfoExtensionPoint(extension: IExtensionPointUser, helpInformation: HelpInformation[]) { @@ -419,38 +448,6 @@ export class RemoteViewlet extends ViewContainerViewlet implements IViewModel { }); } - onDidAddViews(added: IAddedViewDescriptorRef[]): ViewletPanel[] { - // too late, already added to the view model - const result = super.onDidAddViews(added); - - const remoteAuthority = this.environmentService.configuration.remoteAuthority; - if (remoteAuthority) { - const actualRemoteAuthority = remoteAuthority.split('+')[0]; - added.forEach((descriptor) => { - const panel = this.getView(descriptor.viewDescriptor.id); - if (!panel) { - return; - } - - const descriptorAuthority = descriptor.viewDescriptor.remoteAuthority; - if (typeof descriptorAuthority === 'undefined') { - panel.setExpanded(true); - } else if (descriptor.viewDescriptor.id === HelpPanel.ID) { - // Do nothing, keep the default behavior for Help - } else { - const descriptorAuthorityArr = Array.isArray(descriptorAuthority) ? descriptorAuthority : [descriptorAuthority]; - if (descriptorAuthorityArr.indexOf(actualRemoteAuthority) >= 0) { - panel.setExpanded(true); - } else { - panel.setExpanded(false); - } - } - }); - } - - return result; - } - getTitle(): string { const title = nls.localize('remote.explorer', "Remote Explorer"); return title; diff --git a/src/vs/workbench/contrib/remote/browser/remoteViewlet.css b/src/vs/workbench/contrib/remote/browser/remoteViewlet.css index 6f6908846c382..d48d027c617d0 100644 --- a/src/vs/workbench/contrib/remote/browser/remoteViewlet.css +++ b/src/vs/workbench/contrib/remote/browser/remoteViewlet.css @@ -87,3 +87,22 @@ .hc-black .monaco-list .monaco-list-row .remote-help-tree-node-item>.remote-help-tree-node-item-icon.issueReporter { background-image: url('help-report-issue-hc.svg') } + +.monaco-workbench .part > .title > .title-actions .switch-remote { + display: flex; + align-items: center; + font-size: 11px; + margin-right: 0.3em; + height: 20px; + flex-shrink: 1; + margin-top: 7px; +} + +.switch-remote > .monaco-select-box { + border: none; + display: block; +} + +.monaco-workbench .part > .title > .title-actions .switch-remote > .monaco-select-box { + padding-left: 3px; +} diff --git a/src/vs/workbench/contrib/remote/common/remote.contribution.ts b/src/vs/workbench/contrib/remote/common/remote.contribution.ts index 43671fbda5e4a..5d12781e767bb 100644 --- a/src/vs/workbench/contrib/remote/common/remote.contribution.ts +++ b/src/vs/workbench/contrib/remote/common/remote.contribution.ts @@ -34,7 +34,7 @@ export const VIEW_CONTAINER: ViewContainer = Registry.as('remoteExplorerService'); + +export interface IRemoteExplorerService { + _serviceBrand: undefined; + onDidChangeTargetType: Event; + targetType: string; +} + +class RemoteExplorerService implements IRemoteExplorerService { + public _serviceBrand: undefined; + private _targetType: string = ''; + private _onDidChangeTargetType: Emitter = new Emitter(); + public onDidChangeTargetType: Event = this._onDidChangeTargetType.event; + + set targetType(name: string) { + if (this._targetType !== name) { + const oldTarget = this._targetType; + this._targetType = name; + this._onDidChangeTargetType.fire(oldTarget); + } + } + get targetType(): string { + return this._targetType; + } +} + +registerSingleton(IRemoteExplorerService, RemoteExplorerService, true); diff --git a/src/vs/workbench/workbench.common.main.ts b/src/vs/workbench/workbench.common.main.ts index 42cf7aaffd7da..ddb19940d86a6 100644 --- a/src/vs/workbench/workbench.common.main.ts +++ b/src/vs/workbench/workbench.common.main.ts @@ -81,6 +81,7 @@ import 'vs/workbench/services/notification/common/notificationService'; import 'vs/workbench/services/extensions/common/staticExtensions'; import 'vs/workbench/services/userDataSync/common/settingsMergeService'; import 'vs/workbench/services/path/common/remotePathService'; +import 'vs/workbench/services/remote/common/remoteExplorerService'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { ExtensionGalleryService } from 'vs/platform/extensionManagement/common/extensionGalleryService'; From d1d9128573f76c19a55af28def98da5567198362 Mon Sep 17 00:00:00 2001 From: Christof Marti Date: Mon, 11 Nov 2019 17:49:57 +0100 Subject: [PATCH 061/352] Reduce typings files (#83421) --- src/vs/code/test/electron-main/nativeHelpers.test.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/vs/code/test/electron-main/nativeHelpers.test.ts b/src/vs/code/test/electron-main/nativeHelpers.test.ts index c8ffd0c8dbc14..199fa7acaf7a7 100644 --- a/src/vs/code/test/electron-main/nativeHelpers.test.ts +++ b/src/vs/code/test/electron-main/nativeHelpers.test.ts @@ -28,7 +28,9 @@ suite('Windows Native Helpers', () => { }); test('vscode-windows-ca-certs', async () => { - const windowsCerts = await import('vscode-windows-ca-certs'); + const windowsCerts = await new Promise((resolve, reject) => { + require(['vscode-windows-ca-certs'], resolve, reject); + }); assert.ok(windowsCerts, 'Unable to load vscode-windows-ca-certs dependency.'); }); From 33a6efa7fd0147d2d4ca15351eb357ec5b8827ea Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Mon, 11 Nov 2019 17:58:31 +0100 Subject: [PATCH 062/352] navigator work --- .../documentSymbols/outlineNavigation.ts | 109 ++++++++++-------- 1 file changed, 60 insertions(+), 49 deletions(-) diff --git a/src/vs/editor/contrib/documentSymbols/outlineNavigation.ts b/src/vs/editor/contrib/documentSymbols/outlineNavigation.ts index dd13a75eed3ed..139b3bca5cb61 100644 --- a/src/vs/editor/contrib/documentSymbols/outlineNavigation.ts +++ b/src/vs/editor/contrib/documentSymbols/outlineNavigation.ts @@ -6,7 +6,7 @@ import 'vs/css!./media/outlineTree'; import 'vs/css!./media/symbol-icons'; import { Range } from 'vs/editor/common/core/range'; -import { OutlineElement, OutlineModel } from 'vs/editor/contrib/documentSymbols/outlineModel'; +import { OutlineElement, OutlineModel, TreeElement } from 'vs/editor/contrib/documentSymbols/outlineModel'; import { localize } from 'vs/nls'; import { IEditorContribution } from 'vs/editor/common/editorCommon'; import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; @@ -16,12 +16,15 @@ import { EditorAction, registerEditorAction, registerEditorContribution } from ' import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { EditorContextKeys } from 'vs/editor/common/editorContextKeys'; import { values } from 'vs/base/common/collections'; +import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; +import { KeyCode } from 'vs/base/common/keyCodes'; +import { KeyMod } from 'vs/editor/common/standalone/standaloneBase'; class Navigator { - private static readonly _instances = new WeakMap(); + private static readonly _instances = new WeakMap(); - static for(element: OutlineElement): Navigator { + static for(element: TreeElement): Navigator { let res = this._instances.get(element); if (!res) { res = new Navigator(element); @@ -30,65 +33,55 @@ class Navigator { return res; } - private readonly _children: OutlineElement[] = []; + private readonly _children: TreeElement[] = []; - private constructor(readonly element: OutlineElement) { + private constructor(readonly element: TreeElement) { this._children = values(element.children).sort(Navigator._compare); } - parent(): OutlineElement | undefined { - const { parent } = this.element; - return parent instanceof OutlineElement ? parent : undefined; + navigate(up: boolean): TreeElement | undefined { + return up ? this._up() : this._down(); } - firstChild(): OutlineElement | undefined { - return this._children[0]; - } - - lastChild(): OutlineElement | undefined { - return this._children[this._children.length - 1]; + private _up(): TreeElement | undefined { + const sibling = this._sibling(true); + if (sibling) { + return sibling._child(true) ?? sibling.element; + } + return undefined; } - nextSibling(): OutlineElement | undefined { - const parent = this.parent(); - if (!parent) { - return undefined; + private _down(): TreeElement | undefined { + const firstChild = this._child(false); + if (firstChild) { + return firstChild; } - const parentNav = Navigator.for(parent); - const idx = parentNav._children.indexOf(this.element); - if (idx < 0 || idx + 1 >= parentNav._children.length) { - return undefined; + const sibling = this._sibling(false); + if (sibling) { + return sibling.element; } - return parentNav._children[idx + 1]; + return undefined; } - previousSibling(): OutlineElement | undefined { - const parent = this.parent(); - if (!parent) { + private _sibling(up: boolean): Navigator | undefined { + if (!this.element.parent) { return undefined; } - const parentNav = Navigator.for(parent); - const idx = parentNav._children.indexOf(this.element); - if (idx - 1 < 0) { - return undefined; - } - return parentNav._children[idx - 1]; + const parent = Navigator.for(this.element.parent); + const idx = parent._children.indexOf(this.element); + const nexIdx = idx + (up ? -1 : +1); + const element = parent._children[nexIdx]; + return element && Navigator.for(element); } - navigate(next: boolean): OutlineElement | undefined { - return next ? this._navNext() : this._navPrev(); + private _child(last: boolean): TreeElement | undefined { + return this._children[last ? this._children.length - 1 : 0]; } - private _navNext(): OutlineElement | undefined { - return undefined; - } - - private _navPrev(): OutlineElement | undefined { - return undefined; - } - - private static _compare(a: OutlineElement, b: OutlineElement): number { - return Range.compareRangesUsingStarts(a.symbol.range, b.symbol.range); + private static _compare(a: TreeElement, b: TreeElement): number { + return (a instanceof OutlineElement && b instanceof OutlineElement) + ? Range.compareRangesUsingStarts(a.symbol.range, b.symbol.range) + : 0; } } @@ -116,7 +109,7 @@ export class OutlineNavigation implements IEditorContribution { } } - async goto(next: boolean) { + async goto(up: boolean) { if (this._cts) { this._cts.cancel(); @@ -139,9 +132,9 @@ export class OutlineNavigation implements IEditorContribution { } let nav = Navigator.for(element); - let nextElement = nav.navigate(next); + let nextElement = nav.navigate(up); - if (nextElement) { + if (nextElement instanceof OutlineElement) { this._editor.setPosition(Range.lift(nextElement.symbol.selectionRange).getStartPosition()); } } @@ -158,11 +151,20 @@ registerEditorAction(class extends EditorAction { label: localize('label.next', "Go to Next Symbol"), alias: 'Go to Next Symbol', precondition: EditorContextKeys.hasDocumentSymbolProvider, + kbOpts: { + weight: KeybindingWeight.EditorContrib, + kbExpr: EditorContextKeys.focus, + primary: KeyMod.Shift | KeyMod.Alt | KeyCode.DownArrow, + mac: { + primary: KeyMod.CtrlCmd | KeyMod.WinCtrl | KeyMod.Shift | KeyCode.DownArrow, + secondary: [KeyMod.WinCtrl | KeyMod.Shift | KeyCode.DownArrow], + }, + } }); } run(_accessor: ServicesAccessor, editor: ICodeEditor): void | Promise { - OutlineNavigation.get(editor).goto(true); + OutlineNavigation.get(editor).goto(false); } }); @@ -174,10 +176,19 @@ registerEditorAction(class extends EditorAction { label: localize('label.prev', "Go to Previous Symbol"), alias: 'Go to Previous Symbol', precondition: EditorContextKeys.hasDocumentSymbolProvider, + kbOpts: { + weight: KeybindingWeight.EditorContrib, + kbExpr: EditorContextKeys.focus, + primary: KeyMod.Shift | KeyMod.Alt | KeyCode.UpArrow, + mac: { + primary: KeyMod.CtrlCmd | KeyMod.WinCtrl | KeyMod.Shift | KeyCode.UpArrow, + secondary: [KeyMod.WinCtrl | KeyMod.Shift | KeyCode.UpArrow], + }, + } }); } run(_accessor: ServicesAccessor, editor: ICodeEditor): void | Promise { - OutlineNavigation.get(editor).goto(false); + OutlineNavigation.get(editor).goto(true); } }); From 2c79231817aa9d95bde7f4019ce5dfae4e059124 Mon Sep 17 00:00:00 2001 From: Robo Date: Mon, 11 Nov 2019 09:44:57 -0800 Subject: [PATCH 063/352] fix: don't use appendArgument to add switch values (#84320) * fix: don't use appendArgument to add switch values * args - make sure to allow to enabe color correct rendering --- src/main.js | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/main.js b/src/main.js index d5f4c907fe70b..7242b0cb156a3 100644 --- a/src/main.js +++ b/src/main.js @@ -147,13 +147,9 @@ function configureCommandlineSwitchesSync(cliArgs) { if (argvValue === true || argvValue === 'true') { if (argvKey === 'disable-hardware-acceleration') { app.disableHardwareAcceleration(); // needs to be called explicitly - } else if (argvKey === 'disable-color-correct-rendering') { - app.commandLine.appendSwitch('disable-color-correct-rendering'); // needs to be called exactly like this (https://github.com/microsoft/vscode/issues/84154) } else { - app.commandLine.appendArgument(argvKey); + app.commandLine.appendSwitch(argvKey); } - } else { - app.commandLine.appendSwitch(argvKey, argvValue); } }); From 64489f331be04c228745dd1f4f4263811c568454 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Mon, 11 Nov 2019 10:06:15 -0800 Subject: [PATCH 064/352] Webview strict init #78168 --- src/vs/workbench/api/common/extHostWebview.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/api/common/extHostWebview.ts b/src/vs/workbench/api/common/extHostWebview.ts index 7da97013142cf..bd3b3b0daf196 100644 --- a/src/vs/workbench/api/common/extHostWebview.ts +++ b/src/vs/workbench/api/common/extHostWebview.ts @@ -16,6 +16,7 @@ import { asWebviewUri, WebviewInitData } from 'vs/workbench/api/common/shared/we import * as vscode from 'vscode'; import { ExtHostWebviewsShape, IMainContext, MainContext, MainThreadWebviewsShape, WebviewPanelHandle, WebviewPanelViewStateData } from './extHost.protocol'; import { Disposable as VSCodeDisposable } from './extHostTypes'; +import { assertIsDefined } from 'vs/base/common/types'; type IconPath = URI | { light: URI, dark: URI }; @@ -113,7 +114,8 @@ export class ExtHostWebviewEditor extends Disposable implements vscode.WebviewPa readonly _onDidChangeViewStateEmitter = this._register(new Emitter()); public readonly onDidChangeViewState: Event = this._onDidChangeViewStateEmitter.event; - _capabilities: vscode.WebviewEditorCapabilities; + + public _capabilities?: vscode.WebviewEditorCapabilities; constructor( handle: WebviewPanelHandle, @@ -245,7 +247,7 @@ export class ExtHostWebviewEditor extends Disposable implements vscode.WebviewPa } _undoEdits(edits: string[]): void { - this._capabilities.editingCapability?.undoEdits(edits); + assertIsDefined(this._capabilities).editingCapability?.undoEdits(edits); } private assertNotDisposed() { From f4a8c1d587cabef21545fa972ef9f22bb177395b Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Mon, 11 Nov 2019 08:06:58 -0800 Subject: [PATCH 065/352] Fix #84301 --- .../workbench/contrib/url/common/trustedDomainsValidator.ts | 6 +++++- src/vs/workbench/test/contrib/linkProtection.test.ts | 2 ++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/url/common/trustedDomainsValidator.ts b/src/vs/workbench/contrib/url/common/trustedDomainsValidator.ts index 4cce1c3c6c0e6..f930d68bccfde 100644 --- a/src/vs/workbench/contrib/url/common/trustedDomainsValidator.ts +++ b/src/vs/workbench/contrib/url/common/trustedDomainsValidator.ts @@ -158,7 +158,11 @@ export function isURLDomainTrusted(url: URI, trustedDomains: string[]) { } if (url.authority === parsedTrustedDomain.authority) { - return pathMatches(url.path, parsedTrustedDomain.path); + if (pathMatches(url.path, parsedTrustedDomain.path)) { + return true; + } else { + continue; + } } if (trustedDomains[i].indexOf('*') !== -1) { diff --git a/src/vs/workbench/test/contrib/linkProtection.test.ts b/src/vs/workbench/test/contrib/linkProtection.test.ts index 43c443119a7d7..72269c5421487 100644 --- a/src/vs/workbench/test/contrib/linkProtection.test.ts +++ b/src/vs/workbench/test/contrib/linkProtection.test.ts @@ -70,5 +70,7 @@ suite('Link protection domain matching', () => { linkNotAllowedByRules('https://a.x.org/bar', ['https://*.x.org/foo']); linkNotAllowedByRules('https://a.b.x.org/bar', ['https://*.x.org/foo']); + + linkAllowedByRules('https://github.com', ['https://github.com/foo/bar', 'https://github.com']); }); }); From 63c34a5e28e9776f50954f028ea04fbc17abe726 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Mon, 11 Nov 2019 19:27:37 +0100 Subject: [PATCH 066/352] implement/fix navigator --- .../documentSymbols/outlineNavigation.ts | 28 ++++++++++++++----- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/src/vs/editor/contrib/documentSymbols/outlineNavigation.ts b/src/vs/editor/contrib/documentSymbols/outlineNavigation.ts index 139b3bca5cb61..0c92b2fdd5800 100644 --- a/src/vs/editor/contrib/documentSymbols/outlineNavigation.ts +++ b/src/vs/editor/contrib/documentSymbols/outlineNavigation.ts @@ -8,7 +8,7 @@ import 'vs/css!./media/symbol-icons'; import { Range } from 'vs/editor/common/core/range'; import { OutlineElement, OutlineModel, TreeElement } from 'vs/editor/contrib/documentSymbols/outlineModel'; import { localize } from 'vs/nls'; -import { IEditorContribution } from 'vs/editor/common/editorCommon'; +import { IEditorContribution, ScrollType } from 'vs/editor/common/editorCommon'; import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; import { CancellationTokenSource } from 'vs/base/common/cancellation'; import { EditorStateCancellationTokenSource, CodeEditorStateFlag } from 'vs/editor/browser/core/editorState'; @@ -45,8 +45,16 @@ class Navigator { private _up(): TreeElement | undefined { const sibling = this._sibling(true); - if (sibling) { - return sibling._child(true) ?? sibling.element; + if (!sibling) { + return this.element.parent; + } + let nav: Navigator = sibling; + while (nav) { + let next = nav._child(true); + if (!next) { + return nav.element; + } + nav = Navigator.for(next); } return undefined; } @@ -56,9 +64,13 @@ class Navigator { if (firstChild) { return firstChild; } - const sibling = this._sibling(false); - if (sibling) { - return sibling.element; + let nav: Navigator | undefined = this; + while (nav) { + const next = nav._sibling(false); + if (next) { + return next.element; + } + nav = nav.element.parent && Navigator.for(nav.element.parent); } return undefined; } @@ -135,7 +147,9 @@ export class OutlineNavigation implements IEditorContribution { let nextElement = nav.navigate(up); if (nextElement instanceof OutlineElement) { - this._editor.setPosition(Range.lift(nextElement.symbol.selectionRange).getStartPosition()); + const pos = Range.lift(nextElement.symbol.selectionRange).getStartPosition(); + this._editor.setPosition(pos); + this._editor.revealPosition(pos, ScrollType.Smooth); } } From bcede909b4fc963cb029114063abfa8fa5d38128 Mon Sep 17 00:00:00 2001 From: Peng Lyu Date: Thu, 7 Nov 2019 13:36:35 -0800 Subject: [PATCH 067/352] Move keyboard feature detection into caniuse. --- src/vs/base/browser/canIUse.ts | 22 +++++++++++++++---- .../clipboard/browser/clipboardService.ts | 4 ++++ .../keybinding/browser/keybindingService.ts | 12 ++++------ 3 files changed, 26 insertions(+), 12 deletions(-) diff --git a/src/vs/base/browser/canIUse.ts b/src/vs/base/browser/canIUse.ts index 157ce940da50d..061d1bfc74fb3 100644 --- a/src/vs/base/browser/canIUse.ts +++ b/src/vs/base/browser/canIUse.ts @@ -6,6 +6,12 @@ import * as browser from 'vs/base/browser/browser'; import * as platform from 'vs/base/common/platform'; +export const enum KeyboardSupport { + Always, + FullScreen, + None +} + /** * Browser feature we can support in current platform, browser and environment. */ @@ -37,9 +43,17 @@ export const BrowserFeatures = { return true; })() }, - /* - * Full Keyboard Support in Full Screen Mode or Standablone - */ - fullKeyboard: !!(navigator).keyboard || browser.isSafari, + keyboard: (() => { + if (platform.isNative || browser.isStandalone) { + return KeyboardSupport.Always; + } + + if ((navigator).keyboard || browser.isSafari) { + return KeyboardSupport.FullScreen; + } + + return KeyboardSupport.None; + })(), + touch: 'ontouchstart' in window || navigator.maxTouchPoints > 0 || window.navigator.msMaxTouchPoints > 0 }; diff --git a/src/vs/workbench/services/clipboard/browser/clipboardService.ts b/src/vs/workbench/services/clipboard/browser/clipboardService.ts index 1a9272c760305..85a5d9db60c2d 100644 --- a/src/vs/workbench/services/clipboard/browser/clipboardService.ts +++ b/src/vs/workbench/services/clipboard/browser/clipboardService.ts @@ -27,6 +27,10 @@ export class BrowserClipboardService implements IClipboardService { newTextarea.style.visibility = 'false'; newTextarea.style.height = '1px'; newTextarea.style.width = '1px'; + newTextarea.setAttribute('aria-hidden', 'true'); + newTextarea.style.position = 'absolute'; + newTextarea.style.top = '-1000'; + newTextarea.style.left = '-1000'; document.body.appendChild(newTextarea); newTextarea.value = text; newTextarea.focus(); diff --git a/src/vs/workbench/services/keybinding/browser/keybindingService.ts b/src/vs/workbench/services/keybinding/browser/keybindingService.ts index 1adf85f8f61d6..a582ca420a059 100644 --- a/src/vs/workbench/services/keybinding/browser/keybindingService.ts +++ b/src/vs/workbench/services/keybinding/browser/keybindingService.ts @@ -46,7 +46,7 @@ import { isArray } from 'vs/base/common/types'; import { INavigatorWithKeyboard, IKeyboard } from 'vs/workbench/services/keybinding/browser/navigatorKeyboard'; import { ScanCodeUtils, IMMUTABLE_CODE_TO_KEY_CODE } from 'vs/base/common/scanCode'; import { flatten } from 'vs/base/common/arrays'; -import { BrowserFeatures } from 'vs/base/browser/canIUse'; +import { BrowserFeatures, KeyboardSupport } from 'vs/base/browser/canIUse'; interface ContributedKeyBinding { command: string; @@ -241,7 +241,7 @@ export class WorkbenchKeybindingService extends AbstractKeybindingService { this._register(browser.onDidChangeFullscreen(() => { const keyboard: IKeyboard | null = (navigator).keyboard; - if (!BrowserFeatures.fullKeyboard) { + if (BrowserFeatures.keyboard === KeyboardSupport.None) { return; } @@ -352,15 +352,11 @@ export class WorkbenchKeybindingService extends AbstractKeybindingService { } private _assertBrowserConflicts(kb: Keybinding, commandId: string): boolean { - if (!isWeb) { + if (BrowserFeatures.keyboard === KeyboardSupport.Always) { return false; } - if (browser.isStandalone) { - return false; - } - - if (browser.isFullscreen() && BrowserFeatures.fullKeyboard) { + if (BrowserFeatures.keyboard === KeyboardSupport.FullScreen && browser.isFullscreen()) { return false; } From 06cbe30f69581788032b6ed14e518c0e32952518 Mon Sep 17 00:00:00 2001 From: Peng Lyu Date: Mon, 11 Nov 2019 10:41:58 -0800 Subject: [PATCH 068/352] Fix #83599. Run onHide hook when monaco editor is removed from DOM tree. --- src/vs/editor/browser/controller/textAreaHandler.ts | 4 ++++ src/vs/editor/browser/controller/textAreaInput.ts | 10 +++++++++- src/vs/editor/browser/view/viewImpl.ts | 4 ++++ src/vs/editor/browser/widget/codeEditorWidget.ts | 2 ++ src/vs/workbench/browser/parts/editor/baseEditor.ts | 2 ++ src/vs/workbench/browser/parts/editor/editorControl.ts | 1 + .../browser/suggestEnabledInput/suggestEnabledInput.ts | 4 ++++ .../contrib/preferences/browser/settingsEditor2.ts | 4 ++++ 8 files changed, 30 insertions(+), 1 deletion(-) diff --git a/src/vs/editor/browser/controller/textAreaHandler.ts b/src/vs/editor/browser/controller/textAreaHandler.ts index ec222be435488..70cd98a030a34 100644 --- a/src/vs/editor/browser/controller/textAreaHandler.ts +++ b/src/vs/editor/browser/controller/textAreaHandler.ts @@ -406,6 +406,10 @@ export class TextAreaHandler extends ViewPart { this._textAreaInput.focusTextArea(); } + public refreshFocusState() { + this._textAreaInput.refreshFocusState(); + } + // --- end view API private _primaryCursorVisibleRange: HorizontalPosition | null = null; diff --git a/src/vs/editor/browser/controller/textAreaInput.ts b/src/vs/editor/browser/controller/textAreaInput.ts index 6e379a0400fa6..daecfbc4f6860 100644 --- a/src/vs/editor/browser/controller/textAreaInput.ts +++ b/src/vs/editor/browser/controller/textAreaInput.ts @@ -163,7 +163,7 @@ export class TextAreaInput extends Disposable { private _isDoingComposition: boolean; private _nextCommand: ReadFromTextArea; - constructor(host: ITextAreaInputHost, textArea: FastDomNode) { + constructor(host: ITextAreaInputHost, private textArea: FastDomNode) { super(); this._host = host; this._textArea = this._register(new TextAreaWrapper(textArea)); @@ -483,6 +483,14 @@ export class TextAreaInput extends Disposable { return this._hasFocus; } + public refreshFocusState(): void { + if (document.body.contains(this.textArea.domNode) && document.activeElement === this.textArea.domNode) { + this._setHasFocus(true); + } else { + this._setHasFocus(false); + } + } + private _setHasFocus(newHasFocus: boolean): void { if (this._hasFocus === newHasFocus) { // no change diff --git a/src/vs/editor/browser/view/viewImpl.ts b/src/vs/editor/browser/view/viewImpl.ts index 15f286d6abe49..42ef1f6f5425c 100644 --- a/src/vs/editor/browser/view/viewImpl.ts +++ b/src/vs/editor/browser/view/viewImpl.ts @@ -528,6 +528,10 @@ export class View extends ViewEventHandler { return this._textAreaHandler.isFocused(); } + public refreshFocusState() { + this._textAreaHandler.refreshFocusState(); + } + public addContentWidget(widgetData: IContentWidgetData): void { this.contentWidgets.addWidget(widgetData.widget); this.layoutContentWidget(widgetData); diff --git a/src/vs/editor/browser/widget/codeEditorWidget.ts b/src/vs/editor/browser/widget/codeEditorWidget.ts index f387c1308e820..83e47a48f1dd3 100644 --- a/src/vs/editor/browser/widget/codeEditorWidget.ts +++ b/src/vs/editor/browser/widget/codeEditorWidget.ts @@ -869,9 +869,11 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE } public onVisible(): void { + this._modelData?.view.refreshFocusState(); } public onHide(): void { + this._modelData?.view.refreshFocusState(); } public getContribution(id: string): T { diff --git a/src/vs/workbench/browser/parts/editor/baseEditor.ts b/src/vs/workbench/browser/parts/editor/baseEditor.ts index a830603ce5887..669ee10f2941b 100644 --- a/src/vs/workbench/browser/parts/editor/baseEditor.ts +++ b/src/vs/workbench/browser/parts/editor/baseEditor.ts @@ -112,6 +112,8 @@ export abstract class BaseEditor extends Panel implements IEditor { this.createEditor(parent); } + onHide() { } + /** * Called to create the editor in the parent HTMLElement. */ diff --git a/src/vs/workbench/browser/parts/editor/editorControl.ts b/src/vs/workbench/browser/parts/editor/editorControl.ts index 3fe6abaef7341..432a8fdc5465f 100644 --- a/src/vs/workbench/browser/parts/editor/editorControl.ts +++ b/src/vs/workbench/browser/parts/editor/editorControl.ts @@ -208,6 +208,7 @@ export class EditorControl extends Disposable { if (controlInstanceContainer) { this.parent.removeChild(controlInstanceContainer); hide(controlInstanceContainer); + this._activeControl.onHide(); } // Indicate to editor control diff --git a/src/vs/workbench/contrib/codeEditor/browser/suggestEnabledInput/suggestEnabledInput.ts b/src/vs/workbench/contrib/codeEditor/browser/suggestEnabledInput/suggestEnabledInput.ts index bb6029252bf68..19f19686a3d69 100644 --- a/src/vs/workbench/contrib/codeEditor/browser/suggestEnabledInput/suggestEnabledInput.ts +++ b/src/vs/workbench/contrib/codeEditor/browser/suggestEnabledInput/suggestEnabledInput.ts @@ -247,6 +247,10 @@ export class SuggestEnabledInput extends Widget implements IThemable { } } + public onHide(): void { + this.inputWidget.onHide(); + } + public layout(dimension: Dimension): void { this.inputWidget.layout(dimension); this.placeholderText.style.width = `${dimension.width}px`; diff --git a/src/vs/workbench/contrib/preferences/browser/settingsEditor2.ts b/src/vs/workbench/contrib/preferences/browser/settingsEditor2.ts index f8d98b3d05c71..36c63be5ea996 100644 --- a/src/vs/workbench/contrib/preferences/browser/settingsEditor2.ts +++ b/src/vs/workbench/contrib/preferences/browser/settingsEditor2.ts @@ -319,6 +319,10 @@ export class SettingsEditor2 extends BaseEditor { this.focusSearch(); } + onHide(): void { + this.searchWidget.onHide(); + } + focusSettings(): void { // Update ARIA global labels const labelElement = this.settingsAriaExtraLabelsContainer.querySelector('#settings_aria_more_actions_shortcut_label'); From 9b34464c6657b68322efa360f18a58ab6abcdda5 Mon Sep 17 00:00:00 2001 From: Peng Lyu Date: Mon, 11 Nov 2019 10:43:33 -0800 Subject: [PATCH 069/352] remove unused isWeb --- .../workbench/services/keybinding/browser/keybindingService.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/services/keybinding/browser/keybindingService.ts b/src/vs/workbench/services/keybinding/browser/keybindingService.ts index a582ca420a059..3867576370dec 100644 --- a/src/vs/workbench/services/keybinding/browser/keybindingService.ts +++ b/src/vs/workbench/services/keybinding/browser/keybindingService.ts @@ -11,7 +11,7 @@ import { Emitter, Event } from 'vs/base/common/event'; import { IJSONSchema } from 'vs/base/common/jsonSchema'; import { Keybinding, ResolvedKeybinding, KeyCode, KeyMod } from 'vs/base/common/keyCodes'; import { KeybindingParser } from 'vs/base/common/keybindingParser'; -import { OS, OperatingSystem, isWeb } from 'vs/base/common/platform'; +import { OS, OperatingSystem } from 'vs/base/common/platform'; import { ICommandService, CommandsRegistry } from 'vs/platform/commands/common/commands'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { Extensions as ConfigExtensions, IConfigurationNode, IConfigurationRegistry } from 'vs/platform/configuration/common/configurationRegistry'; From 8e94fc342b8b19ee57beed046f8c4b7562c6eff8 Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Fri, 8 Nov 2019 18:47:14 -0500 Subject: [PATCH 070/352] Fixes uri issue with remote uris w/ querystrings --- extensions/image-preview/src/preview.ts | 5 ++++- src/vs/workbench/contrib/webview/common/resourceLoader.ts | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/extensions/image-preview/src/preview.ts b/extensions/image-preview/src/preview.ts index 310043c4d3731..7b859877304b8 100644 --- a/extensions/image-preview/src/preview.ts +++ b/extensions/image-preview/src/preview.ts @@ -229,8 +229,11 @@ class Preview extends Disposable { // Show blank image return encodeURI('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAEElEQVR42gEFAPr/AP///wAI/AL+Sr4t6gAAAABJRU5ErkJggg=='); - default: + // Avoid adding cache busting if there is already a query string + if (resource.query) { + return encodeURI(webviewEditor.webview.asWebviewUri(resource).toString(true)); + } return encodeURI(webviewEditor.webview.asWebviewUri(resource).toString(true) + `?version=${version}`); } } diff --git a/src/vs/workbench/contrib/webview/common/resourceLoader.ts b/src/vs/workbench/contrib/webview/common/resourceLoader.ts index 8bde930f42cca..ea28683ef4ba4 100644 --- a/src/vs/workbench/contrib/webview/common/resourceLoader.ts +++ b/src/vs/workbench/contrib/webview/common/resourceLoader.ts @@ -83,7 +83,10 @@ function normalizeRequestPath(requestUri: URI) { // Modern vscode-resources uris put the scheme of the requested resource as the authority if (requestUri.authority) { - return URI.parse(requestUri.authority + ':' + requestUri.path); + return URI.parse(`${requestUri.authority}:${requestUri.path}`).with({ + query: requestUri.query, + fragment: requestUri.fragment + }); } // Old style vscode-resource uris lose the scheme of the resource which means they are unable to From afc29e93645f263c9b28bd6516d3b47a2bf9a507 Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Mon, 11 Nov 2019 15:34:04 -0500 Subject: [PATCH 071/352] Fixes #83513 - adds custom titlebar note --- src/vs/workbench/common/theme.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/common/theme.ts b/src/vs/workbench/common/theme.ts index 188874a11998f..81c0439428b66 100644 --- a/src/vs/workbench/common/theme.ts +++ b/src/vs/workbench/common/theme.ts @@ -593,13 +593,13 @@ export const WINDOW_ACTIVE_BORDER = registerColor('window.activeBorder', { dark: null, light: null, hc: contrastBorder -}, nls.localize('windowActiveBorder', "The color used for the border of the window when it is active. Only supported in the desktop client.")); +}, nls.localize('windowActiveBorder', "The color used for the border of the window when it is active. Only supported in the desktop client when using the custom title bar.")); export const WINDOW_INACTIVE_BORDER = registerColor('window.inactiveBorder', { dark: null, light: null, hc: contrastBorder -}, nls.localize('windowInactiveBorder', "The color used for the border of the window when it is inactive. Only supported in the desktop client.")); +}, nls.localize('windowInactiveBorder', "The color used for the border of the window when it is inactive. Only supported in the desktop client when using the custom title bar.")); /** * Base class for all themable workbench components. From b9a9714d4cc002bafaad7ad2983efec6e81870c2 Mon Sep 17 00:00:00 2001 From: Rachel Macfarlane Date: Mon, 11 Nov 2019 12:22:36 -0800 Subject: [PATCH 072/352] First cut of OAuth in the AuthTokenService --- build/lib/i18n.resources.json | 4 + .../sharedProcess/sharedProcessMain.ts | 2 +- src/vs/platform/auth/common/auth.ts | 12 +- src/vs/platform/auth/common/authTokenIpc.ts | 7 +- .../auth/electron-browser/authTokenService.ts | 266 ++++++++++++++++++ .../userDataSync/browser/userDataSync.ts | 9 +- .../authToken/browser}/authTokenService.ts | 31 +- .../electron-browser/authTokenService.ts | 27 +- src/vs/workbench/workbench.web.main.ts | 2 +- 9 files changed, 328 insertions(+), 32 deletions(-) create mode 100644 src/vs/platform/auth/electron-browser/authTokenService.ts rename src/vs/{platform/auth/common => workbench/services/authToken/browser}/authTokenService.ts (73%) diff --git a/build/lib/i18n.resources.json b/build/lib/i18n.resources.json index 848f89cd99336..581d2badaf0a3 100644 --- a/build/lib/i18n.resources.json +++ b/build/lib/i18n.resources.json @@ -202,6 +202,10 @@ "name": "vs/workbench/services/actions", "project": "vscode-workbench" }, + { + "name": "vs/workbench/services/authToken", + "project": "vscode-workbench" + }, { "name": "vs/workbench/services/bulkEdit", "project": "vscode-workbench" diff --git a/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts b/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts index 9ddf3c0eca99d..1492e7710c10d 100644 --- a/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts +++ b/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts @@ -59,7 +59,7 @@ import { IElectronService } from 'vs/platform/electron/node/electron'; import { LoggerService } from 'vs/platform/log/node/loggerService'; import { UserDataSyncLogService } from 'vs/platform/userDataSync/common/userDataSyncLog'; import { IAuthTokenService } from 'vs/platform/auth/common/auth'; -import { AuthTokenService } from 'vs/platform/auth/common/authTokenService'; +import { AuthTokenService } from 'vs/platform/auth/electron-browser/authTokenService'; import { AuthTokenChannel } from 'vs/platform/auth/common/authTokenIpc'; import { ICredentialsService } from 'vs/platform/credentials/common/credentials'; import { KeytarCredentialsService } from 'vs/platform/credentials/node/credentialsService'; diff --git a/src/vs/platform/auth/common/auth.ts b/src/vs/platform/auth/common/auth.ts index 7b2961d30b001..99102a0fe9396 100644 --- a/src/vs/platform/auth/common/auth.ts +++ b/src/vs/platform/auth/common/auth.ts @@ -4,7 +4,8 @@ *--------------------------------------------------------------------------------------------*/ import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; -import { Event } from 'vs/base/common/event'; +import { Event, Emitter } from 'vs/base/common/event'; +import { URI } from 'vs/base/common/uri'; export const enum AuthTokenStatus { Disabled = 'Disabled', @@ -19,11 +20,10 @@ export interface IAuthTokenService { readonly status: AuthTokenStatus; readonly onDidChangeStatus: Event; + readonly _onDidGetCallback: Emitter; - getToken(): Promise; - updateToken(token: string): Promise; + getToken(): Promise; refreshToken(): Promise; - deleteToken(): Promise; - + login(callbackUri?: URI): Promise; + logout(): Promise; } - diff --git a/src/vs/platform/auth/common/authTokenIpc.ts b/src/vs/platform/auth/common/authTokenIpc.ts index a5c78c4a8dd67..99a2111750c42 100644 --- a/src/vs/platform/auth/common/authTokenIpc.ts +++ b/src/vs/platform/auth/common/authTokenIpc.ts @@ -22,9 +22,12 @@ export class AuthTokenChannel implements IServerChannel { switch (command) { case '_getInitialStatus': return Promise.resolve(this.service.status); case 'getToken': return this.service.getToken(); - case 'updateToken': return this.service.updateToken(args[0]); + case 'exchangeCodeForToken': + this.service._onDidGetCallback.fire(args); + return Promise.resolve(); case 'refreshToken': return this.service.refreshToken(); - case 'deleteToken': return this.service.deleteToken(); + case 'login': return this.service.login(args); + case 'logout': return this.service.logout(); } throw new Error('Invalid call'); } diff --git a/src/vs/platform/auth/electron-browser/authTokenService.ts b/src/vs/platform/auth/electron-browser/authTokenService.ts new file mode 100644 index 0000000000000..9b70de53d72f5 --- /dev/null +++ b/src/vs/platform/auth/electron-browser/authTokenService.ts @@ -0,0 +1,266 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as crypto from 'crypto'; +import * as https from 'https'; +import { Event, Emitter } from 'vs/base/common/event'; +import { IAuthTokenService, AuthTokenStatus } from 'vs/platform/auth/common/auth'; +import { ICredentialsService } from 'vs/platform/credentials/common/credentials'; +import { Disposable, IDisposable } from 'vs/base/common/lifecycle'; +import { IProductService } from 'vs/platform/product/common/productService'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { URI } from 'vs/base/common/uri'; +import { generateUuid } from 'vs/base/common/uuid'; +import { shell } from 'electron'; + +const SERVICE_NAME = 'VS Code'; +const ACCOUNT = 'MyAccount'; + +const redirectUrlAAD = 'https://vscode-redirect.azurewebsites.net/'; +const activeDirectoryEndpointUrl = 'https://login.microsoftonline.com/'; +const activeDirectoryResourceId = 'https://management.core.windows.net/'; + +const clientId = 'aebc6443-996d-45c2-90f0-388ff96faa56'; +const tenantId = 'common'; + +function parseQuery(uri: URI) { + return uri.query.split('&').reduce((prev: any, current) => { + const queryString = current.split('='); + prev[queryString[0]] = queryString[1]; + return prev; + }, {}); +} + +function toQuery(obj: any): string { + return Object.keys(obj).map(key => `${key}=${obj[key]}`).join('&'); +} + +function toBase64UrlEncoding(base64string: string) { + return base64string.replace(/=/g, '').replace(/\+/g, '-').replace(/\//g, '_'); // Need to use base64url encoding +} + +export interface IToken { + expiresIn: string; // How long access token is valid, in seconds + expiresOn: string; // When the access token expires in epoch time + accessToken: string; + refreshToken: string; +} + +export class AuthTokenService extends Disposable implements IAuthTokenService { + _serviceBrand: undefined; + + private _status: AuthTokenStatus = AuthTokenStatus.Disabled; + get status(): AuthTokenStatus { return this._status; } + private _onDidChangeStatus: Emitter = this._register(new Emitter()); + readonly onDidChangeStatus: Event = this._onDidChangeStatus.event; + + public readonly _onDidGetCallback: Emitter = this._register(new Emitter()); + readonly onDidGetCallback: Event = this._onDidGetCallback.event; + + private _activeToken: IToken | undefined; + + constructor( + @ICredentialsService private readonly credentialsService: ICredentialsService, + @IProductService productService: IProductService, + @IConfigurationService configurationService: IConfigurationService, + ) { + super(); + if (productService.settingsSyncStoreUrl && configurationService.getValue('configurationSync.enableAuth')) { + this.credentialsService.getPassword(SERVICE_NAME, ACCOUNT).then(storedRefreshToken => { + if (storedRefreshToken) { + this.refresh(storedRefreshToken); + } else { + this._status = AuthTokenStatus.Inactive; + } + }); + } + } + + public async login(callbackUri: URI): Promise { + const nonce = generateUuid(); + const port = (callbackUri.authority.match(/:([0-9]*)$/) || [])[1] || (callbackUri.scheme === 'https' || callbackUri.scheme === 'http' ? 443 : 80); + const state = `${callbackUri.scheme},${port},${encodeURIComponent(nonce)},${encodeURIComponent(callbackUri.query)}`; + const signInUrl = `${activeDirectoryEndpointUrl}${tenantId}/oauth2/authorize`; + + const codeVerifier = toBase64UrlEncoding(crypto.randomBytes(32).toString('base64')); + const codeChallenge = toBase64UrlEncoding(crypto.createHash('sha256').update(codeVerifier).digest('base64')); + + let uri = URI.parse(signInUrl); + uri = uri.with({ + query: `response_type=code&client_id=${encodeURIComponent(clientId)}&redirect_uri=${redirectUrlAAD}&state=${encodeURIComponent(state)}&resource=${activeDirectoryResourceId}&prompt=select_account&code_challenge_method=S256&code_challenge=${codeChallenge}` + }); + + await shell.openExternal(uri.toString(true)); + + const timeoutPromise = new Promise((resolve: (value: IToken) => void, reject) => { + const wait = setTimeout(() => { + clearTimeout(wait); + reject('Login timed out.'); + }, 1000 * 60 * 5); + }); + + return Promise.race([this.exchangeCodeForToken(clientId, tenantId, codeVerifier, state), timeoutPromise]).then(token => { + this.setToken(token); + }); + } + + public getToken(): Promise { + if (this.status === AuthTokenStatus.Disabled) { + throw new Error('Not enabled'); + } + return Promise.resolve(this._activeToken?.accessToken); + } + + public async refreshToken(): Promise { + if (this.status === AuthTokenStatus.Disabled) { + throw new Error('Not enabled'); + } + + if (!this._activeToken) { + throw new Error('No token to refresh'); + } + + this.refresh(this._activeToken.refreshToken); + } + + private setToken(token: IToken) { + this._activeToken = token; + this.credentialsService.setPassword(SERVICE_NAME, ACCOUNT, token.refreshToken); + this.setStatus(AuthTokenStatus.Active); + } + + private async exchangeCodeForToken(clientId: string, tenantId: string, codeVerifier: string, state: string): Promise { + let uriEventListener: IDisposable; + return new Promise((resolve: (value: IToken) => void, reject) => { + uriEventListener = this.onDidGetCallback(async (uri: URI) => { + try { + const query = parseQuery(uri); + const code = query.code; + + if (query.state !== state) { + return; + } + + const postData = toQuery({ + grant_type: 'authorization_code', + code: code, + client_id: clientId, + code_verifier: codeVerifier, + redirect_uri: redirectUrlAAD + }); + + const post = https.request({ + host: 'login.microsoftonline.com', + path: `/${tenantId}/oauth2/token`, + method: 'POST', + headers: { + 'Content-Type': 'application/x-www-form-urlencoded', + 'Content-Length': postData.length + } + }, result => { + const buffer: Buffer[] = []; + result.on('data', (chunk: Buffer) => { + buffer.push(chunk); + }); + result.on('end', () => { + if (result.statusCode === 200) { + const json = JSON.parse(Buffer.concat(buffer).toString()); + resolve({ + expiresIn: json.access_token, + expiresOn: json.expires_on, + accessToken: json.access_token, + refreshToken: json.refresh_token + }); + } else { + reject(new Error('Bad!')); + } + }); + }); + + post.write(postData); + + post.end(); + post.on('error', err => { + reject(err); + }); + + } catch (e) { + reject(e); + } + }); + }).then(result => { + uriEventListener.dispose(); + return result; + }).catch(err => { + uriEventListener.dispose(); + throw err; + }); + } + + private async refresh(refreshToken: string): Promise { + return new Promise((resolve, reject) => { + const postData = toQuery({ + refresh_token: refreshToken, + client_id: clientId, + grant_type: 'refresh_token', + resource: activeDirectoryResourceId + }); + + const post = https.request({ + host: 'login.microsoftonline.com', + path: `/${tenantId}/oauth2/token`, + method: 'POST', + headers: { + 'Content-Type': 'application/x-www-form-urlencoded', + 'Content-Length': postData.length + } + }, result => { + const buffer: Buffer[] = []; + result.on('data', (chunk: Buffer) => { + buffer.push(chunk); + }); + result.on('end', () => { + if (result.statusCode === 200) { + const json = JSON.parse(Buffer.concat(buffer).toString()); + this.setToken({ + expiresIn: json.access_token, + expiresOn: json.expires_on, + accessToken: json.access_token, + refreshToken: json.refresh_token + }); + resolve(); + } else { + reject(new Error('Bad!')); + } + }); + }); + + post.write(postData); + + post.end(); + post.on('error', err => { + reject(err); + }); + }); + } + + async logout(): Promise { + if (this.status === AuthTokenStatus.Disabled) { + throw new Error('Not enabled'); + } + await this.credentialsService.deletePassword(SERVICE_NAME, ACCOUNT); + this._activeToken = undefined; + this.setStatus(AuthTokenStatus.Inactive); + } + + private setStatus(status: AuthTokenStatus): void { + if (this._status !== status) { + this._status = status; + this._onDidChangeStatus.fire(status); + } + } + +} + diff --git a/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts b/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts index 92cb1c09c88df..f1a0ded961b36 100644 --- a/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts +++ b/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts @@ -25,7 +25,6 @@ import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/ import { isEqual } from 'vs/base/common/resources'; import { IEditorInput } from 'vs/workbench/common/editor'; import { IAuthTokenService, AuthTokenStatus } from 'vs/platform/auth/common/auth'; -import { IQuickInputService } from 'vs/platform/quickinput/common/quickInput'; import { timeout } from 'vs/base/common/async'; const CONTEXT_AUTH_TOKEN_STATE = new RawContextKey('authTokenStatus', AuthTokenStatus.Inactive); @@ -51,7 +50,6 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo @ITextFileService private readonly textFileService: ITextFileService, @IHistoryService private readonly historyService: IHistoryService, @IWorkbenchEnvironmentService private readonly workbenchEnvironmentService: IWorkbenchEnvironmentService, - @IQuickInputService private readonly quickInputService: IQuickInputService, ) { super(); this.syncStatusContext = CONTEXT_SYNC_STATE.bindTo(contextKeyService); @@ -138,14 +136,11 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo } private async signIn(): Promise { - const token = await this.quickInputService.input({ placeHolder: localize('enter token', "Please provide the auth bearer token"), ignoreFocusLost: true, }); - if (token) { - await this.authTokenService.updateToken(token); - } + return this.authTokenService.login(); } private async signOut(): Promise { - await this.authTokenService.deleteToken(); + await this.authTokenService.logout(); } private async continueSync(): Promise { diff --git a/src/vs/platform/auth/common/authTokenService.ts b/src/vs/workbench/services/authToken/browser/authTokenService.ts similarity index 73% rename from src/vs/platform/auth/common/authTokenService.ts rename to src/vs/workbench/services/authToken/browser/authTokenService.ts index 322ecfb2b09ce..430a11f7bd896 100644 --- a/src/vs/platform/auth/common/authTokenService.ts +++ b/src/vs/workbench/services/authToken/browser/authTokenService.ts @@ -3,12 +3,15 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +import { localize } from 'vs/nls'; import { Event, Emitter } from 'vs/base/common/event'; import { IAuthTokenService, AuthTokenStatus } from 'vs/platform/auth/common/auth'; import { ICredentialsService } from 'vs/platform/credentials/common/credentials'; import { Disposable } from 'vs/base/common/lifecycle'; import { IProductService } from 'vs/platform/product/common/productService'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { IQuickInputService } from 'vs/platform/quickinput/common/quickInput'; +import { URI } from 'vs/base/common/uri'; const SERVICE_NAME = 'VS Code'; const ACCOUNT = 'MyAccount'; @@ -21,10 +24,13 @@ export class AuthTokenService extends Disposable implements IAuthTokenService { private _onDidChangeStatus: Emitter = this._register(new Emitter()); readonly onDidChangeStatus: Event = this._onDidChangeStatus.event; + readonly _onDidGetCallback: Emitter = this._register(new Emitter()); + constructor( @ICredentialsService private readonly credentialsService: ICredentialsService, @IProductService productService: IProductService, @IConfigurationService configurationService: IConfigurationService, + @IQuickInputService private readonly quickInputService: IQuickInputService ) { super(); if (productService.settingsSyncStoreUrl && configurationService.getValue('configurationSync.enableAuth')) { @@ -37,29 +43,35 @@ export class AuthTokenService extends Disposable implements IAuthTokenService { } } - getToken(): Promise { + async getToken(): Promise { if (this.status === AuthTokenStatus.Disabled) { throw new Error('Not enabled'); } - return this.credentialsService.getPassword(SERVICE_NAME, ACCOUNT); + + const token = await this.credentialsService.getPassword(SERVICE_NAME, ACCOUNT); + if (token) { + return token; + } + + return; } - async updateToken(token: string): Promise { - if (this.status === AuthTokenStatus.Disabled) { - throw new Error('Not enabled'); + async login(): Promise { + const token = await this.quickInputService.input({ placeHolder: localize('enter token', "Please provide the auth bearer token"), ignoreFocusLost: true, }); + if (token) { + await this.credentialsService.setPassword(SERVICE_NAME, ACCOUNT, token); + this.setStatus(AuthTokenStatus.Active); } - await this.credentialsService.setPassword(SERVICE_NAME, ACCOUNT, token); - this.setStatus(AuthTokenStatus.Active); } async refreshToken(): Promise { if (this.status === AuthTokenStatus.Disabled) { throw new Error('Not enabled'); } - await this.deleteToken(); + await this.logout(); } - async deleteToken(): Promise { + async logout(): Promise { if (this.status === AuthTokenStatus.Disabled) { throw new Error('Not enabled'); } @@ -75,4 +87,3 @@ export class AuthTokenService extends Disposable implements IAuthTokenService { } } - diff --git a/src/vs/workbench/services/authToken/electron-browser/authTokenService.ts b/src/vs/workbench/services/authToken/electron-browser/authTokenService.ts index b5a2b2d0c0a63..7a06e375569a7 100644 --- a/src/vs/workbench/services/authToken/electron-browser/authTokenService.ts +++ b/src/vs/workbench/services/authToken/electron-browser/authTokenService.ts @@ -9,6 +9,8 @@ import { Emitter, Event } from 'vs/base/common/event'; import { IChannel } from 'vs/base/parts/ipc/common/ipc'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { IAuthTokenService, AuthTokenStatus } from 'vs/platform/auth/common/auth'; +import { IURLService } from 'vs/platform/url/common/url'; +import { URI } from 'vs/base/common/uri'; export class AuthTokenService extends Disposable implements IAuthTokenService { @@ -21,8 +23,11 @@ export class AuthTokenService extends Disposable implements IAuthTokenService { private _onDidChangeStatus: Emitter = this._register(new Emitter()); readonly onDidChangeStatus: Event = this._onDidChangeStatus.event; + readonly _onDidGetCallback: Emitter = this._register(new Emitter()); + constructor( - @ISharedProcessService sharedProcessService: ISharedProcessService + @ISharedProcessService sharedProcessService: ISharedProcessService, + @IURLService private readonly urlService: IURLService ) { super(); this.channel = sharedProcessService.getChannel('authToken'); @@ -30,22 +35,34 @@ export class AuthTokenService extends Disposable implements IAuthTokenService { this.updateStatus(status); this._register(this.channel.listen('onDidChangeStatus')(status => this.updateStatus(status))); }); + + this.urlService.registerHandler(this); + } + + handleURL(uri: URI) { + if (uri.authority === 'vscode.login') { + this.channel.call('exchangeCodeForToken', uri); + return Promise.resolve(true); + } else { + return Promise.resolve(false); + } } getToken(): Promise { return this.channel.call('getToken'); } - updateToken(token: string): Promise { - return this.channel.call('updateToken', [token]); + login(): Promise { + const callbackUri = this.urlService.create({ authority: 'vscode.login ' }); + return this.channel.call('login', callbackUri); } refreshToken(): Promise { return this.channel.call('getToken'); } - deleteToken(): Promise { - return this.channel.call('deleteToken'); + logout(): Promise { + return this.channel.call('logout'); } private async updateStatus(status: AuthTokenStatus): Promise { diff --git a/src/vs/workbench/workbench.web.main.ts b/src/vs/workbench/workbench.web.main.ts index bed3663cfcbe8..0e6601077d354 100644 --- a/src/vs/workbench/workbench.web.main.ts +++ b/src/vs/workbench/workbench.web.main.ts @@ -64,7 +64,7 @@ import { NoOpTunnelService } from 'vs/platform/remote/common/tunnelService'; import { ILoggerService } from 'vs/platform/log/common/log'; import { FileLoggerService } from 'vs/platform/log/common/fileLogService'; import { IAuthTokenService } from 'vs/platform/auth/common/auth'; -import { AuthTokenService } from 'vs/platform/auth/common/authTokenService'; +import { AuthTokenService } from 'vs/workbench/services/authToken/browser/authTokenService'; import { IUserDataSyncStoreService, IUserDataSyncService, IUserDataSyncLogService } from 'vs/platform/userDataSync/common/userDataSync'; import { UserDataSyncLogService } from 'vs/platform/userDataSync/common/userDataSyncLog'; import { UserDataSyncStoreService } from 'vs/platform/userDataSync/common/userDataSyncStoreService'; From 994ed41f2f8232442439080ba112a3aa20c9bc55 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Mon, 11 Nov 2019 22:44:58 +0100 Subject: [PATCH 073/352] Fix #84528 --- .../common/configurationEditingService.ts | 4 +- .../configurationEditingService.test.ts | 37 ++++++++++++++++++- 2 files changed, 38 insertions(+), 3 deletions(-) diff --git a/src/vs/workbench/services/configuration/common/configurationEditingService.ts b/src/vs/workbench/services/configuration/common/configurationEditingService.ts index ead4e246a366f..d0113b72bd795 100644 --- a/src/vs/workbench/services/configuration/common/configurationEditingService.ts +++ b/src/vs/workbench/services/configuration/common/configurationEditingService.ts @@ -436,7 +436,7 @@ export class ConfigurationEditingService { } if (target === EditableConfigurationTarget.WORKSPACE) { - if (!operation.workspaceStandAloneConfigurationKey) { + if (!operation.workspaceStandAloneConfigurationKey && !OVERRIDE_PROPERTY_PATTERN.test(operation.key)) { const configurationProperties = Registry.as(ConfigurationExtensions.Configuration).getConfigurationProperties(); if (configurationProperties[operation.key].scope === ConfigurationScope.APPLICATION) { return this.reject(ConfigurationEditingErrorCode.ERROR_INVALID_WORKSPACE_CONFIGURATION_APPLICATION, target, operation); @@ -452,7 +452,7 @@ export class ConfigurationEditingService { return this.reject(ConfigurationEditingErrorCode.ERROR_INVALID_FOLDER_TARGET, target, operation); } - if (!operation.workspaceStandAloneConfigurationKey) { + if (!operation.workspaceStandAloneConfigurationKey && !OVERRIDE_PROPERTY_PATTERN.test(operation.key)) { const configurationProperties = Registry.as(ConfigurationExtensions.Configuration).getConfigurationProperties(); if (configurationProperties[operation.key].scope !== ConfigurationScope.RESOURCE) { return this.reject(ConfigurationEditingErrorCode.ERROR_INVALID_FOLDER_CONFIGURATION, target, operation); diff --git a/src/vs/workbench/services/configuration/test/electron-browser/configurationEditingService.test.ts b/src/vs/workbench/services/configuration/test/electron-browser/configurationEditingService.test.ts index 7ad581196cce7..d315118d91ccf 100644 --- a/src/vs/workbench/services/configuration/test/electron-browser/configurationEditingService.test.ts +++ b/src/vs/workbench/services/configuration/test/electron-browser/configurationEditingService.test.ts @@ -18,7 +18,7 @@ import * as uuid from 'vs/base/common/uuid'; import { IConfigurationRegistry, Extensions as ConfigurationExtensions } from 'vs/platform/configuration/common/configurationRegistry'; import { WorkspaceService } from 'vs/workbench/services/configuration/browser/configurationService'; import { ConfigurationEditingService, ConfigurationEditingError, ConfigurationEditingErrorCode, EditableConfigurationTarget } from 'vs/workbench/services/configuration/common/configurationEditingService'; -import { WORKSPACE_STANDALONE_CONFIGURATIONS } from 'vs/workbench/services/configuration/common/configuration'; +import { WORKSPACE_STANDALONE_CONFIGURATIONS, FOLDER_SETTINGS_PATH } from 'vs/workbench/services/configuration/common/configuration'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock'; import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; @@ -236,6 +236,41 @@ suite('ConfigurationEditingService', () => { }); }); + test('write overridable settings to user settings', () => { + const key = '[language]'; + const value = { 'configurationEditing.service.testSetting': 'overridden value' }; + return testObject.writeConfiguration(EditableConfigurationTarget.USER_LOCAL, { key, value }) + .then(() => { + const contents = fs.readFileSync(globalSettingsFile).toString('utf8'); + const parsed = json.parse(contents); + assert.deepEqual(parsed[key], value); + }); + }); + + test('write overridable settings to workspace settings', () => { + const key = '[language]'; + const value = { 'configurationEditing.service.testSetting': 'overridden value' }; + return testObject.writeConfiguration(EditableConfigurationTarget.WORKSPACE, { key, value }) + .then(() => { + const target = path.join(workspaceDir, FOLDER_SETTINGS_PATH); + const contents = fs.readFileSync(target).toString('utf8'); + const parsed = json.parse(contents); + assert.deepEqual(parsed[key], value); + }); + }); + + test('write overridable settings to workspace folder settings', () => { + const key = '[language]'; + const value = { 'configurationEditing.service.testSetting': 'overridden value' }; + const folderSettingsFile = path.join(workspaceDir, FOLDER_SETTINGS_PATH); + return testObject.writeConfiguration(EditableConfigurationTarget.WORKSPACE_FOLDER, { key, value }, { scopes: { resource: URI.file(folderSettingsFile) } }) + .then(() => { + const contents = fs.readFileSync(folderSettingsFile).toString('utf8'); + const parsed = json.parse(contents); + assert.deepEqual(parsed[key], value); + }); + }); + test('write workspace standalone setting - empty file', () => { return testObject.writeConfiguration(EditableConfigurationTarget.WORKSPACE, { key: 'tasks.service.testSetting', value: 'value' }) .then(() => { From 0d728c70cd2dfd17da1a7ae461849bb5f4100804 Mon Sep 17 00:00:00 2001 From: Jackson Kearl Date: Mon, 11 Nov 2019 14:21:39 -0800 Subject: [PATCH 074/352] Fix #84456 --- .../contrib/search/test/common/searchModel.test.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/vs/workbench/contrib/search/test/common/searchModel.test.ts b/src/vs/workbench/contrib/search/test/common/searchModel.test.ts index f9cf1306a64fa..4bd8e74e94e3c 100644 --- a/src/vs/workbench/contrib/search/test/common/searchModel.test.ts +++ b/src/vs/workbench/contrib/search/test/common/searchModel.test.ts @@ -70,6 +70,10 @@ suite('SearchModel', () => { instantiationService.stub(IModelService, stubModelService(instantiationService)); instantiationService.stub(ISearchService, {}); instantiationService.stub(ISearchService, 'textSearch', Promise.resolve({ results: [] })); + + const config = new TestConfigurationService(); + config.setUserConfiguration('search', { searchOnType: true }); + instantiationService.stub(IConfigurationService, config); }); teardown(() => { @@ -154,9 +158,6 @@ suite('SearchModel', () => { new TextSearchMatch('preview 1', new OneLineRange(1, 4, 11))), aRawMatch('file://c:/2', new TextSearchMatch('preview 2', lineOneRange))]; - const config = new TestConfigurationService(); - config.setUserConfiguration('search', { searchOnType: true }); - instantiationService.stub(IConfigurationService, config); instantiationService.stub(ISearchService, searchServiceWithResults(results)); const testObject: SearchModel = instantiationService.createInstance(SearchModel); From 8cf0431e9652f7c721085553da18b184e8bcbe87 Mon Sep 17 00:00:00 2001 From: Jackson Kearl Date: Mon, 11 Nov 2019 14:23:09 -0800 Subject: [PATCH 075/352] Make searchConfig getter private --- src/vs/workbench/contrib/search/browser/patternInputWidget.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/search/browser/patternInputWidget.ts b/src/vs/workbench/contrib/search/browser/patternInputWidget.ts index 5cd836f67db65..0dd3066c394aa 100644 --- a/src/vs/workbench/contrib/search/browser/patternInputWidget.ts +++ b/src/vs/workbench/contrib/search/browser/patternInputWidget.ts @@ -180,7 +180,7 @@ export class PatternInputWidget extends Widget { } } - get searchConfig() { + private get searchConfig() { return this.configurationService.getValue('search'); } } From e1d887932e1a7c868be89465966f3155637b202e Mon Sep 17 00:00:00 2001 From: Jackson Kearl Date: Mon, 11 Nov 2019 15:02:11 -0800 Subject: [PATCH 076/352] Dont double run "Find in Files" when "searchOnType" enabled Fixes #84534. --- .../contrib/search/browser/searchView.ts | 3 +-- .../contrib/search/browser/searchWidget.ts | 15 +++++++++++++-- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/src/vs/workbench/contrib/search/browser/searchView.ts b/src/vs/workbench/contrib/search/browser/searchView.ts index f978845537292..150156d7dc27f 100644 --- a/src/vs/workbench/contrib/search/browser/searchView.ts +++ b/src/vs/workbench/contrib/search/browser/searchView.ts @@ -797,8 +797,7 @@ export class SearchView extends ViewletPanel { if (this.searchWidget.searchInput.getRegex()) { selectedText = strings.escapeRegExpCharacters(selectedText); } - - this.searchWidget.searchInput.setValue(selectedText); + this.searchWidget.setValue(selectedText, true); updatedText = true; this.onQueryChanged(); } diff --git a/src/vs/workbench/contrib/search/browser/searchWidget.ts b/src/vs/workbench/contrib/search/browser/searchWidget.ts index 5aa020a689ecb..0652167a7a485 100644 --- a/src/vs/workbench/contrib/search/browser/searchWidget.ts +++ b/src/vs/workbench/contrib/search/browser/searchWidget.ts @@ -149,6 +149,8 @@ export class SearchWidget extends Widget { private _onDidHeightChange = this._register(new Emitter()); readonly onDidHeightChange: Event = this._onDidHeightChange.event; + private temporarilySkipSearchOnChange = false; + constructor( container: HTMLElement, options: ISearchWidgetOptions, @@ -404,6 +406,11 @@ export class SearchWidget extends Widget { this._onReplaceToggled.fire(); } + setValue(value: string, skipSearchOnChange: boolean) { + this.searchInput.setValue(value); + this.temporarilySkipSearchOnChange = skipSearchOnChange || this.temporarilySkipSearchOnChange; + } + setReplaceAllActionState(enabled: boolean): void { if (this.replaceAllAction.enabled !== enabled) { this.replaceAllAction.enabled = enabled; @@ -450,8 +457,12 @@ export class SearchWidget extends Widget { this.setReplaceAllActionState(false); if (this.searchConfiguration.searchOnType) { - this._onSearchCancel.fire({ focus: false }); - this._searchDelayer.trigger((() => this.submitSearch()), this.searchConfiguration.searchOnTypeDebouncePeriod); + if (this.temporarilySkipSearchOnChange) { + this.temporarilySkipSearchOnChange = false; + } else { + this._onSearchCancel.fire({ focus: false }); + this._searchDelayer.trigger((() => this.submitSearch()), this.searchConfiguration.searchOnTypeDebouncePeriod); + } } } From 6118d2713e1a60d29e4b4154905ebdf598cf5b90 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Mon, 11 Nov 2019 14:19:01 -0800 Subject: [PATCH 077/352] Make sure synchronized buffers are reset when tsserver restarts --- .../src/features/bufferSyncSupport.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/extensions/typescript-language-features/src/features/bufferSyncSupport.ts b/extensions/typescript-language-features/src/features/bufferSyncSupport.ts index 6826005b8978a..82803d55639ea 100644 --- a/extensions/typescript-language-features/src/features/bufferSyncSupport.ts +++ b/extensions/typescript-language-features/src/features/bufferSyncSupport.ts @@ -118,7 +118,11 @@ class BufferSynchronizer { } } - public beforeCommand(command: string) { + public reset(): void { + this._pending.clear(); + } + + public beforeCommand(command: string): void { if (command === 'updateOpen') { return; } @@ -397,6 +401,7 @@ export default class BufferSyncSupport extends Disposable { public reset(): void { this.pendingGetErr?.cancel(); this.pendingDiagnostics.clear(); + this.synchronizer.reset(); for (const buffer of this.syncedBuffers.allBuffers) { buffer.open(); From 8904a3cbced77574bcbd743c2b115423311829e6 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Mon, 11 Nov 2019 14:22:51 -0800 Subject: [PATCH 078/352] :lipstick: --- .../src/features/bufferSyncSupport.ts | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/extensions/typescript-language-features/src/features/bufferSyncSupport.ts b/extensions/typescript-language-features/src/features/bufferSyncSupport.ts index 82803d55639ea..4ddc0506ddbc5 100644 --- a/extensions/typescript-language-features/src/features/bufferSyncSupport.ts +++ b/extensions/typescript-language-features/src/features/bufferSyncSupport.ts @@ -269,16 +269,15 @@ class GetErrRequest { files: ResourceMap, onDone: () => void ) { - const token = new vscode.CancellationTokenSource(); - return new GetErrRequest(client, files, token, onDone); + return new GetErrRequest(client, files, onDone); } private _done: boolean = false; + private readonly _token: vscode.CancellationTokenSource = new vscode.CancellationTokenSource(); private constructor( client: ITypeScriptServiceClient, public readonly files: ResourceMap, - private readonly _token: vscode.CancellationTokenSource, onDone: () => void ) { const args: Proto.GeterrRequestArgs = { @@ -286,7 +285,7 @@ class GetErrRequest { files: coalesce(Array.from(files.entries).map(entry => client.normalizedPath(entry.resource))) }; - client.executeAsync('geterr', args, _token.token) + client.executeAsync('geterr', args, this._token.token) .finally(() => { if (this._done) { return; From 2ec3bc4fd0accc9c672d64558d0f06b9efd550db Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Mon, 11 Nov 2019 14:24:48 -0800 Subject: [PATCH 079/352] Removed undocumented setting usage --- .../src/features/bufferSyncSupport.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/typescript-language-features/src/features/bufferSyncSupport.ts b/extensions/typescript-language-features/src/features/bufferSyncSupport.ts index 4ddc0506ddbc5..28e201352061e 100644 --- a/extensions/typescript-language-features/src/features/bufferSyncSupport.ts +++ b/extensions/typescript-language-features/src/features/bufferSyncSupport.ts @@ -154,7 +154,7 @@ class BufferSynchronizer { } private get supportsBatching(): boolean { - return this.client.apiVersion.gte(API.v340) && vscode.workspace.getConfiguration('typescript', null).get('useBatchedBufferSync', true); + return this.client.apiVersion.gte(API.v340); } private updatePending(resource: vscode.Uri, f: (pending: ResourceMap) => void): void { From b9b9ab27766762ea82ff95bd2914a3a10b2808eb Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Mon, 11 Nov 2019 16:12:19 -0800 Subject: [PATCH 080/352] Don't include optional editors in diff view selection --- src/vs/workbench/contrib/customEditor/browser/customEditors.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/customEditor/browser/customEditors.ts b/src/vs/workbench/contrib/customEditor/browser/customEditors.ts index 5ca66eee23da5..5a0b6a47e3bfd 100644 --- a/src/vs/workbench/contrib/customEditor/browser/customEditors.ts +++ b/src/vs/workbench/contrib/customEditor/browser/customEditors.ts @@ -342,7 +342,7 @@ export class CustomEditorContribution implements IWorkbenchContribution { const editors = mergeSort( distinct([ ...this.customEditorService.getUserConfiguredCustomEditors(resource), - ...this.customEditorService.getContributedCustomEditors(resource), + ...this.customEditorService.getContributedCustomEditors(resource).filter(x => x.priority !== CustomEditorPriority.option), ], editor => editor.id), (a, b) => { return priorityToRank(a.priority) - priorityToRank(b.priority); From 0d728c31ebdf03869d2687d9be0b017667c9ff37 Mon Sep 17 00:00:00 2001 From: Jackson Kearl Date: Mon, 11 Nov 2019 17:04:44 -0800 Subject: [PATCH 081/352] Remove backreferences warning (#84092) * Fallback to PCRE2 when backreferences are detected And remove warning that we don't support them. * Remove explicit fallback... ripgrep will do it implicitly * Remove unused --- src/vs/workbench/contrib/search/browser/searchWidget.ts | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/vs/workbench/contrib/search/browser/searchWidget.ts b/src/vs/workbench/contrib/search/browser/searchWidget.ts index 0652167a7a485..d3c846bd0dd74 100644 --- a/src/vs/workbench/contrib/search/browser/searchWidget.ts +++ b/src/vs/workbench/contrib/search/browser/searchWidget.ts @@ -15,7 +15,6 @@ import { Action } from 'vs/base/common/actions'; import { Delayer } from 'vs/base/common/async'; import { Emitter, Event } from 'vs/base/common/event'; import { KeyCode, KeyMod } from 'vs/base/common/keyCodes'; -import * as strings from 'vs/base/common/strings'; import { CONTEXT_FIND_WIDGET_NOT_VISIBLE } from 'vs/editor/contrib/find/findModel'; import * as nls from 'vs/nls'; import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService'; @@ -443,12 +442,6 @@ export class SearchWidget extends Widget { return { content: e.message }; } - if (strings.regExpContainsBackreference(value)) { - if (!this.searchConfiguration.usePCRE2) { - return { content: nls.localize('regexp.backreferenceValidationFailure', "Backreferences are not supported") }; - } - } - return null; } From 68fbaf42c873435a1246fb408dce0d02c1f37f96 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Tue, 12 Nov 2019 08:00:16 +0100 Subject: [PATCH 082/352] debt - adopt windows-foreground-love types --- package.json | 1 + src/typings/windows-foreground-love.d.ts | 10 ---------- yarn.lock | 5 +++++ 3 files changed, 6 insertions(+), 10 deletions(-) delete mode 100644 src/typings/windows-foreground-love.d.ts diff --git a/package.json b/package.json index d4bf37ca9ae26..51c1dc12a7a18 100644 --- a/package.json +++ b/package.json @@ -73,6 +73,7 @@ "@types/semver": "^5.5.0", "@types/sinon": "^1.16.36", "@types/webpack": "^4.4.10", + "@types/windows-foreground-love": "^0.3.0", "@types/winreg": "^1.2.30", "@types/yauzl": "^2.9.1", "@types/yazl": "^2.4.2", diff --git a/src/typings/windows-foreground-love.d.ts b/src/typings/windows-foreground-love.d.ts deleted file mode 100644 index f7d20f13aef8e..0000000000000 --- a/src/typings/windows-foreground-love.d.ts +++ /dev/null @@ -1,10 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -declare module 'windows-foreground-love' { - - export function allowSetForegroundWindow(pid?: number): boolean; - -} \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index 5e44523b3f780..3f00734e764dd 100644 --- a/yarn.lock +++ b/yarn.lock @@ -204,6 +204,11 @@ "@types/uglify-js" "*" source-map "^0.6.0" +"@types/windows-foreground-love@^0.3.0": + version "0.3.0" + resolved "https://registry.yarnpkg.com/@types/windows-foreground-love/-/windows-foreground-love-0.3.0.tgz#26bc230b2568aa7ab7c56d35bb5653c0a6965a42" + integrity sha512-tFUVA/fiofNqOh6lZlymvQiQYPY+cZXZPR9mn9wN6/KS8uwx0zgH4Ij/jmFyRYr+x+DGZWEIeknS2BMi7FZJAQ== + "@types/winreg@^1.2.30": version "1.2.30" resolved "https://registry.yarnpkg.com/@types/winreg/-/winreg-1.2.30.tgz#91d6710e536d345b9c9b017c574cf6a8da64c518" From 382c7f5e9b6db1409212651b897668452bf7e6dd Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Tue, 12 Nov 2019 08:04:33 +0100 Subject: [PATCH 083/352] :lipstick: --- src/vs/base/browser/ui/list/listWidget.ts | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/src/vs/base/browser/ui/list/listWidget.ts b/src/vs/base/browser/ui/list/listWidget.ts index 48a5214a0d23f..65ff0de7f6e4e 100644 --- a/src/vs/base/browser/ui/list/listWidget.ts +++ b/src/vs/base/browser/ui/list/listWidget.ts @@ -1198,7 +1198,11 @@ export class List implements ISpliceable, IDisposable { this.view = new ListView(container, virtualDelegate, renderers, viewOptions); - this.updateAriaRole(); + if (typeof _options.ariaRole !== 'string') { + this.view.domNode.setAttribute('role', ListAriaRootRole.TREE); + } else { + this.view.domNode.setAttribute('role', _options.ariaRole); + } this.styleElement = DOM.createStyleSheet(this.view.domNode); @@ -1610,19 +1614,9 @@ export class List implements ISpliceable, IDisposable { this.view.domNode.removeAttribute('aria-activedescendant'); } - 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(); From 9b620f43def06692d006f63af991c59fb40bb459 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Tue, 12 Nov 2019 08:08:32 +0100 Subject: [PATCH 084/352] Enable `strictPropertyInitialization` (fix #78168) --- src/tsconfig.base.json | 1 + src/vs/base/browser/ui/tree/asyncDataTree.ts | 2 +- src/vs/workbench/api/common/extHostTypes.ts | 4 ++-- src/vs/workbench/browser/parts/views/viewsViewlet.ts | 2 +- 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/tsconfig.base.json b/src/tsconfig.base.json index 907c210b53038..44595cf5246db 100644 --- a/src/tsconfig.base.json +++ b/src/tsconfig.base.json @@ -10,6 +10,7 @@ "alwaysStrict": true, "strictBindCallApply": true, "strictNullChecks": true, + "strictPropertyInitialization": true, "forceConsistentCasingInFileNames": true, "baseUrl": ".", "paths": { diff --git a/src/vs/base/browser/ui/tree/asyncDataTree.ts b/src/vs/base/browser/ui/tree/asyncDataTree.ts index 50ab5ce9be3c3..49cf32517511c 100644 --- a/src/vs/base/browser/ui/tree/asyncDataTree.ts +++ b/src/vs/base/browser/ui/tree/asyncDataTree.ts @@ -1031,7 +1031,7 @@ export interface ICompressibleAsyncDataTreeOptionsUpdate extends IAsyncDataTreeO export class CompressibleAsyncDataTree extends AsyncDataTree { - protected readonly tree: CompressibleObjectTree, TFilterData>; + protected readonly tree!: CompressibleObjectTree, TFilterData>; protected readonly compressibleNodeMapper: CompressibleAsyncDataTreeNodeMapper = new WeakMapper(node => new CompressibleAsyncDataTreeNodeWrapper(node)); constructor( diff --git a/src/vs/workbench/api/common/extHostTypes.ts b/src/vs/workbench/api/common/extHostTypes.ts index 158fe11fda7e7..71bbf302eebdf 100644 --- a/src/vs/workbench/api/common/extHostTypes.ts +++ b/src/vs/workbench/api/common/extHostTypes.ts @@ -1143,8 +1143,8 @@ export class SelectionRange { export class CallHierarchyItem { - _sessionId: string; - _itemId: string; + _sessionId?: string; + _itemId?: string; kind: SymbolKind; name: string; diff --git a/src/vs/workbench/browser/parts/views/viewsViewlet.ts b/src/vs/workbench/browser/parts/views/viewsViewlet.ts index aa4e7f432ed58..cf9681d52e0a8 100644 --- a/src/vs/workbench/browser/parts/views/viewsViewlet.ts +++ b/src/vs/workbench/browser/parts/views/viewsViewlet.ts @@ -328,7 +328,7 @@ export abstract class ViewContainerViewlet extends PanelViewlet implements IView export abstract class FilterViewContainerViewlet extends ViewContainerViewlet { private constantViewDescriptors: Map = new Map(); private allViews: Map> = new Map(); - private filterValue: string; + private filterValue: string | undefined; protected onDidChangeFilterValue: Emitter = new Emitter(); From 90cc118a14370f21a1102eead7c35e410632051d Mon Sep 17 00:00:00 2001 From: Christof Marti Date: Tue, 12 Nov 2019 09:24:38 +0100 Subject: [PATCH 085/352] Update visibilities before computing layout (fixes #84125) --- src/vs/workbench/browser/parts/quickinput/quickInput.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/browser/parts/quickinput/quickInput.ts b/src/vs/workbench/browser/parts/quickinput/quickInput.ts index fec32d605bf36..3a81e8c7c3b3b 100644 --- a/src/vs/workbench/browser/parts/quickinput/quickInput.ts +++ b/src/vs/workbench/browser/parts/quickinput/quickInput.ts @@ -699,6 +699,7 @@ class QuickPick extends QuickInput implements IQuickPi } protected update() { + this.ui.setVisibilities(this.canSelectMany ? { title: !!this.title || !!this.step, checkAll: true, inputBox: true, visibleCount: true, count: true, ok: true, list: true, message: !!this.validationMessage } : { title: !!this.title || !!this.step, inputBox: true, visibleCount: true, list: true, message: !!this.validationMessage, customButton: this.customButton, ok: this.ok }); super.update(); if (!this.visible) { return; @@ -763,7 +764,6 @@ class QuickPick extends QuickInput implements IQuickPi this.ui.list.matchOnLabel = this.matchOnLabel; this.ui.setComboboxAccessibility(true); this.ui.inputBox.setAttribute('aria-label', QuickPick.INPUT_BOX_ARIA_LABEL); - this.ui.setVisibilities(this.canSelectMany ? { title: !!this.title || !!this.step, checkAll: true, inputBox: true, visibleCount: true, count: true, ok: true, list: true, message: !!this.validationMessage } : { title: !!this.title || !!this.step, inputBox: true, visibleCount: true, list: true, message: !!this.validationMessage, customButton: this.customButton, ok: this.ok }); } } @@ -857,6 +857,7 @@ class InputBox extends QuickInput implements IInputBox { } protected update() { + this.ui.setVisibilities({ title: !!this.title || !!this.step, inputBox: true, message: true }); super.update(); if (!this.visible) { return; @@ -882,7 +883,6 @@ class InputBox extends QuickInput implements IInputBox { this.ui.message.textContent = this.validationMessage; this.showMessageDecoration(Severity.Error); } - this.ui.setVisibilities({ title: !!this.title || !!this.step, inputBox: true, message: true }); } } From 623bae89051768933b9a14e93a2e9b496526adfb Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Tue, 12 Nov 2019 09:43:38 +0100 Subject: [PATCH 086/352] fix #84516 --- src/vs/vscode.d.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/vs/vscode.d.ts b/src/vs/vscode.d.ts index 7bc4e66bfef46..b1f5ccc6280ca 100644 --- a/src/vs/vscode.d.ts +++ b/src/vs/vscode.d.ts @@ -5986,6 +5986,9 @@ declare module 'vscode' { /** * Create a new directory (Note, that new files are created via `write`-calls). * + * *Note* that missing directories are created automatically, e.g this call has + * `mkdirp` semantics. + * * @param uri The uri of the new folder. */ createDirectory(uri: Uri): Thenable; From 039899cde9faf0ac7c1d9663c5d672b5ad389381 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=85=B7=E9=85=B7=E7=9A=84=E5=93=80=E6=AE=BF?= Date: Tue, 12 Nov 2019 16:56:31 +0800 Subject: [PATCH 087/352] Support utf-8 encoding guessing (#84504) * Update encoding.ts * fix warnings --- src/vs/base/node/encoding.ts | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/src/vs/base/node/encoding.ts b/src/vs/base/node/encoding.ts index d0501c2fd6d54..c450321317046 100644 --- a/src/vs/base/node/encoding.ts +++ b/src/vs/base/node/encoding.ts @@ -199,8 +199,6 @@ export function detectEncodingByBOMFromBuffer(buffer: Buffer | VSBuffer | null, return null; } -const IGNORE_ENCODINGS = ['ascii', 'utf-8', 'utf-16', 'utf-32']; - /** * Guesses the encoding from buffer. */ @@ -212,14 +210,6 @@ async function guessEncodingByBuffer(buffer: Buffer): Promise { return null; } - const enc = guessed.encoding.toLowerCase(); - - // Ignore encodings that cannot guess correctly - // (http://chardet.readthedocs.io/en/latest/supported-encodings.html) - if (0 <= IGNORE_ENCODINGS.indexOf(enc)) { - return null; - } - return toIconvLiteEncoding(guessed.encoding); } From 2977cfea261ee53face1c6c5f9cf0279d14c5d9c Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Tue, 12 Nov 2019 09:57:53 +0100 Subject: [PATCH 088/352] encoding - more tests --- build/lib/compilation.ts | 2 +- .../base/test/node/encoding/encoding.test.ts | 14 ++++++ .../test/node/encoding/fixtures/some_file.css | 42 ++++++++++++++++++ .../node/encoding/fixtures/some_utf16be.css | Bin 1408 -> 1424 bytes .../node/encoding/fixtures/some_utf16le.css | Bin 1408 -> 1424 bytes .../test/node/encoding/fixtures/some_utf8.css | 6 ++- 6 files changed, 61 insertions(+), 3 deletions(-) create mode 100644 src/vs/base/test/node/encoding/fixtures/some_file.css diff --git a/build/lib/compilation.ts b/build/lib/compilation.ts index 6f37821c7750b..578fae31a19c4 100644 --- a/build/lib/compilation.ts +++ b/build/lib/compilation.ts @@ -54,7 +54,7 @@ function createCompile(src: string, build: boolean, emitError?: boolean) { const input = es.through(); const output = input .pipe(utf8Filter) - .pipe(bom()) + .pipe(bom()) // this is required to preserve BOM in test files that loose it otherwise .pipe(utf8Filter.restore) .pipe(tsFilter) .pipe(util.loadSourcemaps()) diff --git a/src/vs/base/test/node/encoding/encoding.test.ts b/src/vs/base/test/node/encoding/encoding.test.ts index 77ad22264cf6e..d8730a52b366a 100644 --- a/src/vs/base/test/node/encoding/encoding.test.ts +++ b/src/vs/base/test/node/encoding/encoding.test.ts @@ -189,6 +189,20 @@ suite('Encoding', () => { assert.equal(mimes.seemsBinary, false); }); + test('autoGuessEncoding (UTF8)', async function () { + const file = getPathFromAmdModule(require, './fixtures/some_file.css'); + const buffer = await readExactlyByFile(file, 512 * 8); + const mimes = await encoding.detectEncodingFromBuffer(buffer, true); + assert.equal(mimes.encoding, 'utf8'); + }); + + test('autoGuessEncoding (ASCII)', async function () { + const file = getPathFromAmdModule(require, './fixtures/some_ansi.css'); + const buffer = await readExactlyByFile(file, 512 * 8); + const mimes = await encoding.detectEncodingFromBuffer(buffer, true); + assert.equal(mimes.encoding, 'ascii'); + }); + test('autoGuessEncoding (ShiftJIS)', async function () { const file = getPathFromAmdModule(require, './fixtures/some.shiftjis.txt'); const buffer = await readExactlyByFile(file, 512 * 8); diff --git a/src/vs/base/test/node/encoding/fixtures/some_file.css b/src/vs/base/test/node/encoding/fixtures/some_file.css new file mode 100644 index 0000000000000..e4e1350019f02 --- /dev/null +++ b/src/vs/base/test/node/encoding/fixtures/some_file.css @@ -0,0 +1,42 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +/*---------------------------------------------------------- +The base color for this template is #5c87b2. If you'd like +to use a different color start by replacing all instances of +#5c87b2 with your new color. + +öäüßßß +----------------------------------------------------------*/ +body +{ + background-color: #5c87b2; + font-size: .75em; + font-family: Segoe UI, Verdana, Helvetica, Sans-Serif; + margin: 8px; + padding: 0; + color: #696969; +} + +h1, h2, h3, h4, h5, h6 +{ + color: #000; + font-size: 40px; + margin: 0px; +} + +textarea +{ + font-family: Consolas +} + +#results +{ + margin-top: 2em; + margin-left: 2em; + color: black; + font-size: medium; +} + diff --git a/src/vs/base/test/node/encoding/fixtures/some_utf16be.css b/src/vs/base/test/node/encoding/fixtures/some_utf16be.css index 30c3b9d38ba3e73ef884db9b587be76fe28d751f..894438140007df4e2ed5e3e3fbce4f54e5bf5f02 100644 GIT binary patch delta 44 wcmZqRp1{3fJ)%xXjGLIa6&QFKxEQKI Date: Tue, 12 Nov 2019 10:04:35 +0100 Subject: [PATCH 089/352] Use outline (fixes #84062) --- src/vs/workbench/browser/parts/quickinput/quickInputList.ts | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/vs/workbench/browser/parts/quickinput/quickInputList.ts b/src/vs/workbench/browser/parts/quickinput/quickInputList.ts index f49a302fa4200..cb9791317b066 100644 --- a/src/vs/workbench/browser/parts/quickinput/quickInputList.ts +++ b/src/vs/workbench/browser/parts/quickinput/quickInputList.ts @@ -598,10 +598,7 @@ registerThemingParticipant((theme, collector) => { } const activeContrast = theme.getColor(activeContrastBorder); if (activeContrast) { - collector.addRule(`.quick-input-list .monaco-list .monaco-list-row.focused { border: 1px dotted ${activeContrast}; }`); - collector.addRule(`.quick-input-list .monaco-list .monaco-list-row { border: 1px solid transparent; }`); - collector.addRule(`.quick-input-list .monaco-list .quick-input-list-entry { padding: 0 5px; height: 18px; align-items: center; }`); - collector.addRule(`.quick-input-list .monaco-list .quick-input-list-entry-action-bar { margin-top: 0; }`); + collector.addRule(`.quick-input-list .monaco-list .monaco-list-row.focused { outline: 1px dotted ${activeContrast}; outline-offset: -1px; }`); } const pickerGroupBorderColor = theme.getColor(pickerGroupBorder); if (pickerGroupBorderColor) { From 33a084fa4490cdef6c98a6eab1e1ccc89eb46ac5 Mon Sep 17 00:00:00 2001 From: Alex Ross Date: Tue, 12 Nov 2019 10:08:32 +0100 Subject: [PATCH 090/352] Update c++ grammar Fixes #84410 --- extensions/cpp/cgmanifest.json | 4 +- extensions/cpp/syntaxes/c.tmLanguage.json | 4 +- .../cpp.embedded.macro.tmLanguage.json | 88 +++++++++---------- extensions/cpp/syntaxes/cpp.tmLanguage.json | 10 +-- 4 files changed, 53 insertions(+), 53 deletions(-) diff --git a/extensions/cpp/cgmanifest.json b/extensions/cpp/cgmanifest.json index 3dc984e58c2f0..4fba38d93adf1 100644 --- a/extensions/cpp/cgmanifest.json +++ b/extensions/cpp/cgmanifest.json @@ -6,11 +6,11 @@ "git": { "name": "jeff-hykin/cpp-textmate-grammar", "repositoryUrl": "https://github.com/jeff-hykin/cpp-textmate-grammar", - "commitHash": "d937b80a19706d518e5fe52357d7c50d34a26e60" + "commitHash": "fedd206d1b2803f31a278e9b5f098ce4bc76e532" } }, "license": "MIT", - "version": "1.14.11", + "version": "1.14.13", "description": "The files syntaxes/c.json and syntaxes/c++.json were derived from https://github.com/atom/language-c which was originally converted from the C TextMate bundle https://github.com/textmate/c.tmbundle." }, { diff --git a/extensions/cpp/syntaxes/c.tmLanguage.json b/extensions/cpp/syntaxes/c.tmLanguage.json index d8c4dca256bab..916371903fbe8 100644 --- a/extensions/cpp/syntaxes/c.tmLanguage.json +++ b/extensions/cpp/syntaxes/c.tmLanguage.json @@ -4,7 +4,7 @@ "If you want to provide a fix or improvement, please create a pull request against the original repository.", "Once accepted there, we are happy to receive an update request." ], - "version": "https://github.com/jeff-hykin/cpp-textmate-grammar/commit/d937b80a19706d518e5fe52357d7c50d34a26e60", + "version": "https://github.com/jeff-hykin/cpp-textmate-grammar/commit/fedd206d1b2803f31a278e9b5f098ce4bc76e532", "name": "C", "scopeName": "source.c", "patterns": [ @@ -1177,7 +1177,7 @@ ] }, "member_access": { - "match": "((?:[a-zA-Z_]\\w*|(?<=\\]|\\)))\\s*)(?:((?:\\.\\*|\\.))|((?:->\\*|->)))((?:[a-zA-Z_]\\w*\\s*(?:(?:(?:\\.\\*|\\.))|(?:(?:->\\*|->)))\\s*)*)\\s*(\\b(?!(?:atomic_uint_least64_t|atomic_uint_least16_t|atomic_uint_least32_t|atomic_uint_least8_t|atomic_int_least16_t|atomic_uint_fast64_t|atomic_uint_fast32_t|atomic_int_least64_t|atomic_int_least32_t|pthread_rwlockattr_t|atomic_uint_fast16_t|pthread_mutexattr_t|atomic_int_fast16_t|atomic_uint_fast8_t|atomic_int_fast64_t|atomic_int_least8_t|atomic_int_fast32_t|atomic_int_fast8_t|pthread_condattr_t|atomic_uintptr_t|atomic_ptrdiff_t|pthread_rwlock_t|atomic_uintmax_t|pthread_mutex_t|atomic_intmax_t|atomic_intptr_t|atomic_char32_t|atomic_char16_t|pthread_attr_t|atomic_wchar_t|uint_least64_t|uint_least32_t|uint_least16_t|pthread_cond_t|pthread_once_t|uint_fast64_t|uint_fast16_t|atomic_size_t|uint_least8_t|int_least64_t|int_least32_t|int_least16_t|pthread_key_t|atomic_ullong|atomic_ushort|uint_fast32_t|atomic_schar|atomic_short|uint_fast8_t|int_fast64_t|int_fast32_t|int_fast16_t|atomic_ulong|atomic_llong|int_least8_t|atomic_uchar|memory_order|suseconds_t|int_fast8_t|atomic_bool|atomic_char|atomic_uint|atomic_long|atomic_int|useconds_t|_Imaginary|uintptr_t|pthread_t|in_addr_t|blksize_t|in_port_t|uintmax_t|uintmax_t|blkcnt_t|uint16_t|unsigned|_Complex|uint32_t|intptr_t|intmax_t|intmax_t|uint64_t|u_quad_t|int64_t|int32_t|ssize_t|caddr_t|clock_t|uint8_t|u_short|swblk_t|segsz_t|int16_t|fixpt_t|daddr_t|nlink_t|qaddr_t|size_t|time_t|mode_t|signed|quad_t|ushort|u_long|u_char|double|int8_t|ino_t|uid_t|pid_t|_Bool|float|dev_t|div_t|short|gid_t|off_t|u_int|key_t|id_t|uint|long|void|char|bool|id_t|int)\\b)[a-zA-Z_]\\w*\\b(?!\\())", + "match": "((?:[a-zA-Z_]\\w*|(?<=\\]|\\)))\\s*)(?:((?:\\.\\*|\\.))|((?:->\\*|->)))((?:[a-zA-Z_]\\w*\\s*(?:(?:(?:\\.\\*|\\.))|(?:(?:->\\*|->)))\\s*)*)\\s*(\\b(?!(?:atomic_uint_least64_t|atomic_uint_least16_t|atomic_uint_least32_t|atomic_uint_least8_t|atomic_int_least16_t|atomic_uint_fast64_t|atomic_uint_fast32_t|atomic_int_least64_t|atomic_int_least32_t|pthread_rwlockattr_t|atomic_uint_fast16_t|pthread_mutexattr_t|atomic_int_fast16_t|atomic_uint_fast8_t|atomic_int_fast64_t|atomic_int_least8_t|atomic_int_fast32_t|atomic_int_fast8_t|pthread_condattr_t|atomic_uintptr_t|atomic_ptrdiff_t|pthread_rwlock_t|atomic_uintmax_t|pthread_mutex_t|atomic_intmax_t|atomic_intptr_t|atomic_char32_t|atomic_char16_t|pthread_attr_t|atomic_wchar_t|uint_least64_t|uint_least32_t|uint_least16_t|pthread_cond_t|pthread_once_t|uint_fast64_t|uint_fast16_t|atomic_size_t|uint_least8_t|int_least64_t|int_least32_t|int_least16_t|pthread_key_t|atomic_ullong|atomic_ushort|uint_fast32_t|atomic_schar|atomic_short|uint_fast8_t|int_fast64_t|int_fast32_t|int_fast16_t|atomic_ulong|atomic_llong|int_least8_t|atomic_uchar|memory_order|suseconds_t|int_fast8_t|atomic_bool|atomic_char|atomic_uint|atomic_long|atomic_int|useconds_t|_Imaginary|blksize_t|pthread_t|in_addr_t|uintptr_t|in_port_t|uintmax_t|uintmax_t|blkcnt_t|uint16_t|unsigned|_Complex|uint32_t|intptr_t|intmax_t|intmax_t|uint64_t|u_quad_t|int64_t|int32_t|ssize_t|caddr_t|clock_t|uint8_t|u_short|swblk_t|segsz_t|int16_t|fixpt_t|daddr_t|nlink_t|qaddr_t|size_t|time_t|mode_t|signed|quad_t|ushort|u_long|u_char|double|int8_t|ino_t|uid_t|pid_t|_Bool|float|dev_t|div_t|short|gid_t|off_t|u_int|key_t|id_t|uint|long|void|char|bool|id_t|int)\\b)[a-zA-Z_]\\w*\\b(?!\\())", "captures": { "1": { "name": "variable.other.object.access.c" diff --git a/extensions/cpp/syntaxes/cpp.embedded.macro.tmLanguage.json b/extensions/cpp/syntaxes/cpp.embedded.macro.tmLanguage.json index cd2400f2c2562..3f19e1339cd1e 100644 --- a/extensions/cpp/syntaxes/cpp.embedded.macro.tmLanguage.json +++ b/extensions/cpp/syntaxes/cpp.embedded.macro.tmLanguage.json @@ -4,7 +4,7 @@ "If you want to provide a fix or improvement, please create a pull request against the original repository.", "Once accepted there, we are happy to receive an update request." ], - "version": "https://github.com/jeff-hykin/cpp-textmate-grammar/commit/d937b80a19706d518e5fe52357d7c50d34a26e60", + "version": "https://github.com/jeff-hykin/cpp-textmate-grammar/commit/fedd206d1b2803f31a278e9b5f098ce4bc76e532", "name": "C++", "scopeName": "source.cpp.embedded.macro", "patterns": [ @@ -966,7 +966,7 @@ ] }, "class_declare": { - "match": "(class)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))?(?:(?:\\&|\\*)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(?:\\&|\\*))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))\\b(?!override\\W|override\\$|final\\W|final\\$)((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?=\\S)(?![:{])", + "match": "((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))?(?:(?:\\&|\\*)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(?:\\&|\\*))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))\\b(?!override\\W|override\\$|final\\W|final\\$)((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?=\\S)(?![:{])", "captures": { "1": { "name": "storage.type.class.declare.cpp" @@ -1733,7 +1733,7 @@ }, "constructor_root": { "name": "meta.function.definition.special.constructor.cpp", - "begin": "(\\s*+((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?:__cdecl|__clrcall|__stdcall|__fastcall|__thiscall|__vectorcall)?)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|new|try|for|asm|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<14>?)+)>)\\s*)?::)*)(((?>(?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))::((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))\\16((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?=\\()))", + "begin": "(\\s*+((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?:__cdecl|__clrcall|__stdcall|__fastcall|__thiscall|__vectorcall)?)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|asm|try|for|new|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<14>?)+)>)\\s*)?::)*)(((?>(?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))::((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))\\16((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?=\\()))", "beginCaptures": { "1": { "name": "meta.head.function.definition.special.constructor.cpp" @@ -2094,7 +2094,7 @@ ] }, "control_flow_keywords": { - "match": "((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(?:(?:unsigned|signed|short|long)|(?:struct|class|union|enum))((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(((::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|new|try|for|asm|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<27>?)+)>)\\s*)?::)*\\s*+)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\s*+(((?(?:(?>[^<>]*)\\g<27>?)+)>)\\s*)?(::))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?!(?:transaction_safe_dynamic|__has_cpp_attribute|transaction_safe|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|constexpr|consteval|protected|constexpr|co_return|namespace|constexpr|noexcept|typename|decltype|template|operator|noexcept|co_yield|co_await|continue|volatile|register|restrict|explicit|override|volatile|reflexpr|noexcept|requires|default|typedef|nullptr|alignof|mutable|concept|virtual|defined|__asm__|include|_Pragma|mutable|warning|private|alignas|module|switch|not_eq|bitand|and_eq|ifndef|return|sizeof|xor_eq|export|static|delete|public|define|extern|inline|import|pragma|friend|typeid|const|compl|bitor|throw|or_eq|while|catch|break|false|final|const|endif|ifdef|undef|error|using|audit|axiom|line|else|elif|true|NULL|case|goto|else|this|new|asm|not|and|xor|try|for|if|do|or|if)\\b)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\b(((?(?:(?>[^<>]*)\\g<27>?)+)>)\\s*)?(?![\\w<:.]))((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(\\{)", + "begin": "(\\s*+((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\(\\(.*?\\)\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(?:(?:unsigned|signed|short|long)|(?:struct|class|union|enum))((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(((::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|asm|try|for|new|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<27>?)+)>)\\s*)?::)*\\s*+)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\s*+(((?(?:(?>[^<>]*)\\g<27>?)+)>)\\s*)?(::))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?!(?:transaction_safe_dynamic|__has_cpp_attribute|transaction_safe|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|constexpr|consteval|protected|constexpr|co_return|namespace|constexpr|noexcept|typename|decltype|template|operator|noexcept|co_yield|co_await|continue|volatile|register|restrict|explicit|override|volatile|reflexpr|noexcept|requires|default|typedef|nullptr|alignof|mutable|concept|virtual|defined|__asm__|include|_Pragma|mutable|warning|private|alignas|module|switch|not_eq|bitand|and_eq|ifndef|return|sizeof|xor_eq|export|static|delete|public|define|extern|inline|import|pragma|friend|typeid|const|compl|bitor|throw|or_eq|while|catch|break|false|final|const|endif|ifdef|undef|error|using|audit|axiom|line|else|elif|true|NULL|case|goto|else|this|new|asm|not|and|xor|try|for|if|do|or|if)\\b)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\b(((?(?:(?>[^<>]*)\\g<27>?)+)>)\\s*)?(?![\\w<:.]))((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(\\{)", "beginCaptures": { "1": { "name": "meta.qualified_type.cpp", @@ -2773,7 +2773,7 @@ }, "destructor_root": { "name": "meta.function.definition.special.member.destructor.cpp", - "begin": "(((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?:__cdecl|__clrcall|__stdcall|__fastcall|__thiscall|__vectorcall)?)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|new|try|for|asm|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<14>?)+)>)\\s*)?::)*)(((?>(?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))::((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))~\\16((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?=\\()))", + "begin": "(((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?:__cdecl|__clrcall|__stdcall|__fastcall|__thiscall|__vectorcall)?)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|asm|try|for|new|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<14>?)+)>)\\s*)?::)*)(((?>(?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))::((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))~\\16((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?=\\()))", "beginCaptures": { "1": { "name": "meta.head.function.definition.special.member.destructor.cpp" @@ -3179,7 +3179,7 @@ }, "enum_block": { "name": "meta.block.enum.cpp", - "begin": "(((?(?:(?>[^<>]*)\\g<15>?)+)>)\\s*)?::)*\\s*+)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\s*+(((?(?:(?>[^<>]*)\\g<15>?)+)>)\\s*)?(::))?\\s*((?(?:(?>[^<>]*)\\g<15>?)+)>)\\s*)?::)*\\s*+)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\s*+(((?(?:(?>[^<>]*)\\g<15>?)+)>)\\s*)?(::))?\\s*((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))?(?:(?:\\&|\\*)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(?:\\&|\\*))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))\\b(?!override\\W|override\\$|final\\W|final\\$)((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?=\\S)(?![:{])", + "match": "((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))?(?:(?:\\&|\\*)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(?:\\&|\\*))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))\\b(?!override\\W|override\\$|final\\W|final\\$)((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?=\\S)(?![:{])", "captures": { "1": { "name": "storage.type.enum.declare.cpp" @@ -3859,7 +3859,7 @@ ] }, "function_call": { - "begin": "((::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|new|try|for|asm|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<12>?)+)>)\\s*)?::)*\\s*+)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\b(?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(((?(?:(?>[^<>]*)\\g<12>?)+)>)\\s*)?(\\()", + "begin": "((::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|asm|try|for|new|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<12>?)+)>)\\s*)?::)*\\s*+)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\b(?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(((?(?:(?>[^<>]*)\\g<12>?)+)>)\\s*)?(\\()", "beginCaptures": { "1": { "patterns": [ @@ -3933,7 +3933,7 @@ }, "function_definition": { "name": "meta.function.definition.cpp", - "begin": "((?:(?:^|\\G|(?<=;|\\}))|(?<=>))((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))?((?:((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*)(\\s*+((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\(\\(.*?\\)\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(?:(?:unsigned|signed|short|long)|(?:struct|class|union|enum))((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(((::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|new|try|for|asm|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<70>?)+)>)\\s*)?::)*\\s*+)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\s*+(((?(?:(?>[^<>]*)\\g<70>?)+)>)\\s*)?(::))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?!(?:transaction_safe_dynamic|__has_cpp_attribute|transaction_safe|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|constexpr|consteval|protected|constexpr|co_return|namespace|constexpr|noexcept|typename|decltype|template|operator|noexcept|co_yield|co_await|continue|volatile|register|restrict|explicit|override|volatile|reflexpr|noexcept|requires|default|typedef|nullptr|alignof|mutable|concept|virtual|defined|__asm__|include|_Pragma|mutable|warning|private|alignas|module|switch|not_eq|bitand|and_eq|ifndef|return|sizeof|xor_eq|export|static|delete|public|define|extern|inline|import|pragma|friend|typeid|const|compl|bitor|throw|or_eq|while|catch|break|false|final|const|endif|ifdef|undef|error|using|audit|axiom|line|else|elif|true|NULL|case|goto|else|this|new|asm|not|and|xor|try|for|if|do|or|if)\\b)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\b(((?(?:(?>[^<>]*)\\g<70>?)+)>)\\s*)?(?![\\w<:.]))(((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))?(?:(?:\\&|\\*)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(?:\\&|\\*))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?:__cdecl|__clrcall|__stdcall|__fastcall|__thiscall|__vectorcall)?)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|new|try|for|asm|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<70>?)+)>)\\s*)?::)*\\s*+)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\b(?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?=\\())", + "begin": "((?:(?:^|\\G|(?<=;|\\}))|(?<=>))((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))?((?:((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*)(\\s*+((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\(\\(.*?\\)\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(?:(?:unsigned|signed|short|long)|(?:struct|class|union|enum))((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(((::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|asm|try|for|new|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<70>?)+)>)\\s*)?::)*\\s*+)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\s*+(((?(?:(?>[^<>]*)\\g<70>?)+)>)\\s*)?(::))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?!(?:transaction_safe_dynamic|__has_cpp_attribute|transaction_safe|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|constexpr|consteval|protected|constexpr|co_return|namespace|constexpr|noexcept|typename|decltype|template|operator|noexcept|co_yield|co_await|continue|volatile|register|restrict|explicit|override|volatile|reflexpr|noexcept|requires|default|typedef|nullptr|alignof|mutable|concept|virtual|defined|__asm__|include|_Pragma|mutable|warning|private|alignas|module|switch|not_eq|bitand|and_eq|ifndef|return|sizeof|xor_eq|export|static|delete|public|define|extern|inline|import|pragma|friend|typeid|const|compl|bitor|throw|or_eq|while|catch|break|false|final|const|endif|ifdef|undef|error|using|audit|axiom|line|else|elif|true|NULL|case|goto|else|this|new|asm|not|and|xor|try|for|if|do|or|if)\\b)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\b(((?(?:(?>[^<>]*)\\g<70>?)+)>)\\s*)?(?![\\w<:.]))(((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))?(?:(?:\\&|\\*)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(?:\\&|\\*))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?:__cdecl|__clrcall|__stdcall|__fastcall|__thiscall|__vectorcall)?)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|asm|try|for|new|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<70>?)+)>)\\s*)?::)*\\s*+)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\b(?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?=\\())", "beginCaptures": { "1": { "name": "meta.head.function.definition.cpp" @@ -4529,7 +4529,7 @@ ] }, "function_pointer": { - "begin": "(\\s*+((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\(\\(.*?\\)\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(?:(?:unsigned|signed|short|long)|(?:struct|class|union|enum))((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(((::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|new|try|for|asm|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<27>?)+)>)\\s*)?::)*\\s*+)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\s*+(((?(?:(?>[^<>]*)\\g<27>?)+)>)\\s*)?(::))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?!(?:transaction_safe_dynamic|__has_cpp_attribute|transaction_safe|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|constexpr|consteval|protected|constexpr|co_return|namespace|constexpr|noexcept|typename|decltype|template|operator|noexcept|co_yield|co_await|continue|volatile|register|restrict|explicit|override|volatile|reflexpr|noexcept|requires|default|typedef|nullptr|alignof|mutable|concept|virtual|defined|__asm__|include|_Pragma|mutable|warning|private|alignas|module|switch|not_eq|bitand|and_eq|ifndef|return|sizeof|xor_eq|export|static|delete|public|define|extern|inline|import|pragma|friend|typeid|const|compl|bitor|throw|or_eq|while|catch|break|false|final|const|endif|ifdef|undef|error|using|audit|axiom|line|else|elif|true|NULL|case|goto|else|this|new|asm|not|and|xor|try|for|if|do|or|if)\\b)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\b(((?(?:(?>[^<>]*)\\g<27>?)+)>)\\s*)?(?![\\w<:.]))(((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))?(?:(?:\\&|\\*)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(?:\\&|\\*))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(\\()(\\*)\\s*((?:(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)?)\\s*(?:(\\[)(\\w*)(\\])\\s*)*(\\))\\s*(\\()", + "begin": "(\\s*+((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\(\\(.*?\\)\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(?:(?:unsigned|signed|short|long)|(?:struct|class|union|enum))((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(((::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|asm|try|for|new|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<27>?)+)>)\\s*)?::)*\\s*+)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\s*+(((?(?:(?>[^<>]*)\\g<27>?)+)>)\\s*)?(::))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?!(?:transaction_safe_dynamic|__has_cpp_attribute|transaction_safe|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|constexpr|consteval|protected|constexpr|co_return|namespace|constexpr|noexcept|typename|decltype|template|operator|noexcept|co_yield|co_await|continue|volatile|register|restrict|explicit|override|volatile|reflexpr|noexcept|requires|default|typedef|nullptr|alignof|mutable|concept|virtual|defined|__asm__|include|_Pragma|mutable|warning|private|alignas|module|switch|not_eq|bitand|and_eq|ifndef|return|sizeof|xor_eq|export|static|delete|public|define|extern|inline|import|pragma|friend|typeid|const|compl|bitor|throw|or_eq|while|catch|break|false|final|const|endif|ifdef|undef|error|using|audit|axiom|line|else|elif|true|NULL|case|goto|else|this|new|asm|not|and|xor|try|for|if|do|or|if)\\b)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\b(((?(?:(?>[^<>]*)\\g<27>?)+)>)\\s*)?(?![\\w<:.]))(((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))?(?:(?:\\&|\\*)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(?:\\&|\\*))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(\\()(\\*)\\s*((?:(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)?)\\s*(?:(\\[)(\\w*)(\\])\\s*)*(\\))\\s*(\\()", "beginCaptures": { "1": { "name": "meta.qualified_type.cpp", @@ -4881,7 +4881,7 @@ ] }, "function_pointer_parameter": { - "begin": "(\\s*+((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\(\\(.*?\\)\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(?:(?:unsigned|signed|short|long)|(?:struct|class|union|enum))((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(((::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|new|try|for|asm|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<27>?)+)>)\\s*)?::)*\\s*+)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\s*+(((?(?:(?>[^<>]*)\\g<27>?)+)>)\\s*)?(::))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?!(?:transaction_safe_dynamic|__has_cpp_attribute|transaction_safe|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|constexpr|consteval|protected|constexpr|co_return|namespace|constexpr|noexcept|typename|decltype|template|operator|noexcept|co_yield|co_await|continue|volatile|register|restrict|explicit|override|volatile|reflexpr|noexcept|requires|default|typedef|nullptr|alignof|mutable|concept|virtual|defined|__asm__|include|_Pragma|mutable|warning|private|alignas|module|switch|not_eq|bitand|and_eq|ifndef|return|sizeof|xor_eq|export|static|delete|public|define|extern|inline|import|pragma|friend|typeid|const|compl|bitor|throw|or_eq|while|catch|break|false|final|const|endif|ifdef|undef|error|using|audit|axiom|line|else|elif|true|NULL|case|goto|else|this|new|asm|not|and|xor|try|for|if|do|or|if)\\b)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\b(((?(?:(?>[^<>]*)\\g<27>?)+)>)\\s*)?(?![\\w<:.]))(((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))?(?:(?:\\&|\\*)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(?:\\&|\\*))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(\\()(\\*)\\s*((?:(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)?)\\s*(?:(\\[)(\\w*)(\\])\\s*)*(\\))\\s*(\\()", + "begin": "(\\s*+((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\(\\(.*?\\)\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(?:(?:unsigned|signed|short|long)|(?:struct|class|union|enum))((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(((::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|asm|try|for|new|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<27>?)+)>)\\s*)?::)*\\s*+)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\s*+(((?(?:(?>[^<>]*)\\g<27>?)+)>)\\s*)?(::))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?!(?:transaction_safe_dynamic|__has_cpp_attribute|transaction_safe|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|constexpr|consteval|protected|constexpr|co_return|namespace|constexpr|noexcept|typename|decltype|template|operator|noexcept|co_yield|co_await|continue|volatile|register|restrict|explicit|override|volatile|reflexpr|noexcept|requires|default|typedef|nullptr|alignof|mutable|concept|virtual|defined|__asm__|include|_Pragma|mutable|warning|private|alignas|module|switch|not_eq|bitand|and_eq|ifndef|return|sizeof|xor_eq|export|static|delete|public|define|extern|inline|import|pragma|friend|typeid|const|compl|bitor|throw|or_eq|while|catch|break|false|final|const|endif|ifdef|undef|error|using|audit|axiom|line|else|elif|true|NULL|case|goto|else|this|new|asm|not|and|xor|try|for|if|do|or|if)\\b)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\b(((?(?:(?>[^<>]*)\\g<27>?)+)>)\\s*)?(?![\\w<:.]))(((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))?(?:(?:\\&|\\*)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(?:\\&|\\*))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(\\()(\\*)\\s*((?:(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)?)\\s*(?:(\\[)(\\w*)(\\])\\s*)*(\\))\\s*(\\()", "beginCaptures": { "1": { "name": "meta.qualified_type.cpp", @@ -5535,7 +5535,7 @@ "name": "storage.type.modifier.virtual.cpp" }, { - "match": "(?<=protected|virtual|private|public|,|:)\\s*(?!(?:(?:protected|private|public)|virtual))(\\s*+((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\(\\(.*?\\)\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(?:(?:unsigned|signed|short|long)|(?:struct|class|union|enum))((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(((::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|new|try|for|asm|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<27>?)+)>)\\s*)?::)*\\s*+)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\s*+(((?(?:(?>[^<>]*)\\g<27>?)+)>)\\s*)?(::))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?!(?:transaction_safe_dynamic|__has_cpp_attribute|transaction_safe|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|constexpr|consteval|protected|constexpr|co_return|namespace|constexpr|noexcept|typename|decltype|template|operator|noexcept|co_yield|co_await|continue|volatile|register|restrict|explicit|override|volatile|reflexpr|noexcept|requires|default|typedef|nullptr|alignof|mutable|concept|virtual|defined|__asm__|include|_Pragma|mutable|warning|private|alignas|module|switch|not_eq|bitand|and_eq|ifndef|return|sizeof|xor_eq|export|static|delete|public|define|extern|inline|import|pragma|friend|typeid|const|compl|bitor|throw|or_eq|while|catch|break|false|final|const|endif|ifdef|undef|error|using|audit|axiom|line|else|elif|true|NULL|case|goto|else|this|new|asm|not|and|xor|try|for|if|do|or|if)\\b)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\b(((?(?:(?>[^<>]*)\\g<27>?)+)>)\\s*)?(?![\\w<:.]))", + "match": "(?<=protected|virtual|private|public|,|:)\\s*(?!(?:(?:protected|private|public)|virtual))(\\s*+((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\(\\(.*?\\)\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(?:(?:unsigned|signed|short|long)|(?:struct|class|union|enum))((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(((::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|asm|try|for|new|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<27>?)+)>)\\s*)?::)*\\s*+)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\s*+(((?(?:(?>[^<>]*)\\g<27>?)+)>)\\s*)?(::))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?!(?:transaction_safe_dynamic|__has_cpp_attribute|transaction_safe|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|constexpr|consteval|protected|constexpr|co_return|namespace|constexpr|noexcept|typename|decltype|template|operator|noexcept|co_yield|co_await|continue|volatile|register|restrict|explicit|override|volatile|reflexpr|noexcept|requires|default|typedef|nullptr|alignof|mutable|concept|virtual|defined|__asm__|include|_Pragma|mutable|warning|private|alignas|module|switch|not_eq|bitand|and_eq|ifndef|return|sizeof|xor_eq|export|static|delete|public|define|extern|inline|import|pragma|friend|typeid|const|compl|bitor|throw|or_eq|while|catch|break|false|final|const|endif|ifdef|undef|error|using|audit|axiom|line|else|elif|true|NULL|case|goto|else|this|new|asm|not|and|xor|try|for|if|do|or|if)\\b)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\b(((?(?:(?>[^<>]*)\\g<27>?)+)>)\\s*)?(?![\\w<:.]))", "captures": { "1": { "name": "meta.qualified_type.cpp", @@ -6668,7 +6668,7 @@ ] }, "namespace_alias": { - "match": "(?(?:(?>[^<>]*)\\g<9>?)+)>)\\s*)?::)*\\s*+)\\s*((?(?:(?>[^<>]*)\\g<9>?)+)>)\\s*)?::)*\\s*+)\\s*((?(?:(?>[^<>]*)\\g<5>?)+)>)\\s*)?::)*\\s*+)\\s*((?(?:(?>[^<>]*)\\g<5>?)+)>)\\s*)?::)*\\s*+)\\s*((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(?:(?:unsigned|signed|short|long)|(?:struct|class|union|enum))((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(((::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|new|try|for|asm|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<67>?)+)>)\\s*)?::)*\\s*+)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\s*+(((?(?:(?>[^<>]*)\\g<67>?)+)>)\\s*)?(::))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?!(?:transaction_safe_dynamic|__has_cpp_attribute|transaction_safe|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|constexpr|consteval|protected|constexpr|co_return|namespace|constexpr|noexcept|typename|decltype|template|operator|noexcept|co_yield|co_await|continue|volatile|register|restrict|explicit|override|volatile|reflexpr|noexcept|requires|default|typedef|nullptr|alignof|mutable|concept|virtual|defined|__asm__|include|_Pragma|mutable|warning|private|alignas|module|switch|not_eq|bitand|and_eq|ifndef|return|sizeof|xor_eq|export|static|delete|public|define|extern|inline|import|pragma|friend|typeid|const|compl|bitor|throw|or_eq|while|catch|break|false|final|const|endif|ifdef|undef|error|using|audit|axiom|line|else|elif|true|NULL|case|goto|else|this|new|asm|not|and|xor|try|for|if|do|or|if)\\b)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\b(((?(?:(?>[^<>]*)\\g<67>?)+)>)\\s*)?(?![\\w<:.]))(((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))?(?:(?:\\&|\\*)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(?:\\&|\\*))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?:__cdecl|__clrcall|__stdcall|__fastcall|__thiscall|__vectorcall)?)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|new|try|for|asm|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<67>?)+)>)\\s*)?::)*)(operator)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|new|try|for|asm|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<67>?)+)>)\\s*)?::)*)(?:(?:((?:delete\\[\\]|delete|new\\[\\]|<=>|<<=|new|>>=|\\->\\*|\\/=|%=|&=|>=|\\|=|\\+\\+|\\-\\-|\\(\\)|\\[\\]|\\->|\\+\\+|<<|>>|\\-\\-|<=|\\^=|==|!=|&&|\\|\\||\\+=|\\-=|\\*=|,|\\+|\\-|!|~|\\*|&|\\*|\\/|%|\\+|\\-|<|>|&|\\^|\\||=))|((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))?(?:(?:\\&|\\*)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(?:\\&|\\*))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?:\\[\\])?)))|(\"\")((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?=\\<|\\())", + "begin": "((?:(\\s*+((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\(\\(.*?\\)\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(?:(?:unsigned|signed|short|long)|(?:struct|class|union|enum))((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(((::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|asm|try|for|new|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<67>?)+)>)\\s*)?::)*\\s*+)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\s*+(((?(?:(?>[^<>]*)\\g<67>?)+)>)\\s*)?(::))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?!(?:transaction_safe_dynamic|__has_cpp_attribute|transaction_safe|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|constexpr|consteval|protected|constexpr|co_return|namespace|constexpr|noexcept|typename|decltype|template|operator|noexcept|co_yield|co_await|continue|volatile|register|restrict|explicit|override|volatile|reflexpr|noexcept|requires|default|typedef|nullptr|alignof|mutable|concept|virtual|defined|__asm__|include|_Pragma|mutable|warning|private|alignas|module|switch|not_eq|bitand|and_eq|ifndef|return|sizeof|xor_eq|export|static|delete|public|define|extern|inline|import|pragma|friend|typeid|const|compl|bitor|throw|or_eq|while|catch|break|false|final|const|endif|ifdef|undef|error|using|audit|axiom|line|else|elif|true|NULL|case|goto|else|this|new|asm|not|and|xor|try|for|if|do|or|if)\\b)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\b(((?(?:(?>[^<>]*)\\g<67>?)+)>)\\s*)?(?![\\w<:.]))(((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))?(?:(?:\\&|\\*)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(?:\\&|\\*))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?:__cdecl|__clrcall|__stdcall|__fastcall|__thiscall|__vectorcall)?)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|asm|try|for|new|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<67>?)+)>)\\s*)?::)*)(operator)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|asm|try|for|new|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<67>?)+)>)\\s*)?::)*)(?:(?:((?:delete\\[\\]|delete|new\\[\\]|<=>|<<=|new|>>=|\\->\\*|\\/=|%=|&=|>=|\\|=|\\+\\+|\\-\\-|\\(\\)|\\[\\]|\\->|\\+\\+|<<|>>|\\-\\-|<=|\\^=|==|!=|&&|\\|\\||\\+=|\\-=|\\*=|,|\\+|\\-|!|~|\\*|&|\\*|\\/|%|\\+|\\-|<|>|&|\\^|\\||=))|((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))?(?:(?:\\&|\\*)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(?:\\&|\\*))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?:\\[\\])?)))|(\"\")((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?=\\<|\\())", "beginCaptures": { "1": { "name": "meta.head.function.definition.special.operator-overload.cpp" @@ -10607,7 +10607,7 @@ } }, "qualified_type": { - "match": "\\s*+((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\(\\(.*?\\)\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(?:(?:unsigned|signed|short|long)|(?:struct|class|union|enum))((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(((::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|new|try|for|asm|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<26>?)+)>)\\s*)?::)*\\s*+)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\s*+(((?(?:(?>[^<>]*)\\g<26>?)+)>)\\s*)?(::))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?!(?:transaction_safe_dynamic|__has_cpp_attribute|transaction_safe|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|constexpr|consteval|protected|constexpr|co_return|namespace|constexpr|noexcept|typename|decltype|template|operator|noexcept|co_yield|co_await|continue|volatile|register|restrict|explicit|override|volatile|reflexpr|noexcept|requires|default|typedef|nullptr|alignof|mutable|concept|virtual|defined|__asm__|include|_Pragma|mutable|warning|private|alignas|module|switch|not_eq|bitand|and_eq|ifndef|return|sizeof|xor_eq|export|static|delete|public|define|extern|inline|import|pragma|friend|typeid|const|compl|bitor|throw|or_eq|while|catch|break|false|final|const|endif|ifdef|undef|error|using|audit|axiom|line|else|elif|true|NULL|case|goto|else|this|new|asm|not|and|xor|try|for|if|do|or|if)\\b)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\b(((?(?:(?>[^<>]*)\\g<26>?)+)>)\\s*)?(?![\\w<:.])", + "match": "\\s*+((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\(\\(.*?\\)\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(?:(?:unsigned|signed|short|long)|(?:struct|class|union|enum))((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(((::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|asm|try|for|new|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<26>?)+)>)\\s*)?::)*\\s*+)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\s*+(((?(?:(?>[^<>]*)\\g<26>?)+)>)\\s*)?(::))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?!(?:transaction_safe_dynamic|__has_cpp_attribute|transaction_safe|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|constexpr|consteval|protected|constexpr|co_return|namespace|constexpr|noexcept|typename|decltype|template|operator|noexcept|co_yield|co_await|continue|volatile|register|restrict|explicit|override|volatile|reflexpr|noexcept|requires|default|typedef|nullptr|alignof|mutable|concept|virtual|defined|__asm__|include|_Pragma|mutable|warning|private|alignas|module|switch|not_eq|bitand|and_eq|ifndef|return|sizeof|xor_eq|export|static|delete|public|define|extern|inline|import|pragma|friend|typeid|const|compl|bitor|throw|or_eq|while|catch|break|false|final|const|endif|ifdef|undef|error|using|audit|axiom|line|else|elif|true|NULL|case|goto|else|this|new|asm|not|and|xor|try|for|if|do|or|if)\\b)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\b(((?(?:(?>[^<>]*)\\g<26>?)+)>)\\s*)?(?![\\w<:.])", "captures": { "0": { "name": "meta.qualified_type.cpp", @@ -10810,7 +10810,7 @@ } }, "scope_resolution": { - "match": "(::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|new|try|for|asm|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<4>?)+)>)\\s*)?::)*\\s*+", + "match": "(::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|asm|try|for|new|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<4>?)+)>)\\s*)?::)*\\s*+", "captures": { "0": { "patterns": [ @@ -10833,7 +10833,7 @@ } }, "scope_resolution_function_call": { - "match": "(::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|new|try|for|asm|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<4>?)+)>)\\s*)?::)*\\s*+", + "match": "(::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|asm|try|for|new|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<4>?)+)>)\\s*)?::)*\\s*+", "captures": { "0": { "patterns": [ @@ -10856,7 +10856,7 @@ } }, "scope_resolution_function_call_inner_generated": { - "match": "((::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|new|try|for|asm|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<8>?)+)>)\\s*)?::)*\\s*+)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\s*+(((?(?:(?>[^<>]*)\\g<8>?)+)>)\\s*)?(::)", + "match": "((::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|asm|try|for|new|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<8>?)+)>)\\s*)?::)*\\s*+)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\s*+(((?(?:(?>[^<>]*)\\g<8>?)+)>)\\s*)?(::)", "captures": { "1": { "patterns": [ @@ -10893,7 +10893,7 @@ } }, "scope_resolution_function_definition": { - "match": "(::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|new|try|for|asm|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<4>?)+)>)\\s*)?::)*\\s*+", + "match": "(::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|asm|try|for|new|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<4>?)+)>)\\s*)?::)*\\s*+", "captures": { "0": { "patterns": [ @@ -10916,7 +10916,7 @@ } }, "scope_resolution_function_definition_inner_generated": { - "match": "((::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|new|try|for|asm|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<8>?)+)>)\\s*)?::)*\\s*+)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\s*+(((?(?:(?>[^<>]*)\\g<8>?)+)>)\\s*)?(::)", + "match": "((::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|asm|try|for|new|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<8>?)+)>)\\s*)?::)*\\s*+)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\s*+(((?(?:(?>[^<>]*)\\g<8>?)+)>)\\s*)?(::)", "captures": { "1": { "patterns": [ @@ -10953,7 +10953,7 @@ } }, "scope_resolution_function_definition_operator_overload": { - "match": "(::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|new|try|for|asm|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<4>?)+)>)\\s*)?::)*\\s*+", + "match": "(::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|asm|try|for|new|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<4>?)+)>)\\s*)?::)*\\s*+", "captures": { "0": { "patterns": [ @@ -10976,7 +10976,7 @@ } }, "scope_resolution_function_definition_operator_overload_inner_generated": { - "match": "((::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|new|try|for|asm|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<8>?)+)>)\\s*)?::)*\\s*+)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\s*+(((?(?:(?>[^<>]*)\\g<8>?)+)>)\\s*)?(::)", + "match": "((::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|asm|try|for|new|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<8>?)+)>)\\s*)?::)*\\s*+)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\s*+(((?(?:(?>[^<>]*)\\g<8>?)+)>)\\s*)?(::)", "captures": { "1": { "patterns": [ @@ -11013,7 +11013,7 @@ } }, "scope_resolution_inner_generated": { - "match": "((::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|new|try|for|asm|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<8>?)+)>)\\s*)?::)*\\s*+)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\s*+(((?(?:(?>[^<>]*)\\g<8>?)+)>)\\s*)?(::)", + "match": "((::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|asm|try|for|new|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<8>?)+)>)\\s*)?::)*\\s*+)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\s*+(((?(?:(?>[^<>]*)\\g<8>?)+)>)\\s*)?(::)", "captures": { "1": { "patterns": [ @@ -11050,7 +11050,7 @@ } }, "scope_resolution_namespace_alias": { - "match": "(::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|new|try|for|asm|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<4>?)+)>)\\s*)?::)*\\s*+", + "match": "(::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|asm|try|for|new|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<4>?)+)>)\\s*)?::)*\\s*+", "captures": { "0": { "patterns": [ @@ -11073,7 +11073,7 @@ } }, "scope_resolution_namespace_alias_inner_generated": { - "match": "((::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|new|try|for|asm|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<8>?)+)>)\\s*)?::)*\\s*+)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\s*+(((?(?:(?>[^<>]*)\\g<8>?)+)>)\\s*)?(::)", + "match": "((::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|asm|try|for|new|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<8>?)+)>)\\s*)?::)*\\s*+)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\s*+(((?(?:(?>[^<>]*)\\g<8>?)+)>)\\s*)?(::)", "captures": { "1": { "patterns": [ @@ -11110,7 +11110,7 @@ } }, "scope_resolution_namespace_block": { - "match": "(::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|new|try|for|asm|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<4>?)+)>)\\s*)?::)*\\s*+", + "match": "(::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|asm|try|for|new|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<4>?)+)>)\\s*)?::)*\\s*+", "captures": { "0": { "patterns": [ @@ -11133,7 +11133,7 @@ } }, "scope_resolution_namespace_block_inner_generated": { - "match": "((::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|new|try|for|asm|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<8>?)+)>)\\s*)?::)*\\s*+)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\s*+(((?(?:(?>[^<>]*)\\g<8>?)+)>)\\s*)?(::)", + "match": "((::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|asm|try|for|new|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<8>?)+)>)\\s*)?::)*\\s*+)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\s*+(((?(?:(?>[^<>]*)\\g<8>?)+)>)\\s*)?(::)", "captures": { "1": { "patterns": [ @@ -11170,7 +11170,7 @@ } }, "scope_resolution_namespace_using": { - "match": "(::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|new|try|for|asm|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<4>?)+)>)\\s*)?::)*\\s*+", + "match": "(::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|asm|try|for|new|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<4>?)+)>)\\s*)?::)*\\s*+", "captures": { "0": { "patterns": [ @@ -11193,7 +11193,7 @@ } }, "scope_resolution_namespace_using_inner_generated": { - "match": "((::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|new|try|for|asm|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<8>?)+)>)\\s*)?::)*\\s*+)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\s*+(((?(?:(?>[^<>]*)\\g<8>?)+)>)\\s*)?(::)", + "match": "((::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|asm|try|for|new|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<8>?)+)>)\\s*)?::)*\\s*+)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\s*+(((?(?:(?>[^<>]*)\\g<8>?)+)>)\\s*)?(::)", "captures": { "1": { "patterns": [ @@ -11230,7 +11230,7 @@ } }, "scope_resolution_parameter": { - "match": "(::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|new|try|for|asm|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<4>?)+)>)\\s*)?::)*\\s*+", + "match": "(::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|asm|try|for|new|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<4>?)+)>)\\s*)?::)*\\s*+", "captures": { "0": { "patterns": [ @@ -11253,7 +11253,7 @@ } }, "scope_resolution_parameter_inner_generated": { - "match": "((::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|new|try|for|asm|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<8>?)+)>)\\s*)?::)*\\s*+)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\s*+(((?(?:(?>[^<>]*)\\g<8>?)+)>)\\s*)?(::)", + "match": "((::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|asm|try|for|new|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<8>?)+)>)\\s*)?::)*\\s*+)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\s*+(((?(?:(?>[^<>]*)\\g<8>?)+)>)\\s*)?(::)", "captures": { "1": { "patterns": [ @@ -11290,7 +11290,7 @@ } }, "scope_resolution_template_call": { - "match": "(::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|new|try|for|asm|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<4>?)+)>)\\s*)?::)*\\s*+", + "match": "(::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|asm|try|for|new|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<4>?)+)>)\\s*)?::)*\\s*+", "captures": { "0": { "patterns": [ @@ -11313,7 +11313,7 @@ } }, "scope_resolution_template_call_inner_generated": { - "match": "((::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|new|try|for|asm|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<8>?)+)>)\\s*)?::)*\\s*+)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\s*+(((?(?:(?>[^<>]*)\\g<8>?)+)>)\\s*)?(::)", + "match": "((::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|asm|try|for|new|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<8>?)+)>)\\s*)?::)*\\s*+)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\s*+(((?(?:(?>[^<>]*)\\g<8>?)+)>)\\s*)?(::)", "captures": { "1": { "patterns": [ @@ -11350,7 +11350,7 @@ } }, "scope_resolution_template_definition": { - "match": "(::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|new|try|for|asm|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<4>?)+)>)\\s*)?::)*\\s*+", + "match": "(::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|asm|try|for|new|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<4>?)+)>)\\s*)?::)*\\s*+", "captures": { "0": { "patterns": [ @@ -11373,7 +11373,7 @@ } }, "scope_resolution_template_definition_inner_generated": { - "match": "((::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|new|try|for|asm|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<8>?)+)>)\\s*)?::)*\\s*+)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\s*+(((?(?:(?>[^<>]*)\\g<8>?)+)>)\\s*)?(::)", + "match": "((::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|asm|try|for|new|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<8>?)+)>)\\s*)?::)*\\s*+)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\s*+(((?(?:(?>[^<>]*)\\g<8>?)+)>)\\s*)?(::)", "captures": { "1": { "patterns": [ @@ -11414,7 +11414,7 @@ "name": "punctuation.terminator.statement.cpp" }, "simple_type": { - "match": "(\\s*+((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\(\\(.*?\\)\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(?:(?:unsigned|signed|short|long)|(?:struct|class|union|enum))((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(((::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|new|try|for|asm|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<27>?)+)>)\\s*)?::)*\\s*+)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\s*+(((?(?:(?>[^<>]*)\\g<27>?)+)>)\\s*)?(::))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?!(?:transaction_safe_dynamic|__has_cpp_attribute|transaction_safe|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|constexpr|consteval|protected|constexpr|co_return|namespace|constexpr|noexcept|typename|decltype|template|operator|noexcept|co_yield|co_await|continue|volatile|register|restrict|explicit|override|volatile|reflexpr|noexcept|requires|default|typedef|nullptr|alignof|mutable|concept|virtual|defined|__asm__|include|_Pragma|mutable|warning|private|alignas|module|switch|not_eq|bitand|and_eq|ifndef|return|sizeof|xor_eq|export|static|delete|public|define|extern|inline|import|pragma|friend|typeid|const|compl|bitor|throw|or_eq|while|catch|break|false|final|const|endif|ifdef|undef|error|using|audit|axiom|line|else|elif|true|NULL|case|goto|else|this|new|asm|not|and|xor|try|for|if|do|or|if)\\b)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\b(((?(?:(?>[^<>]*)\\g<27>?)+)>)\\s*)?(?![\\w<:.]))(((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))?(?:(?:\\&|\\*)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(?:\\&|\\*))?", + "match": "(\\s*+((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\(\\(.*?\\)\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(?:(?:unsigned|signed|short|long)|(?:struct|class|union|enum))((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(((::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|asm|try|for|new|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<27>?)+)>)\\s*)?::)*\\s*+)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\s*+(((?(?:(?>[^<>]*)\\g<27>?)+)>)\\s*)?(::))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?!(?:transaction_safe_dynamic|__has_cpp_attribute|transaction_safe|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|constexpr|consteval|protected|constexpr|co_return|namespace|constexpr|noexcept|typename|decltype|template|operator|noexcept|co_yield|co_await|continue|volatile|register|restrict|explicit|override|volatile|reflexpr|noexcept|requires|default|typedef|nullptr|alignof|mutable|concept|virtual|defined|__asm__|include|_Pragma|mutable|warning|private|alignas|module|switch|not_eq|bitand|and_eq|ifndef|return|sizeof|xor_eq|export|static|delete|public|define|extern|inline|import|pragma|friend|typeid|const|compl|bitor|throw|or_eq|while|catch|break|false|final|const|endif|ifdef|undef|error|using|audit|axiom|line|else|elif|true|NULL|case|goto|else|this|new|asm|not|and|xor|try|for|if|do|or|if)\\b)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\b(((?(?:(?>[^<>]*)\\g<27>?)+)>)\\s*)?(?![\\w<:.]))(((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))?(?:(?:\\&|\\*)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(?:\\&|\\*))?", "captures": { "1": { "name": "meta.qualified_type.cpp", @@ -12450,7 +12450,7 @@ ] }, "struct_declare": { - "match": "(struct)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))?(?:(?:\\&|\\*)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(?:\\&|\\*))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))\\b(?!override\\W|override\\$|final\\W|final\\$)((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?=\\S)(?![:{])", + "match": "((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))?(?:(?:\\&|\\*)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(?:\\&|\\*))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))\\b(?!override\\W|override\\$|final\\W|final\\$)((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?=\\S)(?![:{])", "captures": { "1": { "name": "storage.type.struct.declare.cpp" @@ -13126,7 +13126,7 @@ } }, "type_alias": { - "match": "(using)\\s*(?!namespace)(\\s*+((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\(\\(.*?\\)\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(?:(?:unsigned|signed|short|long)|(?:struct|class|union|enum))((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(((::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|new|try|for|asm|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<58>?)+)>)\\s*)?::)*\\s*+)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\s*+(((?(?:(?>[^<>]*)\\g<58>?)+)>)\\s*)?(::))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?!(?:transaction_safe_dynamic|__has_cpp_attribute|transaction_safe|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|constexpr|consteval|protected|constexpr|co_return|namespace|constexpr|noexcept|typename|decltype|template|operator|noexcept|co_yield|co_await|continue|volatile|register|restrict|explicit|override|volatile|reflexpr|noexcept|requires|default|typedef|nullptr|alignof|mutable|concept|virtual|defined|__asm__|include|_Pragma|mutable|warning|private|alignas|module|switch|not_eq|bitand|and_eq|ifndef|return|sizeof|xor_eq|export|static|delete|public|define|extern|inline|import|pragma|friend|typeid|const|compl|bitor|throw|or_eq|while|catch|break|false|final|const|endif|ifdef|undef|error|using|audit|axiom|line|else|elif|true|NULL|case|goto|else|this|new|asm|not|and|xor|try|for|if|do|or|if)\\b)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\b(((?(?:(?>[^<>]*)\\g<58>?)+)>)\\s*)?(?![\\w<:.]))\\s*(\\=)\\s*((?:typename)?)\\s*((?:(?:(?:(?:(?>\\s+)|(?:\\/\\*)(?:(?>(?:[^\\*]|(?>\\*+)[^\\/])*)(?:(?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(?:(?:unsigned|signed|short|long)|(?:struct|class|union|enum))((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(((::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|new|try|for|asm|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<58>?)+)>)\\s*)?::)*\\s*+)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\s*+(((?(?:(?>[^<>]*)\\g<58>?)+)>)\\s*)?(::))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?!(?:transaction_safe_dynamic|__has_cpp_attribute|transaction_safe|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|constexpr|consteval|protected|constexpr|co_return|namespace|constexpr|noexcept|typename|decltype|template|operator|noexcept|co_yield|co_await|continue|volatile|register|restrict|explicit|override|volatile|reflexpr|noexcept|requires|default|typedef|nullptr|alignof|mutable|concept|virtual|defined|__asm__|include|_Pragma|mutable|warning|private|alignas|module|switch|not_eq|bitand|and_eq|ifndef|return|sizeof|xor_eq|export|static|delete|public|define|extern|inline|import|pragma|friend|typeid|const|compl|bitor|throw|or_eq|while|catch|break|false|final|const|endif|ifdef|undef|error|using|audit|axiom|line|else|elif|true|NULL|case|goto|else|this|new|asm|not|and|xor|try|for|if|do|or|if)\\b)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\b(((?(?:(?>[^<>]*)\\g<58>?)+)>)\\s*)?(?![\\w<:.]))|(.*(?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))?(?:(?:\\&|\\*)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(?:\\&|\\*))((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))?(?:(\\[)(\\w*)(\\])\\s*)?\\s*(?:(;)|\\n)", + "match": "(using)\\s*(?!namespace)(\\s*+((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\(\\(.*?\\)\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(?:(?:unsigned|signed|short|long)|(?:struct|class|union|enum))((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(((::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|asm|try|for|new|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<58>?)+)>)\\s*)?::)*\\s*+)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\s*+(((?(?:(?>[^<>]*)\\g<58>?)+)>)\\s*)?(::))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?!(?:transaction_safe_dynamic|__has_cpp_attribute|transaction_safe|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|constexpr|consteval|protected|constexpr|co_return|namespace|constexpr|noexcept|typename|decltype|template|operator|noexcept|co_yield|co_await|continue|volatile|register|restrict|explicit|override|volatile|reflexpr|noexcept|requires|default|typedef|nullptr|alignof|mutable|concept|virtual|defined|__asm__|include|_Pragma|mutable|warning|private|alignas|module|switch|not_eq|bitand|and_eq|ifndef|return|sizeof|xor_eq|export|static|delete|public|define|extern|inline|import|pragma|friend|typeid|const|compl|bitor|throw|or_eq|while|catch|break|false|final|const|endif|ifdef|undef|error|using|audit|axiom|line|else|elif|true|NULL|case|goto|else|this|new|asm|not|and|xor|try|for|if|do|or|if)\\b)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\b(((?(?:(?>[^<>]*)\\g<58>?)+)>)\\s*)?(?![\\w<:.]))\\s*(\\=)\\s*((?:typename)?)\\s*((?:(?:(?:(?:(?>\\s+)|(?:\\/\\*)(?:(?>(?:[^\\*]|(?>\\*+)[^\\/])*)(?:(?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(?:(?:unsigned|signed|short|long)|(?:struct|class|union|enum))((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(((::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|asm|try|for|new|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<58>?)+)>)\\s*)?::)*\\s*+)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\s*+(((?(?:(?>[^<>]*)\\g<58>?)+)>)\\s*)?(::))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?!(?:transaction_safe_dynamic|__has_cpp_attribute|transaction_safe|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|constexpr|consteval|protected|constexpr|co_return|namespace|constexpr|noexcept|typename|decltype|template|operator|noexcept|co_yield|co_await|continue|volatile|register|restrict|explicit|override|volatile|reflexpr|noexcept|requires|default|typedef|nullptr|alignof|mutable|concept|virtual|defined|__asm__|include|_Pragma|mutable|warning|private|alignas|module|switch|not_eq|bitand|and_eq|ifndef|return|sizeof|xor_eq|export|static|delete|public|define|extern|inline|import|pragma|friend|typeid|const|compl|bitor|throw|or_eq|while|catch|break|false|final|const|endif|ifdef|undef|error|using|audit|axiom|line|else|elif|true|NULL|case|goto|else|this|new|asm|not|and|xor|try|for|if|do|or|if)\\b)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\b(((?(?:(?>[^<>]*)\\g<58>?)+)>)\\s*)?(?![\\w<:.]))|(.*(?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))?(?:(?:\\&|\\*)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(?:\\&|\\*))((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))?(?:(\\[)(\\w*)(\\])\\s*)?\\s*(?:(;)|\\n)", "captures": { "1": { "name": "keyword.other.using.directive.cpp" @@ -14094,7 +14094,7 @@ "end": "(?<=;)|(?=(?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(?:(?:unsigned|signed|short|long)|(?:struct|class|union|enum))((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(((::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|new|try|for|asm|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<27>?)+)>)\\s*)?::)*\\s*+)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\s*+(((?(?:(?>[^<>]*)\\g<27>?)+)>)\\s*)?(::))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?!(?:transaction_safe_dynamic|__has_cpp_attribute|transaction_safe|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|constexpr|consteval|protected|constexpr|co_return|namespace|constexpr|noexcept|typename|decltype|template|operator|noexcept|co_yield|co_await|continue|volatile|register|restrict|explicit|override|volatile|reflexpr|noexcept|requires|default|typedef|nullptr|alignof|mutable|concept|virtual|defined|__asm__|include|_Pragma|mutable|warning|private|alignas|module|switch|not_eq|bitand|and_eq|ifndef|return|sizeof|xor_eq|export|static|delete|public|define|extern|inline|import|pragma|friend|typeid|const|compl|bitor|throw|or_eq|while|catch|break|false|final|const|endif|ifdef|undef|error|using|audit|axiom|line|else|elif|true|NULL|case|goto|else|this|new|asm|not|and|xor|try|for|if|do|or|if)\\b)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\b(((?(?:(?>[^<>]*)\\g<27>?)+)>)\\s*)?(?![\\w<:.]))(((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))?(?:(?:\\&|\\*)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(?:\\&|\\*))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(\\()(\\*)\\s*((?:(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)?)\\s*(?:(\\[)(\\w*)(\\])\\s*)*(\\))\\s*(\\()", + "begin": "(\\s*+((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\(\\(.*?\\)\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(?:(?:unsigned|signed|short|long)|(?:struct|class|union|enum))((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(((::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|asm|try|for|new|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<27>?)+)>)\\s*)?::)*\\s*+)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\s*+(((?(?:(?>[^<>]*)\\g<27>?)+)>)\\s*)?(::))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?!(?:transaction_safe_dynamic|__has_cpp_attribute|transaction_safe|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|constexpr|consteval|protected|constexpr|co_return|namespace|constexpr|noexcept|typename|decltype|template|operator|noexcept|co_yield|co_await|continue|volatile|register|restrict|explicit|override|volatile|reflexpr|noexcept|requires|default|typedef|nullptr|alignof|mutable|concept|virtual|defined|__asm__|include|_Pragma|mutable|warning|private|alignas|module|switch|not_eq|bitand|and_eq|ifndef|return|sizeof|xor_eq|export|static|delete|public|define|extern|inline|import|pragma|friend|typeid|const|compl|bitor|throw|or_eq|while|catch|break|false|final|const|endif|ifdef|undef|error|using|audit|axiom|line|else|elif|true|NULL|case|goto|else|this|new|asm|not|and|xor|try|for|if|do|or|if)\\b)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\b(((?(?:(?>[^<>]*)\\g<27>?)+)>)\\s*)?(?![\\w<:.]))(((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))?(?:(?:\\&|\\*)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(?:\\&|\\*))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(\\()(\\*)\\s*((?:(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)?)\\s*(?:(\\[)(\\w*)(\\])\\s*)*(\\))\\s*(\\()", "beginCaptures": { "1": { "name": "meta.qualified_type.cpp", @@ -15393,7 +15393,7 @@ ] }, "typename": { - "match": "(((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(\\s*+((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\(\\(.*?\\)\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(?:(?:unsigned|signed|short|long)|(?:struct|class|union|enum))((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(((::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|new|try|for|asm|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<36>?)+)>)\\s*)?::)*\\s*+)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\s*+(((?(?:(?>[^<>]*)\\g<36>?)+)>)\\s*)?(::))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?!(?:transaction_safe_dynamic|__has_cpp_attribute|transaction_safe|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|constexpr|consteval|protected|constexpr|co_return|namespace|constexpr|noexcept|typename|decltype|template|operator|noexcept|co_yield|co_await|continue|volatile|register|restrict|explicit|override|volatile|reflexpr|noexcept|requires|default|typedef|nullptr|alignof|mutable|concept|virtual|defined|__asm__|include|_Pragma|mutable|warning|private|alignas|module|switch|not_eq|bitand|and_eq|ifndef|return|sizeof|xor_eq|export|static|delete|public|define|extern|inline|import|pragma|friend|typeid|const|compl|bitor|throw|or_eq|while|catch|break|false|final|const|endif|ifdef|undef|error|using|audit|axiom|line|else|elif|true|NULL|case|goto|else|this|new|asm|not|and|xor|try|for|if|do|or|if)\\b)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\b(((?(?:(?>[^<>]*)\\g<36>?)+)>)\\s*)?(?![\\w<:.]))", + "match": "(((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(\\s*+((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\(\\(.*?\\)\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(?:(?:unsigned|signed|short|long)|(?:struct|class|union|enum))((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(((::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|asm|try|for|new|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<36>?)+)>)\\s*)?::)*\\s*+)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\s*+(((?(?:(?>[^<>]*)\\g<36>?)+)>)\\s*)?(::))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?!(?:transaction_safe_dynamic|__has_cpp_attribute|transaction_safe|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|constexpr|consteval|protected|constexpr|co_return|namespace|constexpr|noexcept|typename|decltype|template|operator|noexcept|co_yield|co_await|continue|volatile|register|restrict|explicit|override|volatile|reflexpr|noexcept|requires|default|typedef|nullptr|alignof|mutable|concept|virtual|defined|__asm__|include|_Pragma|mutable|warning|private|alignas|module|switch|not_eq|bitand|and_eq|ifndef|return|sizeof|xor_eq|export|static|delete|public|define|extern|inline|import|pragma|friend|typeid|const|compl|bitor|throw|or_eq|while|catch|break|false|final|const|endif|ifdef|undef|error|using|audit|axiom|line|else|elif|true|NULL|case|goto|else|this|new|asm|not|and|xor|try|for|if|do|or|if)\\b)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\b(((?(?:(?>[^<>]*)\\g<36>?)+)>)\\s*)?(?![\\w<:.]))", "captures": { "1": { "name": "storage.modifier.cpp" @@ -15976,7 +15976,7 @@ ] }, "union_declare": { - "match": "(union)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))?(?:(?:\\&|\\*)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(?:\\&|\\*))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))\\b(?!override\\W|override\\$|final\\W|final\\$)((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?=\\S)(?![:{])", + "match": "((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))?(?:(?:\\&|\\*)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(?:\\&|\\*))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))\\b(?!override\\W|override\\$|final\\W|final\\$)((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?=\\S)(?![:{])", "captures": { "1": { "name": "storage.type.union.declare.cpp" @@ -16167,7 +16167,7 @@ }, "using_namespace": { "name": "meta.using-namespace.cpp", - "begin": "(?(?:(?>[^<>]*)\\g<7>?)+)>)\\s*)?::)*\\s*+)?((?(?:(?>[^<>]*)\\g<7>?)+)>)\\s*)?::)*\\s*+)?((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))?(?:(?:\\&|\\*)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(?:\\&|\\*))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))\\b(?!override\\W|override\\$|final\\W|final\\$)((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?=\\S)(?![:{])", + "match": "((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))?(?:(?:\\&|\\*)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(?:\\&|\\*))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))\\b(?!override\\W|override\\$|final\\W|final\\$)((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?=\\S)(?![:{])", "captures": { "1": { "name": "storage.type.class.declare.cpp" @@ -3307,7 +3307,7 @@ ] }, "enum_declare": { - "match": "(enum)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))?(?:(?:\\&|\\*)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(?:\\&|\\*))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))\\b(?!override\\W|override\\$|final\\W|final\\$)((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?=\\S)(?![:{])", + "match": "((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))?(?:(?:\\&|\\*)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(?:\\&|\\*))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))\\b(?!override\\W|override\\$|final\\W|final\\$)((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?=\\S)(?![:{])", "captures": { "1": { "name": "storage.type.enum.declare.cpp" @@ -12450,7 +12450,7 @@ ] }, "struct_declare": { - "match": "(struct)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))?(?:(?:\\&|\\*)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(?:\\&|\\*))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))\\b(?!override\\W|override\\$|final\\W|final\\$)((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?=\\S)(?![:{])", + "match": "((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))?(?:(?:\\&|\\*)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(?:\\&|\\*))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))\\b(?!override\\W|override\\$|final\\W|final\\$)((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?=\\S)(?![:{])", "captures": { "1": { "name": "storage.type.struct.declare.cpp" @@ -15976,7 +15976,7 @@ ] }, "union_declare": { - "match": "(union)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))?(?:(?:\\&|\\*)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(?:\\&|\\*))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))\\b(?!override\\W|override\\$|final\\W|final\\$)((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?=\\S)(?![:{])", + "match": "((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))?(?:(?:\\&|\\*)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(?:\\&|\\*))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))\\b(?!override\\W|override\\$|final\\W|final\\$)((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?=\\S)(?![:{])", "captures": { "1": { "name": "storage.type.union.declare.cpp" From 4312a6feb64f7963ebbe267c0ea38da76ad8d58a Mon Sep 17 00:00:00 2001 From: isidor Date: Tue, 12 Nov 2019 10:25:13 +0100 Subject: [PATCH 091/352] fixes #83465 --- .../contrib/debug/browser/debugConfigurationManager.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/debug/browser/debugConfigurationManager.ts b/src/vs/workbench/contrib/debug/browser/debugConfigurationManager.ts index c4f71f9db2635..0c4a83d2cb42d 100644 --- a/src/vs/workbench/contrib/debug/browser/debugConfigurationManager.ts +++ b/src/vs/workbench/contrib/debug/browser/debugConfigurationManager.ts @@ -416,7 +416,7 @@ export class ConfigurationManager implements IConfigurationManager { return candidates.then(debuggers => { debuggers.sort((first, second) => first.label.localeCompare(second.label)); const picks = debuggers.map(c => ({ label: c.label, debugger: c })); - return this.quickInputService.pick<{ label: string, debugger: Debugger | undefined }>([...picks, { type: 'separator' }, { label: 'More...', debugger: undefined }], { placeHolder: nls.localize('selectDebug', "Select Environment") }) + return this.quickInputService.pick<{ label: string, debugger: Debugger | undefined }>([...picks, { type: 'separator' }, { label: nls.localize('more', "More..."), debugger: undefined }], { placeHolder: nls.localize('selectDebug', "Select Environment") }) .then(picked => { if (picked && picked.debugger) { return picked.debugger; From 1aa537bf59f30de70b02ec3a22aa17b6da96f08e Mon Sep 17 00:00:00 2001 From: Alex Ross Date: Tue, 12 Nov 2019 10:33:11 +0100 Subject: [PATCH 092/352] Use log service in exthosttask and exthosttreeviews Part of #84283 --- src/vs/workbench/api/common/extHostTask.ts | 17 +++++++++++------ src/vs/workbench/api/common/extHostTreeViews.ts | 10 ++++++++-- src/vs/workbench/api/node/extHostTask.ts | 8 +++++--- 3 files changed, 24 insertions(+), 11 deletions(-) diff --git a/src/vs/workbench/api/common/extHostTask.ts b/src/vs/workbench/api/common/extHostTask.ts index 944f6a1961905..fc9f83e5d2ce1 100644 --- a/src/vs/workbench/api/common/extHostTask.ts +++ b/src/vs/workbench/api/common/extHostTask.ts @@ -24,6 +24,7 @@ import { IExtHostInitDataService } from 'vs/workbench/api/common/extHostInitData import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { Schemas } from 'vs/base/common/network'; import * as Platform from 'vs/base/common/platform'; +import { ILogService } from 'vs/platform/log/common/log'; export interface IExtHostTask extends ExtHostTaskShape { @@ -374,6 +375,7 @@ export abstract class ExtHostTaskBase implements ExtHostTaskShape { protected readonly _editorService: IExtHostDocumentsAndEditors; protected readonly _configurationService: IExtHostConfiguration; protected readonly _terminalService: IExtHostTerminalService; + protected readonly _logService: ILogService; protected _handleCounter: number; protected _handlers: Map; protected _taskExecutions: Map; @@ -393,7 +395,8 @@ export abstract class ExtHostTaskBase implements ExtHostTaskShape { @IExtHostWorkspace workspaceService: IExtHostWorkspace, @IExtHostDocumentsAndEditors editorService: IExtHostDocumentsAndEditors, @IExtHostConfiguration configurationService: IExtHostConfiguration, - @IExtHostTerminalService extHostTerminalService: IExtHostTerminalService + @IExtHostTerminalService extHostTerminalService: IExtHostTerminalService, + @ILogService logService: ILogService ) { this._proxy = extHostRpc.getProxy(MainContext.MainThreadTask); this._workspaceProvider = workspaceService; @@ -406,6 +409,7 @@ export abstract class ExtHostTaskBase implements ExtHostTaskShape { this._providedCustomExecutions2 = new Map(); this._notProvidedCustomExecutions = new Set(); this._activeCustomExecutions2 = new Map(); + this._logService = logService; } public registerTaskProvider(extension: IExtensionDescription, type: string, provider: vscode.TaskProvider): vscode.Disposable { @@ -661,9 +665,10 @@ export class WorkerExtHostTask extends ExtHostTaskBase { @IExtHostWorkspace workspaceService: IExtHostWorkspace, @IExtHostDocumentsAndEditors editorService: IExtHostDocumentsAndEditors, @IExtHostConfiguration configurationService: IExtHostConfiguration, - @IExtHostTerminalService extHostTerminalService: IExtHostTerminalService + @IExtHostTerminalService extHostTerminalService: IExtHostTerminalService, + @ILogService logService: ILogService ) { - super(extHostRpc, initData, workspaceService, editorService, configurationService, extHostTerminalService); + super(extHostRpc, initData, workspaceService, editorService, configurationService, extHostTerminalService, logService); if (initData.remote.isRemote && initData.remote.authority) { this.registerTaskSystem(Schemas.vscodeRemote, { scheme: Schemas.vscodeRemote, @@ -696,7 +701,7 @@ export class WorkerExtHostTask extends ExtHostTaskBase { if (value) { for (let task of value) { if (!task.definition || !validTypes[task.definition.type]) { - console.warn(`The task [${task.source}, ${task.name}] uses an undefined task type. The task will be ignored in the future.`); + this._logService.warn(`The task [${task.source}, ${task.name}] uses an undefined task type. The task will be ignored in the future.`); } const taskDTO: tasks.TaskDTO | undefined = TaskDTO.from(task, handler.extension); @@ -707,7 +712,7 @@ export class WorkerExtHostTask extends ExtHostTaskBase { // is invoked, we have to be able to map it back to our data. taskIdPromises.push(this.addCustomExecution(taskDTO, task, true)); } else { - console.warn('Only custom execution tasks supported.'); + this._logService.warn('Only custom execution tasks supported.'); } } } @@ -721,7 +726,7 @@ export class WorkerExtHostTask extends ExtHostTaskBase { if (CustomExecutionDTO.is(resolvedTaskDTO.execution)) { return resolvedTaskDTO; } else { - console.warn('Only custom execution tasks supported.'); + this._logService.warn('Only custom execution tasks supported.'); } return undefined; } diff --git a/src/vs/workbench/api/common/extHostTreeViews.ts b/src/vs/workbench/api/common/extHostTreeViews.ts index 24b55f765df23..15e808589302d 100644 --- a/src/vs/workbench/api/common/extHostTreeViews.ts +++ b/src/vs/workbench/api/common/extHostTreeViews.ts @@ -198,7 +198,13 @@ class ExtHostTreeView extends Disposable { private refreshPromise: Promise = Promise.resolve(); private refreshQueue: Promise = Promise.resolve(); - constructor(private viewId: string, options: vscode.TreeViewOptions, private proxy: MainThreadTreeViewsShape, private commands: CommandsConverter, private logService: ILogService, private extension: IExtensionDescription) { + constructor( + private viewId: string, options: vscode.TreeViewOptions, + private proxy: MainThreadTreeViewsShape, + private commands: CommandsConverter, + private logService: ILogService, + private extension: IExtensionDescription + ) { super(); if (extension.contributes && extension.contributes.views) { for (const location in extension.contributes.views) { @@ -250,7 +256,7 @@ class ExtHostTreeView extends Disposable { getChildren(parentHandle: TreeItemHandle | Root): Promise { const parentElement = parentHandle ? this.getExtensionElement(parentHandle) : undefined; if (parentHandle && !parentElement) { - console.error(`No tree item with id \'${parentHandle}\' found.`); + this.logService.error(`No tree item with id \'${parentHandle}\' found.`); return Promise.resolve([]); } diff --git a/src/vs/workbench/api/node/extHostTask.ts b/src/vs/workbench/api/node/extHostTask.ts index c7a2ea29e9d0e..6e1a647067a75 100644 --- a/src/vs/workbench/api/node/extHostTask.ts +++ b/src/vs/workbench/api/node/extHostTask.ts @@ -22,6 +22,7 @@ import { IExtHostRpcService } from 'vs/workbench/api/common/extHostRpcService'; import { IExtHostInitDataService } from 'vs/workbench/api/common/extHostInitDataService'; import { ExtHostTaskBase, TaskHandleDTO, TaskDTO, CustomExecutionDTO, HandlerData } from 'vs/workbench/api/common/extHostTask'; import { Schemas } from 'vs/base/common/network'; +import { ILogService } from 'vs/platform/log/common/log'; export class ExtHostTask extends ExtHostTaskBase { private _variableResolver: ExtHostVariableResolverService | undefined; @@ -32,9 +33,10 @@ export class ExtHostTask extends ExtHostTaskBase { @IExtHostWorkspace workspaceService: IExtHostWorkspace, @IExtHostDocumentsAndEditors editorService: IExtHostDocumentsAndEditors, @IExtHostConfiguration configurationService: IExtHostConfiguration, - @IExtHostTerminalService extHostTerminalService: IExtHostTerminalService + @IExtHostTerminalService extHostTerminalService: IExtHostTerminalService, + @ILogService logService: ILogService ) { - super(extHostRpc, initData, workspaceService, editorService, configurationService, extHostTerminalService); + super(extHostRpc, initData, workspaceService, editorService, configurationService, extHostTerminalService, logService); if (initData.remote.isRemote && initData.remote.authority) { this.registerTaskSystem(Schemas.vscodeRemote, { scheme: Schemas.vscodeRemote, @@ -71,7 +73,7 @@ export class ExtHostTask extends ExtHostTaskBase { if (value) { for (let task of value) { if (!task.definition || !validTypes[task.definition.type]) { - console.warn(`The task [${task.source}, ${task.name}] uses an undefined task type. The task will be ignored in the future.`); + this._logService.warn(`The task [${task.source}, ${task.name}] uses an undefined task type. The task will be ignored in the future.`); } const taskDTO: tasks.TaskDTO | undefined = TaskDTO.from(task, handler.extension); From 1dae4ffdc665d8dd814055657499040e88d53d6a Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Tue, 12 Nov 2019 10:12:01 +0100 Subject: [PATCH 093/352] catch tree rerender errors fixes #82629 --- src/vs/workbench/browser/parts/views/customView.ts | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/browser/parts/views/customView.ts b/src/vs/workbench/browser/parts/views/customView.ts index 2d6dc484f22b3..c48f38e711898 100644 --- a/src/vs/workbench/browser/parts/views/customView.ts +++ b/src/vs/workbench/browser/parts/views/customView.ts @@ -611,7 +611,15 @@ export class CustomTreeView extends Disposable implements ITreeView { if (tree && this.visible) { this.refreshing = true; await Promise.all(elements.map(element => tree.updateChildren(element, true))); - elements.map(element => tree.rerender(element)); + + elements.map(element => { + try { + tree.rerender(element); + } catch { + // noop + } + }); + this.refreshing = false; this.updateContentAreas(); if (this.focused) { From a8f5f3e0a7128ba36d48f4cd5d63e88dc48156f3 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Tue, 12 Nov 2019 10:12:10 +0100 Subject: [PATCH 094/352] add log tracing to main thread tree views --- .../workbench/api/browser/mainThreadTreeViews.ts | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/api/browser/mainThreadTreeViews.ts b/src/vs/workbench/api/browser/mainThreadTreeViews.ts index 031dae4a7f7e9..58796f182f6f0 100644 --- a/src/vs/workbench/api/browser/mainThreadTreeViews.ts +++ b/src/vs/workbench/api/browser/mainThreadTreeViews.ts @@ -12,6 +12,7 @@ import { INotificationService } from 'vs/platform/notification/common/notificati import { isUndefinedOrNull, isNumber } from 'vs/base/common/types'; import { Registry } from 'vs/platform/registry/common/platform'; import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; +import { ILogService } from 'vs/platform/log/common/log'; @extHostNamedCustomer(MainContext.MainThreadTreeViews) export class MainThreadTreeViews extends Disposable implements MainThreadTreeViewsShape { @@ -23,13 +24,16 @@ export class MainThreadTreeViews extends Disposable implements MainThreadTreeVie extHostContext: IExtHostContext, @IViewsService private readonly viewsService: IViewsService, @INotificationService private readonly notificationService: INotificationService, - @IExtensionService private readonly extensionService: IExtensionService + @IExtensionService private readonly extensionService: IExtensionService, + @ILogService private readonly logService: ILogService ) { super(); this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostTreeViews); } $registerTreeViewDataProvider(treeViewId: string, options: { showCollapseAll: boolean, canSelectMany: boolean }): void { + this.logService.trace('MainThreadTreeViews#$registerTreeViewDataProvider', treeViewId, options); + this.extensionService.whenInstalledExtensionsRegistered().then(() => { const dataProvider = new TreeViewDataProvider(treeViewId, this._proxy, this.notificationService); this._dataProviders.set(treeViewId, dataProvider); @@ -49,6 +53,8 @@ export class MainThreadTreeViews extends Disposable implements MainThreadTreeVie } $reveal(treeViewId: string, item: ITreeItem, parentChain: ITreeItem[], options: IRevealOptions): Promise { + this.logService.trace('MainThreadTreeViews#$reveal', treeViewId, item, parentChain, options); + return this.viewsService.openView(treeViewId, options.focus) .then(() => { const viewer = this.getTreeView(treeViewId); @@ -60,6 +66,8 @@ export class MainThreadTreeViews extends Disposable implements MainThreadTreeVie } $refresh(treeViewId: string, itemsToRefreshByHandle: { [treeItemHandle: string]: ITreeItem }): Promise { + this.logService.trace('MainThreadTreeViews#$refresh', treeViewId, itemsToRefreshByHandle); + const viewer = this.getTreeView(treeViewId); const dataProvider = this._dataProviders.get(treeViewId); if (viewer && dataProvider) { @@ -70,6 +78,8 @@ export class MainThreadTreeViews extends Disposable implements MainThreadTreeVie } $setMessage(treeViewId: string, message: string): void { + this.logService.trace('MainThreadTreeViews#$setMessage', treeViewId, message); + const viewer = this.getTreeView(treeViewId); if (viewer) { viewer.message = message; @@ -77,6 +87,8 @@ export class MainThreadTreeViews extends Disposable implements MainThreadTreeVie } $setTitle(treeViewId: string, title: string): void { + this.logService.trace('MainThreadTreeViews#$setTitle', treeViewId, title); + const viewer = this.getTreeView(treeViewId); if (viewer) { viewer.title = title; From 337ab02cd128ed65abdcd429a30cc57b517883e8 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Tue, 12 Nov 2019 10:39:40 +0100 Subject: [PATCH 095/352] fix extension viewlet shift --- .../workbench/contrib/extensions/browser/extensionsViewlet.ts | 2 +- .../contrib/extensions/browser/media/extensionsViewlet.css | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/contrib/extensions/browser/extensionsViewlet.ts b/src/vs/workbench/contrib/extensions/browser/extensionsViewlet.ts index 2bee5aa811ee9..250084615b91e 100644 --- a/src/vs/workbench/contrib/extensions/browser/extensionsViewlet.ts +++ b/src/vs/workbench/contrib/extensions/browser/extensionsViewlet.ts @@ -442,7 +442,7 @@ export class ExtensionsViewlet extends ViewContainerViewlet implements IExtensio if (this.searchBox) { this.searchBox.layout({ height: 20, width: dimension.width - 34 }); } - super.layout(new Dimension(dimension.width, dimension.height - 38)); + super.layout(new Dimension(dimension.width, dimension.height - 41)); } getOptimalWidth(): number { diff --git a/src/vs/workbench/contrib/extensions/browser/media/extensionsViewlet.css b/src/vs/workbench/contrib/extensions/browser/media/extensionsViewlet.css index 025c3b826ccc0..8c115cdd91220 100644 --- a/src/vs/workbench/contrib/extensions/browser/media/extensionsViewlet.css +++ b/src/vs/workbench/contrib/extensions/browser/media/extensionsViewlet.css @@ -25,7 +25,7 @@ } .extensions-viewlet > .extensions { - height: calc(100% - 38px); + height: calc(100% - 41px); } .extensions-viewlet > .extensions .extension-view-header .monaco-action-bar { From d5ff86c8ec3eb2e6bed120fcbb17a1f7ba18472f Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Tue, 12 Nov 2019 10:05:00 +0100 Subject: [PATCH 096/352] debt - move tests --- .../test => test/node/zip}/fixtures/extract.zip | Bin .../base/{node/test => test/node/zip}/zip.test.ts | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename src/vs/base/{node/test => test/node/zip}/fixtures/extract.zip (100%) rename src/vs/base/{node/test => test/node/zip}/zip.test.ts (100%) diff --git a/src/vs/base/node/test/fixtures/extract.zip b/src/vs/base/test/node/zip/fixtures/extract.zip similarity index 100% rename from src/vs/base/node/test/fixtures/extract.zip rename to src/vs/base/test/node/zip/fixtures/extract.zip diff --git a/src/vs/base/node/test/zip.test.ts b/src/vs/base/test/node/zip/zip.test.ts similarity index 100% rename from src/vs/base/node/test/zip.test.ts rename to src/vs/base/test/node/zip/zip.test.ts From 5ae52b61cbdc1bc545b562fe265ec1e545385e0b Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Tue, 12 Nov 2019 10:41:54 +0100 Subject: [PATCH 097/352] files - implement ctime properly as btime (fix #84525) --- .../singlefolder-tests/workspace.fs.test.ts | 2 + src/vs/platform/files/common/fileService.ts | 3 ++ src/vs/platform/files/common/files.ts | 24 ++++++++-- .../files/node/diskFileSystemProvider.ts | 2 +- .../files/test/node/diskFileService.test.ts | 44 ++++++++++++++++--- .../api/browser/mainThreadFileSystem.ts | 2 +- .../textfile/common/textFileEditorModel.ts | 4 ++ .../workbench/test/workbenchTestServices.ts | 4 ++ 8 files changed, 74 insertions(+), 11 deletions(-) diff --git a/extensions/vscode-api-tests/src/singlefolder-tests/workspace.fs.test.ts b/extensions/vscode-api-tests/src/singlefolder-tests/workspace.fs.test.ts index 06728e206d941..7d552df04a81b 100644 --- a/extensions/vscode-api-tests/src/singlefolder-tests/workspace.fs.test.ts +++ b/extensions/vscode-api-tests/src/singlefolder-tests/workspace.fs.test.ts @@ -23,6 +23,8 @@ suite('workspace-fs', () => { assert.equal(typeof stat.mtime, 'number'); assert.equal(typeof stat.ctime, 'number'); + assert.ok(stat.mtime > 0); + assert.ok(stat.ctime > 0); const entries = await vscode.workspace.fs.readDirectory(root); assert.ok(entries.length > 0); diff --git a/src/vs/platform/files/common/fileService.ts b/src/vs/platform/files/common/fileService.ts index b789748febe1b..c3fd729d148fc 100644 --- a/src/vs/platform/files/common/fileService.ts +++ b/src/vs/platform/files/common/fileService.ts @@ -209,6 +209,8 @@ export class FileService extends Disposable implements IFileService { }); } + private async toFileStat(provider: IFileSystemProvider, resource: URI, stat: IStat | { type: FileType } & Partial, siblings: number | undefined, resolveMetadata: boolean, recurse: (stat: IFileStat, siblings?: number) => boolean): Promise; + private async toFileStat(provider: IFileSystemProvider, resource: URI, stat: IStat, siblings: number | undefined, resolveMetadata: true, recurse: (stat: IFileStat, siblings?: number) => boolean): Promise; private async toFileStat(provider: IFileSystemProvider, resource: URI, stat: IStat | { type: FileType } & Partial, siblings: number | undefined, resolveMetadata: boolean, recurse: (stat: IFileStat, siblings?: number) => boolean): Promise { // convert to file stat @@ -219,6 +221,7 @@ export class FileService extends Disposable implements IFileService { isSymbolicLink: (stat.type & FileType.SymbolicLink) !== 0, isReadonly: !!(provider.capabilities & FileSystemProviderCapabilities.Readonly), mtime: stat.mtime, + ctime: stat.ctime, size: stat.size, etag: etag({ mtime: stat.mtime, size: stat.size }) }; diff --git a/src/vs/platform/files/common/files.ts b/src/vs/platform/files/common/files.ts index 0356e8dfdd3c8..85e140f5b1046 100644 --- a/src/vs/platform/files/common/files.ts +++ b/src/vs/platform/files/common/files.ts @@ -207,8 +207,17 @@ export enum FileType { export interface IStat { type: FileType; + + /** + * The last modification date represented as millis from unix epoch. + */ mtime: number; + + /** + * The creation date represented as millis from unix epoch. + */ ctime: number; + size: number; } @@ -583,14 +592,21 @@ interface IBaseStat { size?: number; /** - * The last modification date represented - * as millis from unix epoch. + * The last modification date represented as millis from unix epoch. * * The value may or may not be resolved as * it is optional. */ mtime?: number; + /** + * The creation date represented as millis from unix epoch. + * + * The value may or may not be resolved as + * it is optional. + */ + ctime?: number; + /** * A unique identifier thet represents the * current state of the file or directory. @@ -608,6 +624,7 @@ interface IBaseStat { export interface IBaseStatWithMetadata extends IBaseStat { mtime: number; + ctime: number; etag: string; size: number; } @@ -635,6 +652,7 @@ export interface IFileStat extends IBaseStat { export interface IFileStatWithMetadata extends IFileStat, IBaseStatWithMetadata { mtime: number; + ctime: number; etag: string; size: number; children?: IFileStatWithMetadata[]; @@ -703,7 +721,7 @@ export interface IResolveFileOptions { readonly resolveSingleChildDescendants?: boolean; /** - * Will resolve mtime, size and etag of files if enabled. This can have a negative impact + * Will resolve mtime, ctime, size and etag of files if enabled. This can have a negative impact * on performance and thus should only be used when these values are required. */ readonly resolveMetadata?: boolean; diff --git a/src/vs/platform/files/node/diskFileSystemProvider.ts b/src/vs/platform/files/node/diskFileSystemProvider.ts index 7c7e255d80e26..0187b5d9bccf8 100644 --- a/src/vs/platform/files/node/diskFileSystemProvider.ts +++ b/src/vs/platform/files/node/diskFileSystemProvider.ts @@ -80,7 +80,7 @@ export class DiskFileSystemProvider extends Disposable implements return { type: this.toType(stat, isSymbolicLink), - ctime: stat.ctime.getTime(), + ctime: stat.birthtime.getTime(), // intentionally not using ctime here, we want the creation time mtime: stat.mtime.getTime(), size: stat.size }; diff --git a/src/vs/platform/files/test/node/diskFileService.test.ts b/src/vs/platform/files/test/node/diskFileService.test.ts index 32cbb18e54582..f1a81f3e20e44 100644 --- a/src/vs/platform/files/test/node/diskFileService.test.ts +++ b/src/vs/platform/files/test/node/diskFileService.test.ts @@ -213,23 +213,32 @@ suite('Disk File Service', function () { assert.equal(exists, false); }); - test('resolve', async () => { - const resolved = await service.resolve(URI.file(testDir), { resolveTo: [URI.file(join(testDir, 'deep'))] }); - assert.equal(resolved.children!.length, 8); + test('resolve - file', async () => { + const resource = URI.file(getPathFromAmdModule(require, './fixtures/resolver/index.html')); + const resolved = await service.resolve(resource); - const deep = (getByName(resolved, 'deep')!); - assert.equal(deep.children!.length, 4); + assert.equal(resolved.name, 'index.html'); + assert.equal(resolved.resource.toString(), resource.toString()); + assert.equal(resolved.children, undefined); + assert.ok(resolved.mtime! > 0); + assert.ok(resolved.ctime! > 0); + assert.ok(resolved.size! > 0); }); test('resolve - directory', async () => { const testsElements = ['examples', 'other', 'index.html', 'site.css']; - const result = await service.resolve(URI.file(getPathFromAmdModule(require, './fixtures/resolver'))); + const resource = URI.file(getPathFromAmdModule(require, './fixtures/resolver')); + const result = await service.resolve(resource); assert.ok(result); + assert.equal(result.resource.toString(), resource.toString()); + assert.equal(result.name, 'resolver'); assert.ok(result.children); assert.ok(result.children!.length > 0); assert.ok(result!.isDirectory); + assert.ok(result.mtime! > 0); + assert.ok(result.ctime! > 0); assert.equal(result.children!.length, testsElements.length); assert.ok(result.children!.every(entry => { @@ -242,12 +251,18 @@ suite('Disk File Service', function () { assert.ok(basename(value.resource.fsPath)); if (['examples', 'other'].indexOf(basename(value.resource.fsPath)) >= 0) { assert.ok(value.isDirectory); + assert.equal(value.mtime, undefined); + assert.equal(value.ctime, undefined); } else if (basename(value.resource.fsPath) === 'index.html') { assert.ok(!value.isDirectory); assert.ok(!value.children); + assert.equal(value.mtime, undefined); + assert.equal(value.ctime, undefined); } else if (basename(value.resource.fsPath) === 'site.css') { assert.ok(!value.isDirectory); assert.ok(!value.children); + assert.equal(value.mtime, undefined); + assert.equal(value.ctime, undefined); } else { assert.ok(!'Unexpected value ' + basename(value.resource.fsPath)); } @@ -260,9 +275,12 @@ suite('Disk File Service', function () { const result = await service.resolve(URI.file(getPathFromAmdModule(require, './fixtures/resolver')), { resolveMetadata: true }); assert.ok(result); + assert.equal(result.name, 'resolver'); assert.ok(result.children); assert.ok(result.children!.length > 0); assert.ok(result!.isDirectory); + assert.ok(result.mtime! > 0); + assert.ok(result.ctime! > 0); assert.equal(result.children!.length, testsElements.length); assert.ok(result.children!.every(entry => { @@ -277,18 +295,32 @@ suite('Disk File Service', function () { assert.ok(basename(value.resource.fsPath)); if (['examples', 'other'].indexOf(basename(value.resource.fsPath)) >= 0) { assert.ok(value.isDirectory); + assert.ok(value.mtime! > 0); + assert.ok(value.ctime! > 0); } else if (basename(value.resource.fsPath) === 'index.html') { assert.ok(!value.isDirectory); assert.ok(!value.children); + assert.ok(value.mtime! > 0); + assert.ok(value.ctime! > 0); } else if (basename(value.resource.fsPath) === 'site.css') { assert.ok(!value.isDirectory); assert.ok(!value.children); + assert.ok(value.mtime! > 0); + assert.ok(value.ctime! > 0); } else { assert.ok(!'Unexpected value ' + basename(value.resource.fsPath)); } }); }); + test('resolve - directory with resolveTo', async () => { + const resolved = await service.resolve(URI.file(testDir), { resolveTo: [URI.file(join(testDir, 'deep'))] }); + assert.equal(resolved.children!.length, 8); + + const deep = (getByName(resolved, 'deep')!); + assert.equal(deep.children!.length, 4); + }); + test('resolve - directory - resolveTo single directory', async () => { const resolverFixturesPath = getPathFromAmdModule(require, './fixtures/resolver'); const result = await service.resolve(URI.file(resolverFixturesPath), { resolveTo: [URI.file(join(resolverFixturesPath, 'other/deep'))] }); diff --git a/src/vs/workbench/api/browser/mainThreadFileSystem.ts b/src/vs/workbench/api/browser/mainThreadFileSystem.ts index 3407a420ca740..fa8c5bdaf7ed7 100644 --- a/src/vs/workbench/api/browser/mainThreadFileSystem.ts +++ b/src/vs/workbench/api/browser/mainThreadFileSystem.ts @@ -52,7 +52,7 @@ export class MainThreadFileSystem implements MainThreadFileSystemShape { $stat(uri: UriComponents): Promise { return this._fileService.resolve(URI.revive(uri), { resolveMetadata: true }).then(stat => { return { - ctime: 0, + ctime: stat.ctime, mtime: stat.mtime, size: stat.size, type: MainThreadFileSystem._getFileType(stat) diff --git a/src/vs/workbench/services/textfile/common/textFileEditorModel.ts b/src/vs/workbench/services/textfile/common/textFileEditorModel.ts index 5cfaec6676bb3..5e6a21d698723 100644 --- a/src/vs/workbench/services/textfile/common/textFileEditorModel.ts +++ b/src/vs/workbench/services/textfile/common/textFileEditorModel.ts @@ -32,6 +32,7 @@ import { Schemas } from 'vs/base/common/network'; export interface IBackupMetaData { mtime: number; + ctime: number; size: number; etag: string; orphaned: boolean; @@ -224,6 +225,7 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil if (isEqual(target, this.resource) && this.lastResolvedFileStat) { meta = { mtime: this.lastResolvedFileStat.mtime, + ctime: this.lastResolvedFileStat.ctime, size: this.lastResolvedFileStat.size, etag: this.lastResolvedFileStat.etag, orphaned: this.inOrphanMode @@ -313,6 +315,7 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil resource: this.resource, name: basename(this.resource), mtime: resolvedBackup.meta ? resolvedBackup.meta.mtime : Date.now(), + ctime: resolvedBackup.meta ? resolvedBackup.meta.ctime : Date.now(), size: resolvedBackup.meta ? resolvedBackup.meta.size : 0, etag: resolvedBackup.meta ? resolvedBackup.meta.etag : ETAG_DISABLED, // etag disabled if unknown! value: resolvedBackup.value, @@ -397,6 +400,7 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil resource: this.resource, name: content.name, mtime: content.mtime, + ctime: content.ctime, size: content.size, etag: content.etag, isDirectory: false, diff --git a/src/vs/workbench/test/workbenchTestServices.ts b/src/vs/workbench/test/workbenchTestServices.ts index 9b4fbf6b47c01..e536d21ee319a 100644 --- a/src/vs/workbench/test/workbenchTestServices.ts +++ b/src/vs/workbench/test/workbenchTestServices.ts @@ -262,6 +262,7 @@ export class TestTextFileService extends NativeTextFileService { resource: content.resource, name: content.name, mtime: content.mtime, + ctime: content.ctime, etag: content.etag, encoding: 'utf8', value: await createTextBufferFactoryFromStream(content.value), @@ -996,6 +997,7 @@ export class TestFileService implements IFileService { etag: 'index.txt', encoding: 'utf8', mtime: Date.now(), + ctime: Date.now(), name: resources.basename(resource), size: 1 }); @@ -1022,6 +1024,7 @@ export class TestFileService implements IFileService { etag: 'index.txt', encoding: 'utf8', mtime: Date.now(), + ctime: Date.now(), size: 1, name: resources.basename(resource) }); @@ -1033,6 +1036,7 @@ export class TestFileService implements IFileService { etag: 'index.txt', encoding: 'utf8', mtime: Date.now(), + ctime: Date.now(), size: 42, isDirectory: false, name: resources.basename(resource) From 77d57689ccc16dfeacc328868b1567136ab1adee Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Tue, 12 Nov 2019 11:11:34 +0100 Subject: [PATCH 098/352] files - introduce IFileStat.isFile() for #84524 --- src/vs/platform/files/common/fileService.ts | 1 + src/vs/platform/files/common/files.ts | 9 +++++++-- src/vs/platform/files/test/node/diskFileService.test.ts | 3 +++ .../services/textfile/common/textFileEditorModel.ts | 1 + src/vs/workbench/test/workbenchTestServices.ts | 4 ++++ 5 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/vs/platform/files/common/fileService.ts b/src/vs/platform/files/common/fileService.ts index c3fd729d148fc..d3a70db859d29 100644 --- a/src/vs/platform/files/common/fileService.ts +++ b/src/vs/platform/files/common/fileService.ts @@ -217,6 +217,7 @@ export class FileService extends Disposable implements IFileService { const fileStat: IFileStat = { resource, name: getBaseLabel(resource), + isFile: (stat.type & FileType.File) !== 0, isDirectory: (stat.type & FileType.Directory) !== 0, isSymbolicLink: (stat.type & FileType.SymbolicLink) !== 0, isReadonly: !!(provider.capabilities & FileSystemProviderCapabilities.Readonly), diff --git a/src/vs/platform/files/common/files.ts b/src/vs/platform/files/common/files.ts index 85e140f5b1046..15f2e20910b81 100644 --- a/src/vs/platform/files/common/files.ts +++ b/src/vs/platform/files/common/files.ts @@ -635,14 +635,19 @@ export interface IBaseStatWithMetadata extends IBaseStat { export interface IFileStat extends IBaseStat { /** - * The resource is a directory + * The resource is a file. + */ + isFile: boolean; + + /** + * The resource is a directory. */ isDirectory: boolean; /** * The resource is a symbolic link. */ - isSymbolicLink?: boolean; + isSymbolicLink: boolean; /** * The children of the file stat or undefined if none. diff --git a/src/vs/platform/files/test/node/diskFileService.test.ts b/src/vs/platform/files/test/node/diskFileService.test.ts index f1a81f3e20e44..79ecd34d5f085 100644 --- a/src/vs/platform/files/test/node/diskFileService.test.ts +++ b/src/vs/platform/files/test/node/diskFileService.test.ts @@ -218,6 +218,9 @@ suite('Disk File Service', function () { const resolved = await service.resolve(resource); assert.equal(resolved.name, 'index.html'); + assert.equal(resolved.isFile, true); + assert.equal(resolved.isDirectory, false); + assert.equal(resolved.isSymbolicLink, false); assert.equal(resolved.resource.toString(), resource.toString()); assert.equal(resolved.children, undefined); assert.ok(resolved.mtime! > 0); diff --git a/src/vs/workbench/services/textfile/common/textFileEditorModel.ts b/src/vs/workbench/services/textfile/common/textFileEditorModel.ts index 5e6a21d698723..8618b539f5a39 100644 --- a/src/vs/workbench/services/textfile/common/textFileEditorModel.ts +++ b/src/vs/workbench/services/textfile/common/textFileEditorModel.ts @@ -403,6 +403,7 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil ctime: content.ctime, size: content.size, etag: content.etag, + isFile: true, isDirectory: false, isSymbolicLink: false, isReadonly: content.isReadonly diff --git a/src/vs/workbench/test/workbenchTestServices.ts b/src/vs/workbench/test/workbenchTestServices.ts index e536d21ee319a..c4acaed37e875 100644 --- a/src/vs/workbench/test/workbenchTestServices.ts +++ b/src/vs/workbench/test/workbenchTestServices.ts @@ -975,7 +975,9 @@ export class TestFileService implements IFileService { encoding: 'utf8', mtime: Date.now(), size: 42, + isFile: true, isDirectory: false, + isSymbolicLink: false, name: resources.basename(resource) }); } @@ -1038,7 +1040,9 @@ export class TestFileService implements IFileService { mtime: Date.now(), ctime: Date.now(), size: 42, + isFile: true, isDirectory: false, + isSymbolicLink: false, name: resources.basename(resource) })); } From 5fbd6bbc56d77c090f729c0d22fb1cf84163a7a1 Mon Sep 17 00:00:00 2001 From: isidor Date: Tue, 12 Nov 2019 11:13:02 +0100 Subject: [PATCH 099/352] fixes #83478 --- src/vs/workbench/contrib/files/browser/views/explorerViewer.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/files/browser/views/explorerViewer.ts b/src/vs/workbench/contrib/files/browser/views/explorerViewer.ts index 054a39beafe57..2a1d6e7a9d676 100644 --- a/src/vs/workbench/contrib/files/browser/views/explorerViewer.ts +++ b/src/vs/workbench/contrib/files/browser/views/explorerViewer.ts @@ -702,7 +702,7 @@ export class FileDragAndDrop implements ITreeDragAndDrop { if (targetStat.children) { const ignoreCase = hasToIgnoreCase(target.resource); targetStat.children.forEach(child => { - targetNames.add(ignoreCase ? child.name : child.name.toLowerCase()); + targetNames.add(ignoreCase ? child.name.toLowerCase() : child.name); }); } From 8faa1d52f1a17bbce681a6d7d00a739a73c27e75 Mon Sep 17 00:00:00 2001 From: Christof Marti Date: Tue, 12 Nov 2019 11:27:34 +0100 Subject: [PATCH 100/352] Only QuickNav if there was a keyDown since shown (fixes #83013) --- src/vs/base/parts/quickopen/browser/quickOpenWidget.ts | 7 ++++++- src/vs/workbench/browser/parts/quickinput/quickInput.ts | 7 ++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/vs/base/parts/quickopen/browser/quickOpenWidget.ts b/src/vs/base/parts/quickopen/browser/quickOpenWidget.ts index 7a3a473d97005..dc7df956ff2c4 100644 --- a/src/vs/base/parts/quickopen/browser/quickOpenWidget.ts +++ b/src/vs/base/parts/quickopen/browser/quickOpenWidget.ts @@ -134,6 +134,7 @@ export class QuickOpenWidget extends Disposable implements IModelProvider { private styles: IQuickOpenStyles; // @ts-ignore (legacy widget - to be replaced with quick input) private renderer: Renderer; + private keyDownSeenSinceShown = false; constructor(container: HTMLElement, callbacks: IQuickOpenCallbacks, options: IQuickOpenOptions) { super(); @@ -170,6 +171,7 @@ export class QuickOpenWidget extends Disposable implements IModelProvider { this._register(DOM.addDisposableListener(this.element, DOM.EventType.FOCUS, e => this.gainingFocus(), true)); this._register(DOM.addDisposableListener(this.element, DOM.EventType.BLUR, e => this.loosingFocus(e), true)); this._register(DOM.addDisposableListener(this.element, DOM.EventType.KEY_DOWN, e => { + this.keyDownSeenSinceShown = true; const keyboardEvent: StandardKeyboardEvent = new StandardKeyboardEvent(e); if (keyboardEvent.keyCode === KeyCode.Escape) { DOM.EventHelper.stop(e, true); @@ -220,6 +222,7 @@ export class QuickOpenWidget extends Disposable implements IModelProvider { this._register(DOM.addDisposableListener(this.inputBox.inputElement, DOM.EventType.INPUT, (e: Event) => this.onType())); this._register(DOM.addDisposableListener(this.inputBox.inputElement, DOM.EventType.KEY_DOWN, (e: KeyboardEvent) => { + this.keyDownSeenSinceShown = true; const keyboardEvent: StandardKeyboardEvent = new StandardKeyboardEvent(e); const shouldOpenInBackground = this.shouldOpenInBackground(keyboardEvent); @@ -300,6 +303,7 @@ export class QuickOpenWidget extends Disposable implements IModelProvider { })); this._register(DOM.addDisposableListener(this.treeContainer, DOM.EventType.KEY_DOWN, e => { + this.keyDownSeenSinceShown = true; const keyboardEvent: StandardKeyboardEvent = new StandardKeyboardEvent(e); // Only handle when in quick navigation mode @@ -320,7 +324,7 @@ export class QuickOpenWidget extends Disposable implements IModelProvider { const keyCode = keyboardEvent.keyCode; // Only handle when in quick navigation mode - if (!this.quickNavigateConfiguration) { + if (!this.quickNavigateConfiguration || !this.keyDownSeenSinceShown) { return; } @@ -595,6 +599,7 @@ export class QuickOpenWidget extends Disposable implements IModelProvider { this.visible = true; this.isLoosingFocus = false; this.quickNavigateConfiguration = options ? options.quickNavigateConfiguration : undefined; + this.keyDownSeenSinceShown = false; // Adjust UI for quick navigate mode if (this.quickNavigateConfiguration) { diff --git a/src/vs/workbench/browser/parts/quickinput/quickInput.ts b/src/vs/workbench/browser/parts/quickinput/quickInput.ts index 3a81e8c7c3b3b..529f2a9c95f28 100644 --- a/src/vs/workbench/browser/parts/quickinput/quickInput.ts +++ b/src/vs/workbench/browser/parts/quickinput/quickInput.ts @@ -84,6 +84,7 @@ interface QuickInputUI { onDidTriggerButton: Event; ignoreFocusOut: boolean; keyMods: Writeable; + keyDownSeenSinceShown: boolean; isScreenReaderOptimized(): boolean; show(controller: QuickInput): void; setVisibilities(visibilities: Visibilities): void; @@ -216,6 +217,7 @@ class QuickInput extends Disposable implements IQuickInput { } }), ); + this.ui.keyDownSeenSinceShown = false; this.ui.show(this); this.visible = true; this.update(); @@ -554,6 +556,7 @@ class QuickPick extends QuickInput implements IQuickPi } })); this.visibleDisposables.add(this.ui.inputBox.onKeyDown(event => { + this.ui.keyDownSeenSinceShown = true; switch (event.keyCode) { case KeyCode.DownArrow: this.ui.list.focus('Next'); @@ -652,7 +655,7 @@ class QuickPick extends QuickInput implements IQuickPi private registerQuickNavigation() { return dom.addDisposableListener(this.ui.container, dom.EventType.KEY_UP, e => { - if (this.canSelectMany || !this.quickNavigate) { + if (this.canSelectMany || !this.quickNavigate || !this.ui.keyDownSeenSinceShown) { return; } @@ -1111,6 +1114,7 @@ export class QuickInputService extends Component implements IQuickInputService { inputBox.setFocus(); })); this._register(dom.addDisposableListener(container, dom.EventType.KEY_DOWN, (e: KeyboardEvent) => { + this.getUI().keyDownSeenSinceShown = true; const event = new StandardKeyboardEvent(e); switch (event.keyCode) { case KeyCode.Enter: @@ -1172,6 +1176,7 @@ export class QuickInputService extends Component implements IQuickInputService { onDidTriggerButton: this.onDidTriggerButtonEmitter.event, ignoreFocusOut: false, keyMods: this.keyMods, + keyDownSeenSinceShown: false, isScreenReaderOptimized: () => this.isScreenReaderOptimized(), show: controller => this.show(controller), hide: () => this.hide(), From 7e333135dd2591b2bca9a52cdd0fad2683f577ad Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Tue, 12 Nov 2019 11:28:48 +0100 Subject: [PATCH 101/352] often set selection range for TS document symbols, #84576 --- .../src/features/documentSymbol.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/extensions/typescript-language-features/src/features/documentSymbol.ts b/extensions/typescript-language-features/src/features/documentSymbol.ts index abcd43238a12b..7145bbd47c345 100644 --- a/extensions/typescript-language-features/src/features/documentSymbol.ts +++ b/extensions/typescript-language-features/src/features/documentSymbol.ts @@ -66,12 +66,13 @@ class TypeScriptDocumentSymbolProvider implements vscode.DocumentSymbolProvider const children = new Set(item.childItems || []); for (const span of item.spans) { const range = typeConverters.Range.fromTextSpan(span); + const selectionRange = item.nameSpan ? typeConverters.Range.fromTextSpan(item.nameSpan) : range; const symbolInfo = new vscode.DocumentSymbol( item.text, '', getSymbolKind(item.kind), range, - range); + range.contains(selectionRange) ? selectionRange : range); for (const child of children) { if (child.spans.some(span => !!range.intersection(typeConverters.Range.fromTextSpan(span)))) { From 87683bddd2cd07870b59d2161b3c752966e21dee Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Tue, 12 Nov 2019 11:29:27 +0100 Subject: [PATCH 102/352] select containing element before selecting next/prev --- src/vs/editor/contrib/documentSymbols/outlineNavigation.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/vs/editor/contrib/documentSymbols/outlineNavigation.ts b/src/vs/editor/contrib/documentSymbols/outlineNavigation.ts index 0c92b2fdd5800..3606e36795202 100644 --- a/src/vs/editor/contrib/documentSymbols/outlineNavigation.ts +++ b/src/vs/editor/contrib/documentSymbols/outlineNavigation.ts @@ -143,8 +143,10 @@ export class OutlineNavigation implements IEditorContribution { return; } - let nav = Navigator.for(element); - let nextElement = nav.navigate(up); + let nextElement: TreeElement | undefined = element; + if (Range.containsPosition(element.symbol.selectionRange, position)) { + nextElement = Navigator.for(element).navigate(up); + } if (nextElement instanceof OutlineElement) { const pos = Range.lift(nextElement.symbol.selectionRange).getStartPosition(); From a7d466093bc6eea36a07ff6e312f7c652dca50e6 Mon Sep 17 00:00:00 2001 From: isidor Date: Tue, 12 Nov 2019 11:37:37 +0100 Subject: [PATCH 103/352] Zen mode react on silentNotifcations setting change fixes #83535 --- src/vs/workbench/browser/layout.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/vs/workbench/browser/layout.ts b/src/vs/workbench/browser/layout.ts index 24ebadeba87ef..81fd79a40a4f4 100644 --- a/src/vs/workbench/browser/layout.ts +++ b/src/vs/workbench/browser/layout.ts @@ -747,6 +747,13 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi if (config.silentNotifications) { this.notificationService.setFilter(NotificationsFilter.ERROR); } + this.state.zenMode.transitionDisposables.add(this.configurationService.onDidChangeConfiguration(c => { + const silentNotificationsKey = 'zenMode.silentNotifications'; + if (c.affectsConfiguration(silentNotificationsKey)) { + const filter = this.configurationService.getValue(silentNotificationsKey) ? NotificationsFilter.ERROR : NotificationsFilter.OFF; + this.notificationService.setFilter(filter); + } + })); if (config.centerLayout) { this.centerEditorLayout(true, true); From a2e9c12994620f6a55dd5df34d49044c6ee84488 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Tue, 12 Nov 2019 11:42:34 +0100 Subject: [PATCH 104/352] use isFile-info instead of defaulting to FileType.File, fixes #84524 --- .../api/browser/mainThreadFileSystem.ts | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/src/vs/workbench/api/browser/mainThreadFileSystem.ts b/src/vs/workbench/api/browser/mainThreadFileSystem.ts index fa8c5bdaf7ed7..4a26a90cd76d4 100644 --- a/src/vs/workbench/api/browser/mainThreadFileSystem.ts +++ b/src/vs/workbench/api/browser/mainThreadFileSystem.ts @@ -55,7 +55,7 @@ export class MainThreadFileSystem implements MainThreadFileSystemShape { ctime: stat.ctime, mtime: stat.mtime, size: stat.size, - type: MainThreadFileSystem._getFileType(stat) + type: MainThreadFileSystem._asFileType(stat) }; }).catch(MainThreadFileSystem._handleError); } @@ -67,12 +67,22 @@ export class MainThreadFileSystem implements MainThreadFileSystemShape { err.name = FileSystemProviderErrorCode.FileNotADirectory; throw err; } - return !stat.children ? [] : stat.children.map(child => [child.name, MainThreadFileSystem._getFileType(child)] as [string, FileType]); + return !stat.children ? [] : stat.children.map(child => [child.name, MainThreadFileSystem._asFileType(child)] as [string, FileType]); }).catch(MainThreadFileSystem._handleError); } - private static _getFileType(stat: IFileStat): FileType { - return (stat.isDirectory ? FileType.Directory : FileType.File) + (stat.isSymbolicLink ? FileType.SymbolicLink : 0); + private static _asFileType(stat: IFileStat): FileType { + let res = 0; + if (stat.isFile) { + res += FileType.File; + + } else if (stat.isDirectory) { + res += FileType.Directory; + } + if (stat.isSymbolicLink) { + res += FileType.SymbolicLink; + } + return res; } $readFile(uri: UriComponents): Promise { From 6f1d6c5c565d8f55dcd63fde245a37d6888f1eeb Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Tue, 12 Nov 2019 11:46:06 +0100 Subject: [PATCH 105/352] one more fix for #84201 --- extensions/git/src/git.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/extensions/git/src/git.ts b/extensions/git/src/git.ts index 6d54fb4db21bb..7066ae2a9ffbb 100644 --- a/extensions/git/src/git.ts +++ b/extensions/git/src/git.ts @@ -1819,8 +1819,11 @@ export class Repository { } // Else, remove all lines starting with whitespace followed by `#`. - //TODO: Support core.commentChar - return message.replace(/^\s*#.*$\n?/gm, '').trim(); + // TODO: Support core.commentChar + return message.replace(/^(\s*#)(.*)$(\n?)/gm, (_, prefix, content, suffix) => { + // https://github.com/microsoft/vscode/issues/84201#issuecomment-552834814 + return /^\d+(\s|$)/.test(content) ? `${prefix}${content}${suffix}` : ''; + }).trim(); } async getMergeMessage(): Promise { From 4583277fbdafb01b1ccb537855fc130fb2d73847 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Tue, 12 Nov 2019 12:11:15 +0100 Subject: [PATCH 106/352] continuation of #84201 --- extensions/git/src/git.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/git/src/git.ts b/extensions/git/src/git.ts index 7066ae2a9ffbb..a710a539c2917 100644 --- a/extensions/git/src/git.ts +++ b/extensions/git/src/git.ts @@ -1822,7 +1822,7 @@ export class Repository { // TODO: Support core.commentChar return message.replace(/^(\s*#)(.*)$(\n?)/gm, (_, prefix, content, suffix) => { // https://github.com/microsoft/vscode/issues/84201#issuecomment-552834814 - return /^\d+(\s|$)/.test(content) ? `${prefix}${content}${suffix}` : ''; + return /^\d/.test(content) ? `${prefix}${content}${suffix}` : ''; }).trim(); } From a1913036404fae80ba2eae76069499eb54f09476 Mon Sep 17 00:00:00 2001 From: isidor Date: Tue, 12 Nov 2019 12:12:27 +0100 Subject: [PATCH 107/352] fixes #84573 --- src/vs/workbench/contrib/debug/browser/callStackView.ts | 2 +- .../workbench/contrib/debug/browser/media/debugViewlet.css | 7 +++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/vs/workbench/contrib/debug/browser/callStackView.ts b/src/vs/workbench/contrib/debug/browser/callStackView.ts index 1706204f2eb75..df3cc5348631b 100644 --- a/src/vs/workbench/contrib/debug/browser/callStackView.ts +++ b/src/vs/workbench/contrib/debug/browser/callStackView.ts @@ -800,7 +800,7 @@ class DisconnectAction extends Action { private readonly session: IDebugSession, @ICommandService private readonly commandService: ICommandService ) { - super(`action.${DISCONNECT_ID}`, DISCONNECT_LABEL, 'debug-action disconnect'); + super(`action.${DISCONNECT_ID}`, DISCONNECT_LABEL, 'debug-action codicon-debug-disconnect'); } public run(): Promise { diff --git a/src/vs/workbench/contrib/debug/browser/media/debugViewlet.css b/src/vs/workbench/contrib/debug/browser/media/debugViewlet.css index 8ce5999aea8d2..9847a8b1d06ac 100644 --- a/src/vs/workbench/contrib/debug/browser/media/debugViewlet.css +++ b/src/vs/workbench/contrib/debug/browser/media/debugViewlet.css @@ -140,9 +140,7 @@ text-transform: uppercase; } -.debug-viewlet .debug-call-stack .thread:hover > .state, -.debug-viewlet .debug-call-stack .session:hover > .state, -.debug-viewlet .debug-call-stack .monaco-list-row.focused .state { +.debug-viewlet .debug-call-stack .monaco-list-row:hover .state { display: none; } @@ -159,6 +157,7 @@ width: 16px; height: 100%; margin-right: 8px; + vertical-align: text-top; } .debug-viewlet .debug-call-stack .thread > .state > .label, @@ -240,7 +239,7 @@ overflow: hidden; } -.debug-viewlet .debug-call-stack .monaco-list:focus .monaco-list-row.selected.focused .codicon { +.debug-viewlet .debug-call-stack .monaco-list:focus .monaco-list-row.selected .codicon { color: inherit !important; } From 8013616a328d760a68a6cf84df7813e614beb418 Mon Sep 17 00:00:00 2001 From: isidor Date: Tue, 12 Nov 2019 12:20:59 +0100 Subject: [PATCH 108/352] debug: remove debugMisconfiuration --- .../contrib/debug/browser/debugService.ts | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/src/vs/workbench/contrib/debug/browser/debugService.ts b/src/vs/workbench/contrib/debug/browser/debugService.ts index 1eb19f2c61dd4..031da0c11ab81 100644 --- a/src/vs/workbench/contrib/debug/browser/debugService.ts +++ b/src/vs/workbench/contrib/debug/browser/debugService.ts @@ -488,8 +488,6 @@ export class DebugService implements IDebugService { } const errorMessage = error instanceof Error ? error.message : error; - this.telemetryDebugMisconfiguration(session.configuration ? session.configuration.type : undefined, errorMessage); - await this.showError(errorMessage, isErrorWithActions(error) ? error.actions : []); return false; } @@ -1201,19 +1199,6 @@ export class DebugService implements IDebugService { }); } - private telemetryDebugMisconfiguration(debugType: string | undefined, message: string): Promise { - /* __GDPR__ - "debugMisconfiguration" : { - "type" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, - "error": { "classification": "CallstackOrException", "purpose": "FeatureInsight" } - } - */ - return this.telemetryService.publicLog('debugMisconfiguration', { - type: debugType, - error: message - }); - } - private telemetryDebugAddBreakpoint(breakpoint: IBreakpoint, context: string): Promise { /* __GDPR__ "debugAddBreakpoint" : { From 73e605653d45e8c64ee6390d5c5f5bcfabd3e7d0 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Tue, 12 Nov 2019 12:40:50 +0100 Subject: [PATCH 109/352] move navigator to outline --- src/vs/editor/editor.all.ts | 1 - .../contrib/outline/browser/outline.contribution.ts | 2 ++ .../contrib/outline/browser}/outlineNavigation.ts | 13 ++++--------- 3 files changed, 6 insertions(+), 10 deletions(-) rename src/vs/{editor/contrib/documentSymbols => workbench/contrib/outline/browser}/outlineNavigation.ts (92%) diff --git a/src/vs/editor/editor.all.ts b/src/vs/editor/editor.all.ts index a862f9accbc3f..31a6ad0497b5b 100644 --- a/src/vs/editor/editor.all.ts +++ b/src/vs/editor/editor.all.ts @@ -18,7 +18,6 @@ import 'vs/editor/contrib/comment/comment'; import 'vs/editor/contrib/contextmenu/contextmenu'; import 'vs/editor/contrib/cursorUndo/cursorUndo'; import 'vs/editor/contrib/dnd/dnd'; -import 'vs/editor/contrib/documentSymbols/outlineNavigation'; import 'vs/editor/contrib/find/findController'; import 'vs/editor/contrib/folding/folding'; import 'vs/editor/contrib/fontZoom/fontZoom'; diff --git a/src/vs/workbench/contrib/outline/browser/outline.contribution.ts b/src/vs/workbench/contrib/outline/browser/outline.contribution.ts index 494add53bf1d5..b99786acfc23d 100644 --- a/src/vs/workbench/contrib/outline/browser/outline.contribution.ts +++ b/src/vs/workbench/contrib/outline/browser/outline.contribution.ts @@ -11,6 +11,8 @@ import { Registry } from 'vs/platform/registry/common/platform'; import { IConfigurationRegistry, Extensions as ConfigurationExtensions } from 'vs/platform/configuration/common/configurationRegistry'; import { OutlineConfigKeys, OutlineViewId } from 'vs/editor/contrib/documentSymbols/outline'; +import './outlineNavigation'; + const _outlineDesc = { id: OutlineViewId, name: localize('name', "Outline"), diff --git a/src/vs/editor/contrib/documentSymbols/outlineNavigation.ts b/src/vs/workbench/contrib/outline/browser/outlineNavigation.ts similarity index 92% rename from src/vs/editor/contrib/documentSymbols/outlineNavigation.ts rename to src/vs/workbench/contrib/outline/browser/outlineNavigation.ts index 3606e36795202..7f22814d066ed 100644 --- a/src/vs/editor/contrib/documentSymbols/outlineNavigation.ts +++ b/src/vs/workbench/contrib/outline/browser/outlineNavigation.ts @@ -3,8 +3,6 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import 'vs/css!./media/outlineTree'; -import 'vs/css!./media/symbol-icons'; import { Range } from 'vs/editor/common/core/range'; import { OutlineElement, OutlineModel, TreeElement } from 'vs/editor/contrib/documentSymbols/outlineModel'; import { localize } from 'vs/nls'; @@ -17,8 +15,7 @@ import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation import { EditorContextKeys } from 'vs/editor/common/editorContextKeys'; import { values } from 'vs/base/common/collections'; import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; -import { KeyCode } from 'vs/base/common/keyCodes'; -import { KeyMod } from 'vs/editor/common/standalone/standaloneBase'; +import { KeyCode, KeyMod } from 'vs/base/common/keyCodes'; class Navigator { @@ -124,7 +121,7 @@ export class OutlineNavigation implements IEditorContribution { async goto(up: boolean) { if (this._cts) { - this._cts.cancel(); + this._cts.dispose(true); } if (!this._editor.hasModel()) { @@ -172,8 +169,7 @@ registerEditorAction(class extends EditorAction { kbExpr: EditorContextKeys.focus, primary: KeyMod.Shift | KeyMod.Alt | KeyCode.DownArrow, mac: { - primary: KeyMod.CtrlCmd | KeyMod.WinCtrl | KeyMod.Shift | KeyCode.DownArrow, - secondary: [KeyMod.WinCtrl | KeyMod.Shift | KeyCode.DownArrow], + primary: KeyMod.WinCtrl | KeyMod.Shift | KeyCode.DownArrow, }, } }); @@ -197,8 +193,7 @@ registerEditorAction(class extends EditorAction { kbExpr: EditorContextKeys.focus, primary: KeyMod.Shift | KeyMod.Alt | KeyCode.UpArrow, mac: { - primary: KeyMod.CtrlCmd | KeyMod.WinCtrl | KeyMod.Shift | KeyCode.UpArrow, - secondary: [KeyMod.WinCtrl | KeyMod.Shift | KeyCode.UpArrow], + primary: KeyMod.WinCtrl | KeyMod.Shift | KeyCode.UpArrow, }, } }); From 7ade4e64605959633a22bd65c5acf7fdd3ff1e6e Mon Sep 17 00:00:00 2001 From: Alexandru Dima Date: Tue, 12 Nov 2019 12:49:11 +0100 Subject: [PATCH 110/352] Fix #84584: Remove transform from codicons that causes them and the text in the same layer with them to be rendered using grayscale rendering --- src/vs/base/browser/ui/codiconLabel/codicon/codicon.css | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/vs/base/browser/ui/codiconLabel/codicon/codicon.css b/src/vs/base/browser/ui/codiconLabel/codicon/codicon.css index b01ce8e6e12a9..b5327ffa48353 100644 --- a/src/vs/base/browser/ui/codiconLabel/codicon/codicon.css +++ b/src/vs/base/browser/ui/codiconLabel/codicon/codicon.css @@ -19,11 +19,6 @@ user-select: none; -webkit-user-select: none; -ms-user-select: none; - - /* Hack to get web rendering to align to pixel grid */ - transform: rotate(0); - -webkit-transform: rotate(0.1deg); - -moz-transform: rotate(0); } From 655e3b3e997cbe46f0da2b1e0a246809b50f42c4 Mon Sep 17 00:00:00 2001 From: isidor Date: Tue, 12 Nov 2019 12:53:51 +0100 Subject: [PATCH 111/352] fixes 83483 --- src/vs/workbench/contrib/files/browser/views/emptyView.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/vs/workbench/contrib/files/browser/views/emptyView.ts b/src/vs/workbench/contrib/files/browser/views/emptyView.ts index f24f0128c6fcc..7d9fbe1c0347f 100644 --- a/src/vs/workbench/contrib/files/browser/views/emptyView.ts +++ b/src/vs/workbench/contrib/files/browser/views/emptyView.ts @@ -134,6 +134,10 @@ export class EmptyView extends ViewletPanel { // no-op } + focus(): void { + this.focusBody(); + } + focusBody(): void { if (this.button) { this.button.element.focus(); From 5f32c01db24732e852998d58c963cdbb3911d77a Mon Sep 17 00:00:00 2001 From: isidor Date: Tue, 12 Nov 2019 13:01:29 +0100 Subject: [PATCH 112/352] fixes #83521 --- .../contrib/files/browser/fileActions.contribution.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/contrib/files/browser/fileActions.contribution.ts b/src/vs/workbench/contrib/files/browser/fileActions.contribution.ts index 3460f9fb6bcd5..cec21f34551ab 100644 --- a/src/vs/workbench/contrib/files/browser/fileActions.contribution.ts +++ b/src/vs/workbench/contrib/files/browser/fileActions.contribution.ts @@ -471,7 +471,7 @@ MenuRegistry.appendMenuItem(MenuId.ExplorerContext, ({ id: DOWNLOAD_COMMAND_ID, title: DOWNLOAD_LABEL, }, - when: ContextKeyExpr.or(ContextKeyExpr.and(ResourceContextKey.Scheme.notEqualsTo(Schemas.file), IsWebContext.toNegated()), ContextKeyExpr.and(ResourceContextKey.Scheme.notEqualsTo(Schemas.file), ExplorerFolderContext.toNegated())) + when: ContextKeyExpr.or(ContextKeyExpr.and(ResourceContextKey.Scheme.notEqualsTo(Schemas.file), IsWebContext.toNegated()), ContextKeyExpr.and(ResourceContextKey.Scheme.notEqualsTo(Schemas.file), ExplorerFolderContext.toNegated(), ExplorerRootContext.toNegated())) })); MenuRegistry.appendMenuItem(MenuId.ExplorerContext, { @@ -495,7 +495,7 @@ MenuRegistry.appendMenuItem(MenuId.ExplorerContext, { id: ADD_ROOT_FOLDER_COMMAND_ID, title: ADD_ROOT_FOLDER_LABEL }, - when: ContextKeyExpr.and(ExplorerRootContext) + when: ExplorerRootContext }); MenuRegistry.appendMenuItem(MenuId.ExplorerContext, { From cd39e8e0a2e39e5c577953b3f95b1175415783f9 Mon Sep 17 00:00:00 2001 From: Alexandru Dima Date: Tue, 12 Nov 2019 13:55:15 +0100 Subject: [PATCH 113/352] Fixes #84565: Mark all editor layers as strictly contained (have the layers always pass the opacity check) --- src/vs/base/browser/fastDomNode.ts | 10 ++++++++++ src/vs/base/browser/ui/scrollbar/abstractScrollbar.ts | 1 + src/vs/editor/browser/viewParts/lines/viewLines.ts | 1 + src/vs/editor/browser/viewParts/margin/margin.ts | 1 + src/vs/editor/browser/viewParts/minimap/minimap.ts | 1 + .../overviewRuler/decorationsOverviewRuler.ts | 1 + .../browser/viewParts/overviewRuler/overviewRuler.ts | 1 + 7 files changed, 16 insertions(+) diff --git a/src/vs/base/browser/fastDomNode.ts b/src/vs/base/browser/fastDomNode.ts index 6dfec19f492bf..180eacdbd0ff8 100644 --- a/src/vs/base/browser/fastDomNode.ts +++ b/src/vs/base/browser/fastDomNode.ts @@ -26,6 +26,7 @@ export class FastDomNode { private _position: string; private _visibility: string; private _layerHint: boolean; + private _contain: 'none' | 'strict' | 'content' | 'size' | 'layout' | 'style' | 'paint'; constructor(domNode: T) { this.domNode = domNode; @@ -47,6 +48,7 @@ export class FastDomNode { this._position = ''; this._visibility = ''; this._layerHint = false; + this._contain = 'none'; } public setMaxWidth(maxWidth: number): void { @@ -206,6 +208,14 @@ export class FastDomNode { (this.domNode.style).willChange = this._layerHint ? 'transform' : 'auto'; } + public setContain(contain: 'none' | 'strict' | 'content' | 'size' | 'layout' | 'style' | 'paint'): void { + if (this._contain === contain) { + return; + } + this._contain = contain; + (this.domNode.style).contain = this._contain; + } + public setAttribute(name: string, value: string): void { this.domNode.setAttribute(name, value); } diff --git a/src/vs/base/browser/ui/scrollbar/abstractScrollbar.ts b/src/vs/base/browser/ui/scrollbar/abstractScrollbar.ts index 4e9245ade07cc..b1d48bc7cf824 100644 --- a/src/vs/base/browser/ui/scrollbar/abstractScrollbar.ts +++ b/src/vs/base/browser/ui/scrollbar/abstractScrollbar.ts @@ -99,6 +99,7 @@ export abstract class AbstractScrollbar extends Widget { this.slider.setHeight(height); } this.slider.setLayerHinting(true); + this.slider.setContain('strict'); this.domNode.domNode.appendChild(this.slider.domNode); diff --git a/src/vs/editor/browser/viewParts/lines/viewLines.ts b/src/vs/editor/browser/viewParts/lines/viewLines.ts index 852d612598508..00b20578698fd 100644 --- a/src/vs/editor/browser/viewParts/lines/viewLines.ts +++ b/src/vs/editor/browser/viewParts/lines/viewLines.ts @@ -544,6 +544,7 @@ export class ViewLines extends ViewPart implements IVisibleLinesHost, // (3) handle scrolling this._linesContent.setLayerHinting(this._canUseLayerHinting); + this._linesContent.setContain('strict'); const adjustedScrollTop = this._context.viewLayout.getCurrentScrollTop() - viewportData.bigNumbersDelta; this._linesContent.setTop(-adjustedScrollTop); this._linesContent.setLeft(-this._context.viewLayout.getCurrentScrollLeft()); diff --git a/src/vs/editor/browser/viewParts/margin/margin.ts b/src/vs/editor/browser/viewParts/margin/margin.ts index 1208e3c56c9ab..8181e2f8aa807 100644 --- a/src/vs/editor/browser/viewParts/margin/margin.ts +++ b/src/vs/editor/browser/viewParts/margin/margin.ts @@ -78,6 +78,7 @@ export class Margin extends ViewPart { public render(ctx: RestrictedRenderingContext): void { this._domNode.setLayerHinting(this._canUseLayerHinting); + this._domNode.setContain('strict'); const adjustedScrollTop = ctx.scrollTop - ctx.bigNumbersDelta; this._domNode.setTop(-adjustedScrollTop); diff --git a/src/vs/editor/browser/viewParts/minimap/minimap.ts b/src/vs/editor/browser/viewParts/minimap/minimap.ts index 5ff05c8835888..8e50b1e0e2d0b 100644 --- a/src/vs/editor/browser/viewParts/minimap/minimap.ts +++ b/src/vs/editor/browser/viewParts/minimap/minimap.ts @@ -503,6 +503,7 @@ export class Minimap extends ViewPart { this._slider.setPosition('absolute'); this._slider.setClassName('minimap-slider'); this._slider.setLayerHinting(true); + this._slider.setContain('strict'); this._domNode.appendChild(this._slider); this._sliderHorizontal = createFastDomNode(document.createElement('div')); diff --git a/src/vs/editor/browser/viewParts/overviewRuler/decorationsOverviewRuler.ts b/src/vs/editor/browser/viewParts/overviewRuler/decorationsOverviewRuler.ts index a4e988745cbc9..687b9985268b1 100644 --- a/src/vs/editor/browser/viewParts/overviewRuler/decorationsOverviewRuler.ts +++ b/src/vs/editor/browser/viewParts/overviewRuler/decorationsOverviewRuler.ts @@ -215,6 +215,7 @@ export class DecorationsOverviewRuler extends ViewPart { this._domNode.setClassName('decorationsOverviewRuler'); this._domNode.setPosition('absolute'); this._domNode.setLayerHinting(true); + this._domNode.setContain('strict'); this._domNode.setAttribute('aria-hidden', 'true'); this._updateSettings(false); diff --git a/src/vs/editor/browser/viewParts/overviewRuler/overviewRuler.ts b/src/vs/editor/browser/viewParts/overviewRuler/overviewRuler.ts index 7b9ef090d2a5d..b75ba0ae4223c 100644 --- a/src/vs/editor/browser/viewParts/overviewRuler/overviewRuler.ts +++ b/src/vs/editor/browser/viewParts/overviewRuler/overviewRuler.ts @@ -26,6 +26,7 @@ export class OverviewRuler extends ViewEventHandler implements IOverviewRuler { this._domNode.setClassName(cssClassName); this._domNode.setPosition('absolute'); this._domNode.setLayerHinting(true); + this._domNode.setContain('strict'); this._zoneManager = new OverviewZoneManager((lineNumber: number) => this._context.viewLayout.getVerticalOffsetForLineNumber(lineNumber)); this._zoneManager.setDOMWidth(0); From 57ddcfd7923f8df0f5c6f09a0041e2dcab91142b Mon Sep 17 00:00:00 2001 From: Christof Marti Date: Tue, 12 Nov 2019 14:40:07 +0100 Subject: [PATCH 114/352] Only update visibilities when visible (#84125) --- src/vs/workbench/browser/parts/quickinput/quickInput.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/vs/workbench/browser/parts/quickinput/quickInput.ts b/src/vs/workbench/browser/parts/quickinput/quickInput.ts index 529f2a9c95f28..4b365e66ae144 100644 --- a/src/vs/workbench/browser/parts/quickinput/quickInput.ts +++ b/src/vs/workbench/browser/parts/quickinput/quickInput.ts @@ -702,11 +702,11 @@ class QuickPick extends QuickInput implements IQuickPi } protected update() { - this.ui.setVisibilities(this.canSelectMany ? { title: !!this.title || !!this.step, checkAll: true, inputBox: true, visibleCount: true, count: true, ok: true, list: true, message: !!this.validationMessage } : { title: !!this.title || !!this.step, inputBox: true, visibleCount: true, list: true, message: !!this.validationMessage, customButton: this.customButton, ok: this.ok }); - super.update(); if (!this.visible) { return; } + this.ui.setVisibilities(this.canSelectMany ? { title: !!this.title || !!this.step, checkAll: true, inputBox: true, visibleCount: true, count: true, ok: true, list: true, message: !!this.validationMessage } : { title: !!this.title || !!this.step, inputBox: true, visibleCount: true, list: true, message: !!this.validationMessage, customButton: this.customButton, ok: this.ok }); + super.update(); if (this.ui.inputBox.value !== this.value) { this.ui.inputBox.value = this.value; } @@ -860,11 +860,11 @@ class InputBox extends QuickInput implements IInputBox { } protected update() { - this.ui.setVisibilities({ title: !!this.title || !!this.step, inputBox: true, message: true }); - super.update(); if (!this.visible) { return; } + this.ui.setVisibilities({ title: !!this.title || !!this.step, inputBox: true, message: true }); + super.update(); if (this.ui.inputBox.value !== this.value) { this.ui.inputBox.value = this.value; } From 7a242cfc3eb7d9697dbfc0d171b61dd14f0676fd Mon Sep 17 00:00:00 2001 From: Alex Ross Date: Tue, 12 Nov 2019 15:28:06 +0100 Subject: [PATCH 115/352] Simplify switch event for remote explorer --- src/vs/workbench/browser/parts/views/viewsViewlet.ts | 7 +++---- src/vs/workbench/contrib/remote/browser/remote.ts | 8 ++------ .../services/remote/common/remoteExplorerService.ts | 3 +-- 3 files changed, 6 insertions(+), 12 deletions(-) diff --git a/src/vs/workbench/browser/parts/views/viewsViewlet.ts b/src/vs/workbench/browser/parts/views/viewsViewlet.ts index cf9681d52e0a8..874677282dd2f 100644 --- a/src/vs/workbench/browser/parts/views/viewsViewlet.ts +++ b/src/vs/workbench/browser/parts/views/viewsViewlet.ts @@ -23,7 +23,7 @@ import { DefaultPanelDndController } from 'vs/base/browser/ui/splitview/panelvie import { WorkbenchTree, IListService } from 'vs/platform/list/browser/listService'; import { IWorkbenchThemeService, IFileIconTheme } from 'vs/workbench/services/themes/common/workbenchThemeService'; import { ITreeConfiguration, ITreeOptions } from 'vs/base/parts/tree/browser/tree'; -import { Event, Emitter } from 'vs/base/common/event'; +import { Event } from 'vs/base/common/event'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService'; import { localize } from 'vs/nls'; @@ -330,10 +330,9 @@ export abstract class FilterViewContainerViewlet extends ViewContainerViewlet { private allViews: Map> = new Map(); private filterValue: string | undefined; - protected onDidChangeFilterValue: Emitter = new Emitter(); - constructor( viewletId: string, + onDidChangeFilterValue: Event, @IConfigurationService configurationService: IConfigurationService, @IWorkbenchLayoutService layoutService: IWorkbenchLayoutService, @ITelemetryService telemetryService: ITelemetryService, @@ -345,7 +344,7 @@ export abstract class FilterViewContainerViewlet extends ViewContainerViewlet { @IWorkspaceContextService contextService: IWorkspaceContextService ) { super(viewletId, `${viewletId}.state`, false, configurationService, layoutService, telemetryService, storageService, instantiationService, themeService, contextMenuService, extensionService, contextService); - this._register(this.onDidChangeFilterValue.event(newFilterValue => { + this._register(onDidChangeFilterValue(newFilterValue => { this.filterValue = newFilterValue; this.onFilterChanged(newFilterValue); })); diff --git a/src/vs/workbench/contrib/remote/browser/remote.ts b/src/vs/workbench/contrib/remote/browser/remote.ts index f87cdc9515a17..5a334ade80781 100644 --- a/src/vs/workbench/contrib/remote/browser/remote.ts +++ b/src/vs/workbench/contrib/remote/browser/remote.ts @@ -381,9 +381,9 @@ export class RemoteViewlet extends FilterViewContainerViewlet implements IViewMo @IThemeService themeService: IThemeService, @IContextMenuService contextMenuService: IContextMenuService, @IExtensionService extensionService: IExtensionService, - @IRemoteExplorerService private readonly remoteExplorerService: IRemoteExplorerService + @IRemoteExplorerService remoteExplorerService: IRemoteExplorerService ) { - super(VIEWLET_ID, configurationService, layoutService, telemetryService, storageService, instantiationService, themeService, contextMenuService, extensionService, contextService); + super(VIEWLET_ID, remoteExplorerService.onDidChangeTargetType, configurationService, layoutService, telemetryService, storageService, instantiationService, themeService, contextMenuService, extensionService, contextService); this.addConstantViewDescriptors([this.helpPanelDescriptor]); remoteHelpExtPoint.setHandler((extensions) => { let helpInformation: HelpInformation[] = []; @@ -400,10 +400,6 @@ export class RemoteViewlet extends FilterViewContainerViewlet implements IViewMo viewsRegistry.deregisterViews([this.helpPanelDescriptor], VIEW_CONTAINER); } }); - - this._register(this.remoteExplorerService.onDidChangeTargetType(() => { - this.onDidChangeFilterValue.fire(this.remoteExplorerService.targetType); - })); } protected getFilterOn(viewDescriptor: IViewDescriptor): string | undefined { diff --git a/src/vs/workbench/services/remote/common/remoteExplorerService.ts b/src/vs/workbench/services/remote/common/remoteExplorerService.ts index 7e3d66db8f22b..da27dccfb2e66 100644 --- a/src/vs/workbench/services/remote/common/remoteExplorerService.ts +++ b/src/vs/workbench/services/remote/common/remoteExplorerService.ts @@ -23,9 +23,8 @@ class RemoteExplorerService implements IRemoteExplorerService { set targetType(name: string) { if (this._targetType !== name) { - const oldTarget = this._targetType; this._targetType = name; - this._onDidChangeTargetType.fire(oldTarget); + this._onDidChangeTargetType.fire(this._targetType); } } get targetType(): string { From 72da3e4c35892369a55c187802f697c5c7a9b994 Mon Sep 17 00:00:00 2001 From: Vladislav Hadzhiyski Date: Tue, 12 Nov 2019 16:31:52 +0200 Subject: [PATCH 116/352] Fix #83940 (#84414) * Add custom "Open with" message to installer script Supported languages: de, en, es, fr, hu, it, pt-br, ru * Fix typo in build/win32/i18n/messages.en.isl Co-Authored-By: jaqra <48099350+jaqra@users.noreply.github.com> * Add tr translation for OpenWithCodeContextMenu * Update translations to be consistent with "AddContextMenuFiles" translation * Fix file encoding * Fix asian lang files * Add translations for Japanese & Chinese * Fix file endings * Remove newline at end of i18n files * Add OpenWith translations without changing the file encoding --- build/win32/code.iss | 4 ++-- build/win32/i18n/messages.de.isl | 3 ++- build/win32/i18n/messages.en.isl | 3 ++- build/win32/i18n/messages.es.isl | 3 ++- build/win32/i18n/messages.fr.isl | 3 ++- build/win32/i18n/messages.hu.isl | 3 ++- build/win32/i18n/messages.it.isl | 3 ++- build/win32/i18n/messages.ja.isl | 3 ++- build/win32/i18n/messages.ko.isl | 3 ++- build/win32/i18n/messages.pt-br.isl | 3 ++- build/win32/i18n/messages.ru.isl | 3 ++- build/win32/i18n/messages.tr.isl | 3 ++- build/win32/i18n/messages.zh-cn.isl | 3 ++- build/win32/i18n/messages.zh-tw.isl | 3 ++- 14 files changed, 28 insertions(+), 15 deletions(-) diff --git a/build/win32/code.iss b/build/win32/code.iss index ee70efb974d02..0e2ed70d64ac0 100644 --- a/build/win32/code.iss +++ b/build/win32/code.iss @@ -957,10 +957,10 @@ Root: {#SoftwareClassesRootKey}; Subkey: "Software\Classes\Applications\{#ExeBas Root: {#SoftwareClassesRootKey}; Subkey: "Software\Classes\Applications\{#ExeBasename}.exe\DefaultIcon"; ValueType: string; ValueName: ""; ValueData: "{app}\resources\app\resources\win32\default.ico" Root: {#SoftwareClassesRootKey}; Subkey: "Software\Classes\Applications\{#ExeBasename}.exe\shell\open\command"; ValueType: string; ValueName: ""; ValueData: """{app}\{#ExeBasename}.exe"" ""%1""" -Root: {#SoftwareClassesRootKey}; Subkey: "Software\Classes\*\shell\{#RegValueName}"; ValueType: expandsz; ValueName: ""; ValueData: "Open w&ith {#ShellNameShort}"; Tasks: addcontextmenufiles; Flags: uninsdeletekey +Root: {#SoftwareClassesRootKey}; Subkey: "Software\Classes\*\shell\{#RegValueName}"; ValueType: expandsz; ValueName: ""; ValueData: "{cm:OpenWithCodeContextMenu, {#ShellNameShort}}"; Tasks: addcontextmenufiles; Flags: uninsdeletekey Root: {#SoftwareClassesRootKey}; Subkey: "Software\Classes\*\shell\{#RegValueName}"; ValueType: expandsz; ValueName: "Icon"; ValueData: "{app}\{#ExeBasename}.exe"; Tasks: addcontextmenufiles Root: {#SoftwareClassesRootKey}; Subkey: "Software\Classes\*\shell\{#RegValueName}\command"; ValueType: expandsz; ValueName: ""; ValueData: """{app}\{#ExeBasename}.exe"" ""%1"""; Tasks: addcontextmenufiles -Root: {#SoftwareClassesRootKey}; Subkey: "Software\Classes\directory\shell\{#RegValueName}"; ValueType: expandsz; ValueName: ""; ValueData: "Open w&ith {#ShellNameShort}"; Tasks: addcontextmenufolders; Flags: uninsdeletekey +Root: {#SoftwareClassesRootKey}; Subkey: "Software\Classes\directory\shell\{#RegValueName}"; ValueType: expandsz; ValueName: ""; ValueData: "{cm:OpenWithCodeContextMenu, {#ShellNameShort}}"; Tasks: addcontextmenufolders; Flags: uninsdeletekey Root: {#SoftwareClassesRootKey}; Subkey: "Software\Classes\directory\shell\{#RegValueName}"; ValueType: expandsz; ValueName: "Icon"; ValueData: "{app}\{#ExeBasename}.exe"; Tasks: addcontextmenufolders Root: {#SoftwareClassesRootKey}; Subkey: "Software\Classes\directory\shell\{#RegValueName}\command"; ValueType: expandsz; ValueName: ""; ValueData: """{app}\{#ExeBasename}.exe"" ""%V"""; Tasks: addcontextmenufolders Root: {#SoftwareClassesRootKey}; Subkey: "Software\Classes\directory\background\shell\{#RegValueName}"; ValueType: expandsz; ValueName: ""; ValueData: "Open w&ith {#ShellNameShort}"; Tasks: addcontextmenufolders; Flags: uninsdeletekey diff --git a/build/win32/i18n/messages.de.isl b/build/win32/i18n/messages.de.isl index 755652bcdbe95..6a9f29aa9c27e 100644 --- a/build/win32/i18n/messages.de.isl +++ b/build/win32/i18n/messages.de.isl @@ -5,4 +5,5 @@ AssociateWithFiles=%1 als Editor f AddToPath=Zu PATH hinzufügen (nach dem Neustart verfügbar) RunAfter=%1 nach der Installation ausführen Other=Andere: -SourceFile=%1-Quelldatei \ No newline at end of file +SourceFile=%1-Quelldatei +OpenWithCodeContextMenu=Mit %1 öffnen \ No newline at end of file diff --git a/build/win32/i18n/messages.en.isl b/build/win32/i18n/messages.en.isl index a6aab59b95a97..6535824eed674 100644 --- a/build/win32/i18n/messages.en.isl +++ b/build/win32/i18n/messages.en.isl @@ -5,4 +5,5 @@ AssociateWithFiles=Register %1 as an editor for supported file types AddToPath=Add to PATH (requires shell restart) RunAfter=Run %1 after installation Other=Other: -SourceFile=%1 Source File \ No newline at end of file +SourceFile=%1 Source File +OpenWithCodeContextMenu=Open with %1 \ No newline at end of file diff --git a/build/win32/i18n/messages.es.isl b/build/win32/i18n/messages.es.isl index e8d5af64b6193..e51f099f9a136 100644 --- a/build/win32/i18n/messages.es.isl +++ b/build/win32/i18n/messages.es.isl @@ -5,4 +5,5 @@ AssociateWithFiles=Registrar %1 como editor para tipos de archivo admitidos AddToPath=Agregar a PATH (disponible después de reiniciar) RunAfter=Ejecutar %1 después de la instalación Other=Otros: -SourceFile=Archivo de origen %1 \ No newline at end of file +SourceFile=Archivo de origen %1 +OpenWithCodeContextMenu=Abrir con %1 \ No newline at end of file diff --git a/build/win32/i18n/messages.fr.isl b/build/win32/i18n/messages.fr.isl index 3e17036f80673..df14041862513 100644 --- a/build/win32/i18n/messages.fr.isl +++ b/build/win32/i18n/messages.fr.isl @@ -5,4 +5,5 @@ AssociateWithFiles=Inscrire %1 en tant qu' AddToPath=Ajouter à PATH (disponible après le redémarrage) RunAfter=Exécuter %1 après l'installation Other=Autre : -SourceFile=Fichier source %1 \ No newline at end of file +SourceFile=Fichier source %1 +OpenWithCodeContextMenu=Ouvrir avec %1 \ No newline at end of file diff --git a/build/win32/i18n/messages.hu.isl b/build/win32/i18n/messages.hu.isl index f141ad1b24ad6..b64553da8e6de 100644 --- a/build/win32/i18n/messages.hu.isl +++ b/build/win32/i18n/messages.hu.isl @@ -5,4 +5,5 @@ AssociateWithFiles=%1 regisztr AddToPath=Hozzáadás a PATH-hoz (újraindítás után lesz elérhetõ) RunAfter=%1 indítása a telepítés után Other=Egyéb: -SourceFile=%1 forrásfájl \ No newline at end of file +SourceFile=%1 forrásfájl +OpenWithCodeContextMenu=Megnyitás a következõvel: %1 \ No newline at end of file diff --git a/build/win32/i18n/messages.it.isl b/build/win32/i18n/messages.it.isl index 7ad8a0622d45a..08248c4ce1ba8 100644 --- a/build/win32/i18n/messages.it.isl +++ b/build/win32/i18n/messages.it.isl @@ -5,4 +5,5 @@ AssociateWithFiles=Registra %1 come editor per i tipi di file supportati AddToPath=Aggiungi a PATH (disponibile dopo il riavvio) RunAfter=Esegui %1 dopo l'installazione Other=Altro: -SourceFile=File di origine %1 \ No newline at end of file +SourceFile=File di origine %1 +OpenWithCodeContextMenu=Apri con %1 \ No newline at end of file diff --git a/build/win32/i18n/messages.ja.isl b/build/win32/i18n/messages.ja.isl index 3a16aaa204e97..9675060e94afd 100644 --- a/build/win32/i18n/messages.ja.isl +++ b/build/win32/i18n/messages.ja.isl @@ -5,4 +5,5 @@ AssociateWithFiles= AddToPath=PATH ‚ւ̒ljÁiÄ‹N“®Œã‚ÉŽg—p‰Â”\j RunAfter=ƒCƒ“ƒXƒg[ƒ‹Œã‚É %1 ‚ðŽÀs‚·‚é Other=‚»‚Ì‘¼: -SourceFile=%1 ƒ\[ƒX ƒtƒ@ƒCƒ‹ \ No newline at end of file +SourceFile=%1 ƒ\[ƒX ƒtƒ@ƒCƒ‹ +OpenWithCodeContextMenu=%1 ‚ÅŠJ‚­ \ No newline at end of file diff --git a/build/win32/i18n/messages.ko.isl b/build/win32/i18n/messages.ko.isl index 28860c36b633e..5a510558bbd2b 100644 --- a/build/win32/i18n/messages.ko.isl +++ b/build/win32/i18n/messages.ko.isl @@ -5,4 +5,5 @@ AssociateWithFiles=%1 AddToPath=PATH¿¡ Ãß°¡(´Ù½Ã ½ÃÀÛÇÑ ÈÄ »ç¿ë °¡´É) RunAfter=¼³Ä¡ ÈÄ %1 ½ÇÇà Other=±âŸ: -SourceFile=%1 ¿øº» ÆÄÀÏ \ No newline at end of file +SourceFile=%1 ¿øº» ÆÄÀÏ +OpenWithCodeContextMenu=%1(À¸)·Î ¿­±â \ No newline at end of file diff --git a/build/win32/i18n/messages.pt-br.isl b/build/win32/i18n/messages.pt-br.isl index d534637f8b613..e327e8fd1a066 100644 --- a/build/win32/i18n/messages.pt-br.isl +++ b/build/win32/i18n/messages.pt-br.isl @@ -5,4 +5,5 @@ AssociateWithFiles=Registre %1 como um editor para tipos de arquivos suportados AddToPath=Adicione em PATH (disponível após reiniciar) RunAfter=Executar %1 após a instalação Other=Outros: -SourceFile=Arquivo Fonte %1 \ No newline at end of file +SourceFile=Arquivo Fonte %1 +OpenWithCodeContextMenu=Abrir com %1 \ No newline at end of file diff --git a/build/win32/i18n/messages.ru.isl b/build/win32/i18n/messages.ru.isl index 4d834663627e1..bca3b864a5f9e 100644 --- a/build/win32/i18n/messages.ru.isl +++ b/build/win32/i18n/messages.ru.isl @@ -5,4 +5,5 @@ AssociateWithFiles= AddToPath=Äîáàâèòü â PATH (äîñòóïíî ïîñëå ïåðåçàãðóçêè) RunAfter=Çàïóñòèòü %1 ïîñëå óñòàíîâêè Other=Äðóãîå: -SourceFile=Èñõîäíûé ôàéë %1 \ No newline at end of file +SourceFile=Èñõîäíûé ôàéë %1 +OpenWithCodeContextMenu=Îòêðûòü ñ ïîìîùüþ %1 \ No newline at end of file diff --git a/build/win32/i18n/messages.tr.isl b/build/win32/i18n/messages.tr.isl index dc241d924c7bc..b13e5e27bd2af 100644 --- a/build/win32/i18n/messages.tr.isl +++ b/build/win32/i18n/messages.tr.isl @@ -5,4 +5,5 @@ AssociateWithFiles=%1 uygulamas AddToPath=PATH'e ekle (yeniden baþlattýktan sonra kullanýlabilir) RunAfter=Kurulumdan sonra %1 uygulamasýný çalýþtýr. Other=Diðer: -SourceFile=%1 Kaynak Dosyasý \ No newline at end of file +SourceFile=%1 Kaynak Dosyasý +OpenWithCodeContextMenu=%1 Ýle Aç \ No newline at end of file diff --git a/build/win32/i18n/messages.zh-cn.isl b/build/win32/i18n/messages.zh-cn.isl index 349fc2ccc29b5..8fa136f6d5a9b 100644 --- a/build/win32/i18n/messages.zh-cn.isl +++ b/build/win32/i18n/messages.zh-cn.isl @@ -5,4 +5,5 @@ AssociateWithFiles= AddToPath=Ìí¼Óµ½ PATH (ÖØÆôºóÉúЧ) RunAfter=°²×°ºóÔËÐÐ %1 Other=ÆäËû: -SourceFile=%1 Ô´Îļþ \ No newline at end of file +SourceFile=%1 Ô´Îļþ +OpenWithCodeContextMenu=ͨ¹ý %1 ´ò¿ª \ No newline at end of file diff --git a/build/win32/i18n/messages.zh-tw.isl b/build/win32/i18n/messages.zh-tw.isl index 7c3f84aa131f5..40c5fa92d793e 100644 --- a/build/win32/i18n/messages.zh-tw.isl +++ b/build/win32/i18n/messages.zh-tw.isl @@ -5,4 +5,5 @@ AssociateWithFiles= AddToPath=¥[¤J PATH ¤¤ (­«·s±Ò°Ê«á¥Í®Ä) RunAfter=¦w¸Ë«á°õ¦æ %1 Other=¨ä¥L: -SourceFile=%1 ¨Ó·½ÀÉ®× \ No newline at end of file +SourceFile=%1 ¨Ó·½ÀÉ®× +OpenWithCodeContextMenu=¥H %1 ¶}±Ò \ No newline at end of file From cf8d61ebd2f022f4ce8280171f0360d1fe0a206d Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Tue, 12 Nov 2019 06:37:21 -0800 Subject: [PATCH 117/352] Fix #81943 --- extensions/scss/cgmanifest.json | 4 +- extensions/scss/syntaxes/scss.tmLanguage.json | 181 ++++++++++++++++-- 2 files changed, 167 insertions(+), 18 deletions(-) diff --git a/extensions/scss/cgmanifest.json b/extensions/scss/cgmanifest.json index 7d152d3d3f3aa..12247769ce224 100644 --- a/extensions/scss/cgmanifest.json +++ b/extensions/scss/cgmanifest.json @@ -6,12 +6,12 @@ "git": { "name": "atom/language-sass", "repositoryUrl": "https://github.com/atom/language-sass", - "commitHash": "d01d29191ab323fb3cf8bde9df0429f8e07902ff" + "commitHash": "f52ab12f7f9346cc2568129d8c4419bd3d506b47" } }, "license": "MIT", "description": "The file syntaxes/scss.json was derived from the Atom package https://github.com/atom/language-sass which was originally converted from the TextMate bundle https://github.com/alexsancho/SASS.tmbundle.", - "version": "0.62.0" + "version": "0.62.1" } ], "version": 1 diff --git a/extensions/scss/syntaxes/scss.tmLanguage.json b/extensions/scss/syntaxes/scss.tmLanguage.json index 5add08181f65a..21ed870a5cc3e 100644 --- a/extensions/scss/syntaxes/scss.tmLanguage.json +++ b/extensions/scss/syntaxes/scss.tmLanguage.json @@ -4,13 +4,19 @@ "If you want to provide a fix or improvement, please create a pull request against the original repository.", "Once accepted there, we are happy to receive an update request." ], - "version": "https://github.com/atom/language-sass/commit/d01d29191ab323fb3cf8bde9df0429f8e07902ff", + "version": "https://github.com/atom/language-sass/commit/f52ab12f7f9346cc2568129d8c4419bd3d506b47", "name": "SCSS", "scopeName": "source.css.scss", "patterns": [ { "include": "#variable_setting" }, + { + "include": "#at_rule_forward" + }, + { + "include": "#at_rule_use" + }, { "include": "#at_rule_include" }, @@ -239,6 +245,55 @@ } ] }, + "at_rule_forward": { + "begin": "\\s*((@)forward\\b)\\s*", + "captures": { + "1": { + "name": "keyword.control.at-rule.forward.scss" + }, + "2": { + "name": "punctuation.definition.keyword.scss" + } + }, + "end": "\\s*(?=;)", + "name": "meta.at-rule.forward.scss", + "patterns": [ + { + "match": "\\b(as|hide|show)\\b", + "name": "keyword.control.operator" + }, + { + "match": "\\b([\\w-]+)(\\*)", + "captures": { + "1": { + "name": "entity.other.attribute-name.module.scss" + }, + "2": { + "name": "punctuation.definition.wildcard.scss" + } + } + }, + { + "match": "\\b[\\w-]+\\b", + "name": "entity.name.function.scss" + }, + { + "include": "#variable" + }, + { + "include": "#string_single" + }, + { + "include": "#string_double" + }, + { + "include": "#comment_line" + }, + { + "include": "#comment_block" + } + ] + }, "at_rule_function": { "patterns": [ { @@ -336,12 +391,18 @@ "at_rule_include": { "patterns": [ { - "begin": "(?<=@include)\\s+([\\w-]+)\\s*(\\()", + "begin": "(?<=@include)\\s+(?:([\\w-]+)\\s*(\\.))?([\\w-]+)\\s*(\\()", "beginCaptures": { "1": { - "name": "entity.name.function.scss" + "name": "variable.scss" }, "2": { + "name": "punctuation.access.module.scss" + }, + "3": { + "name": "entity.name.function.scss" + }, + "4": { "name": "punctuation.definition.parameters.begin.bracket.round.scss" } }, @@ -359,12 +420,18 @@ ] }, { - "match": "(?<=@include)\\s+([\\w-]+)", + "match": "(?<=@include)\\s+(?:([\\w-]+)\\s*(\\.))?([\\w-]+)", "captures": { "0": { "name": "meta.at-rule.include.scss" }, "1": { + "name": "variable.scss" + }, + "2": { + "name": "punctuation.access.module.scss" + }, + "3": { "name": "entity.name.function.scss" } } @@ -794,6 +861,64 @@ } ] }, + "at_rule_use": { + "begin": "\\s*((@)use\\b)\\s*", + "captures": { + "1": { + "name": "keyword.control.at-rule.use.scss" + }, + "2": { + "name": "punctuation.definition.keyword.scss" + } + }, + "end": "\\s*(?=;)", + "name": "meta.at-rule.use.scss", + "patterns": [ + { + "match": "\\b(as|with)\\b", + "name": "keyword.control.operator" + }, + { + "match": "\\b[\\w-]+\\b", + "name": "variable.scss" + }, + { + "match": "\\*", + "name": "variable.language.expanded-namespace.scss" + }, + { + "include": "#string_single" + }, + { + "include": "#string_double" + }, + { + "include": "#comment_line" + }, + { + "include": "#comment_block" + }, + { + "begin": "\\(", + "beginCaptures": { + "0": { + "name": "punctuation.definition.parameters.begin.bracket.round.scss" + } + }, + "end": "\\)", + "endCaptures": { + "0": { + "name": "punctuation.definition.parameters.end.bracket.round.scss" + } + }, + "patterns": [ + { + "include": "#function_attributes" + } + ] + } + ] + }, "at_rule_warn": { "begin": "\\s*((@)(warn|debug|error)\\b)\\s*", "captures": { @@ -890,12 +1015,18 @@ "name": "keyword.other.default.scss" }, "constant_functions": { - "begin": "([\\w-]+)(\\()", + "begin": "(?:([\\w-]+)(\\.))?([\\w-]+)(\\()", "beginCaptures": { "1": { - "name": "support.function.misc.scss" + "name": "variable.scss" }, "2": { + "name": "punctuation.access.module.scss" + }, + "3": { + "name": "support.function.misc.scss" + }, + "4": { "name": "punctuation.section.function.scss" } }, @@ -1050,10 +1181,10 @@ "name": "variable.interpolation.scss", "patterns": [ { - "include": "#property_values" + "include": "#variable" }, { - "include": "#variable" + "include": "#property_values" } ] }, @@ -1118,10 +1249,10 @@ "include": "#map" }, { - "include": "#property_values" + "include": "#variable" }, { - "include": "#variable" + "include": "#property_values" } ] }, @@ -1326,7 +1457,7 @@ ] }, "selector_attribute": { - "match": "(?xi)\n(\\[)\n\\s*\n(\n (?:\n [-a-zA-Z_0-9]|[^\\x00-\\x7F] # Valid identifier characters\n | \\\\(?:[0-9a-fA-F]{1,6}|.) # Escape sequence\n | \\#\\{ # Interpolation (escaped to avoid Coffeelint errors)\n | \\$ # Possible start of interpolation variable\n | } # Possible end of interpolation\n )+?\n)\n(?:\n \\s*([~|^$*]?=)\\s*\n (?:\n (\n (?:\n [-a-zA-Z_0-9]|[^\\x00-\\x7F] # Valid identifier characters\n | \\\\(?:[0-9a-fA-F]{1,6}|.) # Escape sequence\n | \\#\\{ # Interpolation (escaped to avoid Coffeelint errors)\n | \\$ # Possible start of interpolation variable\n | } # Possible end of interpolation\n )+\n )\n |\n ((\")(.*?)(\"))\n |\n ((')(.*?)('))\n )\n)?\n\\s*\n(\\])", + "match": "(?xi)\n(\\[)\n\\s*\n(\n (?:\n [-a-zA-Z_0-9]|[^\\x00-\\x7F] # Valid identifier characters\n | \\\\(?:[0-9a-fA-F]{1,6}|.) # Escape sequence\n | \\#\\{ # Interpolation (escaped to avoid Coffeelint errors)\n | \\.?\\$ # Possible start of interpolation variable\n | } # Possible end of interpolation\n )+?\n)\n(?:\n \\s*([~|^$*]?=)\\s*\n (?:\n (\n (?:\n [-a-zA-Z_0-9]|[^\\x00-\\x7F] # Valid identifier characters\n | \\\\(?:[0-9a-fA-F]{1,6}|.) # Escape sequence\n | \\#\\{ # Interpolation (escaped to avoid Coffeelint errors)\n | \\.?\\$ # Possible start of interpolation variable\n | } # Possible end of interpolation\n )+\n )\n |\n ((\")(.*?)(\"))\n |\n ((')(.*?)('))\n )\n)?\n\\s*\n(\\])", "name": "meta.attribute-selector.scss", "captures": { "1": { @@ -1421,7 +1552,7 @@ } }, "selector_class": { - "match": "(?x)\n(\\.) # Valid class-name\n(\n (?: [-a-zA-Z_0-9]|[^\\x00-\\x7F] # Valid identifier characters\n | \\\\(?:[0-9a-fA-F]{1,6}|.) # Escape sequence\n | \\#\\{ # Interpolation (escaped to avoid Coffeelint errors)\n | \\$ # Possible start of interpolation variable\n | } # Possible end of interpolation\n )+\n) # Followed by either:\n(?= $ # - End of the line\n | [\\s,.\\#)\\[:{>+~|] # - Another selector\n | /\\* # - A block comment\n | ; # - A semicolon\n)", + "match": "(?x)\n(\\.) # Valid class-name\n(\n (?: [-a-zA-Z_0-9]|[^\\x00-\\x7F] # Valid identifier characters\n | \\\\(?:[0-9a-fA-F]{1,6}|.) # Escape sequence\n | \\#\\{ # Interpolation (escaped to avoid Coffeelint errors)\n | \\.?\\$ # Possible start of interpolation variable\n | } # Possible end of interpolation\n )+\n) # Followed by either:\n(?= $ # - End of the line\n | [\\s,\\#)\\[:{>+~|] # - Another selector\n | \\.[^$] # - Class selector, negating module variable\n | /\\* # - A block comment\n | ; # - A semicolon\n)", "name": "entity.other.attribute-name.class.css", "captures": { "1": { @@ -1449,7 +1580,7 @@ "name": "entity.name.tag.custom.scss" }, "selector_id": { - "match": "(?x)\n(\\#) # Valid id-name\n(\n (?: [-a-zA-Z_0-9]|[^\\x00-\\x7F] # Valid identifier characters\n | \\\\(?:[0-9a-fA-F]{1,6}|.) # Escape sequence\n | \\#\\{ # Interpolation (escaped to avoid Coffeelint errors)\n | \\$ # Possible start of interpolation variable\n | } # Possible end of interpolation\n )+\n) # Followed by either:\n(?= $ # - End of the line\n | [\\s,.\\#)\\[:{>+~|] # - Another selector\n | /\\* # - A block comment\n)", + "match": "(?x)\n(\\#) # Valid id-name\n(\n (?: [-a-zA-Z_0-9]|[^\\x00-\\x7F] # Valid identifier characters\n | \\\\(?:[0-9a-fA-F]{1,6}|.) # Escape sequence\n | \\#\\{ # Interpolation (escaped to avoid Coffeelint errors)\n | \\.?\\$ # Possible start of interpolation variable\n | } # Possible end of interpolation\n )+\n) # Followed by either:\n(?= $ # - End of the line\n | [\\s,\\#)\\[:{>+~|] # - Another selector\n | \\.[^$] # - Class selector, negating module variable\n | /\\* # - A block comment\n)", "name": "entity.other.attribute-name.id.css", "captures": { "1": { @@ -1473,7 +1604,7 @@ } }, "selector_placeholder": { - "match": "(?x)\n(%) # Valid placeholder-name\n(\n (?: [-a-zA-Z_0-9]|[^\\x00-\\x7F] # Valid identifier characters\n | \\\\(?:[0-9a-fA-F]{1,6}|.) # Escape sequence\n | \\#\\{ # Interpolation (escaped to avoid Coffeelint errors)\n | \\$ # Possible start of interpolation variable\n | } # Possible end of interpolation\n )+\n) # Followed by either:\n(?= ; # - End of statement\n | $ # - End of the line\n | [\\s,.\\#)\\[:{>+~|] # - Another selector\n | /\\* # - A block comment\n)", + "match": "(?x)\n(%) # Valid placeholder-name\n(\n (?: [-a-zA-Z_0-9]|[^\\x00-\\x7F] # Valid identifier characters\n | \\\\(?:[0-9a-fA-F]{1,6}|.) # Escape sequence\n | \\#\\{ # Interpolation (escaped to avoid Coffeelint errors)\n | \\.\\$ # Possible start of interpolation module scope variable\n | \\$ # Possible start of interpolation variable\n | } # Possible end of interpolation\n )+\n) # Followed by either:\n(?= ; # - End of statement\n | $ # - End of the line\n | [\\s,\\#)\\[:{>+~|] # - Another selector\n | \\.[^$] # - Class selector, negating module variable\n | /\\* # - A block comment\n)", "name": "entity.other.attribute-name.placeholder.css", "captures": { "1": { @@ -1723,8 +1854,26 @@ ] }, "variables": { - "match": "(\\$|\\-\\-)[A-Za-z0-9_-]+\\b", - "name": "variable.scss" + "patterns": [ + { + "match": "\\b([\\w-]+)(\\.)(\\$[\\w-]+)\\b", + "captures": { + "1": { + "name": "variable.scss" + }, + "2": { + "name": "punctuation.access.module.scss" + }, + "3": { + "name": "variable.scss" + } + } + }, + { + "match": "(\\$|\\-\\-)[A-Za-z0-9_-]+\\b", + "name": "variable.scss" + } + ] } } } \ No newline at end of file From dae6c27e334fa10b0c2bc88b384db5bbb9850db4 Mon Sep 17 00:00:00 2001 From: Martin Aeschlimann Date: Tue, 12 Nov 2019 15:38:04 +0100 Subject: [PATCH 118/352] always send exeExtensionRecommendations:alreadyInstalled --- .../browser/extensionTipsService.ts | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/vs/workbench/contrib/extensions/browser/extensionTipsService.ts b/src/vs/workbench/contrib/extensions/browser/extensionTipsService.ts index e7b3de3e4c103..722c6fb9e9d8e 100644 --- a/src/vs/workbench/contrib/extensions/browser/extensionTipsService.ts +++ b/src/vs/workbench/contrib/extensions/browser/extensionTipsService.ts @@ -506,15 +506,6 @@ export class ExtensionTipsService extends Disposable implements IExtensionTipsSe private async promptForImportantExeBasedExtension(): Promise { - const storageKey = 'extensionsAssistant/workspaceRecommendationsIgnore'; - const config = this.configurationService.getValue(ConfigurationKey); - - if (config.ignoreRecommendations - || config.showRecommendationsOnlyOnDemand - || this.storageService.getBoolean(storageKey, StorageScope.WORKSPACE, false)) { - return false; - } - let recommendationsToSuggest = Object.keys(this._importantExeBasedRecommendations); const installed = await this.extensionManagementService.getInstalled(ExtensionType.User); @@ -527,13 +518,23 @@ export class ExtensionTipsService extends Disposable implements IExtensionTipsSe "exeName": { "classification": "PublicNonPersonalData", "purpose": "FeatureInsight" } } */ - this.telemetryService.publicLog('exeExtensionRecommendations:alreadyInstalled', { extensionId, exeName: tip.exeFriendlyName || basename(tip.windowsPath!) }); + this.telemetryService.publicLog('exeExtensionRecommendations:alreadyInstalled', { extensionId, exeName: basename(tip.windowsPath!) }); }); + if (recommendationsToSuggest.length === 0) { return false; } + const storageKey = 'extensionsAssistant/workspaceRecommendationsIgnore'; + const config = this.configurationService.getValue(ConfigurationKey); + + if (config.ignoreRecommendations + || config.showRecommendationsOnlyOnDemand + || this.storageService.getBoolean(storageKey, StorageScope.WORKSPACE, false)) { + return false; + } + recommendationsToSuggest = this.filterIgnoredOrNotAllowed(recommendationsToSuggest); if (recommendationsToSuggest.length === 0) { return false; From 12b7d0aafeaaa65e683e9289126bc75db2278c5c Mon Sep 17 00:00:00 2001 From: Martin Aeschlimann Date: Tue, 12 Nov 2019 16:05:13 +0100 Subject: [PATCH 119/352] window.showOpenDialog throws "TypeError: Default path must be a string" with defaultUri = null. Fixes #84325 --- src/vs/workbench/api/browser/mainThreadDialogs.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/vs/workbench/api/browser/mainThreadDialogs.ts b/src/vs/workbench/api/browser/mainThreadDialogs.ts index b4e38d566987b..94ab09b7eba1b 100644 --- a/src/vs/workbench/api/browser/mainThreadDialogs.ts +++ b/src/vs/workbench/api/browser/mainThreadDialogs.ts @@ -33,11 +33,11 @@ export class MainThreadDialogs implements MainThreadDiaglogsShape { private static _convertOpenOptions(options: MainThreadDialogOpenOptions): IOpenDialogOptions { const result: IOpenDialogOptions = { - openLabel: options.openLabel, + openLabel: options.openLabel || undefined, canSelectFiles: options.canSelectFiles || (!options.canSelectFiles && !options.canSelectFolders), canSelectFolders: options.canSelectFolders, canSelectMany: options.canSelectMany, - defaultUri: URI.revive(options.defaultUri) + defaultUri: options.defaultUri ? URI.revive(options.defaultUri) : undefined }; if (options.filters) { result.filters = []; @@ -48,8 +48,8 @@ export class MainThreadDialogs implements MainThreadDiaglogsShape { private static _convertSaveOptions(options: MainThreadDialogSaveOptions): ISaveDialogOptions { const result: ISaveDialogOptions = { - defaultUri: URI.revive(options.defaultUri), - saveLabel: options.saveLabel + defaultUri: options.defaultUri ? URI.revive(options.defaultUri) : undefined, + saveLabel: options.saveLabel || undefined }; if (options.filters) { result.filters = []; From a660498d441806a1eb14bfd6f1fc92d1bc02d061 Mon Sep 17 00:00:00 2001 From: Alex Ross Date: Tue, 12 Nov 2019 16:13:52 +0100 Subject: [PATCH 120/352] Backup and restore last used remote for explorer --- .../remote/browser/explorerViewItems.ts | 36 +++++++++++-------- .../remote/common/remoteExplorerService.ts | 6 ++++ 2 files changed, 28 insertions(+), 14 deletions(-) diff --git a/src/vs/workbench/contrib/remote/browser/explorerViewItems.ts b/src/vs/workbench/contrib/remote/browser/explorerViewItems.ts index f57014a69b5c4..3cd6c869fca29 100644 --- a/src/vs/workbench/contrib/remote/browser/explorerViewItems.ts +++ b/src/vs/workbench/contrib/remote/browser/explorerViewItems.ts @@ -13,12 +13,13 @@ import { attachSelectBoxStyler, attachStylerCallback } from 'vs/platform/theme/c import { IContextViewService } from 'vs/platform/contextview/browser/contextView'; import { SIDE_BAR_BACKGROUND } from 'vs/workbench/common/theme'; import { selectBorder } from 'vs/platform/theme/common/colorRegistry'; -import { IRemoteExplorerService } from 'vs/workbench/services/remote/common/remoteExplorerService'; +import { IRemoteExplorerService, REMOTE_EXPLORER_TYPE_KEY } from 'vs/workbench/services/remote/common/remoteExplorerService'; import { ISelectOptionItem } from 'vs/base/browser/ui/selectBox/selectBox'; import { IViewDescriptor } from 'vs/workbench/common/views'; import { startsWith } from 'vs/base/common/strings'; import { isStringArray } from 'vs/base/common/types'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; +import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; export interface IRemoteSelectItem extends ISelectOptionItem { authority: string[]; @@ -34,7 +35,8 @@ export class SwitchRemoteViewItem extends SelectActionViewItem { @IThemeService private readonly themeService: IThemeService, @IContextViewService contextViewService: IContextViewService, @IRemoteExplorerService remoteExplorerService: IRemoteExplorerService, - @IWorkbenchEnvironmentService environmentService: IWorkbenchEnvironmentService + @IWorkbenchEnvironmentService environmentService: IWorkbenchEnvironmentService, + @IStorageService private readonly storageService: IStorageService ) { super(null, action, optionsItems, 0, contextViewService, { ariaLabel: nls.localize('remotes', 'Switch Remote') }); this._register(attachSelectBoxStyler(this.selectBox, themeService, { @@ -45,26 +47,32 @@ export class SwitchRemoteViewItem extends SelectActionViewItem { } private setSelectionForConnection(optionsItems: IRemoteSelectItem[], environmentService: IWorkbenchEnvironmentService, remoteExplorerService: IRemoteExplorerService) { - // TODO: set from saved state if (this.optionsItems.length > 0) { - const remoteAuthority = environmentService.configuration.remoteAuthority; let index = 0; - if (remoteAuthority) { - const actualRemoteAuthority = remoteAuthority.split('+')[0]; - for (let optionIterator = 0; (optionIterator < this.optionsItems.length) && (index === 0); optionIterator++) { - for (let authorityIterator = 0; authorityIterator < optionsItems[optionIterator].authority.length; authorityIterator++) { - if (optionsItems[optionIterator].authority[authorityIterator] === actualRemoteAuthority) { - index = optionIterator; - break; - } - } - } + const remoteAuthority = environmentService.configuration.remoteAuthority; + const explorerType: string | undefined = remoteAuthority ? remoteAuthority.split('+')[0] : + this.storageService.get(REMOTE_EXPLORER_TYPE_KEY, StorageScope.WORKSPACE) ?? this.storageService.get(REMOTE_EXPLORER_TYPE_KEY, StorageScope.GLOBAL); + if (explorerType) { + index = this.getOptionIndexForExplorerType(optionsItems, explorerType); } this.select(index); remoteExplorerService.targetType = optionsItems[index].authority[0]; } } + private getOptionIndexForExplorerType(optionsItems: IRemoteSelectItem[], explorerType: string): number { + let index = 0; + for (let optionIterator = 0; (optionIterator < this.optionsItems.length) && (index === 0); optionIterator++) { + for (let authorityIterator = 0; authorityIterator < optionsItems[optionIterator].authority.length; authorityIterator++) { + if (optionsItems[optionIterator].authority[authorityIterator] === explorerType) { + index = optionIterator; + break; + } + } + } + return index; + } + render(container: HTMLElement) { super.render(container); dom.addClass(container, 'switch-remote'); diff --git a/src/vs/workbench/services/remote/common/remoteExplorerService.ts b/src/vs/workbench/services/remote/common/remoteExplorerService.ts index da27dccfb2e66..7aec6e576894a 100644 --- a/src/vs/workbench/services/remote/common/remoteExplorerService.ts +++ b/src/vs/workbench/services/remote/common/remoteExplorerService.ts @@ -6,8 +6,10 @@ import { Event, Emitter } from 'vs/base/common/event'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; export const IRemoteExplorerService = createDecorator('remoteExplorerService'); +export const REMOTE_EXPLORER_TYPE_KEY: string = 'remote.explorerType'; export interface IRemoteExplorerService { _serviceBrand: undefined; @@ -21,9 +23,13 @@ class RemoteExplorerService implements IRemoteExplorerService { private _onDidChangeTargetType: Emitter = new Emitter(); public onDidChangeTargetType: Event = this._onDidChangeTargetType.event; + constructor(@IStorageService private readonly storageService: IStorageService) { } + set targetType(name: string) { if (this._targetType !== name) { this._targetType = name; + this.storageService.store(REMOTE_EXPLORER_TYPE_KEY, this._targetType, StorageScope.WORKSPACE); + this.storageService.store(REMOTE_EXPLORER_TYPE_KEY, this._targetType, StorageScope.GLOBAL); this._onDidChangeTargetType.fire(this._targetType); } } From e3114f4cbcd9aae70dac2538415c3fd1b8fdc576 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Tue, 12 Nov 2019 16:51:33 +0100 Subject: [PATCH 121/352] introduce early version of working copy service Adopt it for untitled and text file models. Use it for indicating dirty count in explorer and document edited on macOS. --- .../common/editor/textEditorModel.ts | 2 + .../common/editor/untitledTextEditorModel.ts | 29 ++-- .../browser/editors/fileEditorTracker.ts | 30 +++- .../files/browser/files.contribution.ts | 6 +- .../files/browser/files.web.contribution.ts | 6 - .../files/common/dirtyFilesIndicator.ts | 70 ++++++++ .../contrib/files/common/dirtyFilesTracker.ts | 113 ------------ .../electron-browser/dirtyFilesTracker.ts | 81 --------- .../electron-browser/files.contribution.ts | 6 - .../browser/testCustomEditors.ts | 40 ++++- src/vs/workbench/electron-browser/window.ts | 30 +++- .../keybindingEditing.test.ts | 6 +- .../textfile/common/textFileEditorModel.ts | 37 +++- .../textfile/test/textFileEditorModel.test.ts | 75 +++++++- .../workingCopy/common/workingCopyService.ts | 161 ++++++++++++++++++ .../test/common/workingCopyService.test.ts | 144 ++++++++++++++++ .../common/editor/untitledTextEditor.test.ts | 29 +++- .../workbench/test/workbenchTestServices.ts | 6 + src/vs/workbench/workbench.common.main.ts | 1 + 19 files changed, 617 insertions(+), 255 deletions(-) create mode 100644 src/vs/workbench/contrib/files/common/dirtyFilesIndicator.ts delete mode 100644 src/vs/workbench/contrib/files/common/dirtyFilesTracker.ts delete mode 100644 src/vs/workbench/contrib/files/electron-browser/dirtyFilesTracker.ts create mode 100644 src/vs/workbench/services/workingCopy/common/workingCopyService.ts create mode 100644 src/vs/workbench/services/workingCopy/test/common/workingCopyService.test.ts diff --git a/src/vs/workbench/common/editor/textEditorModel.ts b/src/vs/workbench/common/editor/textEditorModel.ts index 9385d8e31e6ac..e95e0d87bae90 100644 --- a/src/vs/workbench/common/editor/textEditorModel.ts +++ b/src/vs/workbench/common/editor/textEditorModel.ts @@ -17,7 +17,9 @@ import { withUndefinedAsNull } from 'vs/base/common/types'; * The base text editor model leverages the code editor model. This class is only intended to be subclassed and not instantiated. */ export abstract class BaseTextEditorModel extends EditorModel implements ITextEditorModel, IModeSupport { + protected textEditorModelHandle: URI | null = null; + private createdEditorModel: boolean | undefined; private readonly modelDisposeListener = this._register(new MutableDisposable()); diff --git a/src/vs/workbench/common/editor/untitledTextEditorModel.ts b/src/vs/workbench/common/editor/untitledTextEditorModel.ts index 917f7feeff104..7c47a00dfc9c7 100644 --- a/src/vs/workbench/common/editor/untitledTextEditorModel.ts +++ b/src/vs/workbench/common/editor/untitledTextEditorModel.ts @@ -16,8 +16,9 @@ import { ITextResourceConfigurationService } from 'vs/editor/common/services/res import { ITextBufferFactory } from 'vs/editor/common/model'; import { createTextBufferFactory } from 'vs/editor/common/model/textModel'; import { IResolvedTextEditorModel } from 'vs/editor/common/services/resolverService'; +import { IWorkingCopyService, IWorkingCopy } from 'vs/workbench/services/workingCopy/common/workingCopyService'; -export class UntitledTextEditorModel extends BaseTextEditorModel implements IEncodingSupport { +export class UntitledTextEditorModel extends BaseTextEditorModel implements IEncodingSupport, IWorkingCopy { static DEFAULT_CONTENT_CHANGE_BUFFER_DELAY = CONTENT_CHANGE_EVENT_BUFFER_DELAY; @@ -30,33 +31,33 @@ export class UntitledTextEditorModel extends BaseTextEditorModel implements IEnc private readonly _onDidChangeEncoding: Emitter = this._register(new Emitter()); readonly onDidChangeEncoding: Event = this._onDidChangeEncoding.event; - private dirty: boolean = false; - private versionId: number = 0; - private readonly contentChangeEventScheduler: RunOnceScheduler; + readonly capabilities = 0; + + private dirty = false; + private versionId = 0; + private readonly contentChangeEventScheduler = this._register(new RunOnceScheduler(() => this._onDidChangeContent.fire(), UntitledTextEditorModel.DEFAULT_CONTENT_CHANGE_BUFFER_DELAY)); private configuredEncoding?: string; constructor( private readonly preferredMode: string | undefined, - private readonly resource: URI, - private _hasAssociatedFilePath: boolean, + public readonly resource: URI, + public readonly hasAssociatedFilePath: boolean, private readonly initialValue: string | undefined, private preferredEncoding: string | undefined, @IModeService modeService: IModeService, @IModelService modelService: IModelService, @IBackupFileService private readonly backupFileService: IBackupFileService, - @ITextResourceConfigurationService private readonly configurationService: ITextResourceConfigurationService + @ITextResourceConfigurationService private readonly configurationService: ITextResourceConfigurationService, + @IWorkingCopyService private readonly workingCopyService: IWorkingCopyService ) { super(modelService, modeService); - this.contentChangeEventScheduler = this._register(new RunOnceScheduler(() => this._onDidChangeContent.fire(), UntitledTextEditorModel.DEFAULT_CONTENT_CHANGE_BUFFER_DELAY)); + // Make known to working copy service + this._register(this.workingCopyService.registerWorkingCopy(this)); this.registerListeners(); } - get hasAssociatedFilePath(): boolean { - return this._hasAssociatedFilePath; - } - private registerListeners(): void { // Config Changes @@ -147,7 +148,7 @@ export class UntitledTextEditorModel extends BaseTextEditorModel implements IEnc } // untitled associated to file path are dirty right away as well as untitled with content - this.setDirty(this._hasAssociatedFilePath || !!backup || !!this.initialValue); + this.setDirty(this.hasAssociatedFilePath || !!backup || !!this.initialValue); let untitledContents: ITextBufferFactory; if (backup) { @@ -190,7 +191,7 @@ export class UntitledTextEditorModel extends BaseTextEditorModel implements IEnc // mark the untitled text editor as non-dirty once its content becomes empty and we do // not have an associated path set. we never want dirty indicator in that case. - if (!this._hasAssociatedFilePath && this.textEditorModel.getLineCount() === 1 && this.textEditorModel.getLineContent(1) === '') { + if (!this.hasAssociatedFilePath && this.textEditorModel.getLineCount() === 1 && this.textEditorModel.getLineContent(1) === '') { this.setDirty(false); } diff --git a/src/vs/workbench/contrib/files/browser/editors/fileEditorTracker.ts b/src/vs/workbench/contrib/files/browser/editors/fileEditorTracker.ts index ddc030e106fc8..271741351a970 100644 --- a/src/vs/workbench/contrib/files/browser/editors/fileEditorTracker.ts +++ b/src/vs/workbench/contrib/files/browser/editors/fileEditorTracker.ts @@ -8,7 +8,7 @@ import { URI } from 'vs/base/common/uri'; import * as resources from 'vs/base/common/resources'; import { IEditorViewState } from 'vs/editor/common/editorCommon'; import { toResource, SideBySideEditorInput, IWorkbenchEditorConfiguration, SideBySideEditor as SideBySideEditorChoice } from 'vs/workbench/common/editor'; -import { ITextFileService, ITextFileEditorModel } from 'vs/workbench/services/textfile/common/textfiles'; +import { ITextFileService, ITextFileEditorModel, TextFileModelChangeEvent, ModelState } from 'vs/workbench/services/textfile/common/textfiles'; import { FileOperationEvent, FileOperation, IFileService, FileChangeType, FileChangesEvent } from 'vs/platform/files/common/files'; import { FileEditorInput } from 'vs/workbench/contrib/files/common/editors/fileEditorInput'; import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle'; @@ -61,6 +61,9 @@ export class FileEditorTracker extends Disposable implements IWorkbenchContribut // Update editors from disk changes this._register(this.fileService.onFileChanges(e => this.onFileChanges(e))); + // Open editors from dirty text file models + this._register(this.textFileService.models.onModelsDirty(e => this.onTextFilesDirty(e))); + // Editor changing this._register(this.editorService.onDidVisibleEditorsChange(() => this.handleOutOfWorkspaceWatchers())); @@ -359,6 +362,31 @@ export class FileEditorTracker extends Disposable implements IWorkbenchContribut }); } + private onTextFilesDirty(e: readonly TextFileModelChangeEvent[]): void { + + // If files become dirty but are not opened, we open it in the background unless there are pending to be saved + this.doOpenDirtyResources(distinct(e.filter(e => { + + // Only dirty models that are not PENDING_SAVE + const model = this.textFileService.models.get(e.resource); + const shouldOpen = model?.isDirty() && !model.hasState(ModelState.PENDING_SAVE); + + // Only if not open already + return shouldOpen && !this.editorService.isOpen({ resource: e.resource }); + }).map(e => e.resource), r => r.toString())); + } + + private doOpenDirtyResources(resources: URI[]): void { + + // Open + this.editorService.openEditors(resources.map(resource => { + return { + resource, + options: { inactive: true, pinned: true, preserveFocus: true } + }; + })); + } + dispose(): void { super.dispose(); diff --git a/src/vs/workbench/contrib/files/browser/files.contribution.ts b/src/vs/workbench/contrib/files/browser/files.contribution.ts index 25f5a95c4e318..226a42e22c796 100644 --- a/src/vs/workbench/contrib/files/browser/files.contribution.ts +++ b/src/vs/workbench/contrib/files/browser/files.contribution.ts @@ -38,6 +38,7 @@ import { ExplorerService } from 'vs/workbench/contrib/files/common/explorerServi import { SUPPORTED_ENCODINGS } from 'vs/workbench/services/textfile/common/textfiles'; import { Schemas } from 'vs/base/common/network'; import { WorkspaceWatcher } from 'vs/workbench/contrib/files/common/workspaceWatcher'; +import { DirtyFilesIndicator } from 'vs/workbench/contrib/files/common/dirtyFilesIndicator'; // Viewlet Action export class OpenExplorerViewletAction extends ShowViewletAction { @@ -170,9 +171,12 @@ Registry.as(WorkbenchExtensions.Workbench).regi // Register uri display for file uris Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(FileUriLabelContribution, LifecyclePhase.Starting); -// Workspace Watcher +// Register Workspace Watcher Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(WorkspaceWatcher, LifecyclePhase.Restored); +// Register Dirty Files Indicator +Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(DirtyFilesIndicator, LifecyclePhase.Starting); + // Configuration const configurationRegistry = Registry.as(ConfigurationExtensions.Configuration); diff --git a/src/vs/workbench/contrib/files/browser/files.web.contribution.ts b/src/vs/workbench/contrib/files/browser/files.web.contribution.ts index 0a28e1afb6009..44d91d66b91c1 100644 --- a/src/vs/workbench/contrib/files/browser/files.web.contribution.ts +++ b/src/vs/workbench/contrib/files/browser/files.web.contribution.ts @@ -10,9 +10,6 @@ import { FileEditorInput } from 'vs/workbench/contrib/files/common/editors/fileE import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; import { IEditorRegistry, EditorDescriptor, Extensions as EditorExtensions } from 'vs/workbench/browser/editor'; import { TextFileEditor } from 'vs/workbench/contrib/files/browser/editors/textFileEditor'; -import { DirtyFilesTracker } from 'vs/workbench/contrib/files/common/dirtyFilesTracker'; -import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions'; -import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle'; // Register file editor Registry.as(EditorExtensions.Editors).registerEditor( @@ -25,6 +22,3 @@ Registry.as(EditorExtensions.Editors).registerEditor( new SyncDescriptor(FileEditorInput) ] ); - -// Register Dirty Files Tracker -Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(DirtyFilesTracker, LifecyclePhase.Starting); diff --git a/src/vs/workbench/contrib/files/common/dirtyFilesIndicator.ts b/src/vs/workbench/contrib/files/common/dirtyFilesIndicator.ts new file mode 100644 index 0000000000000..515a11480ba20 --- /dev/null +++ b/src/vs/workbench/contrib/files/common/dirtyFilesIndicator.ts @@ -0,0 +1,70 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as nls from 'vs/nls'; +import { IWorkbenchContribution } from 'vs/workbench/common/contributions'; +import { VIEWLET_ID } from 'vs/workbench/contrib/files/common/files'; +import { ITextFileService, AutoSaveMode } from 'vs/workbench/services/textfile/common/textfiles'; +import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle'; +import { Disposable, MutableDisposable } from 'vs/base/common/lifecycle'; +import { IActivityService, NumberBadge } from 'vs/workbench/services/activity/common/activity'; +import { IWorkingCopyService, IWorkingCopy, WorkingCopyCapabilities } from 'vs/workbench/services/workingCopy/common/workingCopyService'; + +export class DirtyFilesIndicator extends Disposable implements IWorkbenchContribution { + private readonly badgeHandle = this._register(new MutableDisposable()); + + private lastKnownDirtyCount: number | undefined; + + private get hasDirtyCount(): boolean { + return typeof this.lastKnownDirtyCount === 'number' && this.lastKnownDirtyCount > 0; + } + + constructor( + @ITextFileService private readonly textFileService: ITextFileService, + @ILifecycleService private readonly lifecycleService: ILifecycleService, + @IActivityService private readonly activityService: IActivityService, + @IWorkingCopyService private readonly workingCopyService: IWorkingCopyService + ) { + super(); + + this.registerListeners(); + } + + private registerListeners(): void { + + // Working copy dirty indicator + this._register(this.workingCopyService.onDidChangeDirty(c => this.onWorkingCopyDidChangeDirty(c))); + + // Lifecycle + this.lifecycleService.onShutdown(this.dispose, this); + } + + private onWorkingCopyDidChangeDirty(copy: IWorkingCopy): void { + if (!!(copy.capabilities & WorkingCopyCapabilities.AutoSave) && this.textFileService.getAutoSaveMode() === AutoSaveMode.AFTER_SHORT_DELAY) { + return; // do not indicate changes to working copies that are auto saved after short delay + } + + const gotDirty = copy.isDirty(); + if (gotDirty || this.hasDirtyCount) { + this.updateActivityBadge(); + } + } + + private updateActivityBadge(): void { + const dirtyCount = this.workingCopyService.dirtyCount; + this.lastKnownDirtyCount = dirtyCount; + + // Indicate dirty count in badge if any + if (dirtyCount > 0) { + this.badgeHandle.value = this.activityService.showActivity( + VIEWLET_ID, + new NumberBadge(dirtyCount, num => num === 1 ? nls.localize('dirtyFile', "1 unsaved file") : nls.localize('dirtyFiles', "{0} unsaved files", dirtyCount)), + 'explorer-viewlet-label' + ); + } else { + this.badgeHandle.clear(); + } + } +} diff --git a/src/vs/workbench/contrib/files/common/dirtyFilesTracker.ts b/src/vs/workbench/contrib/files/common/dirtyFilesTracker.ts deleted file mode 100644 index 6d070bd03e4e5..0000000000000 --- a/src/vs/workbench/contrib/files/common/dirtyFilesTracker.ts +++ /dev/null @@ -1,113 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import * as nls from 'vs/nls'; -import { IWorkbenchContribution } from 'vs/workbench/common/contributions'; -import { VIEWLET_ID } from 'vs/workbench/contrib/files/common/files'; -import { TextFileModelChangeEvent, ITextFileService, AutoSaveMode, ModelState } from 'vs/workbench/services/textfile/common/textfiles'; -import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle'; -import { Disposable, MutableDisposable } from 'vs/base/common/lifecycle'; -import { URI } from 'vs/base/common/uri'; -import { IActivityService, NumberBadge } from 'vs/workbench/services/activity/common/activity'; -import { IUntitledTextEditorService } from 'vs/workbench/services/untitled/common/untitledTextEditorService'; -import * as arrays from 'vs/base/common/arrays'; -import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; - -export class DirtyFilesTracker extends Disposable implements IWorkbenchContribution { - private lastKnownDirtyCount: number | undefined; - private readonly badgeHandle = this._register(new MutableDisposable()); - - constructor( - @ITextFileService protected readonly textFileService: ITextFileService, - @ILifecycleService private readonly lifecycleService: ILifecycleService, - @IEditorService private readonly editorService: IEditorService, - @IActivityService private readonly activityService: IActivityService, - @IUntitledTextEditorService protected readonly untitledTextEditorService: IUntitledTextEditorService - ) { - super(); - - this.registerListeners(); - } - - private registerListeners(): void { - - // Local text file changes - this._register(this.untitledTextEditorService.onDidChangeDirty(e => this.onUntitledDidChangeDirty(e))); - this._register(this.textFileService.models.onModelsDirty(e => this.onTextFilesDirty(e))); - this._register(this.textFileService.models.onModelsSaved(e => this.onTextFilesSaved(e))); - this._register(this.textFileService.models.onModelsSaveError(e => this.onTextFilesSaveError(e))); - this._register(this.textFileService.models.onModelsReverted(e => this.onTextFilesReverted(e))); - - // Lifecycle - this.lifecycleService.onShutdown(this.dispose, this); - } - - private get hasDirtyCount(): boolean { - return typeof this.lastKnownDirtyCount === 'number' && this.lastKnownDirtyCount > 0; - } - - protected onUntitledDidChangeDirty(resource: URI): void { - const gotDirty = this.untitledTextEditorService.isDirty(resource); - - if (gotDirty || this.hasDirtyCount) { - this.updateActivityBadge(); - } - } - - protected onTextFilesDirty(e: readonly TextFileModelChangeEvent[]): void { - if (this.textFileService.getAutoSaveMode() !== AutoSaveMode.AFTER_SHORT_DELAY) { - this.updateActivityBadge(); // no indication needed when auto save is enabled for short delay - } - - // If files become dirty but are not opened, we open it in the background unless there are pending to be saved - this.doOpenDirtyResources(arrays.distinct(e.filter(e => { - - // Only dirty models that are not PENDING_SAVE - const model = this.textFileService.models.get(e.resource); - const shouldOpen = model?.isDirty() && !model.hasState(ModelState.PENDING_SAVE); - - // Only if not open already - return shouldOpen && !this.editorService.isOpen({ resource: e.resource }); - }).map(e => e.resource), r => r.toString())); - } - - private doOpenDirtyResources(resources: URI[]): void { - - // Open - this.editorService.openEditors(resources.map(resource => { - return { - resource, - options: { inactive: true, pinned: true, preserveFocus: true } - }; - })); - } - - protected onTextFilesSaved(e: readonly TextFileModelChangeEvent[]): void { - if (this.hasDirtyCount) { - this.updateActivityBadge(); - } - } - - protected onTextFilesSaveError(e: readonly TextFileModelChangeEvent[]): void { - this.updateActivityBadge(); - } - - protected onTextFilesReverted(e: readonly TextFileModelChangeEvent[]): void { - if (this.hasDirtyCount) { - this.updateActivityBadge(); - } - } - - private updateActivityBadge(): void { - const dirtyCount = this.textFileService.getDirty().length; - this.lastKnownDirtyCount = dirtyCount; - - this.badgeHandle.clear(); - - if (dirtyCount > 0) { - this.badgeHandle.value = this.activityService.showActivity(VIEWLET_ID, new NumberBadge(dirtyCount, num => num === 1 ? nls.localize('dirtyFile', "1 unsaved file") : nls.localize('dirtyFiles', "{0} unsaved files", dirtyCount)), 'explorer-viewlet-label'); - } - } -} diff --git a/src/vs/workbench/contrib/files/electron-browser/dirtyFilesTracker.ts b/src/vs/workbench/contrib/files/electron-browser/dirtyFilesTracker.ts deleted file mode 100644 index 6f85e8d1bdce5..0000000000000 --- a/src/vs/workbench/contrib/files/electron-browser/dirtyFilesTracker.ts +++ /dev/null @@ -1,81 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import { TextFileModelChangeEvent, ITextFileService, AutoSaveMode } from 'vs/workbench/services/textfile/common/textfiles'; -import { platform, Platform } from 'vs/base/common/platform'; -import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle'; -import { URI } from 'vs/base/common/uri'; -import { IActivityService } from 'vs/workbench/services/activity/common/activity'; -import { IUntitledTextEditorService } from 'vs/workbench/services/untitled/common/untitledTextEditorService'; -import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; -import { DirtyFilesTracker } from 'vs/workbench/contrib/files/common/dirtyFilesTracker'; -import { IElectronService } from 'vs/platform/electron/node/electron'; - -export class NativeDirtyFilesTracker extends DirtyFilesTracker { - private isDocumentedEdited: boolean; - - constructor( - @ITextFileService protected readonly textFileService: ITextFileService, - @ILifecycleService lifecycleService: ILifecycleService, - @IEditorService editorService: IEditorService, - @IActivityService activityService: IActivityService, - @IUntitledTextEditorService protected readonly untitledTextEditorService: IUntitledTextEditorService, - @IElectronService private readonly electronService: IElectronService - ) { - super(textFileService, lifecycleService, editorService, activityService, untitledTextEditorService); - - this.isDocumentedEdited = false; - } - - protected onUntitledDidChangeDirty(resource: URI): void { - const gotDirty = this.untitledTextEditorService.isDirty(resource); - if ((!this.isDocumentedEdited && gotDirty) || (this.isDocumentedEdited && !gotDirty)) { - this.updateDocumentEdited(); - } - - super.onUntitledDidChangeDirty(resource); - } - - protected onTextFilesDirty(e: readonly TextFileModelChangeEvent[]): void { - if ((this.textFileService.getAutoSaveMode() !== AutoSaveMode.AFTER_SHORT_DELAY) && !this.isDocumentedEdited) { - this.updateDocumentEdited(); // no indication needed when auto save is enabled for short delay - } - - super.onTextFilesDirty(e); - } - - protected onTextFilesSaved(e: readonly TextFileModelChangeEvent[]): void { - if (this.isDocumentedEdited) { - this.updateDocumentEdited(); - } - - super.onTextFilesSaved(e); - } - - protected onTextFilesSaveError(e: readonly TextFileModelChangeEvent[]): void { - if (!this.isDocumentedEdited) { - this.updateDocumentEdited(); - } - - super.onTextFilesSaveError(e); - } - - protected onTextFilesReverted(e: readonly TextFileModelChangeEvent[]): void { - if (this.isDocumentedEdited) { - this.updateDocumentEdited(); - } - - super.onTextFilesReverted(e); - } - - private updateDocumentEdited(): void { - if (platform === Platform.Mac) { - const hasDirtyFiles = this.textFileService.isDirty(); - this.isDocumentedEdited = hasDirtyFiles; - - this.electronService.setDocumentEdited(hasDirtyFiles); - } - } -} diff --git a/src/vs/workbench/contrib/files/electron-browser/files.contribution.ts b/src/vs/workbench/contrib/files/electron-browser/files.contribution.ts index 03a2fa2f42198..d5d18ac24ea86 100644 --- a/src/vs/workbench/contrib/files/electron-browser/files.contribution.ts +++ b/src/vs/workbench/contrib/files/electron-browser/files.contribution.ts @@ -10,9 +10,6 @@ import { FileEditorInput } from 'vs/workbench/contrib/files/common/editors/fileE import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; import { IEditorRegistry, EditorDescriptor, Extensions as EditorExtensions } from 'vs/workbench/browser/editor'; import { NativeTextFileEditor } from 'vs/workbench/contrib/files/electron-browser/textFileEditor'; -import { NativeDirtyFilesTracker } from 'vs/workbench/contrib/files/electron-browser/dirtyFilesTracker'; -import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions'; -import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle'; // Register file editor Registry.as(EditorExtensions.Editors).registerEditor( @@ -25,6 +22,3 @@ Registry.as(EditorExtensions.Editors).registerEditor( new SyncDescriptor(FileEditorInput) ] ); - -// Register Dirty Files Tracker -Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(NativeDirtyFilesTracker, LifecyclePhase.Starting); diff --git a/src/vs/workbench/contrib/testCustomEditors/browser/testCustomEditors.ts b/src/vs/workbench/contrib/testCustomEditors/browser/testCustomEditors.ts index 6f25031e1dbdc..6a038352e2d60 100644 --- a/src/vs/workbench/contrib/testCustomEditors/browser/testCustomEditors.ts +++ b/src/vs/workbench/contrib/testCustomEditors/browser/testCustomEditors.ts @@ -24,7 +24,9 @@ import { isEqual } from 'vs/base/common/resources'; import { generateUuid } from 'vs/base/common/uuid'; import { CancellationToken } from 'vs/base/common/cancellation'; import { editorBackground, editorForeground } from 'vs/platform/theme/common/colorRegistry'; +import { IWorkingCopy, IWorkingCopyService } from 'vs/workbench/services/workingCopy/common/workingCopyService'; +const CUSTOM_SCHEME = 'testCustomEditor'; const ENABLE = false; class TestCustomEditorsAction extends Action { @@ -35,13 +37,15 @@ class TestCustomEditorsAction extends Action { constructor( id: string, label: string, - @IEditorService private readonly editorService: IEditorService + @IEditorService private readonly editorService: IEditorService, + @IInstantiationService private readonly instantiationService: IInstantiationService ) { super(id, label); } async run(): Promise { - await this.editorService.openEditor(new TestCustomEditorInput(URI.parse(`testCustomEditor:/${generateUuid()}`))); + const input = this.instantiationService.createInstance(TestCustomEditorInput, URI.parse(`${CUSTOM_SCHEME}:/${generateUuid()}`)); + await this.editorService.openEditor(input); return true; } @@ -111,12 +115,17 @@ class TestCustomEditor extends BaseEditor { layout(dimension: Dimension): void { } } -class TestCustomEditorInput extends EditorInput { +class TestCustomEditorInput extends EditorInput implements IWorkingCopy { private model: TestCustomEditorModel | undefined = undefined; + private dirty = false; - constructor(public readonly resource: URI) { + readonly capabilities = 0; + + constructor(public readonly resource: URI, @IWorkingCopyService workingCopyService: IWorkingCopyService) { super(); + + this._register(workingCopyService.registerWorkingCopy(this)); } getResource(): URI { @@ -128,7 +137,7 @@ class TestCustomEditorInput extends EditorInput { } getName(): string { - return `Custom Editor: ${this.resource.toString()}`; + return this.resource.toString(); } setValue(value: string) { @@ -139,9 +148,11 @@ class TestCustomEditorInput extends EditorInput { this.setDirty(value.length > 0); } - setDirty(dirty: boolean) { - this.dirty = dirty; - this._onDidChangeDirty.fire(); + private setDirty(dirty: boolean) { + if (this.dirty !== dirty) { + this.dirty = dirty; + this._onDidChangeDirty.fire(); + } } isDirty(): boolean { @@ -176,6 +187,17 @@ class TestCustomEditorInput extends EditorInput { matches(other: EditorInput) { return other instanceof TestCustomEditorInput && isEqual(other.resource, this.resource); } + + dispose(): void { + this.setDirty(false); + + if (this.model) { + this.model.dispose(); + this.model = undefined; + } + + super.dispose(); + } } class TestCustomEditorModel extends EditorModel { @@ -212,7 +234,7 @@ if (ENABLE) { } deserialize(instantiationService: IInstantiationService, serializedEditorInput: string): TestCustomEditorInput { - return new TestCustomEditorInput(URI.parse(JSON.parse(serializedEditorInput).resource)); + return instantiationService.createInstance(TestCustomEditorInput, URI.parse(JSON.parse(serializedEditorInput).resource)); } } diff --git a/src/vs/workbench/electron-browser/window.ts b/src/vs/workbench/electron-browser/window.ts index 9f58a3e460125..d7f2c37ac7fba 100644 --- a/src/vs/workbench/electron-browser/window.ts +++ b/src/vs/workbench/electron-browser/window.ts @@ -60,6 +60,7 @@ import { ITunnelService, extractLocalHostUriMetaDataForPortMapping } from 'vs/pl import { IWorkbenchLayoutService, Parts } from 'vs/workbench/services/layout/browser/layoutService'; import { IHostService } from 'vs/workbench/services/host/browser/host'; import { IElectronEnvironmentService } from 'vs/workbench/services/electron/electron-browser/electronEnvironmentService'; +import { IWorkingCopyService } from 'vs/workbench/services/workingCopy/common/workingCopyService'; export class ElectronWindow extends Disposable { @@ -67,14 +68,16 @@ export class ElectronWindow extends Disposable { private readonly touchBarDisposables = this._register(new DisposableStore()); private lastInstalledTouchedBar: ICommandAction[][] | undefined; - private customTitleContextMenuDisposable = this._register(new DisposableStore()); + private readonly customTitleContextMenuDisposable = this._register(new DisposableStore()); private previousConfiguredZoomLevel: number | undefined; - private addFoldersScheduler: RunOnceScheduler; - private pendingFoldersToAdd: URI[]; + private readonly addFoldersScheduler = this._register(new RunOnceScheduler(() => this.doAddFolders(), 100)); + private pendingFoldersToAdd: URI[] = []; - private closeEmptyWindowScheduler: RunOnceScheduler = this._register(new RunOnceScheduler(() => this.onAllEditorsClosed(), 50)); + private readonly closeEmptyWindowScheduler: RunOnceScheduler = this._register(new RunOnceScheduler(() => this.onAllEditorsClosed(), 50)); + + private isDocumentedEdited = false; constructor( @IEditorService private readonly editorService: EditorServiceImpl, @@ -99,13 +102,11 @@ export class ElectronWindow extends Disposable { @IElectronService private readonly electronService: IElectronService, @ITunnelService private readonly tunnelService: ITunnelService, @IWorkbenchLayoutService private readonly layoutService: IWorkbenchLayoutService, - @IElectronEnvironmentService private readonly electronEnvironmentService: IElectronEnvironmentService + @IElectronEnvironmentService private readonly electronEnvironmentService: IElectronEnvironmentService, + @IWorkingCopyService private readonly workingCopyService: IWorkingCopyService ) { super(); - this.pendingFoldersToAdd = []; - this.addFoldersScheduler = this._register(new RunOnceScheduler(() => this.doAddFolders(), 100)); - this.registerListeners(); this.create(); } @@ -261,6 +262,19 @@ export class ElectronWindow extends Disposable { this.electronService.handleTitleDoubleClick(); })); } + + // Document edited (macOS only): indicate for dirty working copies + if (isMacintosh) { + this._register(this.workingCopyService.onDidChangeDirty(workingCopy => { + const gotDirty = workingCopy.isDirty(); + if ((!this.isDocumentedEdited && gotDirty) || (this.isDocumentedEdited && !gotDirty)) { + const hasDirtyFiles = this.workingCopyService.hasDirty; + this.isDocumentedEdited = hasDirtyFiles; + + this.electronService.setDocumentEdited(hasDirtyFiles); + } + })); + } } private onDidVisibleEditorsChange(): void { diff --git a/src/vs/workbench/services/keybinding/test/electron-browser/keybindingEditing.test.ts b/src/vs/workbench/services/keybinding/test/electron-browser/keybindingEditing.test.ts index d4be17512c0fe..26baa78b0abec 100644 --- a/src/vs/workbench/services/keybinding/test/electron-browser/keybindingEditing.test.ts +++ b/src/vs/workbench/services/keybinding/test/electron-browser/keybindingEditing.test.ts @@ -39,7 +39,7 @@ import { KeybindingsEditingService } from 'vs/workbench/services/keybinding/comm import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; import { TextModelResolverService } from 'vs/workbench/services/textmodelResolver/common/textModelResolverService'; import { IUntitledTextEditorService, UntitledTextEditorService } from 'vs/workbench/services/untitled/common/untitledTextEditorService'; -import { TestBackupFileService, TestContextService, TestEditorGroupsService, TestEditorService, TestLifecycleService, TestTextFileService, TestTextResourcePropertiesService } from 'vs/workbench/test/workbenchTestServices'; +import { TestBackupFileService, TestContextService, TestEditorGroupsService, TestEditorService, TestLifecycleService, TestTextFileService, TestTextResourcePropertiesService, TestWorkingCopyService } from 'vs/workbench/test/workbenchTestServices'; import { FileService } from 'vs/platform/files/common/fileService'; import { Schemas } from 'vs/base/common/network'; import { DiskFileSystemProvider } from 'vs/platform/files/node/diskFileSystemProvider'; @@ -49,6 +49,7 @@ import { parseArgs, OPTIONS } from 'vs/platform/environment/node/argv'; import { NativeWorkbenchEnvironmentService } from 'vs/workbench/services/environment/electron-browser/environmentService'; import { IWindowConfiguration } from 'vs/platform/windows/common/windows'; import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService'; +import { IWorkingCopyService } from 'vs/workbench/services/workingCopy/common/workingCopyService'; class TestEnvironmentService extends NativeWorkbenchEnvironmentService { @@ -67,7 +68,7 @@ interface Modifiers { shiftKey?: boolean; } -suite('KeybindingsEditing', () => { +suite.skip('KeybindingsEditing', () => { let instantiationService: TestInstantiationService; let testObject: KeybindingsEditingService; @@ -93,6 +94,7 @@ suite('KeybindingsEditing', () => { instantiationService.stub(IContextKeyService, instantiationService.createInstance(MockContextKeyService)); instantiationService.stub(IEditorGroupsService, new TestEditorGroupsService()); instantiationService.stub(IEditorService, new TestEditorService()); + instantiationService.stub(IWorkingCopyService, new TestWorkingCopyService()); instantiationService.stub(ITelemetryService, NullTelemetryService); instantiationService.stub(IModeService, ModeServiceImpl); instantiationService.stub(ILogService, new NullLogService()); diff --git a/src/vs/workbench/services/textfile/common/textFileEditorModel.ts b/src/vs/workbench/services/textfile/common/textFileEditorModel.ts index 8618b539f5a39..ee2501f8854f0 100644 --- a/src/vs/workbench/services/textfile/common/textFileEditorModel.ts +++ b/src/vs/workbench/services/textfile/common/textFileEditorModel.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import * as nls from 'vs/nls'; -import { Event, Emitter } from 'vs/base/common/event'; +import { Emitter } from 'vs/base/common/event'; import { guessMimeTypes } from 'vs/base/common/mime'; import { toErrorMessage } from 'vs/base/common/errorMessage'; import { URI } from 'vs/base/common/uri'; @@ -29,6 +29,7 @@ import { ILogService } from 'vs/platform/log/common/log'; import { isEqual, isEqualOrParent, extname, basename, joinPath } from 'vs/base/common/resources'; import { onUnexpectedError } from 'vs/base/common/errors'; import { Schemas } from 'vs/base/common/network'; +import { IWorkingCopyService, IWorkingCopy, WorkingCopyCapabilities } from 'vs/workbench/services/workingCopy/common/workingCopyService'; export interface IBackupMetaData { mtime: number; @@ -57,7 +58,7 @@ type TelemetryData = { /** * The text file editor model listens to changes to its underlying code editor model and saves these changes through the file service back to the disk. */ -export class TextFileEditorModel extends BaseTextEditorModel implements ITextFileEditorModel { +export class TextFileEditorModel extends BaseTextEditorModel implements ITextFileEditorModel, IWorkingCopy { static DEFAULT_CONTENT_CHANGE_BUFFER_DELAY = CONTENT_CHANGE_EVENT_BUFFER_DELAY; static DEFAULT_ORPHANED_CHANGE_BUFFER_DELAY = 100; @@ -70,11 +71,16 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil private static saveParticipant: ISaveParticipant | null; static setSaveParticipant(handler: ISaveParticipant | null): void { TextFileEditorModel.saveParticipant = handler; } - private readonly _onDidContentChange: Emitter = this._register(new Emitter()); - readonly onDidContentChange: Event = this._onDidContentChange.event; + private readonly _onDidContentChange = this._register(new Emitter()); + readonly onDidContentChange = this._onDidContentChange.event; - private readonly _onDidStateChange: Emitter = this._register(new Emitter()); - readonly onDidStateChange: Event = this._onDidStateChange.event; + private readonly _onDidStateChange = this._register(new Emitter()); + readonly onDidStateChange = this._onDidStateChange.event; + + private readonly _onDidChangeDirty = this._register(new Emitter()); + readonly onDidChangeDirty = this._onDidChangeDirty.event; + + readonly capabilities = WorkingCopyCapabilities.AutoSave; private contentEncoding: string | undefined; // encoding as reported from disk @@ -101,7 +107,7 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil private disposed = false; constructor( - private readonly resource: URI, + public readonly resource: URI, private preferredEncoding: string | undefined, // encoding as chosen by the user private preferredMode: string | undefined, // mode as chosen by the user @INotificationService private readonly notificationService: INotificationService, @@ -114,12 +120,16 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil @IBackupFileService private readonly backupFileService: IBackupFileService, @IEnvironmentService private readonly environmentService: IEnvironmentService, @IWorkspaceContextService private readonly contextService: IWorkspaceContextService, - @ILogService private readonly logService: ILogService + @ILogService private readonly logService: ILogService, + @IWorkingCopyService private readonly workingCopyService: IWorkingCopyService ) { super(modelService, modeService); this.updateAutoSaveConfiguration(textFileService.getAutoSaveConfiguration()); + // Make known to working copy service + this._register(this.workingCopyService.registerWorkingCopy(this)); + this.registerListeners(); } @@ -249,6 +259,7 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil this.autoSaveDisposable.clear(); // Unset flags + const wasDirty = this.dirty; const undo = this.setDirty(false); // Force read from disk unless reverting soft @@ -266,6 +277,11 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil // Emit file change event this._onDidStateChange.fire(StateChange.REVERTED); + + // Emit dirty change event + if (wasDirty) { + this._onDidChangeDirty.fire(); + } } async load(options?: ILoadOptions): Promise { @@ -528,6 +544,7 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil // Emit event if (wasDirty) { this._onDidStateChange.fire(StateChange.REVERTED); + this._onDidChangeDirty.fire(); } return; @@ -568,6 +585,7 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil // Emit as Event if we turned dirty if (!wasDirty) { this._onDidStateChange.fire(StateChange.DIRTY); + this._onDidChangeDirty.fire(); } } @@ -739,8 +757,9 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil // Cancel any content change event promises as they are no longer valid this.contentChangeEventScheduler.cancel(); - // Emit File Saved Event + // Emit Events this._onDidStateChange.fire(StateChange.SAVED); + this._onDidChangeDirty.fire(); // Telemetry const settingsType = this.getTypeIfSettings(); diff --git a/src/vs/workbench/services/textfile/test/textFileEditorModel.test.ts b/src/vs/workbench/services/textfile/test/textFileEditorModel.test.ts index 07c3271fa9558..dbddfc86a4011 100644 --- a/src/vs/workbench/services/textfile/test/textFileEditorModel.test.ts +++ b/src/vs/workbench/services/textfile/test/textFileEditorModel.test.ts @@ -16,9 +16,15 @@ import { IModelService } from 'vs/editor/common/services/modelService'; import { timeout } from 'vs/base/common/async'; import { ModesRegistry } from 'vs/editor/common/modes/modesRegistry'; import { assertIsDefined } from 'vs/base/common/types'; +import { IWorkingCopyService } from 'vs/workbench/services/workingCopy/common/workingCopyService'; class ServiceAccessor { - constructor(@ITextFileService public textFileService: TestTextFileService, @IModelService public modelService: IModelService, @IFileService public fileService: TestFileService) { + constructor( + @ITextFileService public readonly textFileService: TestTextFileService, + @IModelService public readonly modelService: IModelService, + @IFileService public readonly fileService: TestFileService, + @IWorkingCopyService public readonly workingCopyService: IWorkingCopyService + ) { } } @@ -51,10 +57,15 @@ suite('Files - TextFileEditorModel', () => { await model.load(); + assert.equal(accessor.workingCopyService.dirtyCount, 0); + model.textEditorModel!.setValue('bar'); assert.ok(getLastModifiedTime(model) <= Date.now()); assert.ok(model.hasState(ModelState.DIRTY)); + assert.equal(accessor.workingCopyService.dirtyCount, 1); + assert.equal(accessor.workingCopyService.isDirty(model.resource), true); + let savedEvent = false; model.onDidStateChange(e => { if (e === StateChange.SAVED) { @@ -62,6 +73,13 @@ suite('Files - TextFileEditorModel', () => { } }); + let workingCopyEvent = false; + accessor.workingCopyService.onDidChangeDirty(e => { + if (e.resource.toString() === model.resource.toString()) { + workingCopyEvent = true; + } + }); + const pendingSave = model.save(); assert.ok(model.hasState(ModelState.PENDING_SAVE)); @@ -71,6 +89,10 @@ suite('Files - TextFileEditorModel', () => { assert.ok(model.hasState(ModelState.SAVED)); assert.ok(!model.isDirty()); assert.ok(savedEvent); + assert.ok(workingCopyEvent); + + assert.equal(accessor.workingCopyService.dirtyCount, 0); + assert.equal(accessor.workingCopyService.isDirty(model.resource), false); model.dispose(); assert.ok(!accessor.modelService.getModel(model.getResource())); @@ -88,9 +110,17 @@ suite('Files - TextFileEditorModel', () => { } }); + let workingCopyEvent = false; + accessor.workingCopyService.onDidChangeDirty(e => { + if (e.resource.toString() === model.resource.toString()) { + workingCopyEvent = true; + } + }); + await model.save({ force: true }); assert.ok(savedEvent); + assert.ok(!workingCopyEvent); model.dispose(); assert.ok(!accessor.modelService.getModel(model.getResource())); @@ -182,14 +212,29 @@ suite('Files - TextFileEditorModel', () => { } }); + let workingCopyEvent = false; + accessor.workingCopyService.onDidChangeDirty(e => { + if (e.resource.toString() === model.resource.toString()) { + workingCopyEvent = true; + } + }); + await model.load(); model.textEditorModel!.setValue('foo'); assert.ok(model.isDirty()); + assert.equal(accessor.workingCopyService.dirtyCount, 1); + assert.equal(accessor.workingCopyService.isDirty(model.resource), true); + await model.revert(); assert.ok(!model.isDirty()); assert.equal(model.textEditorModel!.getValue(), 'Hello Html'); assert.equal(eventCounter, 1); + + assert.ok(workingCopyEvent); + assert.equal(accessor.workingCopyService.dirtyCount, 0); + assert.equal(accessor.workingCopyService.isDirty(model.resource), false); + model.dispose(); }); @@ -204,14 +249,29 @@ suite('Files - TextFileEditorModel', () => { } }); + let workingCopyEvent = false; + accessor.workingCopyService.onDidChangeDirty(e => { + if (e.resource.toString() === model.resource.toString()) { + workingCopyEvent = true; + } + }); + await model.load(); model.textEditorModel!.setValue('foo'); assert.ok(model.isDirty()); + assert.equal(accessor.workingCopyService.dirtyCount, 1); + assert.equal(accessor.workingCopyService.isDirty(model.resource), true); + await model.revert(true /* soft revert */); assert.ok(!model.isDirty()); assert.equal(model.textEditorModel!.getValue(), 'foo'); assert.equal(eventCounter, 1); + + assert.ok(workingCopyEvent); + assert.equal(accessor.workingCopyService.dirtyCount, 0); + assert.equal(accessor.workingCopyService.isDirty(model.resource), false); + model.dispose(); }); @@ -223,6 +283,9 @@ suite('Files - TextFileEditorModel', () => { await model.load(); model.textEditorModel!.undo(); assert.ok(model.isDirty()); + + assert.equal(accessor.workingCopyService.dirtyCount, 1); + assert.equal(accessor.workingCopyService.isDirty(model.resource), true); }); test('Make Dirty', async function () { @@ -246,9 +309,18 @@ suite('Files - TextFileEditorModel', () => { } }); + let workingCopyEvent = false; + accessor.workingCopyService.onDidChangeDirty(e => { + if (e.resource.toString() === model.resource.toString()) { + workingCopyEvent = true; + } + }); + model.makeDirty(); assert.ok(model.isDirty()); assert.equal(eventCounter, 1); + assert.ok(workingCopyEvent); + model.dispose(); }); @@ -343,7 +415,6 @@ suite('Files - TextFileEditorModel', () => { }); test('Save Participant, async participant', async function () { - const model: TextFileEditorModel = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/index_async.txt'), 'utf8', undefined); TextFileEditorModel.setSaveParticipant({ diff --git a/src/vs/workbench/services/workingCopy/common/workingCopyService.ts b/src/vs/workbench/services/workingCopy/common/workingCopyService.ts new file mode 100644 index 0000000000000..074a783029151 --- /dev/null +++ b/src/vs/workbench/services/workingCopy/common/workingCopyService.ts @@ -0,0 +1,161 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; +import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { Event, Emitter } from 'vs/base/common/event'; +import { URI } from 'vs/base/common/uri'; +import { Disposable, IDisposable, toDisposable, DisposableStore, dispose } from 'vs/base/common/lifecycle'; +import { TernarySearchTree } from 'vs/base/common/map'; + +export const enum WorkingCopyCapabilities { + + /** + * Signals that the working copy participates + * in auto saving as configured by the user. + */ + AutoSave = 1 << 1 +} + +export interface IWorkingCopy { + + //#region Dirty Tracking + + readonly onDidChangeDirty: Event; + + isDirty(): boolean; + + //#endregion + + readonly resource: URI; + + readonly capabilities: WorkingCopyCapabilities; +} + +export const IWorkingCopyService = createDecorator('workingCopyService'); + +export interface IWorkingCopyService { + + _serviceBrand: undefined; + + //#region Dirty Tracking + + readonly onDidChangeDirty: Event; + + readonly dirtyCount: number; + + readonly hasDirty: boolean; + + isDirty(resource: URI): boolean; + + //#endregion + + + //#region Registry + + registerWorkingCopy(workingCopy: IWorkingCopy): IDisposable; + + //#endregion +} + +export class WorkingCopyService extends Disposable implements IWorkingCopyService { + + _serviceBrand: undefined; + + //#region Dirty Tracking + + private readonly _onDidChangeDirty = this._register(new Emitter()); + readonly onDidChangeDirty = this._onDidChangeDirty.event; + + isDirty(resource: URI): boolean { + const workingCopies = this.mapResourceToWorkingCopy.get(resource.toString()); + if (workingCopies) { + for (const workingCopy of workingCopies) { + if (workingCopy.isDirty()) { + return true; + } + } + } + + return false; + } + + get hasDirty(): boolean { + for (const workingCopy of this.workingCopies) { + if (workingCopy.isDirty()) { + return true; + } + } + + return false; + } + + get dirtyCount(): number { + let totalDirtyCount = 0; + + for (const workingCopy of this.workingCopies) { + if (workingCopy.isDirty()) { + totalDirtyCount++; + } + } + + return totalDirtyCount; + } + + //#endregion + + + //#region Registry + + private mapResourceToWorkingCopy = TernarySearchTree.forPaths>(); + private workingCopies = new Set(); + + registerWorkingCopy(workingCopy: IWorkingCopy): IDisposable { + const disposables = new DisposableStore(); + + // Registry + let workingCopiesForResource = this.mapResourceToWorkingCopy.get(workingCopy.resource.toString()); + if (!workingCopiesForResource) { + workingCopiesForResource = new Set(); + this.mapResourceToWorkingCopy.set(workingCopy.resource.toString(), workingCopiesForResource); + } + + workingCopiesForResource.add(workingCopy); + + this.workingCopies.add(workingCopy); + + // Dirty Events + disposables.add(workingCopy.onDidChangeDirty(() => this._onDidChangeDirty.fire(workingCopy))); + if (workingCopy.isDirty()) { + this._onDidChangeDirty.fire(workingCopy); + } + + return toDisposable(() => { + this.unregisterWorkingCopy(workingCopy); + dispose(disposables); + }); + } + + private unregisterWorkingCopy(workingCopy: IWorkingCopy): void { + + // Remove from registry + const workingCopiesForResource = this.mapResourceToWorkingCopy.get(workingCopy.resource.toString()); + if (workingCopiesForResource && workingCopiesForResource.delete(workingCopy) && workingCopiesForResource.size === 0) { + this.mapResourceToWorkingCopy.delete(workingCopy.resource.toString()); + } + + this.workingCopies.delete(workingCopy); + + // If copy is dirty, ensure to fire an event to signal the dirty change + // (a disposed working copy cannot account for being dirty in our model) + if (workingCopy.isDirty()) { + this._onDidChangeDirty.fire(workingCopy); + } + } + + //#endregion +} + +registerSingleton(IWorkingCopyService, WorkingCopyService, true); diff --git a/src/vs/workbench/services/workingCopy/test/common/workingCopyService.test.ts b/src/vs/workbench/services/workingCopy/test/common/workingCopyService.test.ts new file mode 100644 index 0000000000000..7bff97ff4082e --- /dev/null +++ b/src/vs/workbench/services/workingCopy/test/common/workingCopyService.test.ts @@ -0,0 +1,144 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as assert from 'assert'; +import { WorkingCopyService, IWorkingCopy } from 'vs/workbench/services/workingCopy/common/workingCopyService'; +import { URI } from 'vs/base/common/uri'; +import { Emitter } from 'vs/base/common/event'; +import { Disposable } from 'vs/base/common/lifecycle'; + +suite('WorkingCopyService', () => { + + class TestWorkingCopy extends Disposable implements IWorkingCopy { + + private readonly _onDidChangeDirty = this._register(new Emitter()); + readonly onDidChangeDirty = this._onDidChangeDirty.event; + + private readonly _onDispose = this._register(new Emitter()); + readonly onDispose = this._onDispose.event; + + readonly capabilities = 0; + + private dirty = false; + + constructor(public readonly resource: URI, isDirty = false) { + super(); + + this.dirty = isDirty; + } + + setDirty(dirty: boolean): void { + if (this.dirty !== dirty) { + this.dirty = dirty; + this._onDidChangeDirty.fire(); + } + } + + isDirty(): boolean { + return this.dirty; + } + + dispose(): void { + this._onDispose.fire(); + + super.dispose(); + } + } + + test('registry - basics', () => { + const service = new WorkingCopyService(); + + const onDidChangeDirty: IWorkingCopy[] = []; + service.onDidChangeDirty(copy => onDidChangeDirty.push(copy)); + + assert.equal(service.hasDirty, false); + assert.equal(service.dirtyCount, 0); + assert.equal(service.isDirty(URI.file('/')), false); + + // resource 1 + const resource1 = URI.file('/some/folder/file.txt'); + const copy1 = new TestWorkingCopy(resource1); + const unregister1 = service.registerWorkingCopy(copy1); + + assert.equal(service.dirtyCount, 0); + assert.equal(service.isDirty(resource1), false); + assert.equal(service.hasDirty, false); + + copy1.setDirty(true); + + assert.equal(service.dirtyCount, 1); + assert.equal(service.isDirty(resource1), true); + assert.equal(service.hasDirty, true); + assert.equal(onDidChangeDirty.length, 1); + assert.equal(onDidChangeDirty[0], copy1); + + copy1.setDirty(false); + + assert.equal(service.dirtyCount, 0); + assert.equal(service.isDirty(resource1), false); + assert.equal(service.hasDirty, false); + assert.equal(onDidChangeDirty.length, 2); + assert.equal(onDidChangeDirty[1], copy1); + + unregister1.dispose(); + + // resource 2 + const resource2 = URI.file('/some/folder/file-dirty.txt'); + const copy2 = new TestWorkingCopy(resource2, true); + const unregister2 = service.registerWorkingCopy(copy2); + + assert.equal(service.dirtyCount, 1); + assert.equal(service.isDirty(resource2), true); + assert.equal(service.hasDirty, true); + + assert.equal(onDidChangeDirty.length, 3); + assert.equal(onDidChangeDirty[2], copy2); + + unregister2.dispose(); + assert.equal(service.dirtyCount, 0); + assert.equal(service.hasDirty, false); + assert.equal(onDidChangeDirty.length, 4); + assert.equal(onDidChangeDirty[3], copy2); + }); + + test('registry - multiple copies on same resource', () => { + const service = new WorkingCopyService(); + + const onDidChangeDirty: IWorkingCopy[] = []; + service.onDidChangeDirty(copy => onDidChangeDirty.push(copy)); + + const resource = URI.parse('custom://some/folder/custom.txt'); + + const copy1 = new TestWorkingCopy(resource); + const unregister1 = service.registerWorkingCopy(copy1); + + const copy2 = new TestWorkingCopy(resource); + const unregister2 = service.registerWorkingCopy(copy2); + + copy1.setDirty(true); + + assert.equal(service.dirtyCount, 1); + assert.equal(onDidChangeDirty.length, 1); + assert.equal(service.isDirty(resource), true); + + copy2.setDirty(true); + + assert.equal(service.dirtyCount, 2); + assert.equal(onDidChangeDirty.length, 2); + assert.equal(service.isDirty(resource), true); + + unregister1.dispose(); + + assert.equal(service.dirtyCount, 1); + assert.equal(onDidChangeDirty.length, 3); + assert.equal(service.isDirty(resource), true); + + unregister2.dispose(); + + assert.equal(service.dirtyCount, 0); + assert.equal(onDidChangeDirty.length, 4); + assert.equal(service.isDirty(resource), false); + }); +}); diff --git a/src/vs/workbench/test/common/editor/untitledTextEditor.test.ts b/src/vs/workbench/test/common/editor/untitledTextEditor.test.ts index b963b547b0070..3d55bd3d1449f 100644 --- a/src/vs/workbench/test/common/editor/untitledTextEditor.test.ts +++ b/src/vs/workbench/test/common/editor/untitledTextEditor.test.ts @@ -17,6 +17,7 @@ import { UntitledTextEditorInput } from 'vs/workbench/common/editor/untitledText import { timeout } from 'vs/base/common/async'; import { snapshotToString } from 'vs/workbench/services/textfile/common/textfiles'; import { ModesRegistry, PLAINTEXT_MODE_ID } from 'vs/editor/common/modes/modesRegistry'; +import { IWorkingCopyService, IWorkingCopy } from 'vs/workbench/services/workingCopy/common/workingCopyService'; export class TestUntitledTextEditorService extends UntitledTextEditorService { get(resource: URI) { return super.get(resource); } @@ -25,9 +26,10 @@ export class TestUntitledTextEditorService extends UntitledTextEditorService { class ServiceAccessor { constructor( - @IUntitledTextEditorService public untitledTextEditorService: TestUntitledTextEditorService, - @IModeService public modeService: ModeServiceImpl, - @IConfigurationService public testConfigurationService: TestConfigurationService) { + @IUntitledTextEditorService public readonly untitledTextEditorService: TestUntitledTextEditorService, + @IWorkingCopyService public readonly workingCopyService: IWorkingCopyService, + @IModeService public readonly modeService: ModeServiceImpl, + @IConfigurationService public readonly testConfigurationService: TestConfigurationService) { } } @@ -48,6 +50,8 @@ suite('Workbench untitled text editors', () => { test('Untitled Text Editor Service', async (done) => { const service = accessor.untitledTextEditorService; + const workingCopyService = accessor.workingCopyService; + assert.equal(service.getAll().length, 0); const input1 = service.createOrGet(); @@ -83,11 +87,17 @@ suite('Workbench untitled text editors', () => { assert.equal(service.getDirty([input2.getResource()])[0].toString(), input2.getResource().toString()); assert.equal(service.getDirty([input1.getResource()]).length, 0); + assert.ok(workingCopyService.isDirty(input2.getResource())); + assert.equal(workingCopyService.dirtyCount, 1); + service.revertAll(); assert.equal(service.getAll().length, 0); assert.ok(!input2.isDirty()); assert.ok(!model.isDirty()); + assert.ok(!workingCopyService.isDirty(input2.getResource())); + assert.equal(workingCopyService.dirtyCount, 0); + input2.dispose(); assert.ok(!service.exists(input2.getResource())); @@ -109,14 +119,17 @@ suite('Workbench untitled text editors', () => { test('Untitled no longer dirty when content gets empty', async () => { const service = accessor.untitledTextEditorService; + const workingCopyService = accessor.workingCopyService; const input = service.createOrGet(); // dirty const model = await input.resolve(); model.textEditorModel.setValue('foo bar'); assert.ok(model.isDirty()); + assert.ok(workingCopyService.isDirty(model.resource)); model.textEditorModel.setValue(''); assert.ok(!model.isDirty()); + assert.ok(!workingCopyService.isDirty(model.resource)); input.dispose(); }); @@ -176,11 +189,21 @@ suite('Workbench untitled text editors', () => { test('Untitled with initial content is dirty', async () => { const service = accessor.untitledTextEditorService; const input = service.createOrGet(undefined, undefined, 'Hello World'); + const workingCopyService = accessor.workingCopyService; + + let onDidChangeDirty: IWorkingCopy | undefined = undefined; + const listener = workingCopyService.onDidChangeDirty(copy => { + onDidChangeDirty = copy; + }); // dirty const model = await input.resolve(); assert.ok(model.isDirty()); + assert.equal(workingCopyService.dirtyCount, 1); + assert.equal(onDidChangeDirty, model); + input.dispose(); + listener.dispose(); }); test('Untitled created with files.defaultLanguage setting', () => { diff --git a/src/vs/workbench/test/workbenchTestServices.ts b/src/vs/workbench/test/workbenchTestServices.ts index c4acaed37e875..5d9d717d2bcc1 100644 --- a/src/vs/workbench/test/workbenchTestServices.ts +++ b/src/vs/workbench/test/workbenchTestServices.ts @@ -92,6 +92,7 @@ import { IBackupMainService, IWorkspaceBackupInfo } from 'vs/platform/backup/ele import { IEmptyWindowBackupInfo } from 'vs/platform/backup/node/backup'; import { IDialogMainService } from 'vs/platform/dialogs/electron-main/dialogs'; import { find } from 'vs/base/common/arrays'; +import { WorkingCopyService, IWorkingCopyService } from 'vs/workbench/services/workingCopy/common/workingCopyService'; export function createFileInput(instantiationService: IInstantiationService, resource: URI): FileEditorInput { return instantiationService.createInstance(FileEditorInput, resource, undefined, undefined); @@ -330,6 +331,7 @@ export function workbenchInstantiationService(): IInstantiationService { instantiationService.stub(IEditorService, editorService); instantiationService.stub(ICodeEditorService, new TestCodeEditorService()); instantiationService.stub(IViewletService, new TestViewletService()); + instantiationService.stub(IWorkingCopyService, new TestWorkingCopyService()); return instantiationService; } @@ -1464,3 +1466,7 @@ export class TestDialogMainService implements IDialogMainService { throw new Error('Method not implemented.'); } } + +export class TestWorkingCopyService extends WorkingCopyService { + +} diff --git a/src/vs/workbench/workbench.common.main.ts b/src/vs/workbench/workbench.common.main.ts index ddb19940d86a6..8c9f50ad424b0 100644 --- a/src/vs/workbench/workbench.common.main.ts +++ b/src/vs/workbench/workbench.common.main.ts @@ -82,6 +82,7 @@ import 'vs/workbench/services/extensions/common/staticExtensions'; import 'vs/workbench/services/userDataSync/common/settingsMergeService'; import 'vs/workbench/services/path/common/remotePathService'; import 'vs/workbench/services/remote/common/remoteExplorerService'; +import 'vs/workbench/services/workingCopy/common/workingCopyService'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { ExtensionGalleryService } from 'vs/platform/extensionManagement/common/extensionGalleryService'; From f0f6c8dc4ceda13c9e935895ead2538dff352641 Mon Sep 17 00:00:00 2001 From: isidor Date: Tue, 12 Nov 2019 16:52:13 +0100 Subject: [PATCH 122/352] fixes #83757 --- .../contrib/debug/browser/media/debug.contribution.css | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/debug/browser/media/debug.contribution.css b/src/vs/workbench/contrib/debug/browser/media/debug.contribution.css index 3ab961601acd8..fd184092abdc8 100644 --- a/src/vs/workbench/contrib/debug/browser/media/debug.contribution.css +++ b/src/vs/workbench/contrib/debug/browser/media/debug.contribution.css @@ -120,7 +120,8 @@ } .monaco-editor .debug-top-stack-frame.debug-breakpoint-and-top-stack-frame, -.monaco-editor .inline-breakpoint-widget.debug-breakpoint-and-top-stack-frame-at-column { +.monaco-editor .debug-breakpoint.debug-top-stack-frame, +.monaco-editor .debug-breakpoint-and-top-stack-frame-at-column { background: url('current-and-breakpoint.svg') center center no-repeat; } From cbdb21d24c8f45d1cb5c879324f980b6301b914e Mon Sep 17 00:00:00 2001 From: Andre Weinand Date: Tue, 12 Nov 2019 17:01:58 +0100 Subject: [PATCH 123/352] do a "--inspect-brk" if being asked to do so; fixes #83583 --- .../services/environment/browser/environmentService.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/services/environment/browser/environmentService.ts b/src/vs/workbench/services/environment/browser/environmentService.ts index 4035945e8e383..5437e4c00caaa 100644 --- a/src/vs/workbench/services/environment/browser/environmentService.ts +++ b/src/vs/workbench/services/environment/browser/environmentService.ts @@ -301,7 +301,7 @@ export class BrowserWorkbenchEnvironmentService implements IWorkbenchEnvironment break; case 'inspect-brk-extensions': extensionHostDebugEnvironment.params.port = parseInt(value); - extensionHostDebugEnvironment.params.break = false; + extensionHostDebugEnvironment.params.break = true; break; } } From dc315fcb0feb29cc3683a5887f25890c7fc62633 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Tue, 12 Nov 2019 17:03:18 +0100 Subject: [PATCH 124/352] fixes #84598 --- src/vs/base/browser/ui/tree/asyncDataTree.ts | 75 +++++++++++++++++++- 1 file changed, 73 insertions(+), 2 deletions(-) diff --git a/src/vs/base/browser/ui/tree/asyncDataTree.ts b/src/vs/base/browser/ui/tree/asyncDataTree.ts index 49cf32517511c..9a5dd74b4f530 100644 --- a/src/vs/base/browser/ui/tree/asyncDataTree.ts +++ b/src/vs/base/browser/ui/tree/asyncDataTree.ts @@ -264,7 +264,7 @@ function dfs(node: IAsyncDataTreeNode, fn: (node: IAsyncDa export class AsyncDataTree implements IDisposable { protected readonly tree: ObjectTree, TFilterData>; - private readonly root: IAsyncDataTreeNode; + protected readonly root: IAsyncDataTreeNode; private readonly nodes = new Map>(); private readonly sorter?: ITreeSorter; private readonly collapseByDefault?: { (e: T): boolean; }; @@ -859,7 +859,7 @@ export class AsyncDataTree implements IDisposable return childrenToRefresh; } - private render(node: IAsyncDataTreeNode, viewStateContext?: IAsyncDataTreeViewStateContext): void { + protected render(node: IAsyncDataTreeNode, viewStateContext?: IAsyncDataTreeViewStateContext): void { const children = node.children.map(node => this.asTreeElement(node, viewStateContext)); this.tree.setChildren(node === this.root ? null : node, children); @@ -1098,4 +1098,75 @@ export class CompressibleAsyncDataTree extends As return { focus, selection, expanded, scrollTop: this.scrollTop }; } + + protected render(node: IAsyncDataTreeNode, viewStateContext?: IAsyncDataTreeViewStateContext): void { + if (!this.identityProvider) { + return super.render(node, viewStateContext); + } + + // Preserve traits across compressions. Hacky but does the trick. + // This is hard to fix properly since it requires rewriting the traits + // across trees and lists. Let's just keep it this way for now. + const getId = (element: T) => this.identityProvider!.getId(element).toString(); + const getUncompressedIds = (nodes: IAsyncDataTreeNode[]): Set => { + const result = new Set(); + + for (const node of nodes) { + const compressedNode = this.tree.getCompressedTreeNode(node === this.root ? null : node); + + if (!compressedNode.element) { + continue; + } + + for (const node of compressedNode.element.elements) { + result.add(getId(node.element as T)); + } + } + + return result; + }; + + const oldSelection = getUncompressedIds(this.tree.getSelection() as IAsyncDataTreeNode[]); + const oldFocus = getUncompressedIds(this.tree.getFocus() as IAsyncDataTreeNode[]); + + super.render(node, viewStateContext); + + const selection = this.getSelection(); + let didChangeSelection = false; + + const focus = this.getFocus(); + let didChangeFocus = false; + + const visit = (node: ITreeNode> | null, TFilterData>) => { + const compressedNode = node.element; + + if (compressedNode) { + for (let i = 0; i < compressedNode.elements.length; i++) { + const id = getId(compressedNode.elements[i].element as T); + + if (oldSelection.has(id)) { + selection.push(compressedNode.elements[compressedNode.elements.length - 1].element as T); + didChangeSelection = true; + } + + if (oldFocus.has(id)) { + focus.push(compressedNode.elements[compressedNode.elements.length - 1].element as T); + didChangeFocus = true; + } + } + } + + node.children.forEach(visit); + }; + + visit(this.tree.getCompressedTreeNode(node === this.root ? null : node)); + + if (didChangeSelection) { + this.setSelection(selection); + } + + if (didChangeFocus) { + this.setFocus(focus); + } + } } From da5f40883482e245afb4d87ce4f94a73ecb5c13f Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Tue, 12 Nov 2019 17:04:49 +0100 Subject: [PATCH 125/352] workbench editor model: getResource => resource --- .../api/browser/mainThreadDocuments.ts | 2 +- .../api/browser/mainThreadSaveParticipant.ts | 10 +-- .../browser/parts/editor/binaryEditor.ts | 2 +- .../common/editor/binaryEditorModel.ts | 9 +- .../common/editor/untitledTextEditorModel.ts | 4 - .../browser/editors/fileEditorTracker.ts | 6 +- .../contrib/files/browser/saveErrorHandler.ts | 12 +-- .../textfile/browser/textFileService.ts | 28 +++---- .../textfile/common/textFileEditorModel.ts | 10 +-- .../common/textFileEditorModelManager.ts | 2 +- .../services/textfile/common/textfiles.ts | 7 +- .../textfile/test/textFileEditorModel.test.ts | 8 +- .../test/textFileEditorModelManager.test.ts | 2 +- .../textfile/test/textFileService.test.ts | 82 +++++++++---------- .../test/textModelResolverService.test.ts | 4 +- .../common/editor/untitledTextEditor.test.ts | 4 +- 16 files changed, 88 insertions(+), 104 deletions(-) diff --git a/src/vs/workbench/api/browser/mainThreadDocuments.ts b/src/vs/workbench/api/browser/mainThreadDocuments.ts index 05eb4662f3951..2b743a9484fbc 100644 --- a/src/vs/workbench/api/browser/mainThreadDocuments.ts +++ b/src/vs/workbench/api/browser/mainThreadDocuments.ts @@ -233,7 +233,7 @@ export class MainThreadDocuments implements MainThreadDocumentsShape { initialValue, useResourcePath: Boolean(resource && resource.path) }).then(model => { - const resource = model.getResource(); + const resource = model.resource; if (!this._modelIsSynced.has(resource.toString())) { throw new Error(`expected URI ${resource.toString()} to have come to LIFE`); diff --git a/src/vs/workbench/api/browser/mainThreadSaveParticipant.ts b/src/vs/workbench/api/browser/mainThreadSaveParticipant.ts index 3dff068097ec1..5fdd5b7c95190 100644 --- a/src/vs/workbench/api/browser/mainThreadSaveParticipant.ts +++ b/src/vs/workbench/api/browser/mainThreadSaveParticipant.ts @@ -51,7 +51,7 @@ class TrimWhitespaceParticipant implements ISaveParticipantParticipant { } async participate(model: IResolvedTextFileEditorModel, env: { reason: SaveReason; }): Promise { - if (this.configurationService.getValue('files.trimTrailingWhitespace', { overrideIdentifier: model.textEditorModel.getLanguageIdentifier().language, resource: model.getResource() })) { + if (this.configurationService.getValue('files.trimTrailingWhitespace', { overrideIdentifier: model.textEditorModel.getLanguageIdentifier().language, resource: model.resource })) { this.doTrimTrailingWhitespace(model.textEditorModel, env.reason === SaveReason.AUTO); } } @@ -113,7 +113,7 @@ export class FinalNewLineParticipant implements ISaveParticipantParticipant { } async participate(model: IResolvedTextFileEditorModel, env: { reason: SaveReason; }): Promise { - if (this.configurationService.getValue('files.insertFinalNewline', { overrideIdentifier: model.textEditorModel.getLanguageIdentifier().language, resource: model.getResource() })) { + if (this.configurationService.getValue('files.insertFinalNewline', { overrideIdentifier: model.textEditorModel.getLanguageIdentifier().language, resource: model.resource })) { this.doInsertFinalNewLine(model.textEditorModel); } } @@ -147,7 +147,7 @@ export class TrimFinalNewLinesParticipant implements ISaveParticipantParticipant } async participate(model: IResolvedTextFileEditorModel, env: { reason: SaveReason; }): Promise { - if (this.configurationService.getValue('files.trimFinalNewlines', { overrideIdentifier: model.textEditorModel.getLanguageIdentifier().language, resource: model.getResource() })) { + if (this.configurationService.getValue('files.trimFinalNewlines', { overrideIdentifier: model.textEditorModel.getLanguageIdentifier().language, resource: model.resource })) { this.doTrimFinalNewLines(model.textEditorModel, env.reason === SaveReason.AUTO); } } @@ -257,7 +257,7 @@ class CodeActionOnSaveParticipant implements ISaveParticipant { const model = editorModel.textEditorModel; - const settingsOverrides = { overrideIdentifier: model.getLanguageIdentifier().language, resource: editorModel.getResource() }; + const settingsOverrides = { overrideIdentifier: model.getLanguageIdentifier().language, resource: editorModel.resource }; const setting = this._configurationService.getValue('editor.codeActionsOnSave', settingsOverrides); if (!setting) { return undefined; @@ -343,7 +343,7 @@ class ExtHostSaveParticipant implements ISaveParticipantParticipant { return new Promise((resolve, reject) => { setTimeout(() => reject(localize('timeout.onWillSave', "Aborted onWillSaveTextDocument-event after 1750ms")), 1750); - this._proxy.$participateInSave(editorModel.getResource(), env.reason).then(values => { + this._proxy.$participateInSave(editorModel.resource, env.reason).then(values => { if (!values.every(success => success)) { return Promise.reject(new Error('listener failed')); } diff --git a/src/vs/workbench/browser/parts/editor/binaryEditor.ts b/src/vs/workbench/browser/parts/editor/binaryEditor.ts index 53b00a24b3318..d196daa8517ec 100644 --- a/src/vs/workbench/browser/parts/editor/binaryEditor.ts +++ b/src/vs/workbench/browser/parts/editor/binaryEditor.ts @@ -93,7 +93,7 @@ export abstract class BaseBinaryResourceEditor extends BaseEditor { } const [binaryContainer, scrollbar] = assertAllDefined(this.binaryContainer, this.scrollbar); - this.resourceViewerContext = ResourceViewer.show({ name: model.getName(), resource: model.getResource(), size: model.getSize(), etag: model.getETag(), mime: model.getMime() }, binaryContainer, scrollbar, { + this.resourceViewerContext = ResourceViewer.show({ name: model.getName(), resource: model.resource, size: model.getSize(), etag: model.getETag(), mime: model.getMime() }, binaryContainer, scrollbar, { openInternalClb: () => this.handleOpenInternalCallback(input, options), openExternalClb: this.environmentService.configuration.remoteAuthority ? undefined : resource => this.callbacks.openExternal(resource), metadataClb: meta => this.handleMetadataChanged(meta) diff --git a/src/vs/workbench/common/editor/binaryEditorModel.ts b/src/vs/workbench/common/editor/binaryEditorModel.ts index 5f94a8c947a70..a911af30a8c2a 100644 --- a/src/vs/workbench/common/editor/binaryEditorModel.ts +++ b/src/vs/workbench/common/editor/binaryEditorModel.ts @@ -19,7 +19,7 @@ export class BinaryEditorModel extends EditorModel { private readonly mime: string; constructor( - private readonly resource: URI, + public readonly resource: URI, private readonly name: string | undefined, @IFileService private readonly fileService: IFileService ) { @@ -49,13 +49,6 @@ export class BinaryEditorModel extends EditorModel { return this.name || basename(this.resource); } - /** - * The resource of the binary resource. - */ - getResource(): URI { - return this.resource; - } - /** * The size of the binary resource if known. */ diff --git a/src/vs/workbench/common/editor/untitledTextEditorModel.ts b/src/vs/workbench/common/editor/untitledTextEditorModel.ts index 7c47a00dfc9c7..b0d22deb9b3ad 100644 --- a/src/vs/workbench/common/editor/untitledTextEditorModel.ts +++ b/src/vs/workbench/common/editor/untitledTextEditorModel.ts @@ -115,10 +115,6 @@ export class UntitledTextEditorModel extends BaseTextEditorModel implements IEnc this._onDidChangeDirty.fire(); } - getResource(): URI { - return this.resource; - } - revert(): void { this.setDirty(false); diff --git a/src/vs/workbench/contrib/files/browser/editors/fileEditorTracker.ts b/src/vs/workbench/contrib/files/browser/editors/fileEditorTracker.ts index 271741351a970..ca9dba559e204 100644 --- a/src/vs/workbench/contrib/files/browser/editors/fileEditorTracker.ts +++ b/src/vs/workbench/contrib/files/browser/editors/fileEditorTracker.ts @@ -98,7 +98,7 @@ export class FileEditorTracker extends Disposable implements IWorkbenchContribut return resource ? this.textFileService.models.get(resource) : undefined; })) .filter(model => !model.isDirty()), - m => m.getResource().toString() + m => m.resource.toString() ).forEach(model => this.queueModelLoad(model)); } } @@ -299,7 +299,7 @@ export class FileEditorTracker extends Disposable implements IWorkbenchContribut // and updated right after. distinct(coalesce([...e.getUpdated(), ...e.getAdded()] .map(u => this.textFileService.models.get(u.resource))) - .filter(model => model && !model.isDirty()), m => m.getResource().toString()) + .filter(model => model && !model.isDirty()), m => m.resource.toString()) .forEach(model => this.queueModelLoad(model)); } @@ -308,7 +308,7 @@ export class FileEditorTracker extends Disposable implements IWorkbenchContribut // Load model to update (use a queue to prevent accumulation of loads // when the load actually takes long. At most we only want the queue // to have a size of 2 (1 running load and 1 queued load). - const queue = this.modelLoadQueue.queueFor(model.getResource()); + const queue = this.modelLoadQueue.queueFor(model.resource); if (queue.size <= 1) { queue.queue(() => model.load().then(undefined, onUnexpectedError)); } diff --git a/src/vs/workbench/contrib/files/browser/saveErrorHandler.ts b/src/vs/workbench/contrib/files/browser/saveErrorHandler.ts index 847d044971b8d..635033681e1eb 100644 --- a/src/vs/workbench/contrib/files/browser/saveErrorHandler.ts +++ b/src/vs/workbench/contrib/files/browser/saveErrorHandler.ts @@ -103,7 +103,7 @@ export class SaveErrorHandler extends Disposable implements ISaveErrorHandler, I onSaveError(error: any, model: ITextFileEditorModel): void { const fileOperationError = error as FileOperationError; - const resource = model.getResource(); + const resource = model.resource; let message: string; const primaryActions: IAction[] = []; @@ -113,7 +113,7 @@ export class SaveErrorHandler extends Disposable implements ISaveErrorHandler, I if (fileOperationError.fileOperationResult === FileOperationResult.FILE_MODIFIED_SINCE) { // If the user tried to save from the opened conflict editor, show its message again - if (this.activeConflictResolutionResource && this.activeConflictResolutionResource.toString() === model.getResource().toString()) { + if (this.activeConflictResolutionResource && this.activeConflictResolutionResource.toString() === model.resource.toString()) { if (this.storageService.getBoolean(LEARN_MORE_DIRTY_WRITE_IGNORE_KEY, StorageScope.GLOBAL)) { return; // return if this message is ignored } @@ -178,7 +178,7 @@ export class SaveErrorHandler extends Disposable implements ISaveErrorHandler, I const actions: INotificationActions = { primary: primaryActions, secondary: secondaryActions }; const handle = this.notificationService.notify({ severity: Severity.Error, message, actions }); Event.once(handle.onDidClose)(() => { dispose(primaryActions), dispose(secondaryActions); }); - this.messages.set(model.getResource(), handle); + this.messages.set(model.resource, handle); } dispose(): void { @@ -243,7 +243,7 @@ class ResolveSaveConflictAction extends Action { async run(): Promise { if (!this.model.isDisposed()) { - const resource = this.model.getResource(); + const resource = this.model.resource; const name = basename(resource); const editorLabel = nls.localize('saveConflictDiffLabel', "{0} (in file) ↔ {1} (in {2}) - Resolve save conflict", name, name, this.productService.nameLong); @@ -332,7 +332,7 @@ export const acceptLocalChangesCommand = async (accessor: ServicesAccessor, reso await model.save(); // Reopen file input - await editorService.openEditor({ resource: model.getResource() }, group); + await editorService.openEditor({ resource: model.resource }, group); // Clean up group.closeEditor(editor); @@ -361,7 +361,7 @@ export const revertLocalChangesCommand = async (accessor: ServicesAccessor, reso await model.revert(); // Reopen file input - await editorService.openEditor({ resource: model.getResource() }, group); + await editorService.openEditor({ resource: model.resource }, group); // Clean up group.closeEditor(editor); diff --git a/src/vs/workbench/services/textfile/browser/textFileService.ts b/src/vs/workbench/services/textfile/browser/textFileService.ts index b77eb7be4c0e1..7a68d53bd7a9f 100644 --- a/src/vs/workbench/services/textfile/browser/textFileService.ts +++ b/src/vs/workbench/services/textfile/browser/textFileService.ts @@ -467,7 +467,7 @@ export abstract class AbstractTextFileService extends Disposable implements ITex const sourceModels: ITextFileEditorModel[] = []; const conflictingModels: ITextFileEditorModel[] = []; for (const model of this.getFileModels()) { - const resource = model.getResource(); + const resource = model.resource; if (isEqualOrParent(resource, target, false /* do not ignorecase, see https://github.com/Microsoft/vscode/issues/56384 */)) { conflictingModels.push(model); @@ -483,7 +483,7 @@ export abstract class AbstractTextFileService extends Disposable implements ITex type ModelToRestore = { resource: URI; snapshot?: ITextSnapshot }; const modelsToRestore: ModelToRestore[] = []; for (const sourceModel of sourceModels) { - const sourceModelResource = sourceModel.getResource(); + const sourceModelResource = sourceModel.resource; // If the source is the actual model, just use target as new resource let modelToRestoreResource: URI; @@ -508,7 +508,7 @@ export abstract class AbstractTextFileService extends Disposable implements ITex // in order to move, we need to soft revert all dirty models, // both from the source as well as the target if any const dirtyModels = [...sourceModels, ...conflictingModels].filter(model => model.isDirty()); - await this.revertAll(dirtyModels.map(dirtyModel => dirtyModel.getResource()), { soft: true }); + await this.revertAll(dirtyModels.map(dirtyModel => dirtyModel.resource), { soft: true }); // now we can rename the source to target via file operation let stat: IFileStatWithMetadata; @@ -735,9 +735,9 @@ export abstract class AbstractTextFileService extends Disposable implements ITex }); const mapResourceToResult = new ResourceMap(); - dirtyFileModels.forEach(m => { - mapResourceToResult.set(m.getResource(), { - source: m.getResource() + dirtyFileModels.forEach(dirtyModel => { + mapResourceToResult.set(dirtyModel.resource, { + source: dirtyModel.resource }); }); @@ -745,7 +745,7 @@ export abstract class AbstractTextFileService extends Disposable implements ITex await model.save(options); if (!model.isDirty()) { - const result = mapResourceToResult.get(model.getResource()); + const result = mapResourceToResult.get(model.resource); if (result) { result.success = true; } @@ -861,7 +861,7 @@ export abstract class AbstractTextFileService extends Disposable implements ITex // path. This can happen if the file was created after the untitled file was opened. // See https://github.com/Microsoft/vscode/issues/67946 let write: boolean; - if (sourceModel instanceof UntitledTextEditorModel && sourceModel.hasAssociatedFilePath && targetExists && isEqual(target, toLocalResource(sourceModel.getResource(), this.environmentService.configuration.remoteAuthority))) { + if (sourceModel instanceof UntitledTextEditorModel && sourceModel.hasAssociatedFilePath && targetExists && isEqual(target, toLocalResource(sourceModel.resource, this.environmentService.configuration.remoteAuthority))) { write = await this.confirmOverwrite(target); } else { write = true; @@ -944,9 +944,9 @@ export abstract class AbstractTextFileService extends Disposable implements ITex const fileModels = options?.force ? this.getFileModels(resources) : this.getDirtyFileModels(resources); const mapResourceToResult = new ResourceMap(); - fileModels.forEach(m => { - mapResourceToResult.set(m.getResource(), { - source: m.getResource() + fileModels.forEach(fileModel => { + mapResourceToResult.set(fileModel.resource, { + source: fileModel.resource }); }); @@ -955,7 +955,7 @@ export abstract class AbstractTextFileService extends Disposable implements ITex await model.revert(options?.soft); if (!model.isDirty()) { - const result = mapResourceToResult.get(model.getResource()); + const result = mapResourceToResult.get(model.resource); if (result) { result.success = true; } @@ -964,7 +964,7 @@ export abstract class AbstractTextFileService extends Disposable implements ITex // FileNotFound means the file got deleted meanwhile, so still record as successful revert if ((error).fileOperationResult === FileOperationResult.FILE_NOT_FOUND) { - const result = mapResourceToResult.get(model.getResource()); + const result = mapResourceToResult.get(model.resource); if (result) { result.success = true; } @@ -983,7 +983,7 @@ export abstract class AbstractTextFileService extends Disposable implements ITex getDirty(resources?: URI[]): URI[] { // Collect files - const dirty = this.getDirtyFileModels(resources).map(m => m.getResource()); + const dirty = this.getDirtyFileModels(resources).map(dirtyFileModel => dirtyFileModel.resource); // Add untitled ones dirty.push(...this.untitledTextEditorService.getDirty(resources)); diff --git a/src/vs/workbench/services/textfile/common/textFileEditorModel.ts b/src/vs/workbench/services/textfile/common/textFileEditorModel.ts index ee2501f8854f0..b86d2ed4508d1 100644 --- a/src/vs/workbench/services/textfile/common/textFileEditorModel.ts +++ b/src/vs/workbench/services/textfile/common/textFileEditorModel.ts @@ -29,7 +29,7 @@ import { ILogService } from 'vs/platform/log/common/log'; import { isEqual, isEqualOrParent, extname, basename, joinPath } from 'vs/base/common/resources'; import { onUnexpectedError } from 'vs/base/common/errors'; import { Schemas } from 'vs/base/common/network'; -import { IWorkingCopyService, IWorkingCopy, WorkingCopyCapabilities } from 'vs/workbench/services/workingCopy/common/workingCopyService'; +import { IWorkingCopyService, WorkingCopyCapabilities } from 'vs/workbench/services/workingCopy/common/workingCopyService'; export interface IBackupMetaData { mtime: number; @@ -58,7 +58,7 @@ type TelemetryData = { /** * The text file editor model listens to changes to its underlying code editor model and saves these changes through the file service back to the disk. */ -export class TextFileEditorModel extends BaseTextEditorModel implements ITextFileEditorModel, IWorkingCopy { +export class TextFileEditorModel extends BaseTextEditorModel implements ITextFileEditorModel { static DEFAULT_CONTENT_CHANGE_BUFFER_DELAY = CONTENT_CHANGE_EVENT_BUFFER_DELAY; static DEFAULT_ORPHANED_CHANGE_BUFFER_DELAY = 100; @@ -1030,10 +1030,6 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil return this.disposed; } - getResource(): URI { - return this.resource; - } - getStat(): IFileStatWithMetadata | undefined { return this.lastResolvedFileStat; } @@ -1144,6 +1140,6 @@ class DefaultSaveErrorHandler implements ISaveErrorHandler { constructor(@INotificationService private readonly notificationService: INotificationService) { } onSaveError(error: Error, model: TextFileEditorModel): void { - this.notificationService.error(nls.localize('genericSaveError', "Failed to save '{0}': {1}", basename(model.getResource()), toErrorMessage(error, false))); + this.notificationService.error(nls.localize('genericSaveError', "Failed to save '{0}': {1}", basename(model.resource), toErrorMessage(error, false))); } } diff --git a/src/vs/workbench/services/textfile/common/textFileEditorModelManager.ts b/src/vs/workbench/services/textfile/common/textFileEditorModelManager.ts index 562aa4c727e9f..08ebc5edc4d01 100644 --- a/src/vs/workbench/services/textfile/common/textFileEditorModelManager.ts +++ b/src/vs/workbench/services/textfile/common/textFileEditorModelManager.ts @@ -304,7 +304,7 @@ export class TextFileEditorModelManager extends Disposable implements ITextFileE return; // already disposed } - if (this.mapResourceToPendingModelLoaders.has(model.getResource())) { + if (this.mapResourceToPendingModelLoaders.has(model.resource)) { return; // not yet loaded } diff --git a/src/vs/workbench/services/textfile/common/textfiles.ts b/src/vs/workbench/services/textfile/common/textfiles.ts index 5a752b201286b..4ab9efb61c71b 100644 --- a/src/vs/workbench/services/textfile/common/textfiles.ts +++ b/src/vs/workbench/services/textfile/common/textfiles.ts @@ -15,6 +15,7 @@ import { RawContextKey } from 'vs/platform/contextkey/common/contextkey'; import { VSBuffer, VSBufferReadable } from 'vs/base/common/buffer'; import { isUndefinedOrNull } from 'vs/base/common/types'; import { isNative } from 'vs/base/common/platform'; +import { IWorkingCopy } from 'vs/workbench/services/workingCopy/common/workingCopyService'; export const ITextFileService = createDecorator('textFileService'); @@ -328,7 +329,7 @@ export class TextFileModelChangeEvent { private _resource: URI; constructor(model: ITextFileEditorModel, private _kind: StateChange) { - this._resource = model.getResource(); + this._resource = model.resource; } get resource(): URI { @@ -492,13 +493,11 @@ export interface ILoadOptions { reason?: LoadReason; } -export interface ITextFileEditorModel extends ITextEditorModel, IEncodingSupport, IModeSupport { +export interface ITextFileEditorModel extends ITextEditorModel, IEncodingSupport, IModeSupport, IWorkingCopy { readonly onDidContentChange: Event; readonly onDidStateChange: Event; - getResource(): URI; - hasState(state: ModelState): boolean; updatePreferredEncoding(encoding: string | undefined): void; diff --git a/src/vs/workbench/services/textfile/test/textFileEditorModel.test.ts b/src/vs/workbench/services/textfile/test/textFileEditorModel.test.ts index dbddfc86a4011..8ccf5a25c5db6 100644 --- a/src/vs/workbench/services/textfile/test/textFileEditorModel.test.ts +++ b/src/vs/workbench/services/textfile/test/textFileEditorModel.test.ts @@ -95,7 +95,7 @@ suite('Files - TextFileEditorModel', () => { assert.equal(accessor.workingCopyService.isDirty(model.resource), false); model.dispose(); - assert.ok(!accessor.modelService.getModel(model.getResource())); + assert.ok(!accessor.modelService.getModel(model.resource)); }); test('save - touching also emits saved event', async function () { @@ -123,7 +123,7 @@ suite('Files - TextFileEditorModel', () => { assert.ok(!workingCopyEvent); model.dispose(); - assert.ok(!accessor.modelService.getModel(model.getResource())); + assert.ok(!accessor.modelService.getModel(model.resource)); }); test('setEncoding - encode', function () { @@ -162,7 +162,7 @@ suite('Files - TextFileEditorModel', () => { assert.equal(model.textEditorModel!.getModeId(), mode); model.dispose(); - assert.ok(!accessor.modelService.getModel(model.getResource())); + assert.ok(!accessor.modelService.getModel(model.resource)); }); test('disposes when underlying model is destroyed', async function () { @@ -185,7 +185,7 @@ suite('Files - TextFileEditorModel', () => { await model.load(); assert.ok(model.isResolved()); model.dispose(); - assert.ok(!accessor.modelService.getModel(model.getResource())); + assert.ok(!accessor.modelService.getModel(model.resource)); }); test('Load returns dirty model as long as model is dirty', async function () { diff --git a/src/vs/workbench/services/textfile/test/textFileEditorModelManager.test.ts b/src/vs/workbench/services/textfile/test/textFileEditorModelManager.test.ts index 857096d4b0de7..0494cbf139bb1 100644 --- a/src/vs/workbench/services/textfile/test/textFileEditorModelManager.test.ts +++ b/src/vs/workbench/services/textfile/test/textFileEditorModelManager.test.ts @@ -273,7 +273,7 @@ suite('Files - TextFileEditorModelManager', () => { const model = await manager.loadOrCreate(resource, { encoding: 'utf8' }); model.dispose(); assert.ok(!manager.get(resource)); - assert.ok(!accessor.modelService.getModel(model.getResource())); + assert.ok(!accessor.modelService.getModel(model.resource)); manager.dispose(); }); diff --git a/src/vs/workbench/services/textfile/test/textFileService.test.ts b/src/vs/workbench/services/textfile/test/textFileService.test.ts index d8f09e50b79a3..fc486b3c0b7c8 100644 --- a/src/vs/workbench/services/textfile/test/textFileService.test.ts +++ b/src/vs/workbench/services/textfile/test/textFileService.test.ts @@ -67,7 +67,7 @@ suite('Files - TextFileService', () => { test('confirm onWillShutdown - no veto', async function () { model = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/file.txt'), 'utf8', undefined); - (accessor.textFileService.models).add(model.getResource(), model); + (accessor.textFileService.models).add(model.resource, model); const event = new BeforeShutdownEventImpl(); accessor.lifecycleService.fireWillShutdown(event); @@ -82,7 +82,7 @@ suite('Files - TextFileService', () => { test('confirm onWillShutdown - veto if user cancels', async function () { model = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/file.txt'), 'utf8', undefined); - (accessor.textFileService.models).add(model.getResource(), model); + (accessor.textFileService.models).add(model.resource, model); const service = accessor.textFileService; service.setConfirmResult(ConfirmResult.CANCEL); @@ -98,7 +98,7 @@ suite('Files - TextFileService', () => { test('confirm onWillShutdown - no veto and backups cleaned up if user does not want to save (hot.exit: off)', async function () { model = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/file.txt'), 'utf8', undefined); - (accessor.textFileService.models).add(model.getResource(), model); + (accessor.textFileService.models).add(model.resource, model); const service = accessor.textFileService; service.setConfirmResult(ConfirmResult.DONT_SAVE); @@ -124,7 +124,7 @@ suite('Files - TextFileService', () => { test('confirm onWillShutdown - save (hot.exit: off)', async function () { model = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/file.txt'), 'utf8', undefined); - (accessor.textFileService.models).add(model.getResource(), model); + (accessor.textFileService.models).add(model.resource, model); const service = accessor.textFileService; service.setConfirmResult(ConfirmResult.SAVE); @@ -143,18 +143,18 @@ suite('Files - TextFileService', () => { test('isDirty/getDirty - files and untitled', async function () { model = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/file.txt'), 'utf8', undefined); - (accessor.textFileService.models).add(model.getResource(), model); + (accessor.textFileService.models).add(model.resource, model); const service = accessor.textFileService; await model.load(); - assert.ok(!service.isDirty(model.getResource())); + assert.ok(!service.isDirty(model.resource)); model.textEditorModel!.setValue('foo'); - assert.ok(service.isDirty(model.getResource())); + assert.ok(service.isDirty(model.resource)); assert.equal(service.getDirty().length, 1); - assert.equal(service.getDirty([model.getResource()])[0].toString(), model.getResource().toString()); + assert.equal(service.getDirty([model.resource])[0].toString(), model.resource.toString()); const untitled = accessor.untitledTextEditorService.createOrGet(); const untitledModel = await untitled.resolve(); @@ -170,23 +170,23 @@ suite('Files - TextFileService', () => { test('save - file', async function () { model = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/file.txt'), 'utf8', undefined); - (accessor.textFileService.models).add(model.getResource(), model); + (accessor.textFileService.models).add(model.resource, model); const service = accessor.textFileService; await model.load(); model.textEditorModel!.setValue('foo'); - assert.ok(service.isDirty(model.getResource())); + assert.ok(service.isDirty(model.resource)); - const res = await service.save(model.getResource()); + const res = await service.save(model.resource); assert.ok(res); - assert.ok(!service.isDirty(model.getResource())); + assert.ok(!service.isDirty(model.resource)); }); test('save - UNC path', async function () { const untitledUncUri = URI.from({ scheme: 'untitled', authority: 'server', path: '/share/path/file.txt' }); model = instantiationService.createInstance(TextFileEditorModel, untitledUncUri, 'utf8', undefined); - (accessor.textFileService.models).add(model.getResource(), model); + (accessor.textFileService.models).add(model.resource, model); const mockedFileUri = untitledUncUri.with({ scheme: Schemas.file }); const mockedEditorInput = instantiationService.createInstance(TextFileEditorModel, mockedFileUri, 'utf8', undefined); @@ -210,65 +210,65 @@ suite('Files - TextFileService', () => { test('saveAll - file', async function () { model = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/file.txt'), 'utf8', undefined); - (accessor.textFileService.models).add(model.getResource(), model); + (accessor.textFileService.models).add(model.resource, model); const service = accessor.textFileService; await model.load(); model.textEditorModel!.setValue('foo'); - assert.ok(service.isDirty(model.getResource())); + assert.ok(service.isDirty(model.resource)); - const res = await service.saveAll([model.getResource()]); + const res = await service.saveAll([model.resource]); assert.ok(res); - assert.ok(!service.isDirty(model.getResource())); + assert.ok(!service.isDirty(model.resource)); assert.equal(res.results.length, 1); - assert.equal(res.results[0].source.toString(), model.getResource().toString()); + assert.equal(res.results[0].source.toString(), model.resource.toString()); }); test('saveAs - file', async function () { model = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/file.txt'), 'utf8', undefined); - (accessor.textFileService.models).add(model.getResource(), model); + (accessor.textFileService.models).add(model.resource, model); const service = accessor.textFileService; - service.setPromptPath(model.getResource()); + service.setPromptPath(model.resource); await model.load(); model.textEditorModel!.setValue('foo'); - assert.ok(service.isDirty(model.getResource())); + assert.ok(service.isDirty(model.resource)); - const res = await service.saveAs(model.getResource()); - assert.equal(res!.toString(), model.getResource().toString()); - assert.ok(!service.isDirty(model.getResource())); + const res = await service.saveAs(model.resource); + assert.equal(res!.toString(), model.resource.toString()); + assert.ok(!service.isDirty(model.resource)); }); test('revert - file', async function () { model = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/file.txt'), 'utf8', undefined); - (accessor.textFileService.models).add(model.getResource(), model); + (accessor.textFileService.models).add(model.resource, model); const service = accessor.textFileService; - service.setPromptPath(model.getResource()); + service.setPromptPath(model.resource); await model.load(); model!.textEditorModel!.setValue('foo'); - assert.ok(service.isDirty(model.getResource())); + assert.ok(service.isDirty(model.resource)); - const res = await service.revert(model.getResource()); + const res = await service.revert(model.resource); assert.ok(res); - assert.ok(!service.isDirty(model.getResource())); + assert.ok(!service.isDirty(model.resource)); }); test('delete - dirty file', async function () { model = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/file.txt'), 'utf8', undefined); - (accessor.textFileService.models).add(model.getResource(), model); + (accessor.textFileService.models).add(model.resource, model); const service = accessor.textFileService; await model.load(); model!.textEditorModel!.setValue('foo'); - assert.ok(service.isDirty(model.getResource())); + assert.ok(service.isDirty(model.resource)); - await service.delete(model.getResource()); - assert.ok(!service.isDirty(model.getResource())); + await service.delete(model.resource); + assert.ok(!service.isDirty(model.resource)); }); test('move - dirty file', async function () { @@ -282,27 +282,27 @@ suite('Files - TextFileService', () => { async function testMove(source: URI, target: URI, targetDirty?: boolean): Promise { let sourceModel: TextFileEditorModel = instantiationService.createInstance(TextFileEditorModel, source, 'utf8', undefined); let targetModel: TextFileEditorModel = instantiationService.createInstance(TextFileEditorModel, target, 'utf8', undefined); - (accessor.textFileService.models).add(sourceModel.getResource(), sourceModel); - (accessor.textFileService.models).add(targetModel.getResource(), targetModel); + (accessor.textFileService.models).add(sourceModel.resource, sourceModel); + (accessor.textFileService.models).add(targetModel.resource, targetModel); const service = accessor.textFileService; await sourceModel.load(); sourceModel.textEditorModel!.setValue('foo'); - assert.ok(service.isDirty(sourceModel.getResource())); + assert.ok(service.isDirty(sourceModel.resource)); if (targetDirty) { await targetModel.load(); targetModel.textEditorModel!.setValue('bar'); - assert.ok(service.isDirty(targetModel.getResource())); + assert.ok(service.isDirty(targetModel.resource)); } - await service.move(sourceModel.getResource(), targetModel.getResource(), true); + await service.move(sourceModel.resource, targetModel.resource, true); assert.equal(targetModel.textEditorModel!.getValue(), 'foo'); - assert.ok(!service.isDirty(sourceModel.getResource())); - assert.ok(service.isDirty(targetModel.getResource())); + assert.ok(!service.isDirty(sourceModel.resource)); + assert.ok(service.isDirty(targetModel.resource)); sourceModel.dispose(); targetModel.dispose(); @@ -413,7 +413,7 @@ suite('Files - TextFileService', () => { async function hotExitTest(this: any, setting: string, shutdownReason: ShutdownReason, multipleWindows: boolean, workspace: true, shouldVeto: boolean): Promise { model = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/file.txt'), 'utf8', undefined); - (accessor.textFileService.models).add(model.getResource(), model); + (accessor.textFileService.models).add(model.resource, model); const service = accessor.textFileService; // Set hot exit config diff --git a/src/vs/workbench/services/textmodelResolver/test/textModelResolverService.test.ts b/src/vs/workbench/services/textmodelResolver/test/textModelResolverService.test.ts index a404c7e86e581..3ffe921e4cf60 100644 --- a/src/vs/workbench/services/textmodelResolver/test/textModelResolverService.test.ts +++ b/src/vs/workbench/services/textmodelResolver/test/textModelResolverService.test.ts @@ -88,11 +88,11 @@ suite('Workbench - TextModelResolverService', () => { test('resolve file', async function () { const textModel = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/file_resolver.txt'), 'utf8', undefined); - (accessor.textFileService.models).add(textModel.getResource(), textModel); + (accessor.textFileService.models).add(textModel.resource, textModel); await textModel.load(); - const ref = await accessor.textModelResolverService.createModelReference(textModel.getResource()); + const ref = await accessor.textModelResolverService.createModelReference(textModel.resource); const model = ref.object; const editorModel = model.textEditorModel; diff --git a/src/vs/workbench/test/common/editor/untitledTextEditor.test.ts b/src/vs/workbench/test/common/editor/untitledTextEditor.test.ts index 3d55bd3d1449f..78cb84d606e69 100644 --- a/src/vs/workbench/test/common/editor/untitledTextEditor.test.ts +++ b/src/vs/workbench/test/common/editor/untitledTextEditor.test.ts @@ -151,11 +151,11 @@ suite('Workbench untitled text editors', () => { const model3 = await service.loadOrCreate({ resource: input.getResource() }); - assert.equal(model3.getResource().toString(), input.getResource().toString()); + assert.equal(model3.resource.toString(), input.getResource().toString()); const file = URI.file(join('C:\\', '/foo/file44.txt')); const model4 = await service.loadOrCreate({ resource: file }); - assert.ok(service.hasAssociatedFilePath(model4.getResource())); + assert.ok(service.hasAssociatedFilePath(model4.resource)); assert.ok(model4.isDirty()); model1.dispose(); From 483a8a701d6fe8e76f5995332e0f0149f1e42db8 Mon Sep 17 00:00:00 2001 From: Miguel Solorio Date: Tue, 12 Nov 2019 08:32:13 -0800 Subject: [PATCH 126/352] Add more spacing for dropdowns --- src/vs/base/browser/ui/actionbar/actionbar.css | 1 + 1 file changed, 1 insertion(+) diff --git a/src/vs/base/browser/ui/actionbar/actionbar.css b/src/vs/base/browser/ui/actionbar/actionbar.css index 60979ab095dc8..623ff4d74214b 100644 --- a/src/vs/base/browser/ui/actionbar/actionbar.css +++ b/src/vs/base/browser/ui/actionbar/actionbar.css @@ -90,4 +90,5 @@ display: flex; align-items: center; justify-content: center; + margin-right: 10px; } From a05e629253dbc84922ecffec208b0c00beb2482a Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Tue, 12 Nov 2019 17:12:06 +0100 Subject: [PATCH 127/352] #20183 move current problem contribution to editor status --- .../browser/parts/editor/editorStatus.ts | 135 +++++++++++++++- .../markers/browser/markers.contribution.ts | 148 +----------------- 2 files changed, 135 insertions(+), 148 deletions(-) diff --git a/src/vs/workbench/browser/parts/editor/editorStatus.ts b/src/vs/workbench/browser/parts/editor/editorStatus.ts index b7ecb1411b052..71ac2878d4eeb 100644 --- a/src/vs/workbench/browser/parts/editor/editorStatus.ts +++ b/src/vs/workbench/browser/parts/editor/editorStatus.ts @@ -6,7 +6,7 @@ import 'vs/css!./media/editorstatus'; import * as nls from 'vs/nls'; import { runAtThisOrScheduleAtNextAnimationFrame } from 'vs/base/browser/dom'; -import { format } from 'vs/base/common/strings'; +import { format, compare } from 'vs/base/common/strings'; import { extname, basename, isEqual } from 'vs/base/common/resources'; import { areFunctions, withNullAsUndefined, withUndefinedAsNull } from 'vs/base/common/types'; import { URI } from 'vs/base/common/uri'; @@ -50,6 +50,8 @@ import { Event } from 'vs/base/common/event'; import { IAccessibilityService, AccessibilitySupport } from 'vs/platform/accessibility/common/accessibility'; import { IWorkbenchContribution } from 'vs/workbench/common/contributions'; import { IStatusbarEntryAccessor, IStatusbarService, StatusbarAlignment, IStatusbarEntry } from 'vs/workbench/services/statusbar/common/statusbar'; +import { IMarker, IMarkerService, MarkerSeverity, IMarkerData } from 'vs/platform/markers/common/markers'; +import { find } from 'vs/base/common/arrays'; class SideBySideEditorEncodingSupport implements IEncodingSupport { constructor(private master: IEncodingSupport, private details: IEncodingSupport) { } @@ -282,6 +284,7 @@ export class EditorStatus extends Disposable implements IWorkbenchContribution { private readonly eolElement = this._register(new MutableDisposable()); private readonly modeElement = this._register(new MutableDisposable()); private readonly metadataElement = this._register(new MutableDisposable()); + private readonly currentProblemStatus: ShowCurrentMarkerInStatusbarContribution = this._register(this.instantiationService.createInstance(ShowCurrentMarkerInStatusbarContribution)); private readonly state = new State(); private readonly activeEditorListeners = this._register(new DisposableStore()); @@ -299,7 +302,8 @@ export class EditorStatus extends Disposable implements IWorkbenchContribution { @IConfigurationService private readonly configurationService: IConfigurationService, @INotificationService private readonly notificationService: INotificationService, @IAccessibilityService private readonly accessibilityService: IAccessibilityService, - @IStatusbarService private readonly statusbarService: IStatusbarService + @IStatusbarService private readonly statusbarService: IStatusbarService, + @IInstantiationService private readonly instantiationService: IInstantiationService, ) { super(); @@ -577,6 +581,7 @@ export class EditorStatus extends Disposable implements IWorkbenchContribution { this.onEncodingChange(activeControl, activeCodeEditor); this.onIndentationChange(activeCodeEditor); this.onMetadataChange(activeControl); + this.currentProblemStatus.update(activeCodeEditor); // Dispose old active editor listeners this.activeEditorListeners.clear(); @@ -594,6 +599,7 @@ export class EditorStatus extends Disposable implements IWorkbenchContribution { // Hook Listener for Selection changes this.activeEditorListeners.add(activeCodeEditor.onDidChangeCursorPosition((event: ICursorPositionChangedEvent) => { this.onSelectionChange(activeCodeEditor); + this.currentProblemStatus.update(activeCodeEditor); })); // Hook Listener for mode changes @@ -604,6 +610,7 @@ export class EditorStatus extends Disposable implements IWorkbenchContribution { // Hook Listener for content changes this.activeEditorListeners.add(activeCodeEditor.onDidChangeModelContent((e) => { this.onEOLChange(activeCodeEditor); + this.currentProblemStatus.update(activeCodeEditor); const selections = activeCodeEditor.getSelections(); if (selections) { @@ -824,6 +831,130 @@ export class EditorStatus extends Disposable implements IWorkbenchContribution { } } +class ShowCurrentMarkerInStatusbarContribution extends Disposable { + + private readonly statusBarEntryAccessor: MutableDisposable; + private editor: ICodeEditor | undefined = undefined; + private markers: IMarker[] = []; + private currentMarker: IMarker | null = null; + + constructor( + @IStatusbarService private readonly statusbarService: IStatusbarService, + @IMarkerService private readonly markerService: IMarkerService, + @IConfigurationService private readonly configurationService: IConfigurationService, + ) { + super(); + this.statusBarEntryAccessor = this._register(new MutableDisposable()); + this._register(markerService.onMarkerChanged(changedResources => this.onMarkerChanged(changedResources))); + this._register(Event.filter(configurationService.onDidChangeConfiguration, e => e.affectsConfiguration('problems.showCurrentInStatus'))(() => this.updateStatus())); + } + + update(editor: ICodeEditor | undefined): void { + this.editor = editor; + this.updateStatus(); + } + + private updateStatus(): void { + const previousMarker = this.currentMarker; + this.currentMarker = this.getMarker(); + if (this.hasToUpdateStatus(previousMarker, this.currentMarker)) { + if (this.currentMarker) { + const line = this.currentMarker.message.split(/\r\n|\r|\n/g)[0]; + const text = `${this.getType(this.currentMarker)} ${line}`; + if (!this.statusBarEntryAccessor.value) { + this.statusBarEntryAccessor.value = this.statusbarService.addEntry({ text: '' }, 'statusbar.currentProblem', nls.localize('currentProblem', "Current Problem"), StatusbarAlignment.LEFT); + } + this.statusBarEntryAccessor.value.update({ text }); + } else { + this.statusBarEntryAccessor.clear(); + } + } + } + + private hasToUpdateStatus(previousMarker: IMarker | null, currentMarker: IMarker | null): boolean { + if (!currentMarker) { + return true; + } + if (!previousMarker) { + return true; + } + return IMarkerData.makeKey(previousMarker) !== IMarkerData.makeKey(currentMarker); + } + + private getType(marker: IMarker): string { + switch (marker.severity) { + case MarkerSeverity.Error: return '$(error)'; + case MarkerSeverity.Warning: return '$(warning)'; + case MarkerSeverity.Info: return '$(info)'; + } + return ''; + } + + private getMarker(): IMarker | null { + if (!this.configurationService.getValue('problems.showCurrentInStatus')) { + return null; + } + if (!this.editor) { + return null; + } + const model = this.editor.getModel(); + if (!model) { + return null; + } + const position = this.editor.getPosition(); + if (!position) { + return null; + } + return find(this.markers, marker => Range.containsPosition(marker, position)) || null; + } + + private onMarkerChanged(changedResources: ReadonlyArray): void { + if (!this.editor) { + return; + } + const model = this.editor.getModel(); + if (!model) { + return; + } + if (model && !changedResources.some(r => isEqual(model.uri, r))) { + return; + } + this.updateMarkers(); + } + + private updateMarkers(): void { + if (!this.editor) { + return; + } + const model = this.editor.getModel(); + if (!model) { + return; + } + if (model) { + this.markers = this.markerService.read({ + resource: model.uri, + severities: MarkerSeverity.Error | MarkerSeverity.Warning | MarkerSeverity.Info + }); + this.markers.sort(compareMarker); + } else { + this.markers = []; + } + this.updateStatus(); + } +} + +function compareMarker(a: IMarker, b: IMarker): number { + let res = compare(a.resource.toString(), b.resource.toString()); + if (res === 0) { + res = MarkerSeverity.compare(a.severity, b.severity); + } + if (res === 0) { + res = Range.compareRangesUsingStarts(a, b); + } + return res; +} + + function isWritableCodeEditor(codeEditor: ICodeEditor | undefined): boolean { if (!codeEditor) { return false; diff --git a/src/vs/workbench/contrib/markers/browser/markers.contribution.ts b/src/vs/workbench/contrib/markers/browser/markers.contribution.ts index 48671e13b75a9..578642134276a 100644 --- a/src/vs/workbench/contrib/markers/browser/markers.contribution.ts +++ b/src/vs/workbench/contrib/markers/browser/markers.contribution.ts @@ -25,21 +25,10 @@ import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle'; import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService'; import { ActivePanelContext } from 'vs/workbench/common/panel'; -import { Disposable, MutableDisposable } from 'vs/base/common/lifecycle'; +import { Disposable } from 'vs/base/common/lifecycle'; import { IStatusbarEntryAccessor, IStatusbarService, StatusbarAlignment, IStatusbarEntry } from 'vs/workbench/services/statusbar/common/statusbar'; -import { IMarkerService, MarkerStatistics, IMarker, MarkerSeverity, IMarkerData } from 'vs/platform/markers/common/markers'; +import { IMarkerService, MarkerStatistics } from 'vs/platform/markers/common/markers'; import { CommandsRegistry } from 'vs/platform/commands/common/commands'; -import { IEditorContribution } from 'vs/editor/common/editorCommon'; -import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; -import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { Event } from 'vs/base/common/event'; -import { registerEditorContribution } from 'vs/editor/browser/editorExtensions'; -import { URI } from 'vs/base/common/uri'; -import { isEqual } from 'vs/base/common/resources'; -import { find } from 'vs/base/common/arrays'; -import { Range } from 'vs/editor/common/core/range'; -import { compare } from 'vs/base/common/strings'; registerSingleton(IMarkersWorkbenchService, MarkersWorkbenchService, false); @@ -359,136 +348,3 @@ class MarkersStatusBarContributions extends Disposable implements IWorkbenchCont } workbenchRegistry.registerWorkbenchContribution(MarkersStatusBarContributions, LifecyclePhase.Restored); - -class ShowCurrentMarkerInStatusbarContribution extends Disposable implements IEditorContribution { - - public static readonly ID = 'editor.contrib.showCurrentMarkerInStatusbar'; - - private readonly rendererDisposable: MutableDisposable; - - constructor( - private readonly editor: ICodeEditor, - @IConfigurationService private readonly configurationService: IConfigurationService, - @IInstantiationService private readonly instantiationService: IInstantiationService - ) { - super(); - this.rendererDisposable = new MutableDisposable(); - this.onDidConfigurationChange(); - this._register(Event.filter(configurationService.onDidChangeConfiguration, e => e.affectsConfiguration('problems.showCurrentInStatus'))(() => this.onDidConfigurationChange())); - } - - private onDidConfigurationChange(): void { - this.rendererDisposable.clear(); - if (this.configurationService.getValue('problems.showCurrentInStatus')) { - this.rendererDisposable.value = this.instantiationService.createInstance(ShowCurrentMarkerInStatusbarRenderer, this.editor); - } - } -} - -class ShowCurrentMarkerInStatusbarRenderer extends Disposable { - - private readonly statusBarEntryAccessor: MutableDisposable; - private markers: IMarker[] = []; - private currentMarker: IMarker | null = null; - - constructor( - private readonly editor: ICodeEditor, - @IStatusbarService private readonly statusbarService: IStatusbarService, - @IMarkerService private readonly markerService: IMarkerService - ) { - super(); - this.statusBarEntryAccessor = this._register(new MutableDisposable()); - this._register(markerService.onMarkerChanged(changedResources => this.onMarkerChanged(changedResources))); - this._register(editor.onDidChangeModel(() => this.updateMarkers())); - this._register(editor.onDidChangeCursorPosition(() => this.render())); - this.render(); - } - - private render(): void { - const previousMarker = this.currentMarker; - this.currentMarker = this.getMarker(); - if (this.hasToUpdateStatus(previousMarker, this.currentMarker)) { - this.updateStatus(); - } - } - - private hasToUpdateStatus(previousMarker: IMarker | null, currentMarker: IMarker | null): boolean { - if (!currentMarker) { - return true; - } - if (!previousMarker) { - return true; - } - return IMarkerData.makeKey(previousMarker) !== IMarkerData.makeKey(currentMarker); - } - - private updateStatus(): void { - if (this.currentMarker) { - const line = this.currentMarker.message.split(/\r\n|\r|\n/g)[0]; - const text = `${this.getType(this.currentMarker)} ${line}`; - if (this.statusBarEntryAccessor.value) { - this.statusBarEntryAccessor.value.update({ text }); - } else { - this.statusBarEntryAccessor.value = this.statusbarService.addEntry({ text }, 'statusbar.currentProblem', localize('currentProblem', "Current Problem"), StatusbarAlignment.LEFT); - } - } else { - this.statusBarEntryAccessor.clear(); - } - } - - private getType(marker: IMarker): string { - switch (marker.severity) { - case MarkerSeverity.Error: return '$(error)'; - case MarkerSeverity.Warning: return '$(warning)'; - case MarkerSeverity.Info: return '$(info)'; - } - return ''; - } - - private getMarker(): IMarker | null { - const model = this.editor.getModel(); - if (!model) { - return null; - } - const position = this.editor.getPosition(); - if (!position) { - return null; - } - return find(this.markers, marker => Range.containsPosition(marker, position)) || null; - } - - private onMarkerChanged(changedResources: ReadonlyArray): void { - const editorModel = this.editor.getModel(); - if (editorModel && !changedResources.some(r => isEqual(editorModel.uri, r))) { - return; - } - this.updateMarkers(); - } - - private updateMarkers(): void { - const editorModel = this.editor.getModel(); - if (editorModel) { - this.markers = this.markerService.read({ - resource: editorModel.uri, - severities: MarkerSeverity.Error | MarkerSeverity.Warning | MarkerSeverity.Info - }); - this.markers.sort(compareMarker); - } else { - this.markers = []; - } - this.render(); - } -} - -function compareMarker(a: IMarker, b: IMarker): number { - let res = compare(a.resource.toString(), b.resource.toString()); - if (res === 0) { - res = MarkerSeverity.compare(a.severity, b.severity); - } - if (res === 0) { - res = Range.compareRangesUsingStarts(a, b); - } - return res; -} - -registerEditorContribution(ShowCurrentMarkerInStatusbarContribution.ID, ShowCurrentMarkerInStatusbarContribution); From 8e1ce7174b77f58699d98b932c2605dc9efb82c7 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Tue, 12 Nov 2019 17:46:25 +0100 Subject: [PATCH 128/352] update references view extension --- build/builtInExtensions.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/builtInExtensions.json b/build/builtInExtensions.json index 1723a82b43790..3c85dd690d5ab 100644 --- a/build/builtInExtensions.json +++ b/build/builtInExtensions.json @@ -31,7 +31,7 @@ }, { "name": "ms-vscode.references-view", - "version": "0.0.34", + "version": "0.0.35", "repo": "https://github.com/Microsoft/vscode-reference-view", "metadata": { "id": "dc489f46-520d-4556-ae85-1f9eab3c412d", From 954536db202dc4f96ce02a6229d2c7604f22b061 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Tue, 12 Nov 2019 18:04:50 +0100 Subject: [PATCH 129/352] - Expose visibility change event in status bar - Listen to the event to show or hide status entry by default - Register a command to show current problem status entry --- .../browser/parts/editor/editorStatus.ts | 62 ++++++++++++++++--- .../browser/parts/statusbar/statusbarPart.ts | 27 +++++--- .../markers/browser/markers.contribution.ts | 5 -- .../services/statusbar/common/statusbar.ts | 3 + 4 files changed, 77 insertions(+), 20 deletions(-) diff --git a/src/vs/workbench/browser/parts/editor/editorStatus.ts b/src/vs/workbench/browser/parts/editor/editorStatus.ts index 71ac2878d4eeb..f2f5d2462c7a6 100644 --- a/src/vs/workbench/browser/parts/editor/editorStatus.ts +++ b/src/vs/workbench/browser/parts/editor/editorStatus.ts @@ -52,6 +52,9 @@ import { IWorkbenchContribution } from 'vs/workbench/common/contributions'; import { IStatusbarEntryAccessor, IStatusbarService, StatusbarAlignment, IStatusbarEntry } from 'vs/workbench/services/statusbar/common/statusbar'; import { IMarker, IMarkerService, MarkerSeverity, IMarkerData } from 'vs/platform/markers/common/markers'; import { find } from 'vs/base/common/arrays'; +import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; +import { IContextKey, RawContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; +import { MenuRegistry, MenuId } from 'vs/platform/actions/common/actions'; class SideBySideEditorEncodingSupport implements IEncodingSupport { constructor(private master: IEncodingSupport, private details: IEncodingSupport) { } @@ -831,22 +834,61 @@ export class EditorStatus extends Disposable implements IWorkbenchContribution { } } +const CONTEXT_CURRENT_MARKER = new RawContextKey('hasActiveProblem', false); + class ShowCurrentMarkerInStatusbarContribution extends Disposable { + private static readonly INITIAL_STATE_KEY = 'statusbar.currentProblem.initialState'; + private static readonly STATUSBAR_ENTRY_ID = 'statusbar.currentProblem'; + private readonly statusBarEntryAccessor: MutableDisposable; private editor: ICodeEditor | undefined = undefined; private markers: IMarker[] = []; private currentMarker: IMarker | null = null; + private showByDefault: boolean = false; + + private currentMarkerContextKey: IContextKey; constructor( @IStatusbarService private readonly statusbarService: IStatusbarService, @IMarkerService private readonly markerService: IMarkerService, - @IConfigurationService private readonly configurationService: IConfigurationService, + @IStorageService private readonly storageService: IStorageService, + @IContextKeyService contextKeyService: IContextKeyService, ) { super(); this.statusBarEntryAccessor = this._register(new MutableDisposable()); - this._register(markerService.onMarkerChanged(changedResources => this.onMarkerChanged(changedResources))); - this._register(Event.filter(configurationService.onDidChangeConfiguration, e => e.affectsConfiguration('problems.showCurrentInStatus'))(() => this.updateStatus())); + this.currentMarkerContextKey = CONTEXT_CURRENT_MARKER.bindTo(contextKeyService); + + this.registerListeners(); + this.registerCommand(); + } + + private registerListeners(): void { + this._register(this.markerService.onMarkerChanged(changedResources => this.onMarkerChanged(changedResources))); + + this.showByDefault = this.storageService.getBoolean(ShowCurrentMarkerInStatusbarContribution.INITIAL_STATE_KEY, StorageScope.GLOBAL, false); + this._register(Event.filter(this.statusbarService.onDidChangeEntryVisibility, e => e.id === ShowCurrentMarkerInStatusbarContribution.STATUSBAR_ENTRY_ID && e.visible)(() => { + this.showByDefault = true; + this.storageService.store(ShowCurrentMarkerInStatusbarContribution.INITIAL_STATE_KEY, true, StorageScope.GLOBAL); + })); + this._register(Event.filter(this.storageService.onDidChangeStorage, e => e.key === ShowCurrentMarkerInStatusbarContribution.INITIAL_STATE_KEY && e.scope === StorageScope.GLOBAL)(() => { + this.showByDefault = this.storageService.getBoolean(ShowCurrentMarkerInStatusbarContribution.INITIAL_STATE_KEY, StorageScope.GLOBAL, false); + })); + } + + private registerCommand(): void { + CommandsRegistry.registerCommand('statusbar.showCurrentProblem', () => { + this.showByDefault = true; + this.updateStatus(); + this.statusbarService.updateEntryVisibility(ShowCurrentMarkerInStatusbarContribution.STATUSBAR_ENTRY_ID, true); + }); + MenuRegistry.appendMenuItem(MenuId.CommandPalette, { + command: { + id: 'statusbar.showCurrentProblem', + title: nls.localize('show current problem in status', "Show Current Problem in Status Bar") + }, + when: CONTEXT_CURRENT_MARKER + }); } update(editor: ICodeEditor | undefined): void { @@ -857,12 +899,13 @@ class ShowCurrentMarkerInStatusbarContribution extends Disposable { private updateStatus(): void { const previousMarker = this.currentMarker; this.currentMarker = this.getMarker(); + this.currentMarkerContextKey.set(!!this.currentMarker); if (this.hasToUpdateStatus(previousMarker, this.currentMarker)) { if (this.currentMarker) { const line = this.currentMarker.message.split(/\r\n|\r|\n/g)[0]; const text = `${this.getType(this.currentMarker)} ${line}`; if (!this.statusBarEntryAccessor.value) { - this.statusBarEntryAccessor.value = this.statusbarService.addEntry({ text: '' }, 'statusbar.currentProblem', nls.localize('currentProblem', "Current Problem"), StatusbarAlignment.LEFT); + this.statusBarEntryAccessor.value = this.createStatusbarEntry(); } this.statusBarEntryAccessor.value.update({ text }); } else { @@ -871,6 +914,14 @@ class ShowCurrentMarkerInStatusbarContribution extends Disposable { } } + private createStatusbarEntry(): IStatusbarEntryAccessor { + const entry = this.statusbarService.addEntry({ text: '' }, ShowCurrentMarkerInStatusbarContribution.STATUSBAR_ENTRY_ID, nls.localize('currentProblem', "Current Problem"), StatusbarAlignment.LEFT); + if (!this.showByDefault) { + this.statusbarService.updateEntryVisibility(ShowCurrentMarkerInStatusbarContribution.STATUSBAR_ENTRY_ID, false); + } + return entry; + } + private hasToUpdateStatus(previousMarker: IMarker | null, currentMarker: IMarker | null): boolean { if (!currentMarker) { return true; @@ -891,9 +942,6 @@ class ShowCurrentMarkerInStatusbarContribution extends Disposable { } private getMarker(): IMarker | null { - if (!this.configurationService.getValue('problems.showCurrentInStatus')) { - return null; - } if (!this.editor) { return null; } diff --git a/src/vs/workbench/browser/parts/statusbar/statusbarPart.ts b/src/vs/workbench/browser/parts/statusbar/statusbarPart.ts index b52002f7824be..0b8e947e35d30 100644 --- a/src/vs/workbench/browser/parts/statusbar/statusbarPart.ts +++ b/src/vs/workbench/browser/parts/statusbar/statusbarPart.ts @@ -33,6 +33,7 @@ import { ToggleStatusbarVisibilityAction } from 'vs/workbench/browser/actions/la import { Separator } from 'vs/base/browser/ui/actionbar/actionbar'; import { values } from 'vs/base/common/map'; import { assertIsDefined } from 'vs/base/common/types'; +import { Emitter, Event } from 'vs/base/common/event'; interface IPendingStatusbarEntry { id: string; @@ -60,6 +61,9 @@ class StatusbarViewModel extends Disposable { private hidden!: Set; + private readonly _onDidChangeEntryVisibility: Emitter<{ id: string, visible: boolean }> = this._register(new Emitter<{ id: string, visible: boolean }>()); + readonly onDidChangeEntryVisibility: Event<{ id: string, visible: boolean }> = this._onDidChangeEntryVisibility.event; + constructor(private storageService: IStorageService) { super(); @@ -117,7 +121,7 @@ class StatusbarViewModel extends Disposable { if (changed.size > 0) { this._entries.forEach(entry => { if (changed.has(entry.id)) { - this.updateVisibility(entry.id); + this.updateVisibility(entry.id, true); changed.delete(entry.id); } @@ -130,7 +134,7 @@ class StatusbarViewModel extends Disposable { this._entries.push(entry); // intentionally not using a map here since multiple entries can have the same ID! // Update visibility directly - this.updateVisibility(entry); + this.updateVisibility(entry, false); // Sort according to priority this.sort(); @@ -159,7 +163,7 @@ class StatusbarViewModel extends Disposable { if (!this.hidden.has(id)) { this.hidden.add(id); - this.updateVisibility(id); + this.updateVisibility(id, true); this.saveState(); } @@ -169,7 +173,7 @@ class StatusbarViewModel extends Disposable { if (this.hidden.has(id)) { this.hidden.delete(id); - this.updateVisibility(id); + this.updateVisibility(id, true); this.saveState(); } @@ -183,9 +187,9 @@ class StatusbarViewModel extends Disposable { return this._entries.filter(entry => entry.alignment === alignment); } - private updateVisibility(id: string): void; - private updateVisibility(entry: IStatusbarViewModelEntry): void; - private updateVisibility(arg1: string | IStatusbarViewModelEntry): void { + private updateVisibility(id: string, trigger: boolean): void; + private updateVisibility(entry: IStatusbarViewModelEntry, trigger: boolean): void; + private updateVisibility(arg1: string | IStatusbarViewModelEntry, trigger: boolean): void { // By identifier if (typeof arg1 === 'string') { @@ -193,7 +197,7 @@ class StatusbarViewModel extends Disposable { for (const entry of this._entries) { if (entry.id === id) { - this.updateVisibility(entry); + this.updateVisibility(entry, trigger); } } } @@ -210,6 +214,10 @@ class StatusbarViewModel extends Disposable { show(entry.container); } + if (trigger) { + this._onDidChangeEntryVisibility.fire({ id: entry.id, visible: !isHidden }); + } + // Mark first/last visible entry this.markFirstLastVisibleEntry(); } @@ -341,6 +349,8 @@ export class StatusbarPart extends Part implements IStatusbarService { private leftItemsContainer: HTMLElement | undefined; private rightItemsContainer: HTMLElement | undefined; + readonly onDidChangeEntryVisibility: Event<{ id: string, visible: boolean }>; + constructor( @IInstantiationService private readonly instantiationService: IInstantiationService, @IThemeService themeService: IThemeService, @@ -352,6 +362,7 @@ export class StatusbarPart extends Part implements IStatusbarService { super(Parts.STATUSBAR_PART, { hasTitle: false }, themeService, storageService, layoutService); this.viewModel = this._register(new StatusbarViewModel(storageService)); + this.onDidChangeEntryVisibility = this.viewModel.onDidChangeEntryVisibility; this.registerListeners(); } diff --git a/src/vs/workbench/contrib/markers/browser/markers.contribution.ts b/src/vs/workbench/contrib/markers/browser/markers.contribution.ts index 578642134276a..e08a13a559ffa 100644 --- a/src/vs/workbench/contrib/markers/browser/markers.contribution.ts +++ b/src/vs/workbench/contrib/markers/browser/markers.contribution.ts @@ -81,11 +81,6 @@ Registry.as(Extensions.Configuration).registerConfigurat 'description': Messages.PROBLEMS_PANEL_CONFIGURATION_AUTO_REVEAL, 'type': 'boolean', 'default': true - }, - 'problems.showCurrentInStatus': { - 'description': Messages.PROBLEMS_PANEL_CONFIGURATION_SHOW_CURRENT_STATUS, - 'type': 'boolean', - 'default': false } } }); diff --git a/src/vs/workbench/services/statusbar/common/statusbar.ts b/src/vs/workbench/services/statusbar/common/statusbar.ts index 3cf98b097532c..95e43cdc5fba1 100644 --- a/src/vs/workbench/services/statusbar/common/statusbar.ts +++ b/src/vs/workbench/services/statusbar/common/statusbar.ts @@ -6,6 +6,7 @@ import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { IDisposable } from 'vs/base/common/lifecycle'; import { ThemeColor } from 'vs/platform/theme/common/themeService'; +import { Event } from 'vs/base/common/event'; export const IStatusbarService = createDecorator('statusbarService'); @@ -61,6 +62,8 @@ export interface IStatusbarService { _serviceBrand: undefined; + readonly onDidChangeEntryVisibility: Event<{ id: string, visible: boolean }>; + /** * Adds an entry to the statusbar with the given alignment and priority. Use the returned accessor * to update or remove the statusbar entry. From 609c1374ddeb16a9c16f78d553a155267a1777f7 Mon Sep 17 00:00:00 2001 From: Miguel Solorio Date: Tue, 12 Nov 2019 09:08:42 -0800 Subject: [PATCH 130/352] Add padding to debug toolbar dropdown --- src/vs/workbench/contrib/debug/browser/media/debugToolBar.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/debug/browser/media/debugToolBar.css b/src/vs/workbench/contrib/debug/browser/media/debugToolBar.css index c16ed97a7b77e..a0a76da7ec1d9 100644 --- a/src/vs/workbench/contrib/debug/browser/media/debugToolBar.css +++ b/src/vs/workbench/contrib/debug/browser/media/debugToolBar.css @@ -17,9 +17,9 @@ .monaco-workbench .debug-toolbar .monaco-action-bar .action-item.select-container { margin-right: 7px; - } +.monaco-workbench .debug-toolbar .monaco-action-bar .action-item.select-container .monaco-select-box, .monaco-workbench .start-debug-action-item .select-container .monaco-select-box { padding: 0 22px 0 6px; } From d87b077f1ecc5ad9cebb2d31e6353807c0c18687 Mon Sep 17 00:00:00 2001 From: Miguel Solorio Date: Tue, 12 Nov 2019 09:18:31 -0800 Subject: [PATCH 131/352] Update codicons: fix debug stop icon --- .../ui/codiconLabel/codicon/codicon.css | 2 +- .../ui/codiconLabel/codicon/codicon.ttf | Bin 46380 -> 46380 bytes 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/base/browser/ui/codiconLabel/codicon/codicon.css b/src/vs/base/browser/ui/codiconLabel/codicon/codicon.css index b5327ffa48353..753d70792994e 100644 --- a/src/vs/base/browser/ui/codiconLabel/codicon/codicon.css +++ b/src/vs/base/browser/ui/codiconLabel/codicon/codicon.css @@ -5,7 +5,7 @@ @font-face { font-family: "codicon"; - src: url("./codicon.ttf?7197ad7e38e9644da47ec42494d56501") format("truetype"); + src: url("./codicon.ttf?3443fb4013ab5a04c23a30f912dd6627") format("truetype"); } .codicon[class*='codicon-'] { diff --git a/src/vs/base/browser/ui/codiconLabel/codicon/codicon.ttf b/src/vs/base/browser/ui/codiconLabel/codicon/codicon.ttf index a5b716584910c5d9736ca105d139fb6dc4020648..ba3474205da690928d1da0baa9f557ae33a5b1d3 100644 GIT binary patch delta 89 zcmZ4UifPR&rU?!rN{wQDf6cCnxWaNFWZ`yv(Sr2>`3*9_#=B From 21c09314a89f0a928996af8a7fbacd6df568c838 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Tue, 12 Nov 2019 18:34:08 +0100 Subject: [PATCH 132/352] files - add auto save config service --- .../common/instantiationService.ts | 2 +- .../browser/parts/editor/textDiffEditor.ts | 4 +- .../browser/parts/editor/textEditor.ts | 8 +- .../parts/editor/textResourceEditor.ts | 11 +- .../parts/quickopen/quickOpenController.ts | 8 +- .../backup/common/backupModelTracker.ts | 8 +- .../files/browser/editors/textFileEditor.ts | 6 +- .../files/browser/fileActions.contribution.ts | 2 +- .../contrib/files/browser/fileActions.ts | 21 +-- .../files/browser/views/openEditorsView.ts | 8 +- .../files/common/dirtyFilesIndicator.ts | 8 +- .../files/common/editors/fileEditorInput.ts | 8 +- .../files/electron-browser/textFileEditor.ts | 6 +- .../contrib/output/browser/logViewer.ts | 6 +- .../contrib/output/browser/outputPanel.ts | 6 +- .../preferences/browser/preferencesEditor.ts | 6 +- .../common/autoSaveConfigurationService.ts | 158 ++++++++++++++++++ .../textfile/browser/textFileService.ts | 95 ++--------- .../textfile/common/textFileEditorModel.ts | 10 +- .../services/textfile/common/textfiles.ts | 29 ---- .../electron-browser/nativeTextFileService.ts | 8 +- .../test/common/workingCopyService.test.ts | 7 +- .../workbench/test/workbenchTestServices.ts | 17 +- src/vs/workbench/workbench.common.main.ts | 1 + 24 files changed, 265 insertions(+), 178 deletions(-) create mode 100644 src/vs/workbench/services/autoSaveConfiguration/common/autoSaveConfigurationService.ts diff --git a/src/vs/platform/instantiation/common/instantiationService.ts b/src/vs/platform/instantiation/common/instantiationService.ts index 44be0d2479796..f4b681204c86f 100644 --- a/src/vs/platform/instantiation/common/instantiationService.ts +++ b/src/vs/platform/instantiation/common/instantiationService.ts @@ -157,7 +157,7 @@ export class InstantiationService implements IInstantiationService { graph.lookupOrInsertNode(item); // a weak but working heuristic for cycle checks - if (cycleCount++ > 100) { + if (cycleCount++ > 150) { throw new CyclicDependencyError(graph); } diff --git a/src/vs/workbench/browser/parts/editor/textDiffEditor.ts b/src/vs/workbench/browser/parts/editor/textDiffEditor.ts index e4d132cc598cd..8d4f411c71c54 100644 --- a/src/vs/workbench/browser/parts/editor/textDiffEditor.ts +++ b/src/vs/workbench/browser/parts/editor/textDiffEditor.ts @@ -33,6 +33,7 @@ import { EditorMemento } from 'vs/workbench/browser/parts/editor/baseEditor'; import { IHostService } from 'vs/workbench/services/host/browser/host'; import { EditorActivation, IEditorOptions } from 'vs/platform/editor/common/editor'; import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService'; +import { IAutoSaveConfigurationService } from 'vs/workbench/services/autoSaveConfiguration/common/autoSaveConfigurationService'; /** * The text editor that leverages the diff text editor for the editing experience. @@ -55,8 +56,9 @@ export class TextDiffEditor extends BaseTextEditor implements ITextDiffEditor { @ITextFileService textFileService: ITextFileService, @IHostService hostService: IHostService, @IClipboardService private _clipboardService: IClipboardService, + @IAutoSaveConfigurationService autoSaveConfigurationService: IAutoSaveConfigurationService ) { - super(TextDiffEditor.ID, telemetryService, instantiationService, storageService, configurationService, themeService, textFileService, editorService, editorGroupService, hostService); + super(TextDiffEditor.ID, telemetryService, instantiationService, storageService, configurationService, themeService, textFileService, editorService, editorGroupService, hostService, autoSaveConfigurationService); } protected getEditorMemento(editorGroupService: IEditorGroupsService, key: string, limit: number = 10): IEditorMemento { diff --git a/src/vs/workbench/browser/parts/editor/textEditor.ts b/src/vs/workbench/browser/parts/editor/textEditor.ts index ab5403342c39e..d7042a433102c 100644 --- a/src/vs/workbench/browser/parts/editor/textEditor.ts +++ b/src/vs/workbench/browser/parts/editor/textEditor.ts @@ -16,7 +16,7 @@ import { IStorageService } from 'vs/platform/storage/common/storage'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IThemeService } from 'vs/platform/theme/common/themeService'; -import { ITextFileService, SaveReason, AutoSaveMode } from 'vs/workbench/services/textfile/common/textfiles'; +import { ITextFileService, SaveReason } from 'vs/workbench/services/textfile/common/textfiles'; import { ITextResourceConfigurationService } from 'vs/editor/common/services/resourceConfiguration'; import { IEditorOptions } from 'vs/editor/common/config/editorOptions'; import { isDiffEditor, isCodeEditor, getCodeEditor } from 'vs/editor/browser/editorBrowser'; @@ -24,6 +24,7 @@ import { IEditorGroupsService, IEditorGroup } from 'vs/workbench/services/editor import { CancellationToken } from 'vs/base/common/cancellation'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IHostService } from 'vs/workbench/services/host/browser/host'; +import { IAutoSaveConfigurationService, AutoSaveMode } from 'vs/workbench/services/autoSaveConfiguration/common/autoSaveConfigurationService'; const TEXT_EDITOR_VIEW_STATE_PREFERENCE_KEY = 'textEditorViewState'; @@ -53,7 +54,8 @@ export abstract class BaseTextEditor extends BaseEditor implements ITextEditor { @ITextFileService private readonly _textFileService: ITextFileService, @IEditorService protected editorService: IEditorService, @IEditorGroupsService protected editorGroupService: IEditorGroupsService, - @IHostService private readonly hostService: IHostService + @IHostService private readonly hostService: IHostService, + @IAutoSaveConfigurationService private readonly autoSaveConfigurationService: IAutoSaveConfigurationService ) { super(id, telemetryService, themeService, storageService); @@ -165,7 +167,7 @@ export abstract class BaseTextEditor extends BaseEditor implements ITextEditor { } private maybeTriggerSaveAll(reason: SaveReason): void { - const mode = this.textFileService.getAutoSaveMode(); + const mode = this.autoSaveConfigurationService.getAutoSaveMode(); // Determine if we need to save all. In case of a window focus change we also save if auto save mode // is configured to be ON_FOCUS_CHANGE (editor focus change) diff --git a/src/vs/workbench/browser/parts/editor/textResourceEditor.ts b/src/vs/workbench/browser/parts/editor/textResourceEditor.ts index 640af28854b29..b4e50ce6a8f1a 100644 --- a/src/vs/workbench/browser/parts/editor/textResourceEditor.ts +++ b/src/vs/workbench/browser/parts/editor/textResourceEditor.ts @@ -24,6 +24,7 @@ import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editor import { CancellationToken } from 'vs/base/common/cancellation'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IHostService } from 'vs/workbench/services/host/browser/host'; +import { IAutoSaveConfigurationService } from 'vs/workbench/services/autoSaveConfiguration/common/autoSaveConfigurationService'; /** * An editor implementation that is capable of showing the contents of resource inputs. Uses @@ -41,9 +42,10 @@ export class AbstractTextResourceEditor extends BaseTextEditor { @IEditorGroupsService editorGroupService: IEditorGroupsService, @ITextFileService textFileService: ITextFileService, @IEditorService editorService: IEditorService, - @IHostService hostService: IHostService + @IHostService hostService: IHostService, + @IAutoSaveConfigurationService autoSaveConfigurationService: IAutoSaveConfigurationService ) { - super(id, telemetryService, instantiationService, storageService, configurationService, themeService, textFileService, editorService, editorGroupService, hostService); + super(id, telemetryService, instantiationService, storageService, configurationService, themeService, textFileService, editorService, editorGroupService, hostService, autoSaveConfigurationService); } getTitle(): string | undefined { @@ -205,8 +207,9 @@ export class TextResourceEditor extends AbstractTextResourceEditor { @ITextFileService textFileService: ITextFileService, @IEditorService editorService: IEditorService, @IEditorGroupsService editorGroupService: IEditorGroupsService, - @IHostService hostService: IHostService + @IHostService hostService: IHostService, + @IAutoSaveConfigurationService autoSaveConfigurationService: IAutoSaveConfigurationService ) { - super(TextResourceEditor.ID, telemetryService, instantiationService, storageService, configurationService, themeService, editorGroupService, textFileService, editorService, hostService); + super(TextResourceEditor.ID, telemetryService, instantiationService, storageService, configurationService, themeService, editorGroupService, textFileService, editorService, hostService, autoSaveConfigurationService); } } diff --git a/src/vs/workbench/browser/parts/quickopen/quickOpenController.ts b/src/vs/workbench/browser/parts/quickopen/quickOpenController.ts index 945da6272a879..80aab18b2592f 100644 --- a/src/vs/workbench/browser/parts/quickopen/quickOpenController.ts +++ b/src/vs/workbench/browser/parts/quickopen/quickOpenController.ts @@ -16,7 +16,7 @@ import { Mode, IEntryRunContext, IAutoFocus, IQuickNavigateConfiguration, IModel import { QuickOpenEntry, QuickOpenModel, QuickOpenEntryGroup, QuickOpenItemAccessorClass } from 'vs/base/parts/quickopen/browser/quickOpenModel'; import { QuickOpenWidget, HideReason } from 'vs/base/parts/quickopen/browser/quickOpenWidget'; import { ContributableActionProvider } from 'vs/workbench/browser/actions'; -import { ITextFileService, AutoSaveMode } from 'vs/workbench/services/textfile/common/textfiles'; +import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; import { Registry } from 'vs/platform/registry/common/platform'; import { IResourceInput } from 'vs/platform/editor/common/editor'; import { IModeService } from 'vs/editor/common/services/modeService'; @@ -51,6 +51,7 @@ import { IQuickInputService, IQuickPickItem } from 'vs/platform/quickinput/commo import { CancellationTokenSource, CancellationToken } from 'vs/base/common/cancellation'; import { IStorageService } from 'vs/platform/storage/common/storage'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { IAutoSaveConfigurationService, AutoSaveMode } from 'vs/workbench/services/autoSaveConfiguration/common/autoSaveConfigurationService'; const HELP_PREFIX = '?'; @@ -735,7 +736,8 @@ export class EditorHistoryEntry extends EditorQuickOpenEntry { @ITextFileService private readonly textFileService: ITextFileService, @IConfigurationService private readonly configurationService: IConfigurationService, @ILabelService labelService: ILabelService, - @IFileService fileService: IFileService + @IFileService fileService: IFileService, + @IAutoSaveConfigurationService private readonly autoSaveConfigurationService: IAutoSaveConfigurationService ) { super(editorService); @@ -753,7 +755,7 @@ export class EditorHistoryEntry extends EditorQuickOpenEntry { this.description = labelService.getUriLabel(resources.dirname(this.resource), { relative: true }); this.dirty = this.resource && this.textFileService.isDirty(this.resource); - if (this.dirty && this.textFileService.getAutoSaveMode() === AutoSaveMode.AFTER_SHORT_DELAY) { + if (this.dirty && this.autoSaveConfigurationService.getAutoSaveMode() === AutoSaveMode.AFTER_SHORT_DELAY) { this.dirty = false; // no dirty decoration if auto save is on with a short timeout } } diff --git a/src/vs/workbench/contrib/backup/common/backupModelTracker.ts b/src/vs/workbench/contrib/backup/common/backupModelTracker.ts index 484a7ddce401e..21d022ec1b72c 100644 --- a/src/vs/workbench/contrib/backup/common/backupModelTracker.ts +++ b/src/vs/workbench/contrib/backup/common/backupModelTracker.ts @@ -6,10 +6,11 @@ import { URI as Uri } from 'vs/base/common/uri'; import { IBackupFileService } from 'vs/workbench/services/backup/common/backup'; import { Disposable } from 'vs/base/common/lifecycle'; -import { ITextFileService, TextFileModelChangeEvent, StateChange, IAutoSaveConfiguration } from 'vs/workbench/services/textfile/common/textfiles'; +import { ITextFileService, TextFileModelChangeEvent, StateChange } from 'vs/workbench/services/textfile/common/textfiles'; import { IUntitledTextEditorService } from 'vs/workbench/services/untitled/common/untitledTextEditorService'; import { IWorkbenchContribution } from 'vs/workbench/common/contributions'; import { CONTENT_CHANGE_EVENT_BUFFER_DELAY } from 'vs/platform/files/common/files'; +import { IAutoSaveConfigurationService, IAutoSaveConfiguration } from 'vs/workbench/services/autoSaveConfiguration/common/autoSaveConfigurationService'; const AUTO_SAVE_AFTER_DELAY_DISABLED_TIME = CONTENT_CHANGE_EVENT_BUFFER_DELAY + 500; @@ -21,6 +22,7 @@ export class BackupModelTracker extends Disposable implements IWorkbenchContribu @IBackupFileService private readonly backupFileService: IBackupFileService, @ITextFileService private readonly textFileService: ITextFileService, @IUntitledTextEditorService private readonly untitledTextEditorService: IUntitledTextEditorService, + @IAutoSaveConfigurationService private readonly autoSaveConfigurationService: IAutoSaveConfigurationService ) { super(); @@ -38,8 +40,8 @@ export class BackupModelTracker extends Disposable implements IWorkbenchContribu this._register(this.untitledTextEditorService.onDidChangeContent(e => this.onUntitledModelChanged(e))); this._register(this.untitledTextEditorService.onDidDisposeModel(e => this.discardBackup(e))); - // Listen to config changes - this._register(this.textFileService.onAutoSaveConfigurationChange(c => this.onAutoSaveConfigurationChange(c))); + // Listen to auto save config changes + this._register(this.autoSaveConfigurationService.onAutoSaveConfigurationChange(c => this.onAutoSaveConfigurationChange(c))); } private onAutoSaveConfigurationChange(configuration: IAutoSaveConfiguration): void { diff --git a/src/vs/workbench/contrib/files/browser/editors/textFileEditor.ts b/src/vs/workbench/contrib/files/browser/editors/textFileEditor.ts index 9225325200322..b683a64070aeb 100644 --- a/src/vs/workbench/contrib/files/browser/editors/textFileEditor.ts +++ b/src/vs/workbench/contrib/files/browser/editors/textFileEditor.ts @@ -32,6 +32,7 @@ import { IEditorGroupView } from 'vs/workbench/browser/parts/editor/editor'; import { createErrorWithActions } from 'vs/base/common/errorsWithActions'; import { MutableDisposable } from 'vs/base/common/lifecycle'; import { EditorActivation, IEditorOptions } from 'vs/platform/editor/common/editor'; +import { IAutoSaveConfigurationService } from 'vs/workbench/services/autoSaveConfiguration/common/autoSaveConfigurationService'; /** * An implementation of editor for file system resources. @@ -56,9 +57,10 @@ export class TextFileEditor extends BaseTextEditor { @IEditorGroupsService editorGroupService: IEditorGroupsService, @ITextFileService textFileService: ITextFileService, @IHostService hostService: IHostService, - @IExplorerService private readonly explorerService: IExplorerService + @IExplorerService private readonly explorerService: IExplorerService, + @IAutoSaveConfigurationService autoSaveConfigurationService: IAutoSaveConfigurationService ) { - super(TextFileEditor.ID, telemetryService, instantiationService, storageService, configurationService, themeService, textFileService, editorService, editorGroupService, hostService); + super(TextFileEditor.ID, telemetryService, instantiationService, storageService, configurationService, themeService, textFileService, editorService, editorGroupService, hostService, autoSaveConfigurationService); this.updateRestoreViewStateConfiguration(); diff --git a/src/vs/workbench/contrib/files/browser/fileActions.contribution.ts b/src/vs/workbench/contrib/files/browser/fileActions.contribution.ts index cec21f34551ab..1fb26f4e7639d 100644 --- a/src/vs/workbench/contrib/files/browser/fileActions.contribution.ts +++ b/src/vs/workbench/contrib/files/browser/fileActions.contribution.ts @@ -18,7 +18,7 @@ import { isMacintosh } from 'vs/base/common/platform'; import { FilesExplorerFocusCondition, ExplorerRootContext, ExplorerFolderContext, ExplorerResourceNotReadonlyContext, ExplorerResourceCut, IExplorerService, ExplorerResourceMoveableToTrash, ExplorerViewletVisibleContext } from 'vs/workbench/contrib/files/common/files'; import { ADD_ROOT_FOLDER_COMMAND_ID, ADD_ROOT_FOLDER_LABEL } from 'vs/workbench/browser/actions/workspaceCommands'; import { CLOSE_SAVED_EDITORS_COMMAND_ID, CLOSE_EDITORS_IN_GROUP_COMMAND_ID, CLOSE_EDITOR_COMMAND_ID, CLOSE_OTHER_EDITORS_IN_GROUP_COMMAND_ID } from 'vs/workbench/browser/parts/editor/editorCommands'; -import { AutoSaveContext } from 'vs/workbench/services/textfile/common/textfiles'; +import { AutoSaveContext } from 'vs/workbench/services/autoSaveConfiguration/common/autoSaveConfigurationService'; import { ResourceContextKey } from 'vs/workbench/common/resources'; import { WorkbenchListDoubleSelection } from 'vs/platform/list/browser/listService'; import { URI } from 'vs/base/common/uri'; diff --git a/src/vs/workbench/contrib/files/browser/fileActions.ts b/src/vs/workbench/contrib/files/browser/fileActions.ts index ec20bae93ddea..38d7fbac179e1 100644 --- a/src/vs/workbench/contrib/files/browser/fileActions.ts +++ b/src/vs/workbench/contrib/files/browser/fileActions.ts @@ -5,7 +5,6 @@ import 'vs/css!./media/fileactions'; import * as nls from 'vs/nls'; -import * as types from 'vs/base/common/types'; import { isWindows, isWeb } from 'vs/base/common/platform'; import * as extpath from 'vs/base/common/extpath'; import { extname, basename } from 'vs/base/common/path'; @@ -17,7 +16,7 @@ import { Action } from 'vs/base/common/actions'; import { dispose, IDisposable } from 'vs/base/common/lifecycle'; import { VIEWLET_ID, IExplorerService, IFilesConfiguration } from 'vs/workbench/contrib/files/common/files'; import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; -import { IFileService, AutoSaveConfiguration } from 'vs/platform/files/common/files'; +import { IFileService } from 'vs/platform/files/common/files'; import { toResource, SideBySideEditor } from 'vs/workbench/common/editor'; import { ExplorerViewlet } from 'vs/workbench/contrib/files/browser/explorerViewlet'; import { IUntitledTextEditorService } from 'vs/workbench/services/untitled/common/untitledTextEditorService'; @@ -47,6 +46,7 @@ import { ExplorerItem, NewExplorerItem } from 'vs/workbench/contrib/files/common import { onUnexpectedError, getErrorMessage } from 'vs/base/common/errors'; import { asDomUri, triggerDownload } from 'vs/base/browser/dom'; import { mnemonicButtonLabel } from 'vs/base/common/labels'; +import { IAutoSaveConfigurationService } from 'vs/workbench/services/autoSaveConfiguration/common/autoSaveConfigurationService'; export const NEW_FILE_COMMAND_ID = 'explorer.newFile'; export const NEW_FILE_LABEL = nls.localize('newFile', "New File"); @@ -496,26 +496,13 @@ export class ToggleAutoSaveAction extends Action { constructor( id: string, label: string, - @IConfigurationService private readonly configurationService: IConfigurationService + @IAutoSaveConfigurationService private readonly autoSaveConfigurationService: IAutoSaveConfigurationService ) { super(id, label); } run(): Promise { - const setting = this.configurationService.inspect('files.autoSave'); - let userAutoSaveConfig = setting.user; - if (types.isUndefinedOrNull(userAutoSaveConfig)) { - userAutoSaveConfig = setting.default; // use default if setting not defined - } - - let newAutoSaveValue: string; - if ([AutoSaveConfiguration.AFTER_DELAY, AutoSaveConfiguration.ON_FOCUS_CHANGE, AutoSaveConfiguration.ON_WINDOW_CHANGE].some(s => s === userAutoSaveConfig)) { - newAutoSaveValue = AutoSaveConfiguration.OFF; - } else { - newAutoSaveValue = AutoSaveConfiguration.AFTER_DELAY; - } - - return this.configurationService.updateValue('files.autoSave', newAutoSaveValue, ConfigurationTarget.USER); + return this.autoSaveConfigurationService.toggleAutoSave(); } } diff --git a/src/vs/workbench/contrib/files/browser/views/openEditorsView.ts b/src/vs/workbench/contrib/files/browser/views/openEditorsView.ts index abbc65cacaeba..a182f6f962cad 100644 --- a/src/vs/workbench/contrib/files/browser/views/openEditorsView.ts +++ b/src/vs/workbench/contrib/files/browser/views/openEditorsView.ts @@ -15,7 +15,7 @@ import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { IEditorInput, Verbosity } from 'vs/workbench/common/editor'; import { SaveAllAction, SaveAllInGroupAction, CloseGroupAction } from 'vs/workbench/contrib/files/browser/fileActions'; import { OpenEditorsFocusedContext, ExplorerFocusedContext, IFilesConfiguration, OpenEditor } from 'vs/workbench/contrib/files/common/files'; -import { ITextFileService, AutoSaveMode } from 'vs/workbench/services/textfile/common/textfiles'; +import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; import { IUntitledTextEditorService } from 'vs/workbench/services/untitled/common/untitledTextEditorService'; import { CloseAllEditorsAction, CloseEditorAction } from 'vs/workbench/browser/parts/editor/editorActions'; import { ToggleEditorLayoutAction } from 'vs/workbench/browser/actions/layoutActions'; @@ -43,6 +43,7 @@ import { ElementsDragAndDropData, DesktopDragAndDropData } from 'vs/base/browser import { URI } from 'vs/base/common/uri'; import { withNullAsUndefined, withUndefinedAsNull } from 'vs/base/common/types'; import { isWeb } from 'vs/base/common/platform'; +import { IAutoSaveConfigurationService, AutoSaveMode } from 'vs/workbench/services/autoSaveConfiguration/common/autoSaveConfigurationService'; const $ = dom.$; @@ -76,7 +77,8 @@ export class OpenEditorsView extends ViewletPanel { @IContextKeyService private readonly contextKeyService: IContextKeyService, @IThemeService private readonly themeService: IThemeService, @ITelemetryService private readonly telemetryService: ITelemetryService, - @IMenuService private readonly menuService: IMenuService + @IMenuService private readonly menuService: IMenuService, + @IAutoSaveConfigurationService private readonly autoSaveConfigurationService: IAutoSaveConfigurationService ) { super({ ...(options as IViewletPanelOptions), @@ -413,7 +415,7 @@ export class OpenEditorsView extends ViewletPanel { } private updateDirtyIndicator(): void { - let dirty = this.textFileService.getAutoSaveMode() !== AutoSaveMode.AFTER_SHORT_DELAY ? this.textFileService.getDirty().length + let dirty = this.autoSaveConfigurationService.getAutoSaveMode() !== AutoSaveMode.AFTER_SHORT_DELAY ? this.textFileService.getDirty().length : this.untitledTextEditorService.getDirty().length; if (dirty === 0) { dom.addClass(this.dirtyCountElement, 'hidden'); diff --git a/src/vs/workbench/contrib/files/common/dirtyFilesIndicator.ts b/src/vs/workbench/contrib/files/common/dirtyFilesIndicator.ts index 515a11480ba20..0513fcc3cf2cd 100644 --- a/src/vs/workbench/contrib/files/common/dirtyFilesIndicator.ts +++ b/src/vs/workbench/contrib/files/common/dirtyFilesIndicator.ts @@ -6,11 +6,11 @@ import * as nls from 'vs/nls'; import { IWorkbenchContribution } from 'vs/workbench/common/contributions'; import { VIEWLET_ID } from 'vs/workbench/contrib/files/common/files'; -import { ITextFileService, AutoSaveMode } from 'vs/workbench/services/textfile/common/textfiles'; import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle'; import { Disposable, MutableDisposable } from 'vs/base/common/lifecycle'; import { IActivityService, NumberBadge } from 'vs/workbench/services/activity/common/activity'; import { IWorkingCopyService, IWorkingCopy, WorkingCopyCapabilities } from 'vs/workbench/services/workingCopy/common/workingCopyService'; +import { IAutoSaveConfigurationService, AutoSaveMode } from 'vs/workbench/services/autoSaveConfiguration/common/autoSaveConfigurationService'; export class DirtyFilesIndicator extends Disposable implements IWorkbenchContribution { private readonly badgeHandle = this._register(new MutableDisposable()); @@ -22,10 +22,10 @@ export class DirtyFilesIndicator extends Disposable implements IWorkbenchContrib } constructor( - @ITextFileService private readonly textFileService: ITextFileService, @ILifecycleService private readonly lifecycleService: ILifecycleService, @IActivityService private readonly activityService: IActivityService, - @IWorkingCopyService private readonly workingCopyService: IWorkingCopyService + @IWorkingCopyService private readonly workingCopyService: IWorkingCopyService, + @IAutoSaveConfigurationService private readonly autoSaveConfigurationService: IAutoSaveConfigurationService ) { super(); @@ -42,7 +42,7 @@ export class DirtyFilesIndicator extends Disposable implements IWorkbenchContrib } private onWorkingCopyDidChangeDirty(copy: IWorkingCopy): void { - if (!!(copy.capabilities & WorkingCopyCapabilities.AutoSave) && this.textFileService.getAutoSaveMode() === AutoSaveMode.AFTER_SHORT_DELAY) { + if (!!(copy.capabilities & WorkingCopyCapabilities.AutoSave) && this.autoSaveConfigurationService.getAutoSaveMode() === AutoSaveMode.AFTER_SHORT_DELAY) { return; // do not indicate changes to working copies that are auto saved after short delay } diff --git a/src/vs/workbench/contrib/files/common/editors/fileEditorInput.ts b/src/vs/workbench/contrib/files/common/editors/fileEditorInput.ts index 399c49196c9f9..d4efe1d008479 100644 --- a/src/vs/workbench/contrib/files/common/editors/fileEditorInput.ts +++ b/src/vs/workbench/contrib/files/common/editors/fileEditorInput.ts @@ -11,12 +11,13 @@ import { EncodingMode, ConfirmResult, EditorInput, IFileEditorInput, ITextEditor import { TextFileEditorModel } from 'vs/workbench/services/textfile/common/textFileEditorModel'; import { BinaryEditorModel } from 'vs/workbench/common/editor/binaryEditorModel'; import { FileOperationError, FileOperationResult, IFileService } from 'vs/platform/files/common/files'; -import { ITextFileService, AutoSaveMode, ModelState, TextFileModelChangeEvent, LoadReason, TextFileOperationError, TextFileOperationResult } from 'vs/workbench/services/textfile/common/textfiles'; +import { ITextFileService, ModelState, TextFileModelChangeEvent, LoadReason, TextFileOperationError, TextFileOperationResult } from 'vs/workbench/services/textfile/common/textfiles'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IReference } from 'vs/base/common/lifecycle'; import { ITextModelService } from 'vs/editor/common/services/resolverService'; import { FILE_EDITOR_INPUT_ID, TEXT_FILE_EDITOR_ID, BINARY_FILE_EDITOR_ID } from 'vs/workbench/contrib/files/common/files'; import { ILabelService } from 'vs/platform/label/common/label'; +import { IAutoSaveConfigurationService, AutoSaveMode } from 'vs/workbench/services/autoSaveConfiguration/common/autoSaveConfigurationService'; const enum ForceOpenAs { None, @@ -49,7 +50,8 @@ export class FileEditorInput extends EditorInput implements IFileEditorInput { @ITextFileService private readonly textFileService: ITextFileService, @ITextModelService private readonly textModelResolverService: ITextModelService, @ILabelService private readonly labelService: ILabelService, - @IFileService private readonly fileService: IFileService + @IFileService private readonly fileService: IFileService, + @IAutoSaveConfigurationService private readonly autoSaveConfigurationService: IAutoSaveConfigurationService ) { super(); @@ -234,7 +236,7 @@ export class FileEditorInput extends EditorInput implements IFileEditorInput { return true; // always indicate dirty state if we are in conflict or error state } - if (this.textFileService.getAutoSaveMode() === AutoSaveMode.AFTER_SHORT_DELAY) { + if (this.autoSaveConfigurationService.getAutoSaveMode() === AutoSaveMode.AFTER_SHORT_DELAY) { return false; // fast auto save enabled so we do not declare dirty } diff --git a/src/vs/workbench/contrib/files/electron-browser/textFileEditor.ts b/src/vs/workbench/contrib/files/electron-browser/textFileEditor.ts index 18624e12e9a69..d2b5d4aa360c9 100644 --- a/src/vs/workbench/contrib/files/electron-browser/textFileEditor.ts +++ b/src/vs/workbench/contrib/files/electron-browser/textFileEditor.ts @@ -25,6 +25,7 @@ import { IHostService } from 'vs/workbench/services/host/browser/host'; import { IPreferencesService } from 'vs/workbench/services/preferences/common/preferences'; import { IExplorerService } from 'vs/workbench/contrib/files/common/files'; import { IElectronService } from 'vs/platform/electron/node/electron'; +import { IAutoSaveConfigurationService } from 'vs/workbench/services/autoSaveConfiguration/common/autoSaveConfigurationService'; /** * An implementation of editor for file system resources. @@ -46,9 +47,10 @@ export class NativeTextFileEditor extends TextFileEditor { @IElectronService private readonly electronService: IElectronService, @IPreferencesService private readonly preferencesService: IPreferencesService, @IHostService hostService: IHostService, - @IExplorerService explorerService: IExplorerService + @IExplorerService explorerService: IExplorerService, + @IAutoSaveConfigurationService autoSaveConfigurationService: IAutoSaveConfigurationService ) { - super(telemetryService, fileService, viewletService, instantiationService, contextService, storageService, configurationService, editorService, themeService, editorGroupService, textFileService, hostService, explorerService); + super(telemetryService, fileService, viewletService, instantiationService, contextService, storageService, configurationService, editorService, themeService, editorGroupService, textFileService, hostService, explorerService, autoSaveConfigurationService); } protected handleSetInputError(error: Error, input: FileEditorInput, options: EditorOptions | undefined): void { diff --git a/src/vs/workbench/contrib/output/browser/logViewer.ts b/src/vs/workbench/contrib/output/browser/logViewer.ts index ce500dfe4a33e..31ee5aac46210 100644 --- a/src/vs/workbench/contrib/output/browser/logViewer.ts +++ b/src/vs/workbench/contrib/output/browser/logViewer.ts @@ -20,6 +20,7 @@ import { LOG_SCHEME, IFileOutputChannelDescriptor } from 'vs/workbench/contrib/o import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IHostService } from 'vs/workbench/services/host/browser/host'; +import { IAutoSaveConfigurationService } from 'vs/workbench/services/autoSaveConfiguration/common/autoSaveConfigurationService'; export class LogViewerInput extends ResourceEditorInput { @@ -54,9 +55,10 @@ export class LogViewer extends AbstractTextResourceEditor { @IEditorGroupsService editorGroupService: IEditorGroupsService, @ITextFileService textFileService: ITextFileService, @IEditorService editorService: IEditorService, - @IHostService hostService: IHostService + @IHostService hostService: IHostService, + @IAutoSaveConfigurationService autoSaveConfigurationService: IAutoSaveConfigurationService ) { - super(LogViewer.LOG_VIEWER_EDITOR_ID, telemetryService, instantiationService, storageService, textResourceConfigurationService, themeService, editorGroupService, textFileService, editorService, hostService); + super(LogViewer.LOG_VIEWER_EDITOR_ID, telemetryService, instantiationService, storageService, textResourceConfigurationService, themeService, editorGroupService, textFileService, editorService, hostService, autoSaveConfigurationService); } protected getConfigurationOverrides(): IEditorOptions { diff --git a/src/vs/workbench/contrib/output/browser/outputPanel.ts b/src/vs/workbench/contrib/output/browser/outputPanel.ts index d9eeefed51111..c2e14e0763a25 100644 --- a/src/vs/workbench/contrib/output/browser/outputPanel.ts +++ b/src/vs/workbench/contrib/output/browser/outputPanel.ts @@ -26,6 +26,7 @@ import { CancellationToken } from 'vs/base/common/cancellation'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IHostService } from 'vs/workbench/services/host/browser/host'; import { CursorChangeReason } from 'vs/editor/common/controller/cursorEvents'; +import { IAutoSaveConfigurationService } from 'vs/workbench/services/autoSaveConfiguration/common/autoSaveConfigurationService'; export class OutputPanel extends AbstractTextResourceEditor { private actions: IAction[] | undefined; @@ -44,9 +45,10 @@ export class OutputPanel extends AbstractTextResourceEditor { @IEditorGroupsService editorGroupService: IEditorGroupsService, @ITextFileService textFileService: ITextFileService, @IEditorService editorService: IEditorService, - @IHostService hostService: IHostService + @IHostService hostService: IHostService, + @IAutoSaveConfigurationService autoSaveConfigurationService: IAutoSaveConfigurationService ) { - super(OUTPUT_PANEL_ID, telemetryService, instantiationService, storageService, textResourceConfigurationService, themeService, editorGroupService, textFileService, editorService, hostService); + super(OUTPUT_PANEL_ID, telemetryService, instantiationService, storageService, textResourceConfigurationService, themeService, editorGroupService, textFileService, editorService, hostService, autoSaveConfigurationService); this.scopedInstantiationService = instantiationService; } diff --git a/src/vs/workbench/contrib/preferences/browser/preferencesEditor.ts b/src/vs/workbench/contrib/preferences/browser/preferencesEditor.ts index abec70f1f2815..8c5d0468c3e15 100644 --- a/src/vs/workbench/contrib/preferences/browser/preferencesEditor.ts +++ b/src/vs/workbench/contrib/preferences/browser/preferencesEditor.ts @@ -55,6 +55,7 @@ import { DefaultSettingsEditorModel, SettingsEditorModel } from 'vs/workbench/se import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; import { IHostService } from 'vs/workbench/services/host/browser/host'; import { withNullAsUndefined, withUndefinedAsNull, assertIsDefined } from 'vs/base/common/types'; +import { IAutoSaveConfigurationService } from 'vs/workbench/services/autoSaveConfiguration/common/autoSaveConfigurationService'; export class PreferencesEditor extends BaseEditor { @@ -981,9 +982,10 @@ export class DefaultPreferencesEditor extends BaseTextEditor { @ITextFileService textFileService: ITextFileService, @IEditorGroupsService editorGroupService: IEditorGroupsService, @IEditorService editorService: IEditorService, - @IHostService hostService: IHostService + @IHostService hostService: IHostService, + @IAutoSaveConfigurationService autoSaveConfigurationService: IAutoSaveConfigurationService ) { - super(DefaultPreferencesEditor.ID, telemetryService, instantiationService, storageService, configurationService, themeService, textFileService, editorService, editorGroupService, hostService); + super(DefaultPreferencesEditor.ID, telemetryService, instantiationService, storageService, configurationService, themeService, textFileService, editorService, editorGroupService, hostService, autoSaveConfigurationService); } private static _getContributions(): IEditorContributionDescription[] { diff --git a/src/vs/workbench/services/autoSaveConfiguration/common/autoSaveConfigurationService.ts b/src/vs/workbench/services/autoSaveConfiguration/common/autoSaveConfigurationService.ts new file mode 100644 index 0000000000000..9e7ac720a44bc --- /dev/null +++ b/src/vs/workbench/services/autoSaveConfiguration/common/autoSaveConfigurationService.ts @@ -0,0 +1,158 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; +import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { Event, Emitter } from 'vs/base/common/event'; +import { Disposable } from 'vs/base/common/lifecycle'; +import { RawContextKey, IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; +import { IConfigurationService, ConfigurationTarget } from 'vs/platform/configuration/common/configuration'; +import { IFilesConfiguration, AutoSaveConfiguration } from 'vs/platform/files/common/files'; +import { isUndefinedOrNull } from 'vs/base/common/types'; + +export const AutoSaveContext = new RawContextKey('config.files.autoSave', undefined); + +export interface IAutoSaveConfiguration { + autoSaveDelay?: number; + autoSaveFocusChange: boolean; + autoSaveApplicationChange: boolean; +} + +export const enum AutoSaveMode { + OFF, + AFTER_SHORT_DELAY, + AFTER_LONG_DELAY, + ON_FOCUS_CHANGE, + ON_WINDOW_CHANGE +} + +export const IAutoSaveConfigurationService = createDecorator('autoSaveConfigurationService'); + +export interface IAutoSaveConfigurationService { + + _serviceBrand: undefined; + + readonly onAutoSaveConfigurationChange: Event; + + getAutoSaveMode(): AutoSaveMode; + + getAutoSaveConfiguration(): IAutoSaveConfiguration; + + toggleAutoSave(): Promise; +} + +export class AutoSaveConfigurationService extends Disposable implements IAutoSaveConfigurationService { + + _serviceBrand: undefined; + + private readonly _onAutoSaveConfigurationChange = this._register(new Emitter()); + readonly onAutoSaveConfigurationChange = this._onAutoSaveConfigurationChange.event; + + private configuredAutoSaveDelay?: number; + private configuredAutoSaveOnFocusChange: boolean | undefined; + private configuredAutoSaveOnWindowChange: boolean | undefined; + + private autoSaveContext: IContextKey; + + constructor( + @IContextKeyService contextKeyService: IContextKeyService, + @IConfigurationService private readonly configurationService: IConfigurationService + ) { + super(); + + this.autoSaveContext = AutoSaveContext.bindTo(contextKeyService); + + const configuration = configurationService.getValue(); + this.onFilesConfigurationChange(configuration); + + this.registerListeners(); + } + + private registerListeners(): void { + + // Files configuration changes + this._register(this.configurationService.onDidChangeConfiguration(e => { + if (e.affectsConfiguration('files')) { + this.onFilesConfigurationChange(this.configurationService.getValue()); + } + })); + } + + private onFilesConfigurationChange(configuration: IFilesConfiguration): void { + const autoSaveMode = configuration?.files?.autoSave || AutoSaveConfiguration.OFF; + this.autoSaveContext.set(autoSaveMode); + switch (autoSaveMode) { + case AutoSaveConfiguration.AFTER_DELAY: + this.configuredAutoSaveDelay = configuration?.files?.autoSaveDelay; + this.configuredAutoSaveOnFocusChange = false; + this.configuredAutoSaveOnWindowChange = false; + break; + + case AutoSaveConfiguration.ON_FOCUS_CHANGE: + this.configuredAutoSaveDelay = undefined; + this.configuredAutoSaveOnFocusChange = true; + this.configuredAutoSaveOnWindowChange = false; + break; + + case AutoSaveConfiguration.ON_WINDOW_CHANGE: + this.configuredAutoSaveDelay = undefined; + this.configuredAutoSaveOnFocusChange = false; + this.configuredAutoSaveOnWindowChange = true; + break; + + default: + this.configuredAutoSaveDelay = undefined; + this.configuredAutoSaveOnFocusChange = false; + this.configuredAutoSaveOnWindowChange = false; + break; + } + + // Emit as event + this._onAutoSaveConfigurationChange.fire(this.getAutoSaveConfiguration()); + } + + getAutoSaveMode(): AutoSaveMode { + if (this.configuredAutoSaveOnFocusChange) { + return AutoSaveMode.ON_FOCUS_CHANGE; + } + + if (this.configuredAutoSaveOnWindowChange) { + return AutoSaveMode.ON_WINDOW_CHANGE; + } + + if (this.configuredAutoSaveDelay && this.configuredAutoSaveDelay > 0) { + return this.configuredAutoSaveDelay <= 1000 ? AutoSaveMode.AFTER_SHORT_DELAY : AutoSaveMode.AFTER_LONG_DELAY; + } + + return AutoSaveMode.OFF; + } + + getAutoSaveConfiguration(): IAutoSaveConfiguration { + return { + autoSaveDelay: this.configuredAutoSaveDelay && this.configuredAutoSaveDelay > 0 ? this.configuredAutoSaveDelay : undefined, + autoSaveFocusChange: !!this.configuredAutoSaveOnFocusChange, + autoSaveApplicationChange: !!this.configuredAutoSaveOnWindowChange + }; + } + + async toggleAutoSave(): Promise { + const setting = this.configurationService.inspect('files.autoSave'); + let userAutoSaveConfig = setting.user; + if (isUndefinedOrNull(userAutoSaveConfig)) { + userAutoSaveConfig = setting.default; // use default if setting not defined + } + + let newAutoSaveValue: string; + if ([AutoSaveConfiguration.AFTER_DELAY, AutoSaveConfiguration.ON_FOCUS_CHANGE, AutoSaveConfiguration.ON_WINDOW_CHANGE].some(s => s === userAutoSaveConfig)) { + newAutoSaveValue = AutoSaveConfiguration.OFF; + } else { + newAutoSaveValue = AutoSaveConfiguration.AFTER_DELAY; + } + + return this.configurationService.updateValue('files.autoSave', newAutoSaveValue, ConfigurationTarget.USER); + } +} + +registerSingleton(IAutoSaveConfigurationService, AutoSaveConfigurationService); diff --git a/src/vs/workbench/services/textfile/browser/textFileService.ts b/src/vs/workbench/services/textfile/browser/textFileService.ts index 7a68d53bd7a9f..ea66d626d2e31 100644 --- a/src/vs/workbench/services/textfile/browser/textFileService.ts +++ b/src/vs/workbench/services/textfile/browser/textFileService.ts @@ -9,11 +9,11 @@ import * as objects from 'vs/base/common/objects'; import { Emitter, AsyncEmitter } from 'vs/base/common/event'; import * as platform from 'vs/base/common/platform'; import { IBackupFileService } from 'vs/workbench/services/backup/common/backup'; -import { IResult, ITextFileOperationResult, ITextFileService, ITextFileStreamContent, IAutoSaveConfiguration, AutoSaveMode, SaveReason, ITextFileEditorModelManager, ITextFileEditorModel, ModelState, ISaveOptions, AutoSaveContext, ITextFileContent, IResourceEncodings, IReadTextFileOptions, IWriteTextFileOptions, toBufferOrReadable, TextFileOperationError, TextFileOperationResult, FileOperationWillRunEvent, FileOperationDidRunEvent } from 'vs/workbench/services/textfile/common/textfiles'; +import { IResult, ITextFileOperationResult, ITextFileService, ITextFileStreamContent, SaveReason, ITextFileEditorModelManager, ITextFileEditorModel, ModelState, ISaveOptions, ITextFileContent, IResourceEncodings, IReadTextFileOptions, IWriteTextFileOptions, toBufferOrReadable, TextFileOperationError, TextFileOperationResult, FileOperationWillRunEvent, FileOperationDidRunEvent } from 'vs/workbench/services/textfile/common/textfiles'; import { ConfirmResult, IRevertOptions } from 'vs/workbench/common/editor'; import { ILifecycleService, ShutdownReason, LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle'; import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; -import { IFileService, IFilesConfiguration, FileOperationError, FileOperationResult, AutoSaveConfiguration, HotExitConfiguration, IFileStatWithMetadata, ICreateFileOptions, FileOperation } from 'vs/platform/files/common/files'; +import { IFileService, IFilesConfiguration, FileOperationError, FileOperationResult, HotExitConfiguration, IFileStatWithMetadata, ICreateFileOptions, FileOperation } from 'vs/platform/files/common/files'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { Disposable } from 'vs/base/common/lifecycle'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; @@ -24,7 +24,6 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti import { ResourceMap } from 'vs/base/common/map'; import { Schemas } from 'vs/base/common/network'; import { IHistoryService } from 'vs/workbench/services/history/common/history'; -import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { createTextBufferFactoryFromSnapshot, createTextBufferFactoryFromStream } from 'vs/editor/common/model/textModel'; import { IModelService } from 'vs/editor/common/services/modelService'; import { INotificationService, Severity } from 'vs/platform/notification/common/notification'; @@ -38,6 +37,7 @@ import { VSBuffer } from 'vs/base/common/buffer'; import { ITextSnapshot } from 'vs/editor/common/model'; import { ITextResourceConfigurationService } from 'vs/editor/common/services/resourceConfiguration'; import { PLAINTEXT_MODE_ID } from 'vs/editor/common/modes/modesRegistry'; +import { IAutoSaveConfigurationService, AutoSaveMode } from 'vs/workbench/services/autoSaveConfiguration/common/autoSaveConfigurationService'; /** * The workbench file service implementation implements the raw file service spec and adds additional methods on top. @@ -48,9 +48,6 @@ export abstract class AbstractTextFileService extends Disposable implements ITex //#region events - private readonly _onAutoSaveConfigurationChange = this._register(new Emitter()); - readonly onAutoSaveConfigurationChange = this._onAutoSaveConfigurationChange.event; - private readonly _onFilesAssociationChange = this._register(new Emitter()); readonly onFilesAssociationChange = this._onFilesAssociationChange.event; @@ -68,11 +65,8 @@ export abstract class AbstractTextFileService extends Disposable implements ITex abstract get encoding(): IResourceEncodings; private currentFilesAssociationConfig: { [key: string]: string; }; - private configuredAutoSaveDelay?: number; - private configuredAutoSaveOnFocusChange: boolean | undefined; - private configuredAutoSaveOnWindowChange: boolean | undefined; + private configuredHotExit: string | undefined; - private autoSaveContext: IContextKey; constructor( @IWorkspaceContextService private readonly contextService: IWorkspaceContextService, @@ -87,22 +81,19 @@ export abstract class AbstractTextFileService extends Disposable implements ITex @INotificationService private readonly notificationService: INotificationService, @IBackupFileService private readonly backupFileService: IBackupFileService, @IHistoryService private readonly historyService: IHistoryService, - @IContextKeyService contextKeyService: IContextKeyService, @IDialogService private readonly dialogService: IDialogService, @IFileDialogService private readonly fileDialogService: IFileDialogService, @IEditorService private readonly editorService: IEditorService, - @ITextResourceConfigurationService protected readonly textResourceConfigurationService: ITextResourceConfigurationService + @ITextResourceConfigurationService protected readonly textResourceConfigurationService: ITextResourceConfigurationService, + @IAutoSaveConfigurationService private readonly autoSaveConfigurationService: IAutoSaveConfigurationService ) { super(); this._models = this._register(instantiationService.createInstance(TextFileEditorModelManager)); - this.autoSaveContext = AutoSaveContext.bindTo(contextKeyService); const configuration = configurationService.getValue(); this.currentFilesAssociationConfig = configuration?.files?.associations; - this.onFilesConfigurationChange(configuration); - this.registerListeners(); } @@ -120,6 +111,17 @@ export abstract class AbstractTextFileService extends Disposable implements ITex this.onFilesConfigurationChange(this.configurationService.getValue()); } })); + + // Auto save changes + this._register(this.autoSaveConfigurationService.onAutoSaveConfigurationChange(() => this.onAutoSaveConfigurationChange())); + } + + private onAutoSaveConfigurationChange(): void { + + // save all dirty when enabling auto save + if (this.autoSaveConfigurationService.getAutoSaveMode() !== AutoSaveMode.OFF) { + this.saveAll(); + } } protected onBeforeShutdown(reason: ShutdownReason): boolean | Promise { @@ -130,7 +132,7 @@ export abstract class AbstractTextFileService extends Disposable implements ITex // If auto save is enabled, save all files and then check again for dirty files // We DO NOT run any save participant if we are in the shutdown phase for performance reasons - if (this.getAutoSaveMode() !== AutoSaveMode.OFF) { + if (this.autoSaveConfigurationService.getAutoSaveMode() !== AutoSaveMode.OFF) { return this.saveAll(false /* files only */, { skipSaveParticipants: true }).then(() => { // If we still have dirty files, we either have untitled ones or files that cannot be saved @@ -302,43 +304,6 @@ export abstract class AbstractTextFileService extends Disposable implements ITex } protected onFilesConfigurationChange(configuration: IFilesConfiguration): void { - const wasAutoSaveEnabled = (this.getAutoSaveMode() !== AutoSaveMode.OFF); - - const autoSaveMode = configuration?.files?.autoSave || AutoSaveConfiguration.OFF; - this.autoSaveContext.set(autoSaveMode); - switch (autoSaveMode) { - case AutoSaveConfiguration.AFTER_DELAY: - this.configuredAutoSaveDelay = configuration?.files?.autoSaveDelay; - this.configuredAutoSaveOnFocusChange = false; - this.configuredAutoSaveOnWindowChange = false; - break; - - case AutoSaveConfiguration.ON_FOCUS_CHANGE: - this.configuredAutoSaveDelay = undefined; - this.configuredAutoSaveOnFocusChange = true; - this.configuredAutoSaveOnWindowChange = false; - break; - - case AutoSaveConfiguration.ON_WINDOW_CHANGE: - this.configuredAutoSaveDelay = undefined; - this.configuredAutoSaveOnFocusChange = false; - this.configuredAutoSaveOnWindowChange = true; - break; - - default: - this.configuredAutoSaveDelay = undefined; - this.configuredAutoSaveOnFocusChange = false; - this.configuredAutoSaveOnWindowChange = false; - break; - } - - // Emit as event - this._onAutoSaveConfigurationChange.fire(this.getAutoSaveConfiguration()); - - // save all dirty when enabling auto save - if (!wasAutoSaveEnabled && this.getAutoSaveMode() !== AutoSaveMode.OFF) { - this.saveAll(); - } // Check for change in files associations const filesAssociation = configuration?.files?.associations; @@ -1006,30 +971,6 @@ export abstract class AbstractTextFileService extends Disposable implements ITex //#region config - getAutoSaveMode(): AutoSaveMode { - if (this.configuredAutoSaveOnFocusChange) { - return AutoSaveMode.ON_FOCUS_CHANGE; - } - - if (this.configuredAutoSaveOnWindowChange) { - return AutoSaveMode.ON_WINDOW_CHANGE; - } - - if (this.configuredAutoSaveDelay && this.configuredAutoSaveDelay > 0) { - return this.configuredAutoSaveDelay <= 1000 ? AutoSaveMode.AFTER_SHORT_DELAY : AutoSaveMode.AFTER_LONG_DELAY; - } - - return AutoSaveMode.OFF; - } - - getAutoSaveConfiguration(): IAutoSaveConfiguration { - return { - autoSaveDelay: this.configuredAutoSaveDelay && this.configuredAutoSaveDelay > 0 ? this.configuredAutoSaveDelay : undefined, - autoSaveFocusChange: !!this.configuredAutoSaveOnFocusChange, - autoSaveApplicationChange: !!this.configuredAutoSaveOnWindowChange - }; - } - get isHotExitEnabled(): boolean { return !this.environmentService.isExtensionDevelopment && this.configuredHotExit !== HotExitConfiguration.OFF; } diff --git a/src/vs/workbench/services/textfile/common/textFileEditorModel.ts b/src/vs/workbench/services/textfile/common/textFileEditorModel.ts index b86d2ed4508d1..c50d7ea04042e 100644 --- a/src/vs/workbench/services/textfile/common/textFileEditorModel.ts +++ b/src/vs/workbench/services/textfile/common/textFileEditorModel.ts @@ -11,7 +11,7 @@ import { URI } from 'vs/base/common/uri'; import { isUndefinedOrNull, assertIsDefined } from 'vs/base/common/types'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; -import { ITextFileService, IAutoSaveConfiguration, ModelState, ITextFileEditorModel, ISaveOptions, ISaveErrorHandler, ISaveParticipant, StateChange, SaveReason, ITextFileStreamContent, ILoadOptions, LoadReason, IResolvedTextFileEditorModel } from 'vs/workbench/services/textfile/common/textfiles'; +import { ITextFileService, ModelState, ITextFileEditorModel, ISaveOptions, ISaveErrorHandler, ISaveParticipant, StateChange, SaveReason, ITextFileStreamContent, ILoadOptions, LoadReason, IResolvedTextFileEditorModel } from 'vs/workbench/services/textfile/common/textfiles'; import { EncodingMode } from 'vs/workbench/common/editor'; import { BaseTextEditorModel } from 'vs/workbench/common/editor/textEditorModel'; import { IBackupFileService } from 'vs/workbench/services/backup/common/backup'; @@ -30,6 +30,7 @@ import { isEqual, isEqualOrParent, extname, basename, joinPath } from 'vs/base/c import { onUnexpectedError } from 'vs/base/common/errors'; import { Schemas } from 'vs/base/common/network'; import { IWorkingCopyService, WorkingCopyCapabilities } from 'vs/workbench/services/workingCopy/common/workingCopyService'; +import { IAutoSaveConfigurationService, IAutoSaveConfiguration } from 'vs/workbench/services/autoSaveConfiguration/common/autoSaveConfigurationService'; export interface IBackupMetaData { mtime: number; @@ -121,11 +122,12 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil @IEnvironmentService private readonly environmentService: IEnvironmentService, @IWorkspaceContextService private readonly contextService: IWorkspaceContextService, @ILogService private readonly logService: ILogService, - @IWorkingCopyService private readonly workingCopyService: IWorkingCopyService + @IWorkingCopyService private readonly workingCopyService: IWorkingCopyService, + @IAutoSaveConfigurationService private readonly autoSaveConfigurationService: IAutoSaveConfigurationService ) { super(modelService, modeService); - this.updateAutoSaveConfiguration(textFileService.getAutoSaveConfiguration()); + this.updateAutoSaveConfiguration(autoSaveConfigurationService.getAutoSaveConfiguration()); // Make known to working copy service this._register(this.workingCopyService.registerWorkingCopy(this)); @@ -135,7 +137,7 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil private registerListeners(): void { this._register(this.fileService.onFileChanges(e => this.onFileChanges(e))); - this._register(this.textFileService.onAutoSaveConfigurationChange(config => this.updateAutoSaveConfiguration(config))); + this._register(this.autoSaveConfigurationService.onAutoSaveConfigurationChange(config => this.updateAutoSaveConfiguration(config))); this._register(this.textFileService.onFilesAssociationChange(e => this.onFilesAssociationChange())); this._register(this.onDidStateChange(e => this.onStateChange(e))); } diff --git a/src/vs/workbench/services/textfile/common/textfiles.ts b/src/vs/workbench/services/textfile/common/textfiles.ts index 4ab9efb61c71b..9341412702050 100644 --- a/src/vs/workbench/services/textfile/common/textfiles.ts +++ b/src/vs/workbench/services/textfile/common/textfiles.ts @@ -11,7 +11,6 @@ import { IBaseStatWithMetadata, IFileStatWithMetadata, IReadFileOptions, IWriteF import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { ITextEditorModel } from 'vs/editor/common/services/resolverService'; import { ITextBufferFactory, ITextModel, ITextSnapshot } from 'vs/editor/common/model'; -import { RawContextKey } from 'vs/platform/contextkey/common/contextkey'; import { VSBuffer, VSBufferReadable } from 'vs/base/common/buffer'; import { isUndefinedOrNull } from 'vs/base/common/types'; import { isNative } from 'vs/base/common/platform'; @@ -23,8 +22,6 @@ export interface ITextFileService extends IDisposable { _serviceBrand: undefined; - readonly onAutoSaveConfigurationChange: Event; - readonly onFilesAssociationChange: Event; readonly isHotExitEnabled: boolean; @@ -144,16 +141,6 @@ export interface ITextFileService extends IDisposable { * confirming for all dirty resources. */ confirmSave(resources?: URI[]): Promise; - - /** - * Convenient fast access to the current auto save mode. - */ - getAutoSaveMode(): AutoSaveMode; - - /** - * Convenient fast access to the raw configured auto save settings. - */ - getAutoSaveConfiguration(): IAutoSaveConfiguration; } @@ -341,8 +328,6 @@ export class TextFileModelChangeEvent { } } -export const AutoSaveContext = new RawContextKey('config.files.autoSave', undefined); - export interface ITextFileOperationResult { results: IResult[]; } @@ -353,20 +338,6 @@ export interface IResult { success?: boolean; } -export interface IAutoSaveConfiguration { - autoSaveDelay?: number; - autoSaveFocusChange: boolean; - autoSaveApplicationChange: boolean; -} - -export const enum AutoSaveMode { - OFF, - AFTER_SHORT_DELAY, - AFTER_LONG_DELAY, - ON_FOCUS_CHANGE, - ON_WINDOW_CHANGE -} - export const enum SaveReason { EXPLICIT = 1, AUTO = 2, diff --git a/src/vs/workbench/services/textfile/electron-browser/nativeTextFileService.ts b/src/vs/workbench/services/textfile/electron-browser/nativeTextFileService.ts index 23cf1f058dcd4..3a1487ec77965 100644 --- a/src/vs/workbench/services/textfile/electron-browser/nativeTextFileService.ts +++ b/src/vs/workbench/services/textfile/electron-browser/nativeTextFileService.ts @@ -38,11 +38,11 @@ import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/ import { INotificationService } from 'vs/platform/notification/common/notification'; import { IBackupFileService } from 'vs/workbench/services/backup/common/backup'; import { IHistoryService } from 'vs/workbench/services/history/common/history'; -import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { IDialogService, IFileDialogService } from 'vs/platform/dialogs/common/dialogs'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { ConfirmResult } from 'vs/workbench/common/editor'; import { assign } from 'vs/base/common/objects'; +import { IAutoSaveConfigurationService } from 'vs/workbench/services/autoSaveConfiguration/common/autoSaveConfigurationService'; export class NativeTextFileService extends AbstractTextFileService { @@ -59,15 +59,15 @@ export class NativeTextFileService extends AbstractTextFileService { @INotificationService notificationService: INotificationService, @IBackupFileService backupFileService: IBackupFileService, @IHistoryService historyService: IHistoryService, - @IContextKeyService contextKeyService: IContextKeyService, @IDialogService dialogService: IDialogService, @IFileDialogService fileDialogService: IFileDialogService, @IEditorService editorService: IEditorService, @ITextResourceConfigurationService textResourceConfigurationService: ITextResourceConfigurationService, @IElectronService private readonly electronService: IElectronService, - @IProductService private readonly productService: IProductService + @IProductService private readonly productService: IProductService, + @IAutoSaveConfigurationService autoSaveConfigurationService: IAutoSaveConfigurationService ) { - super(contextService, fileService, untitledTextEditorService, lifecycleService, instantiationService, configurationService, modeService, modelService, environmentService, notificationService, backupFileService, historyService, contextKeyService, dialogService, fileDialogService, editorService, textResourceConfigurationService); + super(contextService, fileService, untitledTextEditorService, lifecycleService, instantiationService, configurationService, modeService, modelService, environmentService, notificationService, backupFileService, historyService, dialogService, fileDialogService, editorService, textResourceConfigurationService, autoSaveConfigurationService); } private _encoding: EncodingOracle | undefined; diff --git a/src/vs/workbench/services/workingCopy/test/common/workingCopyService.test.ts b/src/vs/workbench/services/workingCopy/test/common/workingCopyService.test.ts index 7bff97ff4082e..a7797845a1755 100644 --- a/src/vs/workbench/services/workingCopy/test/common/workingCopyService.test.ts +++ b/src/vs/workbench/services/workingCopy/test/common/workingCopyService.test.ts @@ -4,10 +4,11 @@ *--------------------------------------------------------------------------------------------*/ import * as assert from 'assert'; -import { WorkingCopyService, IWorkingCopy } from 'vs/workbench/services/workingCopy/common/workingCopyService'; +import { IWorkingCopy } from 'vs/workbench/services/workingCopy/common/workingCopyService'; import { URI } from 'vs/base/common/uri'; import { Emitter } from 'vs/base/common/event'; import { Disposable } from 'vs/base/common/lifecycle'; +import { TestWorkingCopyService } from 'vs/workbench/test/workbenchTestServices'; suite('WorkingCopyService', () => { @@ -48,7 +49,7 @@ suite('WorkingCopyService', () => { } test('registry - basics', () => { - const service = new WorkingCopyService(); + const service = new TestWorkingCopyService(); const onDidChangeDirty: IWorkingCopy[] = []; service.onDidChangeDirty(copy => onDidChangeDirty.push(copy)); @@ -104,7 +105,7 @@ suite('WorkingCopyService', () => { }); test('registry - multiple copies on same resource', () => { - const service = new WorkingCopyService(); + const service = new TestWorkingCopyService(); const onDidChangeDirty: IWorkingCopy[] = []; service.onDidChangeDirty(copy => onDidChangeDirty.push(copy)); diff --git a/src/vs/workbench/test/workbenchTestServices.ts b/src/vs/workbench/test/workbenchTestServices.ts index 5d9d717d2bcc1..b1e238cb5d5f0 100644 --- a/src/vs/workbench/test/workbenchTestServices.ts +++ b/src/vs/workbench/test/workbenchTestServices.ts @@ -93,6 +93,7 @@ import { IEmptyWindowBackupInfo } from 'vs/platform/backup/node/backup'; import { IDialogMainService } from 'vs/platform/dialogs/electron-main/dialogs'; import { find } from 'vs/base/common/arrays'; import { WorkingCopyService, IWorkingCopyService } from 'vs/workbench/services/workingCopy/common/workingCopyService'; +import { IAutoSaveConfigurationService, AutoSaveConfigurationService } from 'vs/workbench/services/autoSaveConfiguration/common/autoSaveConfigurationService'; export function createFileInput(instantiationService: IInstantiationService, resource: URI): FileEditorInput { return instantiationService.createInstance(FileEditorInput, resource, undefined, undefined); @@ -207,13 +208,13 @@ export class TestTextFileService extends NativeTextFileService { @INotificationService notificationService: INotificationService, @IBackupFileService backupFileService: IBackupFileService, @IHistoryService historyService: IHistoryService, - @IContextKeyService contextKeyService: IContextKeyService, @IDialogService dialogService: IDialogService, @IFileDialogService fileDialogService: IFileDialogService, @IEditorService editorService: IEditorService, @ITextResourceConfigurationService textResourceConfigurationService: ITextResourceConfigurationService, @IElectronService electronService: IElectronService, - @IProductService productService: IProductService + @IProductService productService: IProductService, + @IAutoSaveConfigurationService autoSaveConfigurationService: IAutoSaveConfigurationService ) { super( contextService, @@ -228,13 +229,13 @@ export class TestTextFileService extends NativeTextFileService { notificationService, backupFileService, historyService, - contextKeyService, dialogService, fileDialogService, editorService, textResourceConfigurationService, electronService, - productService + productService, + autoSaveConfigurationService ); } @@ -297,11 +298,13 @@ export class TestTextFileService extends NativeTextFileService { export function workbenchInstantiationService(): IInstantiationService { let instantiationService = new TestInstantiationService(new ServiceCollection([ILifecycleService, new TestLifecycleService()])); instantiationService.stub(IEnvironmentService, TestEnvironmentService); - instantiationService.stub(IContextKeyService, instantiationService.createInstance(MockContextKeyService)); + const contextKeyService = instantiationService.createInstance(MockContextKeyService); + instantiationService.stub(IContextKeyService, contextKeyService); const workspaceContextService = new TestContextService(TestWorkspace); instantiationService.stub(IWorkspaceContextService, workspaceContextService); const configService = new TestConfigurationService(); instantiationService.stub(IConfigurationService, configService); + instantiationService.stub(IAutoSaveConfigurationService, new AutoSaveConfigurationService(contextKeyService, configService)); instantiationService.stub(ITextResourceConfigurationService, new TestTextResourceConfigurationService(configService)); instantiationService.stub(IUntitledTextEditorService, instantiationService.createInstance(UntitledTextEditorService)); instantiationService.stub(IStorageService, new TestStorageService()); @@ -1467,6 +1470,4 @@ export class TestDialogMainService implements IDialogMainService { } } -export class TestWorkingCopyService extends WorkingCopyService { - -} +export class TestWorkingCopyService extends WorkingCopyService { } diff --git a/src/vs/workbench/workbench.common.main.ts b/src/vs/workbench/workbench.common.main.ts index 8c9f50ad424b0..3c0ed98e54e72 100644 --- a/src/vs/workbench/workbench.common.main.ts +++ b/src/vs/workbench/workbench.common.main.ts @@ -83,6 +83,7 @@ import 'vs/workbench/services/userDataSync/common/settingsMergeService'; import 'vs/workbench/services/path/common/remotePathService'; import 'vs/workbench/services/remote/common/remoteExplorerService'; import 'vs/workbench/services/workingCopy/common/workingCopyService'; +import 'vs/workbench/services/autoSaveConfiguration/common/autoSaveConfigurationService'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { ExtensionGalleryService } from 'vs/platform/extensionManagement/common/extensionGalleryService'; From 2d71ad39e00db56028cc33a445d7e2f6e1a9d10f Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Tue, 12 Nov 2019 18:41:43 +0100 Subject: [PATCH 133/352] fix indicator when auto save is turned on --- .../workbench/contrib/files/common/dirtyFilesIndicator.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/vs/workbench/contrib/files/common/dirtyFilesIndicator.ts b/src/vs/workbench/contrib/files/common/dirtyFilesIndicator.ts index 0513fcc3cf2cd..edb4a75e829c6 100644 --- a/src/vs/workbench/contrib/files/common/dirtyFilesIndicator.ts +++ b/src/vs/workbench/contrib/files/common/dirtyFilesIndicator.ts @@ -42,11 +42,11 @@ export class DirtyFilesIndicator extends Disposable implements IWorkbenchContrib } private onWorkingCopyDidChangeDirty(copy: IWorkingCopy): void { - if (!!(copy.capabilities & WorkingCopyCapabilities.AutoSave) && this.autoSaveConfigurationService.getAutoSaveMode() === AutoSaveMode.AFTER_SHORT_DELAY) { - return; // do not indicate changes to working copies that are auto saved after short delay + const gotDirty = copy.isDirty(); + if (gotDirty && !!(copy.capabilities & WorkingCopyCapabilities.AutoSave) && this.autoSaveConfigurationService.getAutoSaveMode() === AutoSaveMode.AFTER_SHORT_DELAY) { + return; // do not indicate dirty of working copies that are auto saved after short delay } - const gotDirty = copy.isDirty(); if (gotDirty || this.hasDirtyCount) { this.updateActivityBadge(); } From b66599bbfdc539b6ca622e9b1d8f709a9483bfb9 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Tue, 12 Nov 2019 18:45:23 +0100 Subject: [PATCH 134/352] files - fix tests properly --- src/vs/platform/files/test/node/diskFileService.test.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/vs/platform/files/test/node/diskFileService.test.ts b/src/vs/platform/files/test/node/diskFileService.test.ts index 79ecd34d5f085..0b5b1ecf8bc00 100644 --- a/src/vs/platform/files/test/node/diskFileService.test.ts +++ b/src/vs/platform/files/test/node/diskFileService.test.ts @@ -134,7 +134,7 @@ suite('Disk File Service', function () { // we see random test failures when accessing the native file system. To // diagnose further, we retry node.js file access tests up to 3 times to // rule out any random disk issue. - this.retries(3); + // this.retries(3); setup(async () => { const logService = new NullLogService(); @@ -1493,15 +1493,15 @@ suite('Disk File Service', function () { } test('createFile', async () => { - assertCreateFile(contents => VSBuffer.fromString(contents)); + return assertCreateFile(contents => VSBuffer.fromString(contents)); }); test('createFile (readable)', async () => { - assertCreateFile(contents => bufferToReadable(VSBuffer.fromString(contents))); + return assertCreateFile(contents => bufferToReadable(VSBuffer.fromString(contents))); }); test('createFile (stream)', async () => { - assertCreateFile(contents => bufferToStream(VSBuffer.fromString(contents))); + return assertCreateFile(contents => bufferToStream(VSBuffer.fromString(contents))); }); async function assertCreateFile(converter: (content: string) => VSBuffer | VSBufferReadable | VSBufferReadableStream): Promise { From ddfca307b1bd29da040e82c8389638fc508248aa Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Tue, 12 Nov 2019 18:48:27 +0100 Subject: [PATCH 135/352] encoding - still ignore 'ascii' --- src/vs/base/node/encoding.ts | 11 +++++++++++ src/vs/base/test/node/encoding/encoding.test.ts | 2 +- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/vs/base/node/encoding.ts b/src/vs/base/node/encoding.ts index c450321317046..c4cd563ef8f3a 100644 --- a/src/vs/base/node/encoding.ts +++ b/src/vs/base/node/encoding.ts @@ -210,6 +210,17 @@ async function guessEncodingByBuffer(buffer: Buffer): Promise { return null; } + // Ignore 'ascii' as guessed encoding because that + // is almost never what we want, rather fallback + // to the configured encoding then. Otherwise, + // opening a ascii-only file with auto guessing + // enabled will put the file into 'ascii' mode + // and thus typing any special characters is + // not possible anymore. + if (guessed.encoding.toLowerCase() === 'ascii') { + return null; + } + return toIconvLiteEncoding(guessed.encoding); } diff --git a/src/vs/base/test/node/encoding/encoding.test.ts b/src/vs/base/test/node/encoding/encoding.test.ts index d8730a52b366a..eef17fbddb61a 100644 --- a/src/vs/base/test/node/encoding/encoding.test.ts +++ b/src/vs/base/test/node/encoding/encoding.test.ts @@ -200,7 +200,7 @@ suite('Encoding', () => { const file = getPathFromAmdModule(require, './fixtures/some_ansi.css'); const buffer = await readExactlyByFile(file, 512 * 8); const mimes = await encoding.detectEncodingFromBuffer(buffer, true); - assert.equal(mimes.encoding, 'ascii'); + assert.equal(mimes.encoding, null); }); test('autoGuessEncoding (ShiftJIS)', async function () { From 1a1e7c9545001dda62004415de824db918bd65e2 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Tue, 12 Nov 2019 18:57:08 +0100 Subject: [PATCH 136/352] debt - allow extHostSearch in common (#84109) * debt - allow extHostSearch in common * web - implement text search provider * fix text search * Update extensions/vscode-api-tests/src/extension.ts Co-Authored-By: Rob Lourens --- extensions/vscode-api-tests/src/extension.ts | 48 ++- src/vs/workbench/api/common/extHostSearch.ts | 119 +++++- src/vs/workbench/api/node/extHost.services.ts | 4 +- src/vs/workbench/api/node/extHostSearch.ts | 119 +----- .../extensions/worker/extHost.services.ts | 4 +- .../search/common/textSearchManager.ts | 355 ++++++++++++++++++ .../services/search/node/textSearchAdapter.ts | 7 +- .../services/search/node/textSearchManager.ts | 350 +---------------- .../test/node/textSearchManager.test.ts | 6 +- .../api/extHostSearch.test.ts | 12 +- 10 files changed, 561 insertions(+), 463 deletions(-) create mode 100644 src/vs/workbench/services/search/common/textSearchManager.ts diff --git a/extensions/vscode-api-tests/src/extension.ts b/extensions/vscode-api-tests/src/extension.ts index a0aabfb09ec8d..05646e66dc3ab 100644 --- a/extensions/vscode-api-tests/src/extension.ts +++ b/extensions/vscode-api-tests/src/extension.ts @@ -366,9 +366,9 @@ function updateDiagnostics(document: vscode.TextDocument, collection: vscode.Dia } } -function enableSearch(_context: vscode.ExtensionContext, _memFs: MemFS): void { - // NOT YET SUPPORTED - //context.subscriptions.push(vscode.workspace.registerFileSearchProvider(SCHEME, memFs)); +function enableSearch(context: vscode.ExtensionContext, memFs: MemFS): void { + context.subscriptions.push(vscode.workspace.registerFileSearchProvider(SCHEME, memFs)); + context.subscriptions.push(vscode.workspace.registerTextSearchProvider(SCHEME, memFs)); } function enableTasks(): void { @@ -546,7 +546,7 @@ export class Directory implements vscode.FileStat { export type Entry = File | Directory; -export class MemFS implements vscode.FileSystemProvider, vscode.FileSearchProvider { +export class MemFS implements vscode.FileSystemProvider, vscode.FileSearchProvider, vscode.TextSearchProvider { root = new Directory(vscode.Uri.parse('memfs:/'), ''); @@ -796,16 +796,52 @@ export class MemFS implements vscode.FileSystemProvider, vscode.FileSearchProvid // --- search provider provideFileSearchResults(query: vscode.FileSearchQuery, _options: vscode.FileSearchOptions, _token: vscode.CancellationToken): vscode.ProviderResult { + return this._findFiles(query.pattern); + } + + private _findFiles(query: string | undefined): vscode.Uri[] { const files = this._getFiles(); const result: vscode.Uri[] = []; - const pattern = new RegExp(this._convertSimple2RegExpPattern(query.pattern)); + + const pattern = query ? new RegExp(this._convertSimple2RegExpPattern(query)) : null; for (const file of files) { - if (pattern.exec(file.name)) { + if (!pattern || pattern.exec(file.name)) { result.push(file.uri); } } return result; } + + private _textDecoder = new TextDecoder(); + + provideTextSearchResults(query: vscode.TextSearchQuery, options: vscode.TextSearchOptions, progress: vscode.Progress, _token: vscode.CancellationToken) { + const result: vscode.TextSearchComplete = { limitHit: false }; + + const files = this._findFiles(options.includes[0]); + if (files) { + for (const file of files) { + const content = this._textDecoder.decode(this.readFile(file)); + + const lines = content.split('\n'); + for (let i = 0; i < lines.length; i++) { + const line = lines[i]; + const index = line.indexOf(query.pattern); + if (index !== -1) { + progress.report({ + uri: file, + ranges: new vscode.Range(new vscode.Position(i, index), new vscode.Position(i, index + query.pattern.length)), + preview: { + text: line, + matches: new vscode.Range(new vscode.Position(0, index), new vscode.Position(0, index + query.pattern.length)) + } + }); + } + } + } + } + + return result; + } } diff --git a/src/vs/workbench/api/common/extHostSearch.ts b/src/vs/workbench/api/common/extHostSearch.ts index efc6ca49825e9..adc7c29d6ec4d 100644 --- a/src/vs/workbench/api/common/extHostSearch.ts +++ b/src/vs/workbench/api/common/extHostSearch.ts @@ -3,10 +3,17 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { IDisposable } from 'vs/base/common/lifecycle'; +import { IDisposable, toDisposable } from 'vs/base/common/lifecycle'; import * as vscode from 'vscode'; -import { ExtHostSearchShape } from '../common/extHost.protocol'; +import { ExtHostSearchShape, MainThreadSearchShape, MainContext } from '../common/extHost.protocol'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; +import { FileSearchManager } from 'vs/workbench/services/search/common/fileSearchManager'; +import { IExtHostRpcService } from 'vs/workbench/api/common/extHostRpcService'; +import { IURITransformerService } from 'vs/workbench/api/common/extHostUriTransformerService'; +import { ILogService } from 'vs/platform/log/common/log'; +import { IRawFileQuery, ISearchCompleteStats, IFileQuery, IRawTextQuery, IRawQuery, ITextQuery, IFolderQuery } from 'vs/workbench/services/search/common/search'; +import { URI, UriComponents } from 'vs/base/common/uri'; +import { TextSearchManager } from 'vs/workbench/services/search/common/textSearchManager'; export interface IExtHostSearch extends ExtHostSearchShape { registerTextSearchProvider(scheme: string, provider: vscode.TextSearchProvider): IDisposable; @@ -14,3 +21,111 @@ export interface IExtHostSearch extends ExtHostSearchShape { } export const IExtHostSearch = createDecorator('IExtHostSearch'); + +export class ExtHostSearch implements ExtHostSearchShape { + + protected readonly _proxy: MainThreadSearchShape = this.extHostRpc.getProxy(MainContext.MainThreadSearch); + protected _handlePool: number = 0; + + private readonly _textSearchProvider = new Map(); + private readonly _textSearchUsedSchemes = new Set(); + private readonly _fileSearchProvider = new Map(); + private readonly _fileSearchUsedSchemes = new Set(); + + private readonly _fileSearchManager = new FileSearchManager(); + + constructor( + @IExtHostRpcService private extHostRpc: IExtHostRpcService, + @IURITransformerService protected _uriTransformer: IURITransformerService, + @ILogService protected _logService: ILogService + ) { } + + protected _transformScheme(scheme: string): string { + return this._uriTransformer.transformOutgoingScheme(scheme); + } + + registerTextSearchProvider(scheme: string, provider: vscode.TextSearchProvider): IDisposable { + if (this._textSearchUsedSchemes.has(scheme)) { + throw new Error(`a text search provider for the scheme '${scheme}' is already registered`); + } + + this._textSearchUsedSchemes.add(scheme); + const handle = this._handlePool++; + this._textSearchProvider.set(handle, provider); + this._proxy.$registerTextSearchProvider(handle, this._transformScheme(scheme)); + return toDisposable(() => { + this._textSearchUsedSchemes.delete(scheme); + this._textSearchProvider.delete(handle); + this._proxy.$unregisterProvider(handle); + }); + } + + registerFileSearchProvider(scheme: string, provider: vscode.FileSearchProvider): IDisposable { + if (this._fileSearchUsedSchemes.has(scheme)) { + throw new Error(`a file search provider for the scheme '${scheme}' is already registered`); + } + + this._fileSearchUsedSchemes.add(scheme); + const handle = this._handlePool++; + this._fileSearchProvider.set(handle, provider); + this._proxy.$registerFileSearchProvider(handle, this._transformScheme(scheme)); + return toDisposable(() => { + this._fileSearchUsedSchemes.delete(scheme); + this._fileSearchProvider.delete(handle); + this._proxy.$unregisterProvider(handle); + }); + } + + $provideFileSearchResults(handle: number, session: number, rawQuery: IRawFileQuery, token: vscode.CancellationToken): Promise { + const query = reviveQuery(rawQuery); + const provider = this._fileSearchProvider.get(handle); + if (provider) { + return this._fileSearchManager.fileSearch(query, provider, batch => { + this._proxy.$handleFileMatch(handle, session, batch.map(p => p.resource)); + }, token); + } else { + throw new Error('unknown provider: ' + handle); + } + } + + $clearCache(cacheKey: string): Promise { + this._fileSearchManager.clearCache(cacheKey); + + return Promise.resolve(undefined); + } + + $provideTextSearchResults(handle: number, session: number, rawQuery: IRawTextQuery, token: vscode.CancellationToken): Promise { + const provider = this._textSearchProvider.get(handle); + if (!provider || !provider.provideTextSearchResults) { + throw new Error(`Unknown provider ${handle}`); + } + + const query = reviveQuery(rawQuery); + const engine = this.createTextSearchManager(query, provider); + return engine.search(progress => this._proxy.$handleTextMatch(handle, session, progress), token); + } + + protected createTextSearchManager(query: ITextQuery, provider: vscode.TextSearchProvider): TextSearchManager { + return new TextSearchManager(query, provider, { + readdir: resource => Promise.resolve([]), // TODO@rob implement + toCanonicalName: encoding => encoding + }); + } +} + +export function reviveQuery(rawQuery: U): U extends IRawTextQuery ? ITextQuery : IFileQuery { + return { + ...rawQuery, // TODO@rob ??? + ...{ + folderQueries: rawQuery.folderQueries && rawQuery.folderQueries.map(reviveFolderQuery), + extraFileResources: rawQuery.extraFileResources && rawQuery.extraFileResources.map(components => URI.revive(components)) + } + }; +} + +function reviveFolderQuery(rawFolderQuery: IFolderQuery): IFolderQuery { + return { + ...rawFolderQuery, + folder: URI.revive(rawFolderQuery.folder) + }; +} diff --git a/src/vs/workbench/api/node/extHost.services.ts b/src/vs/workbench/api/node/extHost.services.ts index a227d8a67b3f7..9ae085f536641 100644 --- a/src/vs/workbench/api/node/extHost.services.ts +++ b/src/vs/workbench/api/node/extHost.services.ts @@ -18,7 +18,7 @@ import { ExtHostTask } from 'vs/workbench/api/node/extHostTask'; import { ExtHostDebugService } from 'vs/workbench/api/node/extHostDebugService'; import { IExtHostDebugService } from 'vs/workbench/api/common/extHostDebugService'; import { IExtHostSearch } from 'vs/workbench/api/common/extHostSearch'; -import { ExtHostSearch } from 'vs/workbench/api/node/extHostSearch'; +import { NativeExtHostSearch } from 'vs/workbench/api/node/extHostSearch'; import { ExtensionStoragePaths } from 'vs/workbench/api/node/extHostStoragePaths'; import { IExtensionStoragePaths } from 'vs/workbench/api/common/extHostStoragePaths'; import { IExtHostExtensionService } from 'vs/workbench/api/common/extHostExtensionService'; @@ -38,7 +38,7 @@ registerSingleton(IExtHostDocumentsAndEditors, ExtHostDocumentsAndEditors); registerSingleton(IExtHostTerminalService, ExtHostTerminalService); registerSingleton(IExtHostTask, ExtHostTask); registerSingleton(IExtHostDebugService, ExtHostDebugService); -registerSingleton(IExtHostSearch, ExtHostSearch); +registerSingleton(IExtHostSearch, NativeExtHostSearch); registerSingleton(IExtensionStoragePaths, ExtensionStoragePaths); registerSingleton(IExtHostExtensionService, ExtHostExtensionService); registerSingleton(IExtHostStorage, ExtHostStorage); diff --git a/src/vs/workbench/api/node/extHostSearch.ts b/src/vs/workbench/api/node/extHostSearch.ts index a5af222b2e667..3082bb7062551 100644 --- a/src/vs/workbench/api/node/extHostSearch.ts +++ b/src/vs/workbench/api/node/extHostSearch.ts @@ -3,47 +3,37 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { CancellationToken } from 'vs/base/common/cancellation'; import { IDisposable, toDisposable } from 'vs/base/common/lifecycle'; -import { URI, UriComponents } from 'vs/base/common/uri'; +import { URI } from 'vs/base/common/uri'; import * as pfs from 'vs/base/node/pfs'; import { ILogService } from 'vs/platform/log/common/log'; -import { IFileQuery, IFolderQuery, IRawFileQuery, IRawQuery, IRawTextQuery, ISearchCompleteStats, ITextQuery, isSerializedFileMatch, ISerializedSearchProgressItem } from 'vs/workbench/services/search/common/search'; -import { FileSearchManager } from 'vs/workbench/services/search/common/fileSearchManager'; +import { IFileQuery, IRawFileQuery, ISearchCompleteStats, isSerializedFileMatch, ISerializedSearchProgressItem, ITextQuery } from 'vs/workbench/services/search/common/search'; import { SearchService } from 'vs/workbench/services/search/node/rawSearchService'; import { RipgrepSearchProvider } from 'vs/workbench/services/search/node/ripgrepSearchProvider'; import { OutputChannel } from 'vs/workbench/services/search/node/ripgrepSearchUtils'; -import { TextSearchManager } from 'vs/workbench/services/search/node/textSearchManager'; import * as vscode from 'vscode'; -import { ExtHostSearchShape, MainContext, MainThreadSearchShape } from '../common/extHost.protocol'; import { IExtHostRpcService } from 'vs/workbench/api/common/extHostRpcService'; import { IURITransformerService } from 'vs/workbench/api/common/extHostUriTransformerService'; import { IExtHostInitDataService } from 'vs/workbench/api/common/extHostInitDataService'; +import { ExtHostSearch, reviveQuery } from 'vs/workbench/api/common/extHostSearch'; +import { Schemas } from 'vs/base/common/network'; +import { NativeTextSearchManager } from 'vs/workbench/services/search/node/textSearchManager'; +import { TextSearchManager } from 'vs/workbench/services/search/common/textSearchManager'; -export class ExtHostSearch implements ExtHostSearchShape { +export class NativeExtHostSearch extends ExtHostSearch { - private readonly _proxy: MainThreadSearchShape; - private readonly _textSearchProvider = new Map(); - private readonly _textSearchUsedSchemes = new Set(); - private readonly _fileSearchProvider = new Map(); - private readonly _fileSearchUsedSchemes = new Set(); - private _handlePool: number = 0; + protected _pfs: typeof pfs = pfs; // allow extending for tests private _internalFileSearchHandle: number = -1; private _internalFileSearchProvider: SearchService | null = null; - private _fileSearchManager: FileSearchManager; - - protected _pfs: typeof pfs = pfs; // allow extending for tests - constructor( @IExtHostRpcService extHostRpc: IExtHostRpcService, @IExtHostInitDataService initData: IExtHostInitDataService, - @IURITransformerService private _uriTransformer: IURITransformerService, - @ILogService private _logService: ILogService, + @IURITransformerService _uriTransformer: IURITransformerService, + @ILogService _logService: ILogService, ) { - this._proxy = extHostRpc.getProxy(MainContext.MainThreadSearch); - this._fileSearchManager = new FileSearchManager(); + super(extHostRpc, _uriTransformer, _logService); if (initData.remote.isRemote && initData.remote.authority) { this._registerEHSearchProviders(); @@ -52,8 +42,8 @@ export class ExtHostSearch implements ExtHostSearchShape { private _registerEHSearchProviders(): void { const outputChannel = new OutputChannel(this._logService); - this.registerTextSearchProvider('file', new RipgrepSearchProvider(outputChannel)); - this.registerInternalFileSearchProvider('file', new SearchService()); + this.registerTextSearchProvider(Schemas.file, new RipgrepSearchProvider(outputChannel)); + this.registerInternalFileSearchProvider(Schemas.file, new SearchService()); } private registerInternalFileSearchProvider(scheme: string, provider: SearchService): IDisposable { @@ -67,59 +57,16 @@ export class ExtHostSearch implements ExtHostSearchShape { }); } - private _transformScheme(scheme: string): string { - return this._uriTransformer.transformOutgoingScheme(scheme); - } - - registerTextSearchProvider(scheme: string, provider: vscode.TextSearchProvider): IDisposable { - if (this._textSearchUsedSchemes.has(scheme)) { - throw new Error(`a text search provider for the scheme '${scheme}' is already registered`); - } - - this._textSearchUsedSchemes.add(scheme); - const handle = this._handlePool++; - this._textSearchProvider.set(handle, provider); - this._proxy.$registerTextSearchProvider(handle, this._transformScheme(scheme)); - return toDisposable(() => { - this._textSearchUsedSchemes.delete(scheme); - this._textSearchProvider.delete(handle); - this._proxy.$unregisterProvider(handle); - }); - } - - registerFileSearchProvider(scheme: string, provider: vscode.FileSearchProvider): IDisposable { - if (this._fileSearchUsedSchemes.has(scheme)) { - throw new Error(`a file search provider for the scheme '${scheme}' is already registered`); - } - - this._fileSearchUsedSchemes.add(scheme); - const handle = this._handlePool++; - this._fileSearchProvider.set(handle, provider); - this._proxy.$registerFileSearchProvider(handle, this._transformScheme(scheme)); - return toDisposable(() => { - this._fileSearchUsedSchemes.delete(scheme); - this._fileSearchProvider.delete(handle); - this._proxy.$unregisterProvider(handle); - }); - } - - $provideFileSearchResults(handle: number, session: number, rawQuery: IRawFileQuery, token: CancellationToken): Promise { + $provideFileSearchResults(handle: number, session: number, rawQuery: IRawFileQuery, token: vscode.CancellationToken): Promise { const query = reviveQuery(rawQuery); if (handle === this._internalFileSearchHandle) { return this.doInternalFileSearch(handle, session, query, token); - } else { - const provider = this._fileSearchProvider.get(handle); - if (provider) { - return this._fileSearchManager.fileSearch(query, provider, batch => { - this._proxy.$handleFileMatch(handle, session, batch.map(p => p.resource)); - }, token); - } else { - throw new Error('unknown provider: ' + handle); - } } + + return super.$provideFileSearchResults(handle, session, rawQuery, token); } - private doInternalFileSearch(handle: number, session: number, rawQuery: IFileQuery, token: CancellationToken): Promise { + private doInternalFileSearch(handle: number, session: number, rawQuery: IFileQuery, token: vscode.CancellationToken): Promise { const onResult = (ev: ISerializedSearchProgressItem) => { if (isSerializedFileMatch(ev)) { ev = [ev]; @@ -147,37 +94,11 @@ export class ExtHostSearch implements ExtHostSearchShape { this._internalFileSearchProvider.clearCache(cacheKey); } - this._fileSearchManager.clearCache(cacheKey); - - return Promise.resolve(undefined); + return super.$clearCache(cacheKey); } - $provideTextSearchResults(handle: number, session: number, rawQuery: IRawTextQuery, token: CancellationToken): Promise { - const provider = this._textSearchProvider.get(handle); - if (!provider || !provider.provideTextSearchResults) { - throw new Error(`Unknown provider ${handle}`); - } - - const query = reviveQuery(rawQuery); - const engine = new TextSearchManager(query, provider, this._pfs); - return engine.search(progress => this._proxy.$handleTextMatch(handle, session, progress), token); + protected createTextSearchManager(query: ITextQuery, provider: vscode.TextSearchProvider): TextSearchManager { + return new NativeTextSearchManager(query, provider); } } -function reviveQuery(rawQuery: U): U extends IRawTextQuery ? ITextQuery : IFileQuery { - return { - ...rawQuery, // TODO - ...{ - folderQueries: rawQuery.folderQueries && rawQuery.folderQueries.map(reviveFolderQuery), - extraFileResources: rawQuery.extraFileResources && rawQuery.extraFileResources.map(components => URI.revive(components)) - } - }; -} - -function reviveFolderQuery(rawFolderQuery: IFolderQuery): IFolderQuery { - return { - ...rawFolderQuery, - folder: URI.revive(rawFolderQuery.folder) - }; -} - diff --git a/src/vs/workbench/services/extensions/worker/extHost.services.ts b/src/vs/workbench/services/extensions/worker/extHost.services.ts index 3bdfa1a79fa57..ed2e8767cf12b 100644 --- a/src/vs/workbench/services/extensions/worker/extHost.services.ts +++ b/src/vs/workbench/services/extensions/worker/extHost.services.ts @@ -13,7 +13,7 @@ import { IExtHostDocumentsAndEditors, ExtHostDocumentsAndEditors } from 'vs/work import { IExtHostTerminalService, WorkerExtHostTerminalService } from 'vs/workbench/api/common/extHostTerminalService'; import { IExtHostTask, WorkerExtHostTask } from 'vs/workbench/api/common/extHostTask'; import { IExtHostDebugService } from 'vs/workbench/api/common/extHostDebugService'; -import { IExtHostSearch } from 'vs/workbench/api/common/extHostSearch'; +import { IExtHostSearch, ExtHostSearch } from 'vs/workbench/api/common/extHostSearch'; import { IExtensionStoragePaths } from 'vs/workbench/api/common/extHostStoragePaths'; import { IExtHostExtensionService } from 'vs/workbench/api/common/extHostExtensionService'; import { IExtHostStorage, ExtHostStorage } from 'vs/workbench/api/common/extHostStorage'; @@ -32,6 +32,7 @@ registerSingleton(IExtHostCommands, ExtHostCommands); registerSingleton(IExtHostDocumentsAndEditors, ExtHostDocumentsAndEditors); registerSingleton(IExtHostStorage, ExtHostStorage); registerSingleton(IExtHostExtensionService, ExtHostExtensionService); +registerSingleton(IExtHostSearch, ExtHostSearch); // register services that only throw errors function NotImplementedProxy(name: ServiceIdentifier): { new(): T } { @@ -51,7 +52,6 @@ function NotImplementedProxy(name: ServiceIdentifier): { new(): T } { registerSingleton(IExtHostTerminalService, WorkerExtHostTerminalService); registerSingleton(IExtHostTask, WorkerExtHostTask); registerSingleton(IExtHostDebugService, class extends NotImplementedProxy(IExtHostDebugService) { }); -registerSingleton(IExtHostSearch, class extends NotImplementedProxy(IExtHostSearch) { }); registerSingleton(IExtensionStoragePaths, class extends NotImplementedProxy(IExtensionStoragePaths) { whenReady = Promise.resolve(); }); diff --git a/src/vs/workbench/services/search/common/textSearchManager.ts b/src/vs/workbench/services/search/common/textSearchManager.ts new file mode 100644 index 0000000000000..223374a7bdd3e --- /dev/null +++ b/src/vs/workbench/services/search/common/textSearchManager.ts @@ -0,0 +1,355 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as path from 'vs/base/common/path'; +import { mapArrayOrNot } from 'vs/base/common/arrays'; +import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation'; +import { toErrorMessage } from 'vs/base/common/errorMessage'; +import * as resources from 'vs/base/common/resources'; +import * as glob from 'vs/base/common/glob'; +import { URI } from 'vs/base/common/uri'; +import { IExtendedExtensionSearchOptions, IFileMatch, IFolderQuery, IPatternInfo, ISearchCompleteStats, ITextQuery, ITextSearchContext, ITextSearchMatch, ITextSearchResult, QueryGlobTester, resolvePatternsForProvider } from 'vs/workbench/services/search/common/search'; +import { TextSearchProvider, TextSearchResult, TextSearchMatch, TextSearchComplete, Range, TextSearchOptions, TextSearchQuery } from 'vs/workbench/services/search/common/searchExtTypes'; +import { nextTick } from 'vs/base/common/process'; + +export interface IFileUtils { + readdir: (resource: URI) => Promise; + toCanonicalName: (encoding: string) => string; +} + +export class TextSearchManager { + + private collector: TextSearchResultsCollector | null = null; + + private isLimitHit = false; + private resultCount = 0; + + constructor(private query: ITextQuery, private provider: TextSearchProvider, private fileUtils: IFileUtils) { } + + search(onProgress: (matches: IFileMatch[]) => void, token: CancellationToken): Promise { + const folderQueries = this.query.folderQueries || []; + const tokenSource = new CancellationTokenSource(); + token.onCancellationRequested(() => tokenSource.cancel()); + + return new Promise((resolve, reject) => { + this.collector = new TextSearchResultsCollector(onProgress); + + let isCanceled = false; + const onResult = (result: TextSearchResult, folderIdx: number) => { + if (isCanceled) { + return; + } + + if (!this.isLimitHit) { + const resultSize = this.resultSize(result); + if (extensionResultIsMatch(result) && typeof this.query.maxResults === 'number' && this.resultCount + resultSize > this.query.maxResults) { + this.isLimitHit = true; + isCanceled = true; + tokenSource.cancel(); + + result = this.trimResultToSize(result, this.query.maxResults - this.resultCount); + } + + const newResultSize = this.resultSize(result); + this.resultCount += newResultSize; + if (newResultSize > 0) { + this.collector!.add(result, folderIdx); + } + } + }; + + // For each root folder + Promise.all(folderQueries.map((fq, i) => { + return this.searchInFolder(fq, r => onResult(r, i), tokenSource.token); + })).then(results => { + tokenSource.dispose(); + this.collector!.flush(); + + const someFolderHitLImit = results.some(result => !!result && !!result.limitHit); + resolve({ + limitHit: this.isLimitHit || someFolderHitLImit, + stats: { + type: 'textSearchProvider' + } + }); + }, (err: Error) => { + tokenSource.dispose(); + const errMsg = toErrorMessage(err); + reject(new Error(errMsg)); + }); + }); + } + + private resultSize(result: TextSearchResult): number { + const match = result; + return Array.isArray(match.ranges) ? + match.ranges.length : + 1; + } + + private trimResultToSize(result: TextSearchMatch, size: number): TextSearchMatch { + const rangesArr = Array.isArray(result.ranges) ? result.ranges : [result.ranges]; + const matchesArr = Array.isArray(result.preview.matches) ? result.preview.matches : [result.preview.matches]; + + return { + ranges: rangesArr.slice(0, size), + preview: { + matches: matchesArr.slice(0, size), + text: result.preview.text + }, + uri: result.uri + }; + } + + private searchInFolder(folderQuery: IFolderQuery, onResult: (result: TextSearchResult) => void, token: CancellationToken): Promise { + const queryTester = new QueryGlobTester(this.query, folderQuery); + const testingPs: Promise[] = []; + const progress = { + report: (result: TextSearchResult) => { + if (!this.validateProviderResult(result)) { + return; + } + + const hasSibling = folderQuery.folder.scheme === 'file' ? + glob.hasSiblingPromiseFn(() => { + return this.fileUtils.readdir(resources.dirname(result.uri)); + }) : + undefined; + + const relativePath = resources.relativePath(folderQuery.folder, result.uri); + if (relativePath) { + testingPs.push( + queryTester.includedInQuery(relativePath, path.basename(relativePath), hasSibling) + .then(included => { + if (included) { + onResult(result); + } + })); + } + } + }; + + const searchOptions = this.getSearchOptionsForFolder(folderQuery); + return new Promise(resolve => nextTick(resolve)) + .then(() => this.provider.provideTextSearchResults(patternInfoToQuery(this.query.contentPattern), searchOptions, progress, token)) + .then(result => { + return Promise.all(testingPs) + .then(() => result); + }); + } + + private validateProviderResult(result: TextSearchResult): boolean { + if (extensionResultIsMatch(result)) { + if (Array.isArray(result.ranges)) { + if (!Array.isArray(result.preview.matches)) { + console.warn('INVALID - A text search provider match\'s`ranges` and`matches` properties must have the same type.'); + return false; + } + + if ((result.preview.matches).length !== result.ranges.length) { + console.warn('INVALID - A text search provider match\'s`ranges` and`matches` properties must have the same length.'); + return false; + } + } else { + if (Array.isArray(result.preview.matches)) { + console.warn('INVALID - A text search provider match\'s`ranges` and`matches` properties must have the same length.'); + return false; + } + } + } + + return true; + } + + private getSearchOptionsForFolder(fq: IFolderQuery): TextSearchOptions { + const includes = resolvePatternsForProvider(this.query.includePattern, fq.includePattern); + const excludes = resolvePatternsForProvider(this.query.excludePattern, fq.excludePattern); + + const options = { + folder: URI.from(fq.folder), + excludes, + includes, + useIgnoreFiles: !fq.disregardIgnoreFiles, + useGlobalIgnoreFiles: !fq.disregardGlobalIgnoreFiles, + followSymlinks: !fq.ignoreSymlinks, + encoding: fq.fileEncoding && this.fileUtils.toCanonicalName(fq.fileEncoding), + maxFileSize: this.query.maxFileSize, + maxResults: this.query.maxResults, + previewOptions: this.query.previewOptions, + afterContext: this.query.afterContext, + beforeContext: this.query.beforeContext + }; + (options).usePCRE2 = this.query.usePCRE2; + return options; + } +} + +function patternInfoToQuery(patternInfo: IPatternInfo): TextSearchQuery { + return { + isCaseSensitive: patternInfo.isCaseSensitive || false, + isRegExp: patternInfo.isRegExp || false, + isWordMatch: patternInfo.isWordMatch || false, + isMultiline: patternInfo.isMultiline || false, + pattern: patternInfo.pattern + }; +} + +export class TextSearchResultsCollector { + private _batchedCollector: BatchedCollector; + + private _currentFolderIdx: number = -1; + private _currentUri: URI | undefined; + private _currentFileMatch: IFileMatch | null = null; + + constructor(private _onResult: (result: IFileMatch[]) => void) { + this._batchedCollector = new BatchedCollector(512, items => this.sendItems(items)); + } + + add(data: TextSearchResult, folderIdx: number): void { + // Collects TextSearchResults into IInternalFileMatches and collates using BatchedCollector. + // This is efficient for ripgrep which sends results back one file at a time. It wouldn't be efficient for other search + // providers that send results in random order. We could do this step afterwards instead. + if (this._currentFileMatch && (this._currentFolderIdx !== folderIdx || !resources.isEqual(this._currentUri, data.uri))) { + this.pushToCollector(); + this._currentFileMatch = null; + } + + if (!this._currentFileMatch) { + this._currentFolderIdx = folderIdx; + this._currentFileMatch = { + resource: data.uri, + results: [] + }; + } + + this._currentFileMatch.results!.push(extensionResultToFrontendResult(data)); + } + + private pushToCollector(): void { + const size = this._currentFileMatch && this._currentFileMatch.results ? + this._currentFileMatch.results.length : + 0; + this._batchedCollector.addItem(this._currentFileMatch!, size); + } + + flush(): void { + this.pushToCollector(); + this._batchedCollector.flush(); + } + + private sendItems(items: IFileMatch[]): void { + this._onResult(items); + } +} + +function extensionResultToFrontendResult(data: TextSearchResult): ITextSearchResult { + // Warning: result from RipgrepTextSearchEH has fake Range. Don't depend on any other props beyond these... + if (extensionResultIsMatch(data)) { + return { + preview: { + matches: mapArrayOrNot(data.preview.matches, m => ({ + startLineNumber: m.start.line, + startColumn: m.start.character, + endLineNumber: m.end.line, + endColumn: m.end.character + })), + text: data.preview.text + }, + ranges: mapArrayOrNot(data.ranges, r => ({ + startLineNumber: r.start.line, + startColumn: r.start.character, + endLineNumber: r.end.line, + endColumn: r.end.character + })) + }; + } else { + return { + text: data.text, + lineNumber: data.lineNumber + }; + } +} + +export function extensionResultIsMatch(data: TextSearchResult): data is TextSearchMatch { + return !!(data).preview; +} + +/** + * Collects items that have a size - before the cumulative size of collected items reaches START_BATCH_AFTER_COUNT, the callback is called for every + * set of items collected. + * But after that point, the callback is called with batches of maxBatchSize. + * If the batch isn't filled within some time, the callback is also called. + */ +export class BatchedCollector { + private static readonly TIMEOUT = 4000; + + // After START_BATCH_AFTER_COUNT items have been collected, stop flushing on timeout + private static readonly START_BATCH_AFTER_COUNT = 50; + + private totalNumberCompleted = 0; + private batch: T[] = []; + private batchSize = 0; + private timeoutHandle: any; + + constructor(private maxBatchSize: number, private cb: (items: T[]) => void) { + } + + addItem(item: T, size: number): void { + if (!item) { + return; + } + + this.addItemToBatch(item, size); + } + + addItems(items: T[], size: number): void { + if (!items) { + return; + } + + this.addItemsToBatch(items, size); + } + + private addItemToBatch(item: T, size: number): void { + this.batch.push(item); + this.batchSize += size; + this.onUpdate(); + } + + private addItemsToBatch(item: T[], size: number): void { + this.batch = this.batch.concat(item); + this.batchSize += size; + this.onUpdate(); + } + + private onUpdate(): void { + if (this.totalNumberCompleted < BatchedCollector.START_BATCH_AFTER_COUNT) { + // Flush because we aren't batching yet + this.flush(); + } else if (this.batchSize >= this.maxBatchSize) { + // Flush because the batch is full + this.flush(); + } else if (!this.timeoutHandle) { + // No timeout running, start a timeout to flush + this.timeoutHandle = setTimeout(() => { + this.flush(); + }, BatchedCollector.TIMEOUT); + } + } + + flush(): void { + if (this.batchSize) { + this.totalNumberCompleted += this.batchSize; + this.cb(this.batch); + this.batch = []; + this.batchSize = 0; + + if (this.timeoutHandle) { + clearTimeout(this.timeoutHandle); + this.timeoutHandle = 0; + } + } + } +} diff --git a/src/vs/workbench/services/search/node/textSearchAdapter.ts b/src/vs/workbench/services/search/node/textSearchAdapter.ts index 37bca799785e0..5d7c484e3ca57 100644 --- a/src/vs/workbench/services/search/node/textSearchAdapter.ts +++ b/src/vs/workbench/services/search/node/textSearchAdapter.ts @@ -7,12 +7,11 @@ import { CancellationToken } from 'vs/base/common/cancellation'; import * as pfs from 'vs/base/node/pfs'; import { IFileMatch, IProgressMessage, ITextQuery, ITextSearchStats, ITextSearchMatch, ISerializedFileMatch, ISerializedSearchSuccess } from 'vs/workbench/services/search/common/search'; import { RipgrepTextSearchEngine } from 'vs/workbench/services/search/node/ripgrepTextSearchEngine'; -import { TextSearchManager } from 'vs/workbench/services/search/node/textSearchManager'; +import { NativeTextSearchManager } from 'vs/workbench/services/search/node/textSearchManager'; export class TextSearchEngineAdapter { - constructor(private query: ITextQuery) { - } + constructor(private query: ITextQuery) { } search(token: CancellationToken, onResult: (matches: ISerializedFileMatch[]) => void, onMessage: (message: IProgressMessage) => void): Promise { if ((!this.query.folderQueries || !this.query.folderQueries.length) && (!this.query.extraFileResources || !this.query.extraFileResources.length)) { @@ -30,7 +29,7 @@ export class TextSearchEngineAdapter { onMessage({ message: msg }); } }; - const textSearchManager = new TextSearchManager(this.query, new RipgrepTextSearchEngine(pretendOutputChannel), pfs); + const textSearchManager = new NativeTextSearchManager(this.query, new RipgrepTextSearchEngine(pretendOutputChannel), pfs); return new Promise((resolve, reject) => { return textSearchManager .search( diff --git a/src/vs/workbench/services/search/node/textSearchManager.ts b/src/vs/workbench/services/search/node/textSearchManager.ts index e7586a912cdfa..3433ce3553767 100644 --- a/src/vs/workbench/services/search/node/textSearchManager.ts +++ b/src/vs/workbench/services/search/node/textSearchManager.ts @@ -3,352 +3,18 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import * as path from 'vs/base/common/path'; -import { mapArrayOrNot } from 'vs/base/common/arrays'; -import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation'; -import { toErrorMessage } from 'vs/base/common/errorMessage'; -import * as resources from 'vs/base/common/resources'; -import * as glob from 'vs/base/common/glob'; -import { URI } from 'vs/base/common/uri'; import { toCanonicalName } from 'vs/base/node/encoding'; import * as pfs from 'vs/base/node/pfs'; -import { IExtendedExtensionSearchOptions, IFileMatch, IFolderQuery, IPatternInfo, ISearchCompleteStats, ITextQuery, ITextSearchContext, ITextSearchMatch, ITextSearchResult, QueryGlobTester, resolvePatternsForProvider } from 'vs/workbench/services/search/common/search'; -import { TextSearchProvider, TextSearchResult, TextSearchMatch, TextSearchComplete, Range, TextSearchOptions, TextSearchQuery } from 'vs/workbench/services/search/common/searchExtTypes'; +import { ITextQuery } from 'vs/workbench/services/search/common/search'; +import { TextSearchProvider } from 'vs/workbench/services/search/common/searchExtTypes'; +import { TextSearchManager } from 'vs/workbench/services/search/common/textSearchManager'; -export class TextSearchManager { +export class NativeTextSearchManager extends TextSearchManager { - private collector: TextSearchResultsCollector | null = null; - - private isLimitHit = false; - private resultCount = 0; - - constructor(private query: ITextQuery, private provider: TextSearchProvider, private _pfs: typeof pfs = pfs) { - } - - search(onProgress: (matches: IFileMatch[]) => void, token: CancellationToken): Promise { - const folderQueries = this.query.folderQueries || []; - const tokenSource = new CancellationTokenSource(); - token.onCancellationRequested(() => tokenSource.cancel()); - - return new Promise((resolve, reject) => { - this.collector = new TextSearchResultsCollector(onProgress); - - let isCanceled = false; - const onResult = (result: TextSearchResult, folderIdx: number) => { - if (isCanceled) { - return; - } - - if (!this.isLimitHit) { - const resultSize = this.resultSize(result); - if (extensionResultIsMatch(result) && typeof this.query.maxResults === 'number' && this.resultCount + resultSize > this.query.maxResults) { - this.isLimitHit = true; - isCanceled = true; - tokenSource.cancel(); - - result = this.trimResultToSize(result, this.query.maxResults - this.resultCount); - } - - const newResultSize = this.resultSize(result); - this.resultCount += newResultSize; - if (newResultSize > 0) { - this.collector!.add(result, folderIdx); - } - } - }; - - // For each root folder - Promise.all(folderQueries.map((fq, i) => { - return this.searchInFolder(fq, r => onResult(r, i), tokenSource.token); - })).then(results => { - tokenSource.dispose(); - this.collector!.flush(); - - const someFolderHitLImit = results.some(result => !!result && !!result.limitHit); - resolve({ - limitHit: this.isLimitHit || someFolderHitLImit, - stats: { - type: 'textSearchProvider' - } - }); - }, (err: Error) => { - tokenSource.dispose(); - const errMsg = toErrorMessage(err); - reject(new Error(errMsg)); - }); + constructor(query: ITextQuery, provider: TextSearchProvider, _pfs: typeof pfs = pfs) { + super(query, provider, { + readdir: resource => _pfs.readdir(resource.fsPath), + toCanonicalName: name => toCanonicalName(name) }); } - - private resultSize(result: TextSearchResult): number { - const match = result; - return Array.isArray(match.ranges) ? - match.ranges.length : - 1; - } - - private trimResultToSize(result: TextSearchMatch, size: number): TextSearchMatch { - const rangesArr = Array.isArray(result.ranges) ? result.ranges : [result.ranges]; - const matchesArr = Array.isArray(result.preview.matches) ? result.preview.matches : [result.preview.matches]; - - return { - ranges: rangesArr.slice(0, size), - preview: { - matches: matchesArr.slice(0, size), - text: result.preview.text - }, - uri: result.uri - }; - } - - private searchInFolder(folderQuery: IFolderQuery, onResult: (result: TextSearchResult) => void, token: CancellationToken): Promise { - const queryTester = new QueryGlobTester(this.query, folderQuery); - const testingPs: Promise[] = []; - const progress = { - report: (result: TextSearchResult) => { - if (!this.validateProviderResult(result)) { - return; - } - - const hasSibling = folderQuery.folder.scheme === 'file' ? - glob.hasSiblingPromiseFn(() => { - return this.readdir(path.dirname(result.uri.fsPath)); - }) : - undefined; - - const relativePath = path.relative(folderQuery.folder.fsPath, result.uri.fsPath); - testingPs.push( - queryTester.includedInQuery(relativePath, path.basename(relativePath), hasSibling) - .then(included => { - if (included) { - onResult(result); - } - })); - } - }; - - const searchOptions = this.getSearchOptionsForFolder(folderQuery); - return new Promise(resolve => process.nextTick(resolve)) - .then(() => this.provider.provideTextSearchResults(patternInfoToQuery(this.query.contentPattern), searchOptions, progress, token)) - .then(result => { - return Promise.all(testingPs) - .then(() => result); - }); - } - - private validateProviderResult(result: TextSearchResult): boolean { - if (extensionResultIsMatch(result)) { - if (Array.isArray(result.ranges)) { - if (!Array.isArray(result.preview.matches)) { - console.warn('INVALID - A text search provider match\'s`ranges` and`matches` properties must have the same type.'); - return false; - } - - if ((result.preview.matches).length !== result.ranges.length) { - console.warn('INVALID - A text search provider match\'s`ranges` and`matches` properties must have the same length.'); - return false; - } - } else { - if (Array.isArray(result.preview.matches)) { - console.warn('INVALID - A text search provider match\'s`ranges` and`matches` properties must have the same length.'); - return false; - } - } - } - - return true; - } - - private readdir(dirname: string): Promise { - return this._pfs.readdir(dirname); - } - - private getSearchOptionsForFolder(fq: IFolderQuery): TextSearchOptions { - const includes = resolvePatternsForProvider(this.query.includePattern, fq.includePattern); - const excludes = resolvePatternsForProvider(this.query.excludePattern, fq.excludePattern); - - const options = { - folder: URI.from(fq.folder), - excludes, - includes, - useIgnoreFiles: !fq.disregardIgnoreFiles, - useGlobalIgnoreFiles: !fq.disregardGlobalIgnoreFiles, - followSymlinks: !fq.ignoreSymlinks, - encoding: fq.fileEncoding && toCanonicalName(fq.fileEncoding), - maxFileSize: this.query.maxFileSize, - maxResults: this.query.maxResults, - previewOptions: this.query.previewOptions, - afterContext: this.query.afterContext, - beforeContext: this.query.beforeContext - }; - (options).usePCRE2 = this.query.usePCRE2; - return options; - } -} - -function patternInfoToQuery(patternInfo: IPatternInfo): TextSearchQuery { - return { - isCaseSensitive: patternInfo.isCaseSensitive || false, - isRegExp: patternInfo.isRegExp || false, - isWordMatch: patternInfo.isWordMatch || false, - isMultiline: patternInfo.isMultiline || false, - pattern: patternInfo.pattern - }; -} - -export class TextSearchResultsCollector { - private _batchedCollector: BatchedCollector; - - private _currentFolderIdx: number = -1; - private _currentUri: URI | undefined; - private _currentFileMatch: IFileMatch | null = null; - - constructor(private _onResult: (result: IFileMatch[]) => void) { - this._batchedCollector = new BatchedCollector(512, items => this.sendItems(items)); - } - - add(data: TextSearchResult, folderIdx: number): void { - // Collects TextSearchResults into IInternalFileMatches and collates using BatchedCollector. - // This is efficient for ripgrep which sends results back one file at a time. It wouldn't be efficient for other search - // providers that send results in random order. We could do this step afterwards instead. - if (this._currentFileMatch && (this._currentFolderIdx !== folderIdx || !resources.isEqual(this._currentUri, data.uri))) { - this.pushToCollector(); - this._currentFileMatch = null; - } - - if (!this._currentFileMatch) { - this._currentFolderIdx = folderIdx; - this._currentFileMatch = { - resource: data.uri, - results: [] - }; - } - - this._currentFileMatch.results!.push(extensionResultToFrontendResult(data)); - } - - private pushToCollector(): void { - const size = this._currentFileMatch && this._currentFileMatch.results ? - this._currentFileMatch.results.length : - 0; - this._batchedCollector.addItem(this._currentFileMatch!, size); - } - - flush(): void { - this.pushToCollector(); - this._batchedCollector.flush(); - } - - private sendItems(items: IFileMatch[]): void { - this._onResult(items); - } -} - -function extensionResultToFrontendResult(data: TextSearchResult): ITextSearchResult { - // Warning: result from RipgrepTextSearchEH has fake Range. Don't depend on any other props beyond these... - if (extensionResultIsMatch(data)) { - return { - preview: { - matches: mapArrayOrNot(data.preview.matches, m => ({ - startLineNumber: m.start.line, - startColumn: m.start.character, - endLineNumber: m.end.line, - endColumn: m.end.character - })), - text: data.preview.text - }, - ranges: mapArrayOrNot(data.ranges, r => ({ - startLineNumber: r.start.line, - startColumn: r.start.character, - endLineNumber: r.end.line, - endColumn: r.end.character - })) - }; - } else { - return { - text: data.text, - lineNumber: data.lineNumber - }; - } -} - -export function extensionResultIsMatch(data: TextSearchResult): data is TextSearchMatch { - return !!(data).preview; -} - -/** - * Collects items that have a size - before the cumulative size of collected items reaches START_BATCH_AFTER_COUNT, the callback is called for every - * set of items collected. - * But after that point, the callback is called with batches of maxBatchSize. - * If the batch isn't filled within some time, the callback is also called. - */ -export class BatchedCollector { - private static readonly TIMEOUT = 4000; - - // After START_BATCH_AFTER_COUNT items have been collected, stop flushing on timeout - private static readonly START_BATCH_AFTER_COUNT = 50; - - private totalNumberCompleted = 0; - private batch: T[] = []; - private batchSize = 0; - private timeoutHandle: any; - - constructor(private maxBatchSize: number, private cb: (items: T[]) => void) { - } - - addItem(item: T, size: number): void { - if (!item) { - return; - } - - this.addItemToBatch(item, size); - } - - addItems(items: T[], size: number): void { - if (!items) { - return; - } - - this.addItemsToBatch(items, size); - } - - private addItemToBatch(item: T, size: number): void { - this.batch.push(item); - this.batchSize += size; - this.onUpdate(); - } - - private addItemsToBatch(item: T[], size: number): void { - this.batch = this.batch.concat(item); - this.batchSize += size; - this.onUpdate(); - } - - private onUpdate(): void { - if (this.totalNumberCompleted < BatchedCollector.START_BATCH_AFTER_COUNT) { - // Flush because we aren't batching yet - this.flush(); - } else if (this.batchSize >= this.maxBatchSize) { - // Flush because the batch is full - this.flush(); - } else if (!this.timeoutHandle) { - // No timeout running, start a timeout to flush - this.timeoutHandle = setTimeout(() => { - this.flush(); - }, BatchedCollector.TIMEOUT); - } - } - - flush(): void { - if (this.batchSize) { - this.totalNumberCompleted += this.batchSize; - this.cb(this.batch); - this.batch = []; - this.batchSize = 0; - - if (this.timeoutHandle) { - clearTimeout(this.timeoutHandle); - this.timeoutHandle = 0; - } - } - } } diff --git a/src/vs/workbench/services/search/test/node/textSearchManager.test.ts b/src/vs/workbench/services/search/test/node/textSearchManager.test.ts index 1efabf6224d83..fec67730fa07e 100644 --- a/src/vs/workbench/services/search/test/node/textSearchManager.test.ts +++ b/src/vs/workbench/services/search/test/node/textSearchManager.test.ts @@ -9,9 +9,9 @@ import { URI } from 'vs/base/common/uri'; import { Progress } from 'vs/platform/progress/common/progress'; import { ITextQuery, QueryType } from 'vs/workbench/services/search/common/search'; import { ProviderResult, TextSearchComplete, TextSearchOptions, TextSearchProvider, TextSearchQuery, TextSearchResult } from 'vs/workbench/services/search/common/searchExtTypes'; -import { TextSearchManager } from 'vs/workbench/services/search/node/textSearchManager'; +import { NativeTextSearchManager } from 'vs/workbench/services/search/node/textSearchManager'; -suite('TextSearchManager', () => { +suite('NativeTextSearchManager', () => { test('fixes encoding', async () => { let correctEncoding = false; const provider: TextSearchProvider = { @@ -33,7 +33,7 @@ suite('TextSearchManager', () => { }] }; - const m = new TextSearchManager(query, provider); + const m = new NativeTextSearchManager(query, provider); await m.search(() => { }, new CancellationTokenSource().token); assert.ok(correctEncoding); diff --git a/src/vs/workbench/test/electron-browser/api/extHostSearch.test.ts b/src/vs/workbench/test/electron-browser/api/extHostSearch.test.ts index bf71ebfaf5c29..d90cbe0425674 100644 --- a/src/vs/workbench/test/electron-browser/api/extHostSearch.test.ts +++ b/src/vs/workbench/test/electron-browser/api/extHostSearch.test.ts @@ -12,7 +12,7 @@ import { joinPath } from 'vs/base/common/resources'; import { URI, UriComponents } from 'vs/base/common/uri'; import * as pfs from 'vs/base/node/pfs'; import { MainContext, MainThreadSearchShape } from 'vs/workbench/api/common/extHost.protocol'; -import { ExtHostSearch } from 'vs/workbench/api/node/extHostSearch'; +import { NativeExtHostSearch } from 'vs/workbench/api/node/extHostSearch'; import { Range } from 'vs/workbench/api/common/extHostTypes'; import { IFileMatch, IFileQuery, IPatternInfo, IRawFileMatch2, ISearchCompleteStats, ISearchQuery, ITextQuery, QueryType, resultIsMatch } from 'vs/workbench/services/search/common/search'; import { TestRPCProtocol } from 'vs/workbench/test/electron-browser/api/testRPCProtocol'; @@ -21,9 +21,11 @@ import { NullLogService } from 'vs/platform/log/common/log'; import { URITransformerService } from 'vs/workbench/api/common/extHostUriTransformerService'; import { mock } from 'vs/workbench/test/electron-browser/api/mock'; import { IExtHostInitDataService } from 'vs/workbench/api/common/extHostInitDataService'; +import { TextSearchManager } from 'vs/workbench/services/search/common/textSearchManager'; +import { NativeTextSearchManager } from 'vs/workbench/services/search/node/textSearchManager'; let rpcProtocol: TestRPCProtocol; -let extHostSearch: ExtHostSearch; +let extHostSearch: NativeExtHostSearch; const disposables = new DisposableStore(); let mockMainThreadSearch: MockMainThreadSearch; @@ -138,7 +140,7 @@ suite('ExtHostSearch', () => { rpcProtocol.set(MainContext.MainThreadSearch, mockMainThreadSearch); mockPFS = {}; - extHostSearch = new class extends ExtHostSearch { + extHostSearch = new class extends NativeExtHostSearch { constructor() { super( rpcProtocol, @@ -148,6 +150,10 @@ suite('ExtHostSearch', () => { ); this._pfs = mockPFS as any; } + + protected createTextSearchManager(query: ITextQuery, provider: vscode.TextSearchProvider): TextSearchManager { + return new NativeTextSearchManager(query, provider, this._pfs); + } }; }); From 6d1ddf073053ec4f63de39f07b57b4f619c0cb4c Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Tue, 12 Nov 2019 19:06:48 +0100 Subject: [PATCH 137/352] web - fix problems to show up from yarn web --- extensions/vscode-api-tests/src/extension.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/vscode-api-tests/src/extension.ts b/extensions/vscode-api-tests/src/extension.ts index 05646e66dc3ab..7d345d9ae9555 100644 --- a/extensions/vscode-api-tests/src/extension.ts +++ b/extensions/vscode-api-tests/src/extension.ts @@ -344,7 +344,7 @@ function enableProblems(context: vscode.ExtensionContext): void { } function updateDiagnostics(document: vscode.TextDocument, collection: vscode.DiagnosticCollection): void { - if (document && document.fileName === '/large.ts') { + if (document && document.fileName === '/sample-folder/large.ts') { collection.set(document.uri, [{ code: '', message: 'cannot assign twice to immutable variable `storeHouses`', From 54a6229d6855fbd5b861276a3ff6eccd6b3f1cc7 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Tue, 12 Nov 2019 19:19:35 +0100 Subject: [PATCH 138/352] web - workaround new window issue with pwa --- src/vs/code/browser/workbench/workbench.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/vs/code/browser/workbench/workbench.ts b/src/vs/code/browser/workbench/workbench.ts index a599f5a7ebf07..28b0e9a3b156c 100644 --- a/src/vs/code/browser/workbench/workbench.ts +++ b/src/vs/code/browser/workbench/workbench.ts @@ -11,7 +11,6 @@ import { Disposable } from 'vs/base/common/lifecycle'; import { request } from 'vs/base/parts/request/browser/request'; import { isFolderToOpen, isWorkspaceToOpen } from 'vs/platform/windows/common/windows'; import { isEqual } from 'vs/base/common/resources'; -import { isStandalone } from 'vs/base/browser/browser'; interface ICredential { service: string; @@ -223,7 +222,7 @@ class WorkspaceProvider implements IWorkspaceProvider { if (options?.reuse) { window.location.href = targetHref; } else { - if (isStandalone) { + if (this.isRunningInPWA()) { // TODO@ben figure out why browser.isStandalone would not work? window.open(targetHref, '_blank', 'toolbar=no'); // ensures to open another 'standalone' window! } else { window.open(targetHref); @@ -232,6 +231,10 @@ class WorkspaceProvider implements IWorkspaceProvider { } } + private isRunningInPWA(): boolean { + return (window.matchMedia && window.matchMedia('(display-mode: standalone)').matches); + } + private createTargetUrl(workspace: IWorkspace, options?: { reuse?: boolean, payload?: object }): string | undefined { // Empty From beb12c256ea719abe45f217e90121e984c8c0d5d Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Tue, 12 Nov 2019 19:23:22 +0100 Subject: [PATCH 139/352] honor outline.showXYZ filters --- .../outline/browser/outlineNavigation.ts | 57 ++++++++++++------- 1 file changed, 35 insertions(+), 22 deletions(-) diff --git a/src/vs/workbench/contrib/outline/browser/outlineNavigation.ts b/src/vs/workbench/contrib/outline/browser/outlineNavigation.ts index 7f22814d066ed..4caed47d6cf58 100644 --- a/src/vs/workbench/contrib/outline/browser/outlineNavigation.ts +++ b/src/vs/workbench/contrib/outline/browser/outlineNavigation.ts @@ -16,24 +16,20 @@ import { EditorContextKeys } from 'vs/editor/common/editorContextKeys'; import { values } from 'vs/base/common/collections'; import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; import { KeyCode, KeyMod } from 'vs/base/common/keyCodes'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { OutlineFilter } from 'vs/editor/contrib/documentSymbols/outlineTree'; class Navigator { - private static readonly _instances = new WeakMap(); - - static for(element: TreeElement): Navigator { - let res = this._instances.get(element); - if (!res) { - res = new Navigator(element); - this._instances.set(element, res); - } - return res; - } - private readonly _children: TreeElement[] = []; - private constructor(readonly element: TreeElement) { - this._children = values(element.children).sort(Navigator._compare); + constructor( + readonly element: TreeElement, + private readonly _filter: OutlineFilter + ) { + this._children = values(element.children) + .filter(entry => !(entry instanceof OutlineElement) || _filter.filter(entry)) + .sort(Navigator._compare); } navigate(up: boolean): TreeElement | undefined { @@ -51,7 +47,7 @@ class Navigator { if (!next) { return nav.element; } - nav = Navigator.for(next); + nav = new Navigator(next, this._filter); } return undefined; } @@ -67,7 +63,7 @@ class Navigator { if (next) { return next.element; } - nav = nav.element.parent && Navigator.for(nav.element.parent); + nav = nav.element.parent && new Navigator(nav.element.parent, this._filter); } return undefined; } @@ -76,11 +72,11 @@ class Navigator { if (!this.element.parent) { return undefined; } - const parent = Navigator.for(this.element.parent); + const parent = new Navigator(this.element.parent, this._filter); const idx = parent._children.indexOf(this.element); const nexIdx = idx + (up ? -1 : +1); const element = parent._children[nexIdx]; - return element && Navigator.for(element); + return element && new Navigator(element, this._filter); } private _child(last: boolean): TreeElement | undefined { @@ -108,6 +104,7 @@ export class OutlineNavigation implements IEditorContribution { constructor( editor: ICodeEditor, + @IConfigurationService private readonly _configService: IConfigurationService, ) { this._editor = editor; } @@ -133,16 +130,33 @@ export class OutlineNavigation implements IEditorContribution { this._cts = new EditorStateCancellationTokenSource(this._editor, CodeEditorStateFlag.Position | CodeEditorStateFlag.Value | CodeEditorStateFlag.Scroll); + const filter = new OutlineFilter('outline', this._configService); const outlineModel = await OutlineModel.create(textModel, this._cts.token); - const element = outlineModel.getItemEnclosingPosition(position); - if (!element || this._cts.token.isCancellationRequested) { + let element: TreeElement | undefined = outlineModel.getItemEnclosingPosition(position); + if (!(element instanceof OutlineElement) || this._cts.token.isCancellationRequested) { return; } + // don't start in a filtered element + let stack: OutlineElement[] = [element]; + while (element instanceof OutlineElement) { + if (!filter.filter(element)) { + stack.length = 0; + } else { + stack.push(element); + } + element = element.parent; + } + element = stack[0]; + if (!(element instanceof OutlineElement)) { + return; + } + + // reveal container first (unless already at its range) let nextElement: TreeElement | undefined = element; - if (Range.containsPosition(element.symbol.selectionRange, position)) { - nextElement = Navigator.for(element).navigate(up); + if (!up || Range.containsPosition(element.symbol.selectionRange, position)) { + nextElement = new Navigator(element, filter).navigate(up); } if (nextElement instanceof OutlineElement) { @@ -151,7 +165,6 @@ export class OutlineNavigation implements IEditorContribution { this._editor.revealPosition(pos, ScrollType.Smooth); } } - } registerEditorContribution(OutlineNavigation.ID, OutlineNavigation); From fdd406ef822101f5d133bdaaf818af48edecde20 Mon Sep 17 00:00:00 2001 From: Rob Lourens Date: Tue, 12 Nov 2019 10:13:38 -0800 Subject: [PATCH 140/352] Fix #83850 Intercept ctrl+A on the settings page so it won't select the full page text --- .../preferences/browser/settingsEditor2.ts | 25 ++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/src/vs/workbench/contrib/preferences/browser/settingsEditor2.ts b/src/vs/workbench/contrib/preferences/browser/settingsEditor2.ts index 36c63be5ea996..b05433b5f86bc 100644 --- a/src/vs/workbench/contrib/preferences/browser/settingsEditor2.ts +++ b/src/vs/workbench/contrib/preferences/browser/settingsEditor2.ts @@ -4,13 +4,18 @@ *--------------------------------------------------------------------------------------------*/ import * as DOM from 'vs/base/browser/dom'; +import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent'; +import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar'; import { ITreeElement } from 'vs/base/browser/ui/tree/tree'; +import { Action } from 'vs/base/common/actions'; import * as arrays from 'vs/base/common/arrays'; import { Delayer, ThrottledDelayer, timeout } from 'vs/base/common/async'; import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation'; import * as collections from 'vs/base/common/collections'; import { getErrorMessage, isPromiseCanceledError } from 'vs/base/common/errors'; import { Iterator } from 'vs/base/common/iterator'; +import { KeyCode } from 'vs/base/common/keyCodes'; +import * as platform from 'vs/base/common/platform'; import * as strings from 'vs/base/common/strings'; import { isArray, withNullAsUndefined, withUndefinedAsNull } from 'vs/base/common/types'; import { URI } from 'vs/base/common/uri'; @@ -36,13 +41,11 @@ import { AbstractSettingRenderer, ISettingLinkClickEvent, ISettingOverrideClickE import { ISettingsEditorViewState, parseQuery, SearchResultIdx, SearchResultModel, SettingsTreeElement, SettingsTreeGroupChild, SettingsTreeGroupElement, SettingsTreeModel, SettingsTreeSettingElement } from 'vs/workbench/contrib/preferences/browser/settingsTreeModels'; import { settingsTextInputBorder } from 'vs/workbench/contrib/preferences/browser/settingsWidgets'; import { createTOCIterator, TOCTree, TOCTreeModel } from 'vs/workbench/contrib/preferences/browser/tocTree'; -import { CONTEXT_SETTINGS_EDITOR, CONTEXT_SETTINGS_SEARCH_FOCUS, CONTEXT_TOC_ROW_FOCUS, EXTENSION_SETTING_TAG, IPreferencesSearchService, ISearchProvider, MODIFIED_SETTING_TAG, SETTINGS_EDITOR_COMMAND_SHOW_CONTEXT_MENU, SETTINGS_EDITOR_COMMAND_CLEAR_SEARCH_RESULTS } from 'vs/workbench/contrib/preferences/common/preferences'; +import { CONTEXT_SETTINGS_EDITOR, CONTEXT_SETTINGS_SEARCH_FOCUS, CONTEXT_TOC_ROW_FOCUS, EXTENSION_SETTING_TAG, IPreferencesSearchService, ISearchProvider, MODIFIED_SETTING_TAG, SETTINGS_EDITOR_COMMAND_CLEAR_SEARCH_RESULTS, SETTINGS_EDITOR_COMMAND_SHOW_CONTEXT_MENU } from 'vs/workbench/contrib/preferences/common/preferences'; import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService'; import { IPreferencesService, ISearchResult, ISettingsEditorModel, ISettingsEditorOptions, SettingsEditorOptions, SettingValueType } from 'vs/workbench/services/preferences/common/preferences'; import { SettingsEditor2Input } from 'vs/workbench/services/preferences/common/preferencesEditorInput'; import { Settings2EditorModel } from 'vs/workbench/services/preferences/common/preferencesModels'; -import { Action } from 'vs/base/common/actions'; -import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar'; function createGroupIterator(group: SettingsTreeGroupElement): Iterator> { const groupsIt = Iterator.fromArray(group.children); @@ -212,6 +215,7 @@ export class SettingsEditor2 extends BaseEditor { this.createHeader(this.rootElement); this.createBody(this.rootElement); + this.addCtrlAInterceptor(this.rootElement); this.updateStyles(); } @@ -587,6 +591,21 @@ export class SettingsEditor2 extends BaseEditor { ); } + private addCtrlAInterceptor(container: HTMLElement): void { + this._register(DOM.addStandardDisposableListener(container, DOM.EventType.KEY_DOWN, (e: StandardKeyboardEvent) => { + if ( + e.keyCode === KeyCode.KEY_A && + (platform.isMacintosh ? e.metaKey : e.ctrlKey) && + e.target.tagName !== 'TEXTAREA' && + e.target.tagName !== 'INPUT' + ) { + // Avoid browser ctrl+a + e.browserEvent.stopPropagation(); + e.browserEvent.preventDefault(); + } + })); + } + private createFocusSink(container: HTMLElement, callback: (e: any) => boolean, label: string): HTMLElement { const listFocusSink = DOM.append(container, $('.settings-tree-focus-sink')); listFocusSink.setAttribute('aria-label', label); From 40677e0787f109d642bc114e3f69bff2f835e21d Mon Sep 17 00:00:00 2001 From: Rob Lourens Date: Tue, 12 Nov 2019 10:28:08 -0800 Subject: [PATCH 141/352] Fix #84496 Handle getting non-JSON response from the experiment service endpoint --- .../experiments/common/experimentService.ts | 20 +++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/src/vs/workbench/contrib/experiments/common/experimentService.ts b/src/vs/workbench/contrib/experiments/common/experimentService.ts index 188efd95a27fc..11b6c10aa5116 100644 --- a/src/vs/workbench/contrib/experiments/common/experimentService.ts +++ b/src/vs/workbench/contrib/experiments/common/experimentService.ts @@ -167,18 +167,22 @@ export class ExperimentService extends Disposable implements IExperimentService this.storageService.store(storageKey, JSON.stringify(experimentState), StorageScope.GLOBAL); } - protected getExperiments(): Promise { + protected async getExperiments(): Promise { if (!this.productService.experimentsUrl || this.configurationService.getValue('workbench.enableExperiments') === false) { - return Promise.resolve([]); + return []; } - return this.requestService.request({ type: 'GET', url: this.productService.experimentsUrl }, CancellationToken.None).then(context => { + + try { + const context = await this.requestService.request({ type: 'GET', url: this.productService.experimentsUrl }, CancellationToken.None); if (context.res.statusCode !== 200) { - return Promise.resolve(null); + return null; } - return asJson(context).then((result: any) => { - return result && Array.isArray(result['experiments']) ? result['experiments'] : []; - }); - }, () => Promise.resolve(null)); + const result: any = await asJson(context); + return result && Array.isArray(result['experiments']) ? result['experiments'] : []; + } catch (_e) { + // Bad request or invalid JSON + return null; + } } private loadExperiments(): Promise { From 8ae2921645a9f06686e66580b59a24cce63733b7 Mon Sep 17 00:00:00 2001 From: Greg Van Liew Date: Tue, 12 Nov 2019 10:55:04 -0800 Subject: [PATCH 142/352] Nits in settings comments --- extensions/typescript-language-features/package.nls.json | 6 +++--- src/vs/editor/common/config/editorOptions.ts | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/extensions/typescript-language-features/package.nls.json b/extensions/typescript-language-features/package.nls.json index c9ea95731934c..bb4187716ba01 100644 --- a/extensions/typescript-language-features/package.nls.json +++ b/extensions/typescript-language-features/package.nls.json @@ -30,7 +30,7 @@ "format.placeOpenBraceOnNewLineForFunctions": "Defines whether an open brace is put onto a new line for functions or not.", "format.placeOpenBraceOnNewLineForControlBlocks": "Defines whether an open brace is put onto a new line for control blocks or not.", "format.semicolons": "Defines handling of optional semicolons. Requires using TypeScript 3.7 or newer in the workspace.", - "format.semicolons.ignore": "Don’t insert or remove any semicolons.", + "format.semicolons.ignore": "Don't insert or remove any semicolons.", "format.semicolons.insert": "Insert semicolons at statement ends.", "format.semicolons.remove": "Remove unnecessary semicolons.", "javascript.validate.enable": "Enable/disable JavaScript validation.", @@ -43,8 +43,8 @@ "typescript.selectTypeScriptVersion.title": "Select TypeScript Version...", "typescript.reportStyleChecksAsWarnings": "Report style checks as warnings.", "javascript.implicitProjectConfig.checkJs": "Enable/disable semantic checking of JavaScript files. Existing jsconfig.json or tsconfig.json files override this setting. Requires using TypeScript 2.3.1 or newer in the workspace.", - "typescript.npm": "Specifies the path to the NPM executable used for Automatic Type Acquisition. Requires using TypeScript 2.3.4 or newer in the workspace.", - "typescript.check.npmIsInstalled": "Check if NPM is installed for Automatic Type Acquisition.", + "typescript.npm": "Specifies the path to the npm executable used for Automatic Type Acquisition. Requires using TypeScript 2.3.4 or newer in the workspace.", + "typescript.check.npmIsInstalled": "Check if npm is installed for Automatic Type Acquisition.", "configuration.suggest.names": "Enable/disable including unique names from the file in JavaScript suggestions. Note that name suggestions are always disabled in JavaScript code that is semantically checked using `@ts-check` or `checkJs`.", "typescript.tsc.autoDetect": "Controls auto detection of tsc tasks.", "typescript.tsc.autoDetect.off": "Disable this feature.", diff --git a/src/vs/editor/common/config/editorOptions.ts b/src/vs/editor/common/config/editorOptions.ts index b20246a3734ac..de2c41dddd370 100644 --- a/src/vs/editor/common/config/editorOptions.ts +++ b/src/vs/editor/common/config/editorOptions.ts @@ -3155,10 +3155,10 @@ export const EditorOptions = { ['default', 'all'] as const, { enumDescriptions: [ - nls.localize('cursorSurroundingLinesStyle.default', "`cursorSurroundingLines` is enforced only when triggered from keyboard and api"), + nls.localize('cursorSurroundingLinesStyle.default', "`cursorSurroundingLines` is enforced only when triggered via the keyboard or API."), nls.localize('cursorSurroundingLinesStyle.all', "`cursorSurroundingLines` is enforced always.") ], - description: nls.localize('cursorSurroundingLinesStyle', "Controls when `cursorSurroundingLines` should be enforced") + description: nls.localize('cursorSurroundingLinesStyle', "Controls when `cursorSurroundingLines` should be enforced.") } )), cursorWidth: register(new EditorIntOption( From b33979cbe433b8ea25e35a07f7bb16d30508d7b3 Mon Sep 17 00:00:00 2001 From: Christof Marti Date: Tue, 12 Nov 2019 17:39:41 +0100 Subject: [PATCH 143/352] Use active foreground when inactive (fixes #72952) --- .../workbench/browser/parts/quickinput/quickInputList.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/browser/parts/quickinput/quickInputList.ts b/src/vs/workbench/browser/parts/quickinput/quickInputList.ts index cb9791317b066..1e62ba48a8aa1 100644 --- a/src/vs/workbench/browser/parts/quickinput/quickInputList.ts +++ b/src/vs/workbench/browser/parts/quickinput/quickInputList.ts @@ -22,7 +22,7 @@ import { HighlightedLabel } from 'vs/base/browser/ui/highlightedlabel/highlighte import { memoize } from 'vs/base/common/decorators'; import { range } from 'vs/base/common/arrays'; import * as platform from 'vs/base/common/platform'; -import { listFocusBackground, pickerGroupBorder, pickerGroupForeground, activeContrastBorder } from 'vs/platform/theme/common/colorRegistry'; +import { listFocusBackground, pickerGroupBorder, pickerGroupForeground, activeContrastBorder, listFocusForeground } from 'vs/platform/theme/common/colorRegistry'; import { registerThemingParticipant } from 'vs/platform/theme/common/themeService'; import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar'; import { Action } from 'vs/base/common/actions'; @@ -590,12 +590,18 @@ function compareEntries(elementA: ListElement, elementB: ListElement, lookFor: s } registerThemingParticipant((theme, collector) => { + // Override inactive focus foreground with active focus foreground for single-pick case. + const listInactiveFocusForeground = theme.getColor(listFocusForeground); + if (listInactiveFocusForeground) { + collector.addRule(`.quick-input-list .monaco-list .monaco-list-row.focused { color: ${listInactiveFocusForeground}; }`); + } // Override inactive focus background with active focus background for single-pick case. const listInactiveFocusBackground = theme.getColor(listFocusBackground); if (listInactiveFocusBackground) { collector.addRule(`.quick-input-list .monaco-list .monaco-list-row.focused { background-color: ${listInactiveFocusBackground}; }`); collector.addRule(`.quick-input-list .monaco-list .monaco-list-row.focused:hover { background-color: ${listInactiveFocusBackground}; }`); } + // dotted instead of solid (as in listWidget.ts) to match QuickOpen const activeContrast = theme.getColor(activeContrastBorder); if (activeContrast) { collector.addRule(`.quick-input-list .monaco-list .monaco-list-row.focused { outline: 1px dotted ${activeContrast}; outline-offset: -1px; }`); From 3948b798b62ded00076422f30064ccf7214848f8 Mon Sep 17 00:00:00 2001 From: Rob Lourens Date: Tue, 12 Nov 2019 13:56:51 -0600 Subject: [PATCH 144/352] Fix #84355 Always open settings GUI when command is invoked with a query --- .../contrib/preferences/browser/preferences.contribution.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/preferences/browser/preferences.contribution.ts b/src/vs/workbench/contrib/preferences/browser/preferences.contribution.ts index 5e544b6a1c50a..36d2c63d1b0aa 100644 --- a/src/vs/workbench/contrib/preferences/browser/preferences.contribution.ts +++ b/src/vs/workbench/contrib/preferences/browser/preferences.contribution.ts @@ -215,7 +215,8 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({ when: null, primary: KeyMod.CtrlCmd | KeyCode.US_COMMA, handler: (accessor, args: string | undefined) => { - accessor.get(IPreferencesService).openSettings(undefined, typeof args === 'string' ? args : undefined); + const query = typeof args === 'string' ? args : undefined; + accessor.get(IPreferencesService).openSettings(query ? false : undefined, query); } }); From a170916295427aa03768eb5d54b19198a0d8fb2a Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Tue, 12 Nov 2019 13:30:55 -0800 Subject: [PATCH 145/352] Highlight a few other types in jsdoc comments Fixes #84622 --- extensions/typescript-language-features/src/utils/previewer.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/extensions/typescript-language-features/src/utils/previewer.ts b/extensions/typescript-language-features/src/utils/previewer.ts index 2b2108ccd5778..5ad230d662e0e 100644 --- a/extensions/typescript-language-features/src/utils/previewer.ts +++ b/extensions/typescript-language-features/src/utils/previewer.ts @@ -38,7 +38,10 @@ function getTagBodyText(tag: Proto.JSDocTagInfo): string | undefined { function getTagDocumentation(tag: Proto.JSDocTagInfo): string | undefined { switch (tag.name) { + case 'augments': + case 'extends': case 'param': + case 'template': const body = (tag.text || '').split(/^([\w\.]+)\s*-?\s*/); if (body && body.length === 3) { const param = body[1]; From 8f60641b7118fbc67e1094f54431c310af9caf97 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Tue, 12 Nov 2019 13:51:55 -0800 Subject: [PATCH 146/352] Remove some duplicate configuration node (#84070) For #79144 Currently we duplicate information for the `editor` and `workbench` configuration nodes in a few places. This change extracts some of those to be constants instead --- src/vs/editor/common/config/commonEditorConfig.ts | 8 ++++++-- src/vs/workbench/browser/workbench.contribution.ts | 6 ++---- src/vs/workbench/common/configuration.ts | 14 ++++++++++++++ .../contrib/codeActions/common/configuration.ts | 7 ++----- .../browser/webviewEditor.contribution.ts | 6 ++---- .../contrib/files/browser/files.contribution.ts | 6 ++---- .../format/browser/formatActionsMultiple.ts | 6 ++---- .../contrib/watermark/browser/watermark.ts | 5 ++--- .../page/browser/welcomePage.contribution.ts | 5 ++--- 9 files changed, 34 insertions(+), 29 deletions(-) create mode 100644 src/vs/workbench/common/configuration.ts diff --git a/src/vs/editor/common/config/commonEditorConfig.ts b/src/vs/editor/common/config/commonEditorConfig.ts index c7f50efd2d9cf..5ef39172f5e72 100644 --- a/src/vs/editor/common/config/commonEditorConfig.ts +++ b/src/vs/editor/common/config/commonEditorConfig.ts @@ -413,14 +413,18 @@ export abstract class CommonEditorConfiguration extends Disposable implements ed } -const configurationRegistry = Registry.as(Extensions.Configuration); -const editorConfiguration: IConfigurationNode = { +export const editorConfigurationBaseNode = Object.freeze({ id: 'editor', order: 5, type: 'object', title: nls.localize('editorConfigurationTitle', "Editor"), overridable: true, scope: ConfigurationScope.RESOURCE, +}); + +const configurationRegistry = Registry.as(Extensions.Configuration); +const editorConfiguration: IConfigurationNode = { + ...editorConfigurationBaseNode, properties: { 'editor.tabSize': { type: 'number', diff --git a/src/vs/workbench/browser/workbench.contribution.ts b/src/vs/workbench/browser/workbench.contribution.ts index 2b634951bf224..854db17c376aa 100644 --- a/src/vs/workbench/browser/workbench.contribution.ts +++ b/src/vs/workbench/browser/workbench.contribution.ts @@ -7,6 +7,7 @@ import { Registry } from 'vs/platform/registry/common/platform'; import * as nls from 'vs/nls'; import { IConfigurationRegistry, Extensions as ConfigurationExtensions, ConfigurationScope } from 'vs/platform/configuration/common/configurationRegistry'; import { isMacintosh, isWindows, isLinux, isWeb, isNative } from 'vs/base/common/platform'; +import { workbenchConfigurationNodeBase } from 'vs/workbench/common/configuration'; // Configuration (function registerConfiguration(): void { @@ -14,10 +15,7 @@ import { isMacintosh, isWindows, isLinux, isWeb, isNative } from 'vs/base/common // Workbench registry.registerConfiguration({ - 'id': 'workbench', - 'order': 7, - 'title': nls.localize('workbenchConfigurationTitle', "Workbench"), - 'type': 'object', + ...workbenchConfigurationNodeBase, 'properties': { 'workbench.editor.showTabs': { 'type': 'boolean', diff --git a/src/vs/workbench/common/configuration.ts b/src/vs/workbench/common/configuration.ts new file mode 100644 index 0000000000000..8405ae63a5fba --- /dev/null +++ b/src/vs/workbench/common/configuration.ts @@ -0,0 +1,14 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { localize } from 'vs/nls'; +import { IConfigurationNode } from 'vs/platform/configuration/common/configurationRegistry'; + +export const workbenchConfigurationNodeBase = Object.freeze({ + 'id': 'workbench', + 'order': 7, + 'title': localize('workbenchConfigurationTitle', "Workbench"), + 'type': 'object', +}); diff --git a/src/vs/workbench/contrib/codeActions/common/configuration.ts b/src/vs/workbench/contrib/codeActions/common/configuration.ts index c307bf994b50d..d8878cd01813f 100644 --- a/src/vs/workbench/contrib/codeActions/common/configuration.ts +++ b/src/vs/workbench/contrib/codeActions/common/configuration.ts @@ -17,6 +17,7 @@ import { Registry } from 'vs/platform/registry/common/platform'; import { IWorkbenchContribution } from 'vs/workbench/common/contributions'; import { CodeActionsExtensionPoint, ContributedCodeAction } from 'vs/workbench/contrib/codeActions/common/extensionPoint'; import { IExtensionPoint } from 'vs/workbench/services/extensions/common/extensionsRegistry'; +import { editorConfigurationBaseNode } from 'vs/editor/common/config/commonEditorConfig'; const codeActionsOnSaveDefaultProperties = Object.freeze({ 'source.fixAll': { @@ -37,11 +38,7 @@ const codeActionsOnSaveSchema: IConfigurationPropertySchema = { }; export const editorConfiguration = Object.freeze({ - id: 'editor', - order: 5, - type: 'object', - title: nls.localize('editorConfigurationTitle', "Editor"), - overridable: true, + ...editorConfigurationBaseNode, properties: { 'editor.codeActionsOnSave': codeActionsOnSaveSchema, 'editor.codeActionsOnSaveTimeout': { diff --git a/src/vs/workbench/contrib/customEditor/browser/webviewEditor.contribution.ts b/src/vs/workbench/contrib/customEditor/browser/webviewEditor.contribution.ts index b8eaf3ae0d052..d544ec1ee51e7 100644 --- a/src/vs/workbench/contrib/customEditor/browser/webviewEditor.contribution.ts +++ b/src/vs/workbench/contrib/customEditor/browser/webviewEditor.contribution.ts @@ -18,6 +18,7 @@ import { WebviewEditor } from 'vs/workbench/contrib/webview/browser/webviewEdito import './commands'; import { CustomFileEditorInput } from './customEditorInput'; import { CustomEditorContribution, customEditorsAssociationsKey, CustomEditorService } from './customEditors'; +import { workbenchConfigurationNodeBase } from 'vs/workbench/common/configuration'; registerSingleton(ICustomEditorService, CustomEditorService); @@ -39,10 +40,7 @@ Registry.as(EditorInputExtensions.EditorInputFactor Registry.as(ConfigurationExtensions.Configuration) .registerConfiguration({ - 'id': 'workbench', - 'order': 7, - 'title': nls.localize('workbenchConfigurationTitle', "Workbench"), - 'type': 'object', + ...workbenchConfigurationNodeBase, 'properties': { [customEditorsAssociationsKey]: { type: 'array', diff --git a/src/vs/workbench/contrib/files/browser/files.contribution.ts b/src/vs/workbench/contrib/files/browser/files.contribution.ts index 226a42e22c796..f2332dd7eb5c8 100644 --- a/src/vs/workbench/contrib/files/browser/files.contribution.ts +++ b/src/vs/workbench/contrib/files/browser/files.contribution.ts @@ -38,6 +38,7 @@ import { ExplorerService } from 'vs/workbench/contrib/files/common/explorerServi import { SUPPORTED_ENCODINGS } from 'vs/workbench/services/textfile/common/textfiles'; import { Schemas } from 'vs/base/common/network'; import { WorkspaceWatcher } from 'vs/workbench/contrib/files/common/workspaceWatcher'; +import { editorConfigurationBaseNode } from 'vs/editor/common/config/commonEditorConfig'; import { DirtyFilesIndicator } from 'vs/workbench/contrib/files/common/dirtyFilesIndicator'; // Viewlet Action @@ -343,10 +344,7 @@ configurationRegistry.registerConfiguration({ }); configurationRegistry.registerConfiguration({ - id: 'editor', - order: 5, - title: nls.localize('editorConfigurationTitle', "Editor"), - type: 'object', + ...editorConfigurationBaseNode, properties: { 'editor.formatOnSave': { 'type': 'boolean', diff --git a/src/vs/workbench/contrib/format/browser/formatActionsMultiple.ts b/src/vs/workbench/contrib/format/browser/formatActionsMultiple.ts index 9283054b31d26..887d6a87d2fd3 100644 --- a/src/vs/workbench/contrib/format/browser/formatActionsMultiple.ts +++ b/src/vs/workbench/contrib/format/browser/formatActionsMultiple.ts @@ -28,6 +28,7 @@ import { INotificationService, Severity } from 'vs/platform/notification/common/ import { IModeService } from 'vs/editor/common/services/modeService'; import { ILabelService } from 'vs/platform/label/common/label'; import { IExtensionEnablementService } from 'vs/workbench/services/extensionManagement/common/extensionManagement'; +import { editorConfigurationBaseNode } from 'vs/editor/common/config/commonEditorConfig'; type FormattingEditProvider = DocumentFormattingEditProvider | DocumentRangeFormattingEditProvider; @@ -152,10 +153,7 @@ Registry.as(WorkbenchExtensions.Workbench).regi ); Registry.as(ConfigurationExtensions.Configuration).registerConfiguration({ - id: 'editor', - order: 5, - type: 'object', - overridable: true, + ...editorConfigurationBaseNode, properties: { [DefaultFormatter.configName]: { description: nls.localize('formatter.default', "Defines a default formatter which takes precedence over all other formatter settings. Must be the identifier of an extension contributing a formatter."), diff --git a/src/vs/workbench/contrib/watermark/browser/watermark.ts b/src/vs/workbench/contrib/watermark/browser/watermark.ts index e68c960a1f41e..9a84c9a84c12b 100644 --- a/src/vs/workbench/contrib/watermark/browser/watermark.ts +++ b/src/vs/workbench/contrib/watermark/browser/watermark.ts @@ -29,6 +29,7 @@ import { CommandsRegistry } from 'vs/platform/commands/common/commands'; import { IDimension } from 'vs/platform/layout/browser/layoutService'; import { TERMINAL_COMMAND_ID } from 'vs/workbench/contrib/terminal/common/terminal'; import { assertIsDefined } from 'vs/base/common/types'; +import { workbenchConfigurationNodeBase } from 'vs/workbench/common/configuration'; const $ = dom.$; @@ -188,9 +189,7 @@ Registry.as(WorkbenchExtensions.Workbench) Registry.as(ConfigurationExtensions.Configuration) .registerConfiguration({ - 'id': 'workbench', - 'order': 7, - 'title': nls.localize('workbenchConfigurationTitle', "Workbench"), + ...workbenchConfigurationNodeBase, 'properties': { 'workbench.tips.enabled': { 'type': 'boolean', diff --git a/src/vs/workbench/contrib/welcome/page/browser/welcomePage.contribution.ts b/src/vs/workbench/contrib/welcome/page/browser/welcomePage.contribution.ts index 0b8457849d85a..42978506c8cc1 100644 --- a/src/vs/workbench/contrib/welcome/page/browser/welcomePage.contribution.ts +++ b/src/vs/workbench/contrib/welcome/page/browser/welcomePage.contribution.ts @@ -12,12 +12,11 @@ import { SyncActionDescriptor, MenuRegistry, MenuId } from 'vs/platform/actions/ import { IConfigurationRegistry, Extensions as ConfigurationExtensions, ConfigurationScope } from 'vs/platform/configuration/common/configurationRegistry'; import { IEditorInputFactoryRegistry, Extensions as EditorExtensions } from 'vs/workbench/common/editor'; import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle'; +import { workbenchConfigurationNodeBase } from 'vs/workbench/common/configuration'; Registry.as(ConfigurationExtensions.Configuration) .registerConfiguration({ - 'id': 'workbench', - 'order': 7, - 'title': localize('workbenchConfigurationTitle', "Workbench"), + ...workbenchConfigurationNodeBase, 'properties': { 'workbench.startupEditor': { 'scope': ConfigurationScope.APPLICATION, // Make sure repositories cannot trigger opening a README for tracking. From 9b70b1804c1f8af3137160f606139fae045436f3 Mon Sep 17 00:00:00 2001 From: Rachel Macfarlane Date: Tue, 12 Nov 2019 14:06:00 -0800 Subject: [PATCH 147/352] Show sign out command for settings sync in gear menu --- src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts b/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts index f1a0ded961b36..476d3ab6ce9c6 100644 --- a/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts +++ b/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts @@ -207,6 +207,7 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo MenuRegistry.appendMenuItem(MenuId.CommandPalette, signInMenuItem); const signOutMenuItem: IMenuItem = { + group: '5_sync', command: { id: 'workbench.userData.actions.logout', title: localize('sign out', "Sign Out") @@ -214,6 +215,7 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo when: ContextKeyExpr.and(CONTEXT_AUTH_TOKEN_STATE.isEqualTo(AuthTokenStatus.Active)), }; CommandsRegistry.registerCommand(signOutMenuItem.command.id, () => this.signOut()); + MenuRegistry.appendMenuItem(MenuId.GlobalActivity, signOutMenuItem); MenuRegistry.appendMenuItem(MenuId.CommandPalette, signOutMenuItem); const startSyncMenuItem: IMenuItem = { From 36bf1c9140517429adb29dfad4fa71fda0478f13 Mon Sep 17 00:00:00 2001 From: Miguel Solorio Date: Tue, 12 Nov 2019 14:09:03 -0800 Subject: [PATCH 148/352] Clean up activity bar size and margins --- .../activitybar/media/activityaction.css | 38 +++++++++---------- 1 file changed, 17 insertions(+), 21 deletions(-) diff --git a/src/vs/workbench/browser/parts/activitybar/media/activityaction.css b/src/vs/workbench/browser/parts/activitybar/media/activityaction.css index 1fb755062de79..c4e9ea9430c64 100644 --- a/src/vs/workbench/browser/parts/activitybar/media/activityaction.css +++ b/src/vs/workbench/browser/parts/activitybar/media/activityaction.css @@ -6,14 +6,15 @@ .monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-item { display: block; position: relative; - padding: 5px 0; + margin-bottom: 8px; } + .monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-label { position: relative; z-index: 1; display: flex; overflow: hidden; - height: 40px; + height: 48px; margin-right: 0; box-sizing: border-box; @@ -35,11 +36,10 @@ .monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-item:focus:before { content: ""; position: absolute; - top: 9px; - height: 32px; + top: 0; z-index: 1; - top: 5px; - height: 40px; + top: 0; + height: 100%; width: 0; border-left: 2px solid; } @@ -50,7 +50,7 @@ } .monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-item.checked:focus .active-item-indicator:before { - border-left: none; /* don't show active border + focus at the same time, focus takes priority */ + visibility: hidden; /* don't show active border + focus at the same time, focus takes priority */ } /* Hides active elements in high contrast mode */ @@ -62,20 +62,14 @@ border-left: none !important; /* no focus feedback when using mouse */ } +.monaco-workbench .activitybar.left > .content :not(.monaco-menu) > .monaco-action-bar .action-item:focus:before, .monaco-workbench .activitybar.left > .content :not(.monaco-menu) > .monaco-action-bar .action-item.checked .active-item-indicator:before{ left: 0; } -.monaco-workbench .activitybar.left > .content :not(.monaco-menu) > .monaco-action-bar .action-item:focus:before { - left: 1px; -} - +.monaco-workbench .activitybar.right > .content :not(.monaco-menu) > .monaco-action-bar .action-item.checked .active-item-indicator:before, .monaco-workbench .activitybar.right > .content :not(.monaco-menu) > .monaco-action-bar .action-item:focus:before { - right: 1px; -} - -.monaco-workbench .activitybar.right > .content :not(.monaco-menu) > .monaco-action-bar .action-item.checked .active-item-indicator:before { - right: 2px; + right: 0; } /* Hides outline on HC as focus is handled by border */ @@ -88,16 +82,18 @@ .monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .badge { position: absolute; z-index: 1; - top: 5px; + top: 0; + bottom: 0; + margin: auto; left: 0; overflow: hidden; - width: 50px; - height: 40px; + width: 100%; + height: 100%; } .monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .badge .badge-content { position: absolute; - top: 20px; + top: 24px; right: 8px; font-size: 9px; font-weight: 600; @@ -113,7 +109,7 @@ .monaco-workbench .activitybar.right > .content :not(.monaco-menu) > .monaco-action-bar .action-label:not(.codicon) { margin-left: 0; - padding: 0 50px 0 0; + padding: 0 48px 0 0; background-position: calc(100% - 9px) center; } From 677ff6efff3758f3afa53f7f30c06de1159bb252 Mon Sep 17 00:00:00 2001 From: Miguel Solorio Date: Tue, 12 Nov 2019 14:09:23 -0800 Subject: [PATCH 149/352] Add activity bar active border focus color --- .../parts/activitybar/activitybarActions.ts | 16 +++++++++++++++- src/vs/workbench/common/theme.ts | 6 ++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/browser/parts/activitybar/activitybarActions.ts b/src/vs/workbench/browser/parts/activitybar/activitybarActions.ts index bd8425e05552b..3d7e6603cfa70 100644 --- a/src/vs/workbench/browser/parts/activitybar/activitybarActions.ts +++ b/src/vs/workbench/browser/parts/activitybar/activitybarActions.ts @@ -22,7 +22,7 @@ import { ActivityAction, ActivityActionViewItem, ICompositeBar, ICompositeBarCol import { ViewletDescriptor } from 'vs/workbench/browser/viewlet'; import { Extensions as ActionExtensions, IWorkbenchActionRegistry } from 'vs/workbench/common/actions'; import { IActivity } from 'vs/workbench/common/activity'; -import { ACTIVITY_BAR_FOREGROUND, ACTIVITY_BAR_ACTIVE_BORDER, ACTIVITY_BAR_ACTIVE_BACKGROUND } from 'vs/workbench/common/theme'; +import { ACTIVITY_BAR_FOREGROUND, ACTIVITY_BAR_ACTIVE_BORDER, ACTIVITY_BAR_ACTIVE_BORDER_FOCUS, ACTIVITY_BAR_ACTIVE_BACKGROUND } from 'vs/workbench/common/theme'; import { IActivityBarService } from 'vs/workbench/services/activityBar/browser/activityBarService'; import { IWorkbenchLayoutService, Parts } from 'vs/workbench/services/layout/browser/layoutService'; import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet'; @@ -297,6 +297,20 @@ registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => { `); } + const activeBorderFocusColor = theme.getColor(ACTIVITY_BAR_ACTIVE_BORDER_FOCUS); + if (activeBorderFocusColor) { + collector.addRule(` + .monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-item.checked:focus::before { + visibility: hidden; + } + + .monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-item.checked:focus .active-item-indicator:before { + visibility: visible; + border-left-color: ${activeBorderFocusColor}; + } + `); + } + const activeBackgroundColor = theme.getColor(ACTIVITY_BAR_ACTIVE_BACKGROUND); if (activeBackgroundColor) { collector.addRule(` diff --git a/src/vs/workbench/common/theme.ts b/src/vs/workbench/common/theme.ts index 81c0439428b66..24a8d2c834599 100644 --- a/src/vs/workbench/common/theme.ts +++ b/src/vs/workbench/common/theme.ts @@ -352,6 +352,12 @@ export const ACTIVITY_BAR_ACTIVE_BORDER = registerColor('activityBar.activeBorde hc: null }, nls.localize('activityBarActiveBorder', "Activity bar border color for the active item. The activity bar is showing on the far left or right and allows to switch between views of the side bar.")); +export const ACTIVITY_BAR_ACTIVE_BORDER_FOCUS = registerColor('activityBar.activeBorderFocus', { + dark: null, + light: null, + hc: null +}, nls.localize('activityBarActiveBorderFocus', "Activity bar focus border color for the active item. The activity bar is showing on the far left or right and allows to switch between views of the side bar.")); + export const ACTIVITY_BAR_ACTIVE_BACKGROUND = registerColor('activityBar.activeBackground', { dark: null, light: null, From 895786b78369cfae75aa59744282ed473b51affa Mon Sep 17 00:00:00 2001 From: Miguel Solorio Date: Tue, 12 Nov 2019 14:21:46 -0800 Subject: [PATCH 150/352] Rename activity bar active focus border color token --- .../browser/parts/activitybar/activitybarActions.ts | 8 ++++---- src/vs/workbench/common/theme.ts | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/vs/workbench/browser/parts/activitybar/activitybarActions.ts b/src/vs/workbench/browser/parts/activitybar/activitybarActions.ts index 3d7e6603cfa70..7041678d9bd09 100644 --- a/src/vs/workbench/browser/parts/activitybar/activitybarActions.ts +++ b/src/vs/workbench/browser/parts/activitybar/activitybarActions.ts @@ -22,7 +22,7 @@ import { ActivityAction, ActivityActionViewItem, ICompositeBar, ICompositeBarCol import { ViewletDescriptor } from 'vs/workbench/browser/viewlet'; import { Extensions as ActionExtensions, IWorkbenchActionRegistry } from 'vs/workbench/common/actions'; import { IActivity } from 'vs/workbench/common/activity'; -import { ACTIVITY_BAR_FOREGROUND, ACTIVITY_BAR_ACTIVE_BORDER, ACTIVITY_BAR_ACTIVE_BORDER_FOCUS, ACTIVITY_BAR_ACTIVE_BACKGROUND } from 'vs/workbench/common/theme'; +import { ACTIVITY_BAR_FOREGROUND, ACTIVITY_BAR_ACTIVE_BORDER, ACTIVITY_BAR_ACTIVE_FOCUS_BORDER, ACTIVITY_BAR_ACTIVE_BACKGROUND } from 'vs/workbench/common/theme'; import { IActivityBarService } from 'vs/workbench/services/activityBar/browser/activityBarService'; import { IWorkbenchLayoutService, Parts } from 'vs/workbench/services/layout/browser/layoutService'; import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet'; @@ -297,8 +297,8 @@ registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => { `); } - const activeBorderFocusColor = theme.getColor(ACTIVITY_BAR_ACTIVE_BORDER_FOCUS); - if (activeBorderFocusColor) { + const activeFocusBorderColor = theme.getColor(ACTIVITY_BAR_ACTIVE_FOCUS_BORDER); + if (activeFocusBorderColor) { collector.addRule(` .monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-item.checked:focus::before { visibility: hidden; @@ -306,7 +306,7 @@ registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => { .monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-item.checked:focus .active-item-indicator:before { visibility: visible; - border-left-color: ${activeBorderFocusColor}; + border-left-color: ${activeFocusBorderColor}; } `); } diff --git a/src/vs/workbench/common/theme.ts b/src/vs/workbench/common/theme.ts index 24a8d2c834599..e465329f6b003 100644 --- a/src/vs/workbench/common/theme.ts +++ b/src/vs/workbench/common/theme.ts @@ -352,11 +352,11 @@ export const ACTIVITY_BAR_ACTIVE_BORDER = registerColor('activityBar.activeBorde hc: null }, nls.localize('activityBarActiveBorder', "Activity bar border color for the active item. The activity bar is showing on the far left or right and allows to switch between views of the side bar.")); -export const ACTIVITY_BAR_ACTIVE_BORDER_FOCUS = registerColor('activityBar.activeBorderFocus', { +export const ACTIVITY_BAR_ACTIVE_FOCUS_BORDER = registerColor('activityBar.activeFocusBorder', { dark: null, light: null, hc: null -}, nls.localize('activityBarActiveBorderFocus', "Activity bar focus border color for the active item. The activity bar is showing on the far left or right and allows to switch between views of the side bar.")); +}, nls.localize('activityBarActiveFocusBorder', "Activity bar focus border color for the active item. The activity bar is showing on the far left or right and allows to switch between views of the side bar.")); export const ACTIVITY_BAR_ACTIVE_BACKGROUND = registerColor('activityBar.activeBackground', { dark: null, From 1f3642a07d8787e014ce6620580866b50cd16585 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Tue, 12 Nov 2019 14:25:53 -0800 Subject: [PATCH 151/352] Add explicit type on experimental fixAll provider For #84602 --- .../typescript-language-features/src/features/fixAll.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/extensions/typescript-language-features/src/features/fixAll.ts b/extensions/typescript-language-features/src/features/fixAll.ts index 8c6f09659c332..d9461442e51df 100644 --- a/extensions/typescript-language-features/src/features/fixAll.ts +++ b/extensions/typescript-language-features/src/features/fixAll.ts @@ -22,8 +22,10 @@ const autoFixableDiagnosticCodes = new Set([ class TypeScriptAutoFixProvider implements vscode.CodeActionProvider { + private static readonly kind = vscode.CodeActionKind.SourceFixAll.append('ts'); + public static readonly metadata: vscode.CodeActionProviderMetadata = { - providedCodeActionKinds: [vscode.CodeActionKind.SourceFixAll] + providedCodeActionKinds: [TypeScriptAutoFixProvider.kind] }; constructor( @@ -82,7 +84,7 @@ class TypeScriptAutoFixProvider implements vscode.CodeActionProvider { const { edit, fixedDiagnostics } = autoFixResponse; const codeAction = new vscode.CodeAction( localize('autoFix.label', 'Auto fix'), - vscode.CodeActionKind.SourceFixAll); + TypeScriptAutoFixProvider.kind); codeAction.edit = edit; codeAction.diagnostics = fixedDiagnostics; From c26325fb469bb445f5b2a8979987bb664aae655f Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Tue, 12 Nov 2019 14:28:32 -0800 Subject: [PATCH 152/352] Support excluding subsets of code actions for codeActionsOnSave Fixes #84602 --- .../editor/contrib/codeAction/codeAction.ts | 4 +-- .../contrib/codeAction/codeActionCommands.ts | 12 +++---- .../editor/contrib/codeAction/codeActionUi.ts | 2 +- .../codeAction/test/codeAction.test.ts | 34 +++++++++++++++---- src/vs/editor/contrib/codeAction/types.ts | 20 ++++++++--- .../editor/contrib/hover/modesContentHover.ts | 2 +- .../api/browser/mainThreadSaveParticipant.ts | 14 +++++--- .../markers/browser/markersTreeViewer.ts | 2 +- 8 files changed, 63 insertions(+), 27 deletions(-) diff --git a/src/vs/editor/contrib/codeAction/codeAction.ts b/src/vs/editor/contrib/codeAction/codeAction.ts index 62c19dcf1501a..2cfc82d83cc24 100644 --- a/src/vs/editor/contrib/codeAction/codeAction.ts +++ b/src/vs/editor/contrib/codeAction/codeAction.ts @@ -66,7 +66,7 @@ export function getCodeActions( const filter = trigger.filter || {}; const codeActionContext: CodeActionContext = { - only: filter.kind?.value, + only: filter.include?.value, trigger: trigger.type === 'manual' ? CodeActionTriggerKind.Manual : CodeActionTriggerKind.Automatic }; @@ -146,7 +146,7 @@ registerLanguageCommand('_executeCodeActionProvider', async function (accessor, const codeActionSet = await getCodeActions( model, validatedRangeOrSelection, - { type: 'manual', filter: { includeSourceActions: true, kind: kind && kind.value ? new CodeActionKind(kind.value) : undefined } }, + { type: 'manual', filter: { includeSourceActions: true, include: kind && kind.value ? new CodeActionKind(kind.value) : undefined } }, CancellationToken.None); setTimeout(() => codeActionSet.dispose(), 100); diff --git a/src/vs/editor/contrib/codeAction/codeActionCommands.ts b/src/vs/editor/contrib/codeAction/codeActionCommands.ts index ba92b4136039a..c555ceec6d6a2 100644 --- a/src/vs/editor/contrib/codeAction/codeActionCommands.ts +++ b/src/vs/editor/contrib/codeAction/codeActionCommands.ts @@ -240,7 +240,7 @@ export class CodeActionCommand extends EditorCommand { ? nls.localize('editor.action.codeAction.noneMessage.preferred', "No preferred code actions available") : nls.localize('editor.action.codeAction.noneMessage', "No code actions available"), { - kind: args.kind, + include: args.kind, includeSourceActions: true, onlyIncludePreferredActions: args.preferred, }, @@ -293,7 +293,7 @@ export class RefactorAction extends EditorAction { ? nls.localize('editor.action.refactor.noneMessage.preferred', "No preferred refactorings available") : nls.localize('editor.action.refactor.noneMessage', "No refactorings available"), { - kind: CodeActionKind.Refactor.contains(args.kind) ? args.kind : CodeActionKind.None, + include: CodeActionKind.Refactor.contains(args.kind) ? args.kind : CodeActionKind.None, onlyIncludePreferredActions: args.preferred, }, args.apply); @@ -336,7 +336,7 @@ export class SourceAction extends EditorAction { ? nls.localize('editor.action.source.noneMessage.preferred', "No preferred source actions available") : nls.localize('editor.action.source.noneMessage', "No source actions available"), { - kind: CodeActionKind.Source.contains(args.kind) ? args.kind : CodeActionKind.None, + include: CodeActionKind.Source.contains(args.kind) ? args.kind : CodeActionKind.None, includeSourceActions: true, onlyIncludePreferredActions: args.preferred, }, @@ -365,7 +365,7 @@ export class OrganizeImportsAction extends EditorAction { public run(_accessor: ServicesAccessor, editor: ICodeEditor): void { return triggerCodeActionsForEditorSelection(editor, nls.localize('editor.action.organize.noneMessage', "No organize imports action available"), - { kind: CodeActionKind.SourceOrganizeImports, includeSourceActions: true }, + { include: CodeActionKind.SourceOrganizeImports, includeSourceActions: true }, CodeActionAutoApply.IfSingle); } } @@ -386,7 +386,7 @@ export class FixAllAction extends EditorAction { public run(_accessor: ServicesAccessor, editor: ICodeEditor): void { return triggerCodeActionsForEditorSelection(editor, nls.localize('fixAll.noneMessage', "No fix all action available"), - { kind: CodeActionKind.SourceFixAll, includeSourceActions: true }, + { include: CodeActionKind.SourceFixAll, includeSourceActions: true }, CodeActionAutoApply.IfSingle); } } @@ -418,7 +418,7 @@ export class AutoFixAction extends EditorAction { return triggerCodeActionsForEditorSelection(editor, nls.localize('editor.action.autoFix.noneMessage', "No auto fixes available"), { - kind: CodeActionKind.QuickFix, + include: CodeActionKind.QuickFix, onlyIncludePreferredActions: true }, CodeActionAutoApply.IfSingle); diff --git a/src/vs/editor/contrib/codeAction/codeActionUi.ts b/src/vs/editor/contrib/codeAction/codeActionUi.ts index 8db5d28fa240e..5dfd9228ff0bc 100644 --- a/src/vs/editor/contrib/codeAction/codeActionUi.ts +++ b/src/vs/editor/contrib/codeAction/codeActionUi.ts @@ -75,7 +75,7 @@ export class CodeActionUi extends Disposable { } if (newState.trigger.type === 'manual') { - if (newState.trigger.filter && newState.trigger.filter.kind) { + if (newState.trigger.filter && newState.trigger.filter.include) { // Triggered for specific scope if (actions.actions.length > 0) { // Apply if we only have one action or requested autoApply diff --git a/src/vs/editor/contrib/codeAction/test/codeAction.test.ts b/src/vs/editor/contrib/codeAction/test/codeAction.test.ts index a85b4a1ea5811..730d96fc9a570 100644 --- a/src/vs/editor/contrib/codeAction/test/codeAction.test.ts +++ b/src/vs/editor/contrib/codeAction/test/codeAction.test.ts @@ -140,20 +140,20 @@ suite('CodeAction', () => { disposables.add(modes.CodeActionProviderRegistry.register('fooLang', provider)); { - const { actions } = await getCodeActions(model, new Range(1, 1, 2, 1), { type: 'auto', filter: { kind: new CodeActionKind('a') } }, CancellationToken.None); + const { actions } = await getCodeActions(model, new Range(1, 1, 2, 1), { type: 'auto', filter: { include: new CodeActionKind('a') } }, CancellationToken.None); assert.equal(actions.length, 2); assert.strictEqual(actions[0].title, 'a'); assert.strictEqual(actions[1].title, 'a.b'); } { - const { actions } = await getCodeActions(model, new Range(1, 1, 2, 1), { type: 'auto', filter: { kind: new CodeActionKind('a.b') } }, CancellationToken.None); + const { actions } = await getCodeActions(model, new Range(1, 1, 2, 1), { type: 'auto', filter: { include: new CodeActionKind('a.b') } }, CancellationToken.None); assert.equal(actions.length, 1); assert.strictEqual(actions[0].title, 'a.b'); } { - const { actions } = await getCodeActions(model, new Range(1, 1, 2, 1), { type: 'auto', filter: { kind: new CodeActionKind('a.b.c') } }, CancellationToken.None); + const { actions } = await getCodeActions(model, new Range(1, 1, 2, 1), { type: 'auto', filter: { include: new CodeActionKind('a.b.c') } }, CancellationToken.None); assert.equal(actions.length, 0); } }); @@ -172,7 +172,7 @@ suite('CodeAction', () => { disposables.add(modes.CodeActionProviderRegistry.register('fooLang', provider)); - const { actions } = await getCodeActions(model, new Range(1, 1, 2, 1), { type: 'auto', filter: { kind: new CodeActionKind('a') } }, CancellationToken.None); + const { actions } = await getCodeActions(model, new Range(1, 1, 2, 1), { type: 'auto', filter: { include: new CodeActionKind('a') } }, CancellationToken.None); assert.equal(actions.length, 1); assert.strictEqual(actions[0].title, 'a'); }); @@ -192,12 +192,34 @@ suite('CodeAction', () => { } { - const { actions } = await getCodeActions(model, new Range(1, 1, 2, 1), { type: 'auto', filter: { kind: CodeActionKind.Source, includeSourceActions: true } }, CancellationToken.None); + const { actions } = await getCodeActions(model, new Range(1, 1, 2, 1), { type: 'auto', filter: { include: CodeActionKind.Source, includeSourceActions: true } }, CancellationToken.None); assert.equal(actions.length, 1); assert.strictEqual(actions[0].title, 'a'); } }); + test('getCodeActions should support filtering out some requested source code actions #84602', async function () { + const provider = staticCodeActionProvider( + { title: 'a', kind: CodeActionKind.Source.value }, + { title: 'b', kind: CodeActionKind.Source.append('test').value }, + { title: 'c', kind: 'c' } + ); + + disposables.add(modes.CodeActionProviderRegistry.register('fooLang', provider)); + + { + const { actions } = await getCodeActions(model, new Range(1, 1, 2, 1), { + type: 'auto', filter: { + include: CodeActionKind.Source.append('test'), + excludes: [CodeActionKind.Source], + includeSourceActions: true, + } + }, CancellationToken.None); + assert.equal(actions.length, 1); + assert.strictEqual(actions[0].title, 'b'); + } + }); + test('getCodeActions should not invoke code action providers filtered out by providedCodeActionKinds', async function () { let wasInvoked = false; const provider = new class implements modes.CodeActionProvider { @@ -214,7 +236,7 @@ suite('CodeAction', () => { const { actions } = await getCodeActions(model, new Range(1, 1, 2, 1), { type: 'auto', filter: { - kind: CodeActionKind.QuickFix + include: CodeActionKind.QuickFix } }, CancellationToken.None); assert.strictEqual(actions.length, 0); diff --git a/src/vs/editor/contrib/codeAction/types.ts b/src/vs/editor/contrib/codeAction/types.ts index ffbf8bbe94db6..650be89e98c72 100644 --- a/src/vs/editor/contrib/codeAction/types.ts +++ b/src/vs/editor/contrib/codeAction/types.ts @@ -46,19 +46,20 @@ export const enum CodeActionAutoApply { } export interface CodeActionFilter { - readonly kind?: CodeActionKind; + readonly include?: CodeActionKind; + readonly excludes?: readonly CodeActionKind[]; readonly includeSourceActions?: boolean; readonly onlyIncludePreferredActions?: boolean; } export function mayIncludeActionsOfKind(filter: CodeActionFilter, providedKind: CodeActionKind): boolean { // A provided kind may be a subset or superset of our filtered kind. - if (filter.kind && !filter.kind.intersects(providedKind)) { + if (filter.include && !filter.include.intersects(providedKind)) { return false; } // Don't return source actions unless they are explicitly requested - if (CodeActionKind.Source.contains(providedKind) && !filter.includeSourceActions) { + if (!filter.includeSourceActions && CodeActionKind.Source.contains(providedKind)) { return false; } @@ -69,8 +70,17 @@ export function filtersAction(filter: CodeActionFilter, action: CodeAction): boo const actionKind = action.kind ? new CodeActionKind(action.kind) : undefined; // Filter out actions by kind - if (filter.kind) { - if (!actionKind || !filter.kind.contains(actionKind)) { + if (filter.include) { + if (!actionKind || !filter.include.contains(actionKind)) { + return false; + } + } + + if (filter.excludes) { + if (actionKind && filter.excludes.some(exclude => { + // Excludes are overwritten by includes + return exclude.contains(actionKind) && (!filter.include || !filter.include.contains(actionKind)); + })) { return false; } } diff --git a/src/vs/editor/contrib/hover/modesContentHover.ts b/src/vs/editor/contrib/hover/modesContentHover.ts index 4efa784f4beaf..f37254d776f34 100644 --- a/src/vs/editor/contrib/hover/modesContentHover.ts +++ b/src/vs/editor/contrib/hover/modesContentHover.ts @@ -586,7 +586,7 @@ export class ModesContentHoverWidget extends ContentHoverWidget { return getCodeActions( this._editor.getModel()!, new Range(marker.startLineNumber, marker.startColumn, marker.endLineNumber, marker.endColumn), - { type: 'manual', filter: { kind: CodeActionKind.QuickFix } }, + { type: 'manual', filter: { include: CodeActionKind.QuickFix } }, cancellationToken); }); } diff --git a/src/vs/workbench/api/browser/mainThreadSaveParticipant.ts b/src/vs/workbench/api/browser/mainThreadSaveParticipant.ts index 5fdd5b7c95190..3e79332f086b5 100644 --- a/src/vs/workbench/api/browser/mainThreadSaveParticipant.ts +++ b/src/vs/workbench/api/browser/mainThreadSaveParticipant.ts @@ -282,6 +282,10 @@ class CodeActionOnSaveParticipant implements ISaveParticipant { return undefined; } + const excludedActions = Object.keys(setting) + .filter(x => setting[x] === false) + .map(x => new CodeActionKind(x)); + const tokenSource = new CancellationTokenSource(); const timeout = this._configurationService.getValue('editor.codeActionsOnSaveTimeout', settingsOverrides); @@ -292,15 +296,15 @@ class CodeActionOnSaveParticipant implements ISaveParticipant { tokenSource.cancel(); reject(localize('codeActionsOnSave.didTimeout', "Aborted codeActionsOnSave after {0}ms", timeout)); }, timeout)), - this.applyOnSaveActions(model, codeActionsOnSave, tokenSource.token) + this.applyOnSaveActions(model, codeActionsOnSave, excludedActions, tokenSource.token) ]).finally(() => { tokenSource.cancel(); }); } - private async applyOnSaveActions(model: ITextModel, codeActionsOnSave: CodeActionKind[], token: CancellationToken): Promise { + private async applyOnSaveActions(model: ITextModel, codeActionsOnSave: readonly CodeActionKind[], excludes: readonly CodeActionKind[], token: CancellationToken): Promise { for (const codeActionKind of codeActionsOnSave) { - const actionsToRun = await this.getActionsToRun(model, codeActionKind, token); + const actionsToRun = await this.getActionsToRun(model, codeActionKind, excludes, token); try { await this.applyCodeActions(actionsToRun.actions); } catch { @@ -317,10 +321,10 @@ class CodeActionOnSaveParticipant implements ISaveParticipant { } } - private getActionsToRun(model: ITextModel, codeActionKind: CodeActionKind, token: CancellationToken) { + private getActionsToRun(model: ITextModel, codeActionKind: CodeActionKind, excludes: readonly CodeActionKind[], token: CancellationToken) { return getCodeActions(model, model.getFullModelRange(), { type: 'auto', - filter: { kind: codeActionKind, includeSourceActions: true }, + filter: { include: codeActionKind, excludes: excludes, includeSourceActions: true }, }, token); } } diff --git a/src/vs/workbench/contrib/markers/browser/markersTreeViewer.ts b/src/vs/workbench/contrib/markers/browser/markersTreeViewer.ts index c085096f8227f..2201cbe11d0cb 100644 --- a/src/vs/workbench/contrib/markers/browser/markersTreeViewer.ts +++ b/src/vs/workbench/contrib/markers/browser/markersTreeViewer.ts @@ -551,7 +551,7 @@ export class MarkerViewModel extends Disposable { if (model) { if (!this.codeActionsPromise) { this.codeActionsPromise = createCancelablePromise(cancellationToken => { - return getCodeActions(model, new Range(this.marker.range.startLineNumber, this.marker.range.startColumn, this.marker.range.endLineNumber, this.marker.range.endColumn), { type: 'manual', filter: { kind: CodeActionKind.QuickFix } }, cancellationToken).then(actions => { + return getCodeActions(model, new Range(this.marker.range.startLineNumber, this.marker.range.startColumn, this.marker.range.endLineNumber, this.marker.range.endColumn), { type: 'manual', filter: { include: CodeActionKind.QuickFix } }, cancellationToken).then(actions => { return this._register(actions); }); }); From f50c8264faa909634836e8afb5d3d36814c6f91e Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Tue, 12 Nov 2019 14:36:22 -0800 Subject: [PATCH 153/352] Don't try rendering TGAs in the built-in image preview Fixes #84533 Looks like tga is not currently supported by Chrome --- extensions/image-preview/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/image-preview/package.json b/extensions/image-preview/package.json index c6149de85decc..ea7927fd6127a 100644 --- a/extensions/image-preview/package.json +++ b/extensions/image-preview/package.json @@ -29,7 +29,7 @@ "priority": "builtin", "selector": [ { - "filenamePattern": "*.{jpg,jpe,jpeg,png,bmp,gif,ico,tga,webp}", + "filenamePattern": "*.{jpg,jpe,jpeg,png,bmp,gif,ico,webp}", "mime": "image/*" } ] From 6eaef4bdc62843cd893450782406a58a42b7d19b Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Wed, 13 Nov 2019 00:19:57 +0100 Subject: [PATCH 154/352] revert changes - use setting for enabling the feature --- .../browser/parts/editor/editorStatus.ts | 62 +++---------------- .../markers/browser/markers.contribution.ts | 5 ++ 2 files changed, 12 insertions(+), 55 deletions(-) diff --git a/src/vs/workbench/browser/parts/editor/editorStatus.ts b/src/vs/workbench/browser/parts/editor/editorStatus.ts index f2f5d2462c7a6..71ac2878d4eeb 100644 --- a/src/vs/workbench/browser/parts/editor/editorStatus.ts +++ b/src/vs/workbench/browser/parts/editor/editorStatus.ts @@ -52,9 +52,6 @@ import { IWorkbenchContribution } from 'vs/workbench/common/contributions'; import { IStatusbarEntryAccessor, IStatusbarService, StatusbarAlignment, IStatusbarEntry } from 'vs/workbench/services/statusbar/common/statusbar'; import { IMarker, IMarkerService, MarkerSeverity, IMarkerData } from 'vs/platform/markers/common/markers'; import { find } from 'vs/base/common/arrays'; -import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; -import { IContextKey, RawContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; -import { MenuRegistry, MenuId } from 'vs/platform/actions/common/actions'; class SideBySideEditorEncodingSupport implements IEncodingSupport { constructor(private master: IEncodingSupport, private details: IEncodingSupport) { } @@ -834,61 +831,22 @@ export class EditorStatus extends Disposable implements IWorkbenchContribution { } } -const CONTEXT_CURRENT_MARKER = new RawContextKey('hasActiveProblem', false); - class ShowCurrentMarkerInStatusbarContribution extends Disposable { - private static readonly INITIAL_STATE_KEY = 'statusbar.currentProblem.initialState'; - private static readonly STATUSBAR_ENTRY_ID = 'statusbar.currentProblem'; - private readonly statusBarEntryAccessor: MutableDisposable; private editor: ICodeEditor | undefined = undefined; private markers: IMarker[] = []; private currentMarker: IMarker | null = null; - private showByDefault: boolean = false; - - private currentMarkerContextKey: IContextKey; constructor( @IStatusbarService private readonly statusbarService: IStatusbarService, @IMarkerService private readonly markerService: IMarkerService, - @IStorageService private readonly storageService: IStorageService, - @IContextKeyService contextKeyService: IContextKeyService, + @IConfigurationService private readonly configurationService: IConfigurationService, ) { super(); this.statusBarEntryAccessor = this._register(new MutableDisposable()); - this.currentMarkerContextKey = CONTEXT_CURRENT_MARKER.bindTo(contextKeyService); - - this.registerListeners(); - this.registerCommand(); - } - - private registerListeners(): void { - this._register(this.markerService.onMarkerChanged(changedResources => this.onMarkerChanged(changedResources))); - - this.showByDefault = this.storageService.getBoolean(ShowCurrentMarkerInStatusbarContribution.INITIAL_STATE_KEY, StorageScope.GLOBAL, false); - this._register(Event.filter(this.statusbarService.onDidChangeEntryVisibility, e => e.id === ShowCurrentMarkerInStatusbarContribution.STATUSBAR_ENTRY_ID && e.visible)(() => { - this.showByDefault = true; - this.storageService.store(ShowCurrentMarkerInStatusbarContribution.INITIAL_STATE_KEY, true, StorageScope.GLOBAL); - })); - this._register(Event.filter(this.storageService.onDidChangeStorage, e => e.key === ShowCurrentMarkerInStatusbarContribution.INITIAL_STATE_KEY && e.scope === StorageScope.GLOBAL)(() => { - this.showByDefault = this.storageService.getBoolean(ShowCurrentMarkerInStatusbarContribution.INITIAL_STATE_KEY, StorageScope.GLOBAL, false); - })); - } - - private registerCommand(): void { - CommandsRegistry.registerCommand('statusbar.showCurrentProblem', () => { - this.showByDefault = true; - this.updateStatus(); - this.statusbarService.updateEntryVisibility(ShowCurrentMarkerInStatusbarContribution.STATUSBAR_ENTRY_ID, true); - }); - MenuRegistry.appendMenuItem(MenuId.CommandPalette, { - command: { - id: 'statusbar.showCurrentProblem', - title: nls.localize('show current problem in status', "Show Current Problem in Status Bar") - }, - when: CONTEXT_CURRENT_MARKER - }); + this._register(markerService.onMarkerChanged(changedResources => this.onMarkerChanged(changedResources))); + this._register(Event.filter(configurationService.onDidChangeConfiguration, e => e.affectsConfiguration('problems.showCurrentInStatus'))(() => this.updateStatus())); } update(editor: ICodeEditor | undefined): void { @@ -899,13 +857,12 @@ class ShowCurrentMarkerInStatusbarContribution extends Disposable { private updateStatus(): void { const previousMarker = this.currentMarker; this.currentMarker = this.getMarker(); - this.currentMarkerContextKey.set(!!this.currentMarker); if (this.hasToUpdateStatus(previousMarker, this.currentMarker)) { if (this.currentMarker) { const line = this.currentMarker.message.split(/\r\n|\r|\n/g)[0]; const text = `${this.getType(this.currentMarker)} ${line}`; if (!this.statusBarEntryAccessor.value) { - this.statusBarEntryAccessor.value = this.createStatusbarEntry(); + this.statusBarEntryAccessor.value = this.statusbarService.addEntry({ text: '' }, 'statusbar.currentProblem', nls.localize('currentProblem', "Current Problem"), StatusbarAlignment.LEFT); } this.statusBarEntryAccessor.value.update({ text }); } else { @@ -914,14 +871,6 @@ class ShowCurrentMarkerInStatusbarContribution extends Disposable { } } - private createStatusbarEntry(): IStatusbarEntryAccessor { - const entry = this.statusbarService.addEntry({ text: '' }, ShowCurrentMarkerInStatusbarContribution.STATUSBAR_ENTRY_ID, nls.localize('currentProblem', "Current Problem"), StatusbarAlignment.LEFT); - if (!this.showByDefault) { - this.statusbarService.updateEntryVisibility(ShowCurrentMarkerInStatusbarContribution.STATUSBAR_ENTRY_ID, false); - } - return entry; - } - private hasToUpdateStatus(previousMarker: IMarker | null, currentMarker: IMarker | null): boolean { if (!currentMarker) { return true; @@ -942,6 +891,9 @@ class ShowCurrentMarkerInStatusbarContribution extends Disposable { } private getMarker(): IMarker | null { + if (!this.configurationService.getValue('problems.showCurrentInStatus')) { + return null; + } if (!this.editor) { return null; } diff --git a/src/vs/workbench/contrib/markers/browser/markers.contribution.ts b/src/vs/workbench/contrib/markers/browser/markers.contribution.ts index e08a13a559ffa..578642134276a 100644 --- a/src/vs/workbench/contrib/markers/browser/markers.contribution.ts +++ b/src/vs/workbench/contrib/markers/browser/markers.contribution.ts @@ -81,6 +81,11 @@ Registry.as(Extensions.Configuration).registerConfigurat 'description': Messages.PROBLEMS_PANEL_CONFIGURATION_AUTO_REVEAL, 'type': 'boolean', 'default': true + }, + 'problems.showCurrentInStatus': { + 'description': Messages.PROBLEMS_PANEL_CONFIGURATION_SHOW_CURRENT_STATUS, + 'type': 'boolean', + 'default': false } } }); From cc7038cdffecfcf437d3e6eb06e9c991afc9237f Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Wed, 13 Nov 2019 00:21:07 +0100 Subject: [PATCH 155/352] feedback --- src/vs/workbench/browser/parts/statusbar/statusbarPart.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/browser/parts/statusbar/statusbarPart.ts b/src/vs/workbench/browser/parts/statusbar/statusbarPart.ts index 0b8e947e35d30..3fe32716b3018 100644 --- a/src/vs/workbench/browser/parts/statusbar/statusbarPart.ts +++ b/src/vs/workbench/browser/parts/statusbar/statusbarPart.ts @@ -61,8 +61,8 @@ class StatusbarViewModel extends Disposable { private hidden!: Set; - private readonly _onDidChangeEntryVisibility: Emitter<{ id: string, visible: boolean }> = this._register(new Emitter<{ id: string, visible: boolean }>()); - readonly onDidChangeEntryVisibility: Event<{ id: string, visible: boolean }> = this._onDidChangeEntryVisibility.event; + private readonly _onDidChangeEntryVisibility = this._register(new Emitter<{ id: string, visible: boolean }>()); + readonly onDidChangeEntryVisibility = this._onDidChangeEntryVisibility.event; constructor(private storageService: IStorageService) { super(); From cfbf6b58f68bed5dab2b96c5de37ad64c3c20532 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Tue, 12 Nov 2019 15:41:41 -0800 Subject: [PATCH 156/352] Better fix for disabling pinch to zoom in a webview zooming the entire editor in chrome Fixes #84406 --- extensions/image-preview/media/main.js | 10 ++++++---- extensions/image-preview/src/preview.ts | 7 +++++-- .../workbench/contrib/webview/browser/pre/index.html | 3 +++ 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/extensions/image-preview/media/main.js b/extensions/image-preview/media/main.js index a657ca04e4025..bc1e25a4bdf61 100644 --- a/extensions/image-preview/media/main.js +++ b/extensions/image-preview/media/main.js @@ -241,7 +241,11 @@ }); container.addEventListener('wheel', (/** @type {WheelEvent} */ e) => { - e.preventDefault(); + // Prevent pinch to zoom + if (e.ctrlKey) { + e.preventDefault(); + } + if (!image || !hasLoadedImage) { return; } @@ -260,8 +264,6 @@ }, { passive: false }); window.addEventListener('scroll', e => { - e.preventDefault(); - if (!image || !hasLoadedImage || !image.parentElement || scale === 'fit') { return; } @@ -270,7 +272,7 @@ if (entry) { vscode.setState({ scale: entry.scale, offsetX: window.scrollX, offsetY: window.scrollY }); } - }, { passive: false }); + }, { passive: true }); container.classList.add('image'); diff --git a/extensions/image-preview/src/preview.ts b/extensions/image-preview/src/preview.ts index 7b859877304b8..962ea5e48664f 100644 --- a/extensions/image-preview/src/preview.ts +++ b/extensions/image-preview/src/preview.ts @@ -203,8 +203,11 @@ class Preview extends Disposable { - - + + + + Image Preview diff --git a/src/vs/workbench/contrib/webview/browser/pre/index.html b/src/vs/workbench/contrib/webview/browser/pre/index.html index f4ed42759569d..d142be649a6e5 100644 --- a/src/vs/workbench/contrib/webview/browser/pre/index.html +++ b/src/vs/workbench/contrib/webview/browser/pre/index.html @@ -3,8 +3,11 @@ + + + Virtual Document From 0fcc0aa84cd1aa2191881d068f094f884ef46e58 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Tue, 12 Nov 2019 15:41:55 -0800 Subject: [PATCH 157/352] Update webview fallback versions --- .../services/environment/browser/environmentService.ts | 2 +- .../services/environment/electron-browser/environmentService.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/services/environment/browser/environmentService.ts b/src/vs/workbench/services/environment/browser/environmentService.ts index 5437e4c00caaa..bdbed598a7738 100644 --- a/src/vs/workbench/services/environment/browser/environmentService.ts +++ b/src/vs/workbench/services/environment/browser/environmentService.ts @@ -187,7 +187,7 @@ export class BrowserWorkbenchEnvironmentService implements IWorkbenchEnvironment @memoize get webviewExternalEndpoint(): string { // TODO: get fallback from product.json - return (this.options.webviewEndpoint || 'https://{{uuid}}.vscode-webview-test.com/{{commit}}').replace('{{commit}}', product.commit || 'b53811e67e65c6a564a80e1c412ca2b13de02907'); + return (this.options.webviewEndpoint || 'https://{{uuid}}.vscode-webview-test.com/{{commit}}').replace('{{commit}}', product.commit || '0d728c31ebdf03869d2687d9be0b017667c9ff37'); } @memoize diff --git a/src/vs/workbench/services/environment/electron-browser/environmentService.ts b/src/vs/workbench/services/environment/electron-browser/environmentService.ts index 903c6457566d0..8d32aff4ee6c9 100644 --- a/src/vs/workbench/services/environment/electron-browser/environmentService.ts +++ b/src/vs/workbench/services/environment/electron-browser/environmentService.ts @@ -21,7 +21,7 @@ export class NativeWorkbenchEnvironmentService extends EnvironmentService implem get webviewExternalEndpoint(): string { const baseEndpoint = 'https://{{uuid}}.vscode-webview-test.com/{{commit}}'; - return baseEndpoint.replace('{{commit}}', product.commit || 'b53811e67e65c6a564a80e1c412ca2b13de02907'); + return baseEndpoint.replace('{{commit}}', product.commit || '0d728c31ebdf03869d2687d9be0b017667c9ff37'); } @memoize From 7e71822af36067e3671412783d551e932b6d2a5d Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Tue, 12 Nov 2019 15:54:32 -0800 Subject: [PATCH 158/352] Hook up CustomEditorModel to workingCopyService --- .../api/browser/mainThreadWebview.ts | 6 ++-- .../customEditor/browser/customEditorModel.ts | 32 ++++++++++++++++--- 2 files changed, 31 insertions(+), 7 deletions(-) diff --git a/src/vs/workbench/api/browser/mainThreadWebview.ts b/src/vs/workbench/api/browser/mainThreadWebview.ts index 5056c3feb6194..29b532253ec42 100644 --- a/src/vs/workbench/api/browser/mainThreadWebview.ts +++ b/src/vs/workbench/api/browser/mainThreadWebview.ts @@ -12,6 +12,7 @@ import { URI, UriComponents } from 'vs/base/common/uri'; import * as modes from 'vs/editor/common/modes'; import { localize } from 'vs/nls'; import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions'; +import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IOpenerService } from 'vs/platform/opener/common/opener'; import { IProductService } from 'vs/platform/product/common/productService'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; @@ -20,6 +21,7 @@ import { editorGroupToViewColumn, EditorViewColumn, viewColumnToEditorGroup } fr import { IEditorInput } from 'vs/workbench/common/editor'; import { DiffEditorInput } from 'vs/workbench/common/editor/diffEditorInput'; import { CustomFileEditorInput } from 'vs/workbench/contrib/customEditor/browser/customEditorInput'; +import { CustomEditorModel } from 'vs/workbench/contrib/customEditor/browser/customEditorModel'; import { WebviewExtensionDescription } from 'vs/workbench/contrib/webview/browser/webview'; import { WebviewInput } from 'vs/workbench/contrib/webview/browser/webviewEditorInput'; import { ICreateWebViewShowOptions, IWebviewWorkbenchService, WebviewInputOptions } from 'vs/workbench/contrib/webview/browser/webviewWorkbenchService'; @@ -27,7 +29,6 @@ import { IEditorGroup, IEditorGroupsService } from 'vs/workbench/services/editor import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; import { extHostNamedCustomer } from '../common/extHostCustomers'; -import { CustomEditorModel } from 'vs/workbench/contrib/customEditor/browser/customEditorModel'; /** * Bi-directional map between webview handles and inputs. @@ -102,6 +103,7 @@ export class MainThreadWebviews extends Disposable implements extHostProtocol.Ma @IExtensionService extensionService: IExtensionService, @IEditorGroupsService private readonly _editorGroupService: IEditorGroupsService, @IEditorService private readonly _editorService: IEditorService, + @IInstantiationService private readonly _instantiationService: IInstantiationService, @IOpenerService private readonly _openerService: IOpenerService, @IProductService private readonly _productService: IProductService, @ITelemetryService private readonly _telemetryService: ITelemetryService, @@ -271,7 +273,7 @@ export class MainThreadWebviews extends Disposable implements extHostProtocol.Ma webviewInput.webview.options = options; webviewInput.webview.extension = extension; - const model = new CustomEditorModel(); + const model = this._instantiationService.createInstance(CustomEditorModel, webviewInput.getResource()); webviewInput.setModel(model); this._models.set(handle, model); diff --git a/src/vs/workbench/contrib/customEditor/browser/customEditorModel.ts b/src/vs/workbench/contrib/customEditor/browser/customEditorModel.ts index 003630bf19dff..4afe96cdc35dd 100644 --- a/src/vs/workbench/contrib/customEditor/browser/customEditorModel.ts +++ b/src/vs/workbench/contrib/customEditor/browser/customEditorModel.ts @@ -5,18 +5,44 @@ import { Emitter, Event } from 'vs/base/common/event'; import { Disposable } from 'vs/base/common/lifecycle'; +import { URI } from 'vs/base/common/uri'; +import { IWorkingCopy, IWorkingCopyService, WorkingCopyCapabilities } from 'vs/workbench/services/workingCopy/common/workingCopyService'; type Edit = string; -export class CustomEditorModel extends Disposable { +export class CustomEditorModel extends Disposable implements IWorkingCopy { private _currentEditIndex: number = 0; private _savePoint: number = -1; private _edits: Array = []; + constructor( + private readonly _resource: URI, + @IWorkingCopyService private readonly _workingCopyService: IWorkingCopyService, + ) { + super(); + this._register(this._workingCopyService.registerWorkingCopy(this)); + } + + //#region IWorkingCopy + + public get resource() { + return this._resource; + } + + public get capabilities(): WorkingCopyCapabilities { + return 0; + } + + public isDirty(): boolean { + return this._edits.length > 0 && this._savePoint !== this._edits.length; + } + protected readonly _onDidChangeDirty: Emitter = this._register(new Emitter()); readonly onDidChangeDirty: Event = this._onDidChangeDirty.event; + //#endregion + protected readonly _onUndo: Emitter = this._register(new Emitter()); readonly onUndo: Event = this._onUndo.event; @@ -26,10 +52,6 @@ export class CustomEditorModel extends Disposable { this.updateDirty(); } - public isDirty(): boolean { - return this._edits.length > 0 && this._savePoint !== this._edits.length; - } - private updateDirty() { this._onDidChangeDirty.fire(); } From 06a48362f3eeea3c053a98c6c335c4fb5fd8991a Mon Sep 17 00:00:00 2001 From: Rachel Macfarlane Date: Tue, 12 Nov 2019 16:00:17 -0800 Subject: [PATCH 159/352] Replace typings file for windows-process-tree with @types module --- build/npm/postinstall.js | 7 --- package.json | 1 + src/typings/windows-process-tree.d.ts | 63 --------------------------- yarn.lock | 5 +++ 4 files changed, 6 insertions(+), 70 deletions(-) delete mode 100644 src/typings/windows-process-tree.d.ts diff --git a/build/npm/postinstall.js b/build/npm/postinstall.js index e89344d9139e5..83e31e8b85315 100644 --- a/build/npm/postinstall.js +++ b/build/npm/postinstall.js @@ -73,10 +73,3 @@ yarnInstall(`build`); // node modules required for build yarnInstall('test/automation'); // node modules required for smoketest yarnInstall('test/smoke'); // node modules required for smoketest yarnInstallBuildDependencies(); // node modules for watching, specific to host node version, not electron - -// Remove the windows process tree typings as this causes duplicate identifier errors in tsc builds -const processTreeDts = path.join('node_modules', 'windows-process-tree', 'typings', 'windows-process-tree.d.ts'); -if (fs.existsSync(processTreeDts)) { - console.log('Removing windows-process-tree.d.ts'); - fs.unlinkSync(processTreeDts); -} diff --git a/package.json b/package.json index 51c1dc12a7a18..ba04b1cf11b30 100644 --- a/package.json +++ b/package.json @@ -74,6 +74,7 @@ "@types/sinon": "^1.16.36", "@types/webpack": "^4.4.10", "@types/windows-foreground-love": "^0.3.0", + "@types/windows-process-tree": "^0.2.0", "@types/winreg": "^1.2.30", "@types/yauzl": "^2.9.1", "@types/yazl": "^2.4.2", diff --git a/src/typings/windows-process-tree.d.ts b/src/typings/windows-process-tree.d.ts deleted file mode 100644 index b9db4ea76a84e..0000000000000 --- a/src/typings/windows-process-tree.d.ts +++ /dev/null @@ -1,63 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -declare module 'windows-process-tree' { - export enum ProcessDataFlag { - None = 0, - Memory = 1, - CommandLine = 2 - } - - export interface IProcessInfo { - pid: number; - ppid: number; - name: string; - - /** - * The working set size of the process, in bytes. - */ - memory?: number; - - /** - * The string returned is at most 512 chars, strings exceeding this length are truncated. - */ - commandLine?: string; - } - - export interface IProcessCpuInfo extends IProcessInfo { - cpu?: number; - } - - export interface IProcessTreeNode { - pid: number; - name: string; - memory?: number; - commandLine?: string; - children: IProcessTreeNode[]; - } - - /** - * Returns a tree of processes with the rootPid process as the root. - * @param rootPid - The pid of the process that will be the root of the tree. - * @param callback - The callback to use with the returned list of processes. - * @param flags - The flags for what process data should be included. - */ - export function getProcessTree(rootPid: number, callback: (tree: IProcessTreeNode) => void, flags?: ProcessDataFlag): void; - - /** - * Returns a list of processes containing the rootPid process and all of its descendants. - * @param rootPid - The pid of the process of interest. - * @param callback - The callback to use with the returned set of processes. - * @param flags - The flags for what process data should be included. - */ - export function getProcessList(rootPid: number, callback: (processList: IProcessInfo[]) => void, flags?: ProcessDataFlag): void; - - /** - * Returns the list of processes annotated with cpu usage information. - * @param processList - The list of processes. - * @param callback - The callback to use with the returned list of processes. - */ - export function getProcessCpuUsage(processList: IProcessInfo[], callback: (processListWithCpu: IProcessCpuInfo[]) => void): void; -} diff --git a/yarn.lock b/yarn.lock index 3f00734e764dd..25111e8c9c3b4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -209,6 +209,11 @@ resolved "https://registry.yarnpkg.com/@types/windows-foreground-love/-/windows-foreground-love-0.3.0.tgz#26bc230b2568aa7ab7c56d35bb5653c0a6965a42" integrity sha512-tFUVA/fiofNqOh6lZlymvQiQYPY+cZXZPR9mn9wN6/KS8uwx0zgH4Ij/jmFyRYr+x+DGZWEIeknS2BMi7FZJAQ== +"@types/windows-process-tree@^0.2.0": + version "0.2.0" + resolved "https://registry.yarnpkg.com/@types/windows-process-tree/-/windows-process-tree-0.2.0.tgz#2fa205c838a8ef0a07697cd747c954653978d22c" + integrity sha512-vQAnkWpMX4HUPjubkxKta4Rfh2EDy2ksalnr37gFHNrmk+uxx50PRH+/fM5nTsEBCi4ESFT/7t7Za3jGqyTZ4g== + "@types/winreg@^1.2.30": version "1.2.30" resolved "https://registry.yarnpkg.com/@types/winreg/-/winreg-1.2.30.tgz#91d6710e536d345b9c9b017c574cf6a8da64c518" From 60f8583d951810aad7ba4384edf2ca2712e93dbc Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Tue, 12 Nov 2019 16:07:45 -0800 Subject: [PATCH 160/352] Adding setting to enable a test command for making a fake "edit" to an image preview This will be use for testing custom editors --- extensions/image-preview/package.json | 10 ++++++++ extensions/image-preview/src/extension.ts | 15 ++++++++++++ extensions/image-preview/src/preview.ts | 29 ++++++++++++++++------- 3 files changed, 45 insertions(+), 9 deletions(-) diff --git a/extensions/image-preview/package.json b/extensions/image-preview/package.json index ea7927fd6127a..1ad08ffa55e9d 100644 --- a/extensions/image-preview/package.json +++ b/extensions/image-preview/package.json @@ -45,6 +45,11 @@ "command": "imagePreview.zoomOut", "title": "%command.zoomOut%", "category": "Image Preview" + }, + { + "command": "imagePreview.testing.makeEdit", + "title": "Make test edit", + "category": "Image Preview" } ], "menus": { @@ -58,6 +63,11 @@ "command": "imagePreview.zoomOut", "when": "imagePreviewFocus", "group": "1_imagePreview" + }, + { + "command": "imagePreview.testing.makeEdit", + "when": "imagePreviewTestMode", + "group": "1_imagePreview" } ] } diff --git a/extensions/image-preview/src/extension.ts b/extensions/image-preview/src/extension.ts index 81e2451e35b1b..49563c75ee561 100644 --- a/extensions/image-preview/src/extension.ts +++ b/extensions/image-preview/src/extension.ts @@ -34,5 +34,20 @@ export function activate(context: vscode.ExtensionContext) { context.subscriptions.push(vscode.commands.registerCommand('imagePreview.zoomOut', () => { previewManager.activePreview?.zoomOut(); })); + + context.subscriptions.push(vscode.commands.registerCommand('imagePreview.testing.makeEdit', () => { + previewManager.activePreview?.test_makeEdit(); + })); + + context.subscriptions.push(vscode.workspace.onDidChangeConfiguration(e => { + if (e.affectsConfiguration('imagePreview.customEditorTestMode')) { + updateTestMode(); + } + })); + updateTestMode(); } +function updateTestMode() { + const isInTestMode = vscode.workspace.getConfiguration('imagePreview').get('customEditorTestMode', false); + vscode.commands.executeCommand('setContext', 'imagePreviewTestMode', isInTestMode); +} diff --git a/extensions/image-preview/src/preview.ts b/extensions/image-preview/src/preview.ts index 962ea5e48664f..8aa6d1fe395d7 100644 --- a/extensions/image-preview/src/preview.ts +++ b/extensions/image-preview/src/preview.ts @@ -43,15 +43,8 @@ export class PreviewManager { } }); - const onEdit = new vscode.EventEmitter<{ now: number }>(); return { - editingCapability: { - onEdit: onEdit.event, - save: async () => { }, - hotExit: async () => { }, - applyEdits: async () => { }, - undoEdits: async (edits) => { console.log('undo', edits); }, - } + editingCapability: preview }; } @@ -73,7 +66,7 @@ const enum PreviewState { Active, } -class Preview extends Disposable { +class Preview extends Disposable implements vscode.WebviewEditorEditingCapability { private readonly id: string = `${Date.now()}-${Math.random().toString()}`; @@ -246,6 +239,24 @@ class Preview extends Disposable { path: this.extensionRoot.path + path })); } + + //#region WebviewEditorCapabilities + private readonly _onEdit = this._register(new vscode.EventEmitter<{ now: number }>()); + public readonly onEdit = this._onEdit.event; + + async save() { } + + async hotExit() { } + + async applyEdits(_edits: any[]) { } + + async undoEdits(edits: any[]) { console.log('undo', edits); } + + //#endregion + + public test_makeEdit() { + this._onEdit.fire({ now: Date.now() }); + } } function escapeAttribute(value: string | vscode.Uri): string { From 96f2f3d66f4ba3cd81a7d4def60a32b3effa48d7 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Tue, 12 Nov 2019 16:45:12 -0800 Subject: [PATCH 161/352] Remove jsdoc markdown injections New extension offers a replacement: https://marketplace.visualstudio.com/items?itemName=bierner.jsdoc-markdown-highlighting --- extensions/typescript-basics/package.json | 16 ------ .../jsdoc.js.injection.tmLanguage.json | 54 ------------------- .../jsdoc.ts.injection.tmLanguage.json | 54 ------------------- 3 files changed, 124 deletions(-) delete mode 100644 extensions/typescript-basics/syntaxes/jsdoc.js.injection.tmLanguage.json delete mode 100644 extensions/typescript-basics/syntaxes/jsdoc.ts.injection.tmLanguage.json diff --git a/extensions/typescript-basics/package.json b/extensions/typescript-basics/package.json index 6fb73d06a9d05..307958534b9b0 100644 --- a/extensions/typescript-basics/package.json +++ b/extensions/typescript-basics/package.json @@ -77,22 +77,6 @@ "meta.import string.quoted": "other", "variable.other.jsdoc": "other" } - }, - { - "scopeName": "documentation.injection.ts", - "path": "./syntaxes/jsdoc.ts.injection.tmLanguage.json", - "injectTo": [ - "source.ts", - "source.tsx" - ] - }, - { - "scopeName": "documentation.injection.js.jsx", - "path": "./syntaxes/jsdoc.js.injection.tmLanguage.json", - "injectTo": [ - "source.js", - "source.js.jsx" - ] } ], "snippets": [ diff --git a/extensions/typescript-basics/syntaxes/jsdoc.js.injection.tmLanguage.json b/extensions/typescript-basics/syntaxes/jsdoc.js.injection.tmLanguage.json deleted file mode 100644 index cef9f49ff36fa..0000000000000 --- a/extensions/typescript-basics/syntaxes/jsdoc.js.injection.tmLanguage.json +++ /dev/null @@ -1,54 +0,0 @@ - -{ - "injectionSelector": "L:comment.block.documentation", - "patterns": [ - { - "include": "#jsdocbody" - } - ], - "repository": { - "jsdocbody": { - "begin": "(?<=/\\*\\*)([^*]|\\*(?!/))*$", - "while": "(^|\\G)\\s*\\*(?!/)(?=([^*]|[*](?!/))*$)", - "patterns": [ - { - "include": "text.html.markdown#fenced_code_block_js" - }, - { - "include": "text.html.markdown#fenced_code_block_ts" - }, - { - "include": "text.html.markdown#fenced_code_block_unknown" - }, - { - "include": "#example" - }, - { - "include": "source.ts#docblock" - }, - { - "include": "text.html.markdown#inline" - } - ] - }, - "example": { - "begin": "((@)example)\\s+(?=([^*]|[*](?!/))*$).*$", - "while": "(^|\\G)\\s(?!@)(?=([^*]|[*](?!/))*$)", - "beginCaptures": { - "1": { - "name": "storage.type.class.jsdoc" - }, - "2": { - "name": "punctuation.definition.block.tag.jsdoc" - } - }, - "contentName": "meta.embedded.block.example.source.ts", - "patterns": [ - { - "include": "source.js.jsx" - } - ] - } - }, - "scopeName": "documentation.injection.js.jsx" -} diff --git a/extensions/typescript-basics/syntaxes/jsdoc.ts.injection.tmLanguage.json b/extensions/typescript-basics/syntaxes/jsdoc.ts.injection.tmLanguage.json deleted file mode 100644 index 4c567864852a0..0000000000000 --- a/extensions/typescript-basics/syntaxes/jsdoc.ts.injection.tmLanguage.json +++ /dev/null @@ -1,54 +0,0 @@ - -{ - "injectionSelector": "L:comment.block.documentation", - "patterns": [ - { - "include": "#jsdocbody" - } - ], - "repository": { - "jsdocbody": { - "begin": "(?<=/\\*\\*)([^*]|\\*(?!/))*$", - "while": "(^|\\G)\\s*\\*(?!/)(?=([^*]|[*](?!/))*$)", - "patterns": [ - { - "include": "text.html.markdown#fenced_code_block_js" - }, - { - "include": "text.html.markdown#fenced_code_block_ts" - }, - { - "include": "text.html.markdown#fenced_code_block_unknown" - }, - { - "include": "#example" - }, - { - "include": "source.ts#docblock" - }, - { - "include": "text.html.markdown#inline" - } - ] - }, - "example": { - "begin": "((@)example)\\s+(?=([^*]|[*](?!/))*$).*$", - "while": "(^|\\G)\\s(?!@)(?=([^*]|[*](?!/))*$)", - "beginCaptures": { - "1": { - "name": "storage.type.class.jsdoc" - }, - "2": { - "name": "punctuation.definition.block.tag.jsdoc" - } - }, - "contentName": "meta.embedded.block.example.source.ts", - "patterns": [ - { - "include": "source.tsx" - } - ] - } - }, - "scopeName": "documentation.injection.ts" -} From 403f364a72331db6d109f7676b2c685a5b3de409 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Tue, 12 Nov 2019 17:06:20 -0800 Subject: [PATCH 162/352] Remove test fixtures for jsdoc --- .../colorize-fixtures/test-jsdoc-example.ts | 8 - .../colorize-fixtures/test-jsdoc-markdown.ts | 7 - .../test-jsdoc-example_ts.json | 277 ---------------- .../test-jsdoc-markdown_ts.json | 310 ------------------ 4 files changed, 602 deletions(-) delete mode 100644 extensions/typescript-basics/test/colorize-fixtures/test-jsdoc-example.ts delete mode 100644 extensions/typescript-basics/test/colorize-fixtures/test-jsdoc-markdown.ts delete mode 100644 extensions/typescript-basics/test/colorize-results/test-jsdoc-example_ts.json delete mode 100644 extensions/typescript-basics/test/colorize-results/test-jsdoc-markdown_ts.json diff --git a/extensions/typescript-basics/test/colorize-fixtures/test-jsdoc-example.ts b/extensions/typescript-basics/test/colorize-fixtures/test-jsdoc-example.ts deleted file mode 100644 index 411f9bbede300..0000000000000 --- a/extensions/typescript-basics/test/colorize-fixtures/test-jsdoc-example.ts +++ /dev/null @@ -1,8 +0,0 @@ -/** - * @example - * 1 + 1 - * - * @other - * not colored - */ -const a = 1 \ No newline at end of file diff --git a/extensions/typescript-basics/test/colorize-fixtures/test-jsdoc-markdown.ts b/extensions/typescript-basics/test/colorize-fixtures/test-jsdoc-markdown.ts deleted file mode 100644 index 136f8b1bafbc7..0000000000000 --- a/extensions/typescript-basics/test/colorize-fixtures/test-jsdoc-markdown.ts +++ /dev/null @@ -1,7 +0,0 @@ -/** - * **Bold** - * ```js - * 1 + code - * ``` - */ -const a = 1 \ No newline at end of file diff --git a/extensions/typescript-basics/test/colorize-results/test-jsdoc-example_ts.json b/extensions/typescript-basics/test/colorize-results/test-jsdoc-example_ts.json deleted file mode 100644 index ea15234c21400..0000000000000 --- a/extensions/typescript-basics/test/colorize-results/test-jsdoc-example_ts.json +++ /dev/null @@ -1,277 +0,0 @@ -[ - { - "c": "/**", - "t": "source.ts comment.block.documentation.ts punctuation.definition.comment.ts", - "r": { - "dark_plus": "comment: #6A9955", - "light_plus": "comment: #008000", - "dark_vs": "comment: #6A9955", - "light_vs": "comment: #008000", - "hc_black": "comment: #7CA668" - } - }, - { - "c": " * ", - "t": "source.ts comment.block.documentation.ts", - "r": { - "dark_plus": "comment: #6A9955", - "light_plus": "comment: #008000", - "dark_vs": "comment: #6A9955", - "light_vs": "comment: #008000", - "hc_black": "comment: #7CA668" - } - }, - { - "c": "@", - "t": "source.ts comment.block.documentation.ts storage.type.class.jsdoc punctuation.definition.block.tag.jsdoc", - "r": { - "dark_plus": "storage.type: #569CD6", - "light_plus": "storage.type: #0000FF", - "dark_vs": "storage.type: #569CD6", - "light_vs": "storage.type: #0000FF", - "hc_black": "storage.type: #569CD6" - } - }, - { - "c": "example", - "t": "source.ts comment.block.documentation.ts storage.type.class.jsdoc", - "r": { - "dark_plus": "storage.type: #569CD6", - "light_plus": "storage.type: #0000FF", - "dark_vs": "storage.type: #569CD6", - "light_vs": "storage.type: #0000FF", - "hc_black": "storage.type: #569CD6" - } - }, - { - "c": " *", - "t": "source.ts comment.block.documentation.ts", - "r": { - "dark_plus": "comment: #6A9955", - "light_plus": "comment: #008000", - "dark_vs": "comment: #6A9955", - "light_vs": "comment: #008000", - "hc_black": "comment: #7CA668" - } - }, - { - "c": " ", - "t": "source.ts comment.block.documentation.ts meta.embedded.block.example.source.ts", - "r": { - "dark_plus": "meta.embedded: #D4D4D4", - "light_plus": "meta.embedded: #000000", - "dark_vs": "meta.embedded: #D4D4D4", - "light_vs": "meta.embedded: #000000", - "hc_black": "meta.embedded: #FFFFFF" - } - }, - { - "c": "1", - "t": "source.ts comment.block.documentation.ts meta.embedded.block.example.source.ts constant.numeric.decimal.tsx", - "r": { - "dark_plus": "constant.numeric: #B5CEA8", - "light_plus": "constant.numeric: #09885A", - "dark_vs": "constant.numeric: #B5CEA8", - "light_vs": "constant.numeric: #09885A", - "hc_black": "constant.numeric: #B5CEA8" - } - }, - { - "c": " ", - "t": "source.ts comment.block.documentation.ts meta.embedded.block.example.source.ts", - "r": { - "dark_plus": "meta.embedded: #D4D4D4", - "light_plus": "meta.embedded: #000000", - "dark_vs": "meta.embedded: #D4D4D4", - "light_vs": "meta.embedded: #000000", - "hc_black": "meta.embedded: #FFFFFF" - } - }, - { - "c": "+", - "t": "source.ts comment.block.documentation.ts meta.embedded.block.example.source.ts keyword.operator.arithmetic.tsx", - "r": { - "dark_plus": "keyword.operator: #D4D4D4", - "light_plus": "keyword.operator: #000000", - "dark_vs": "keyword.operator: #D4D4D4", - "light_vs": "keyword.operator: #000000", - "hc_black": "keyword.operator: #D4D4D4" - } - }, - { - "c": " ", - "t": "source.ts comment.block.documentation.ts meta.embedded.block.example.source.ts", - "r": { - "dark_plus": "meta.embedded: #D4D4D4", - "light_plus": "meta.embedded: #000000", - "dark_vs": "meta.embedded: #D4D4D4", - "light_vs": "meta.embedded: #000000", - "hc_black": "meta.embedded: #FFFFFF" - } - }, - { - "c": "1", - "t": "source.ts comment.block.documentation.ts meta.embedded.block.example.source.ts constant.numeric.decimal.tsx", - "r": { - "dark_plus": "constant.numeric: #B5CEA8", - "light_plus": "constant.numeric: #09885A", - "dark_vs": "constant.numeric: #B5CEA8", - "light_vs": "constant.numeric: #09885A", - "hc_black": "constant.numeric: #B5CEA8" - } - }, - { - "c": " *", - "t": "source.ts comment.block.documentation.ts", - "r": { - "dark_plus": "comment: #6A9955", - "light_plus": "comment: #008000", - "dark_vs": "comment: #6A9955", - "light_vs": "comment: #008000", - "hc_black": "comment: #7CA668" - } - }, - { - "c": " * ", - "t": "source.ts comment.block.documentation.ts", - "r": { - "dark_plus": "comment: #6A9955", - "light_plus": "comment: #008000", - "dark_vs": "comment: #6A9955", - "light_vs": "comment: #008000", - "hc_black": "comment: #7CA668" - } - }, - { - "c": "@", - "t": "source.ts comment.block.documentation.ts storage.type.class.jsdoc punctuation.definition.block.tag.jsdoc", - "r": { - "dark_plus": "storage.type: #569CD6", - "light_plus": "storage.type: #0000FF", - "dark_vs": "storage.type: #569CD6", - "light_vs": "storage.type: #0000FF", - "hc_black": "storage.type: #569CD6" - } - }, - { - "c": "other", - "t": "source.ts comment.block.documentation.ts storage.type.class.jsdoc", - "r": { - "dark_plus": "storage.type: #569CD6", - "light_plus": "storage.type: #0000FF", - "dark_vs": "storage.type: #569CD6", - "light_vs": "storage.type: #0000FF", - "hc_black": "storage.type: #569CD6" - } - }, - { - "c": " * not colored", - "t": "source.ts comment.block.documentation.ts", - "r": { - "dark_plus": "comment: #6A9955", - "light_plus": "comment: #008000", - "dark_vs": "comment: #6A9955", - "light_vs": "comment: #008000", - "hc_black": "comment: #7CA668" - } - }, - { - "c": " ", - "t": "source.ts comment.block.documentation.ts", - "r": { - "dark_plus": "comment: #6A9955", - "light_plus": "comment: #008000", - "dark_vs": "comment: #6A9955", - "light_vs": "comment: #008000", - "hc_black": "comment: #7CA668" - } - }, - { - "c": "*/", - "t": "source.ts comment.block.documentation.ts punctuation.definition.comment.ts", - "r": { - "dark_plus": "comment: #6A9955", - "light_plus": "comment: #008000", - "dark_vs": "comment: #6A9955", - "light_vs": "comment: #008000", - "hc_black": "comment: #7CA668" - } - }, - { - "c": "const", - "t": "source.ts meta.var.expr.ts storage.type.ts", - "r": { - "dark_plus": "storage.type: #569CD6", - "light_plus": "storage.type: #0000FF", - "dark_vs": "storage.type: #569CD6", - "light_vs": "storage.type: #0000FF", - "hc_black": "storage.type: #569CD6" - } - }, - { - "c": " ", - "t": "source.ts meta.var.expr.ts", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": "a", - "t": "source.ts meta.var.expr.ts meta.var-single-variable.expr.ts meta.definition.variable.ts variable.other.constant.ts", - "r": { - "dark_plus": "variable: #9CDCFE", - "light_plus": "variable: #001080", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "variable: #9CDCFE" - } - }, - { - "c": " ", - "t": "source.ts meta.var.expr.ts meta.var-single-variable.expr.ts", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": "=", - "t": "source.ts meta.var.expr.ts keyword.operator.assignment.ts", - "r": { - "dark_plus": "keyword.operator: #D4D4D4", - "light_plus": "keyword.operator: #000000", - "dark_vs": "keyword.operator: #D4D4D4", - "light_vs": "keyword.operator: #000000", - "hc_black": "keyword.operator: #D4D4D4" - } - }, - { - "c": " ", - "t": "source.ts meta.var.expr.ts", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": "1", - "t": "source.ts meta.var.expr.ts constant.numeric.decimal.ts", - "r": { - "dark_plus": "constant.numeric: #B5CEA8", - "light_plus": "constant.numeric: #09885A", - "dark_vs": "constant.numeric: #B5CEA8", - "light_vs": "constant.numeric: #09885A", - "hc_black": "constant.numeric: #B5CEA8" - } - } -] \ No newline at end of file diff --git a/extensions/typescript-basics/test/colorize-results/test-jsdoc-markdown_ts.json b/extensions/typescript-basics/test/colorize-results/test-jsdoc-markdown_ts.json deleted file mode 100644 index 22ccb1e897299..0000000000000 --- a/extensions/typescript-basics/test/colorize-results/test-jsdoc-markdown_ts.json +++ /dev/null @@ -1,310 +0,0 @@ -[ - { - "c": "/**", - "t": "source.ts comment.block.documentation.ts punctuation.definition.comment.ts", - "r": { - "dark_plus": "comment: #6A9955", - "light_plus": "comment: #008000", - "dark_vs": "comment: #6A9955", - "light_vs": "comment: #008000", - "hc_black": "comment: #7CA668" - } - }, - { - "c": " * ", - "t": "source.ts comment.block.documentation.ts", - "r": { - "dark_plus": "comment: #6A9955", - "light_plus": "comment: #008000", - "dark_vs": "comment: #6A9955", - "light_vs": "comment: #008000", - "hc_black": "comment: #7CA668" - } - }, - { - "c": "**", - "t": "source.ts comment.block.documentation.ts markup.bold.markdown punctuation.definition.bold.markdown", - "r": { - "dark_plus": "markup.bold: #569CD6", - "light_plus": "markup.bold: #000080", - "dark_vs": "markup.bold: #569CD6", - "light_vs": "markup.bold: #000080", - "hc_black": "comment: #7CA668" - } - }, - { - "c": "Bold", - "t": "source.ts comment.block.documentation.ts markup.bold.markdown", - "r": { - "dark_plus": "markup.bold: #569CD6", - "light_plus": "markup.bold: #000080", - "dark_vs": "markup.bold: #569CD6", - "light_vs": "markup.bold: #000080", - "hc_black": "comment: #7CA668" - } - }, - { - "c": "**", - "t": "source.ts comment.block.documentation.ts markup.bold.markdown punctuation.definition.bold.markdown", - "r": { - "dark_plus": "markup.bold: #569CD6", - "light_plus": "markup.bold: #000080", - "dark_vs": "markup.bold: #569CD6", - "light_vs": "markup.bold: #000080", - "hc_black": "comment: #7CA668" - } - }, - { - "c": " *", - "t": "source.ts comment.block.documentation.ts", - "r": { - "dark_plus": "comment: #6A9955", - "light_plus": "comment: #008000", - "dark_vs": "comment: #6A9955", - "light_vs": "comment: #008000", - "hc_black": "comment: #7CA668" - } - }, - { - "c": " ", - "t": "source.ts comment.block.documentation.ts markup.fenced_code.block.markdown", - "r": { - "dark_plus": "comment: #6A9955", - "light_plus": "comment: #008000", - "dark_vs": "comment: #6A9955", - "light_vs": "comment: #008000", - "hc_black": "comment: #7CA668" - } - }, - { - "c": "```", - "t": "source.ts comment.block.documentation.ts markup.fenced_code.block.markdown punctuation.definition.markdown", - "r": { - "dark_plus": "comment: #6A9955", - "light_plus": "comment: #008000", - "dark_vs": "comment: #6A9955", - "light_vs": "comment: #008000", - "hc_black": "comment: #7CA668" - } - }, - { - "c": "js", - "t": "source.ts comment.block.documentation.ts markup.fenced_code.block.markdown fenced_code.block.language.markdown", - "r": { - "dark_plus": "comment: #6A9955", - "light_plus": "comment: #008000", - "dark_vs": "comment: #6A9955", - "light_vs": "comment: #008000", - "hc_black": "comment: #7CA668" - } - }, - { - "c": " *", - "t": "source.ts comment.block.documentation.ts", - "r": { - "dark_plus": "comment: #6A9955", - "light_plus": "comment: #008000", - "dark_vs": "comment: #6A9955", - "light_vs": "comment: #008000", - "hc_black": "comment: #7CA668" - } - }, - { - "c": " ", - "t": "source.ts comment.block.documentation.ts markup.fenced_code.block.markdown meta.embedded.block.javascript", - "r": { - "dark_plus": "meta.embedded: #D4D4D4", - "light_plus": "meta.embedded: #000000", - "dark_vs": "meta.embedded: #D4D4D4", - "light_vs": "meta.embedded: #000000", - "hc_black": "meta.embedded: #FFFFFF" - } - }, - { - "c": "1", - "t": "source.ts comment.block.documentation.ts markup.fenced_code.block.markdown meta.embedded.block.javascript constant.numeric.decimal.js", - "r": { - "dark_plus": "constant.numeric: #B5CEA8", - "light_plus": "constant.numeric: #09885A", - "dark_vs": "constant.numeric: #B5CEA8", - "light_vs": "constant.numeric: #09885A", - "hc_black": "constant.numeric: #B5CEA8" - } - }, - { - "c": " ", - "t": "source.ts comment.block.documentation.ts markup.fenced_code.block.markdown meta.embedded.block.javascript", - "r": { - "dark_plus": "meta.embedded: #D4D4D4", - "light_plus": "meta.embedded: #000000", - "dark_vs": "meta.embedded: #D4D4D4", - "light_vs": "meta.embedded: #000000", - "hc_black": "meta.embedded: #FFFFFF" - } - }, - { - "c": "+", - "t": "source.ts comment.block.documentation.ts markup.fenced_code.block.markdown meta.embedded.block.javascript keyword.operator.arithmetic.js", - "r": { - "dark_plus": "keyword.operator: #D4D4D4", - "light_plus": "keyword.operator: #000000", - "dark_vs": "keyword.operator: #D4D4D4", - "light_vs": "keyword.operator: #000000", - "hc_black": "keyword.operator: #D4D4D4" - } - }, - { - "c": " ", - "t": "source.ts comment.block.documentation.ts markup.fenced_code.block.markdown meta.embedded.block.javascript", - "r": { - "dark_plus": "meta.embedded: #D4D4D4", - "light_plus": "meta.embedded: #000000", - "dark_vs": "meta.embedded: #D4D4D4", - "light_vs": "meta.embedded: #000000", - "hc_black": "meta.embedded: #FFFFFF" - } - }, - { - "c": "code", - "t": "source.ts comment.block.documentation.ts markup.fenced_code.block.markdown meta.embedded.block.javascript variable.other.readwrite.js", - "r": { - "dark_plus": "variable: #9CDCFE", - "light_plus": "variable: #001080", - "dark_vs": "meta.embedded: #D4D4D4", - "light_vs": "meta.embedded: #000000", - "hc_black": "variable: #9CDCFE" - } - }, - { - "c": " *", - "t": "source.ts comment.block.documentation.ts", - "r": { - "dark_plus": "comment: #6A9955", - "light_plus": "comment: #008000", - "dark_vs": "comment: #6A9955", - "light_vs": "comment: #008000", - "hc_black": "comment: #7CA668" - } - }, - { - "c": " ", - "t": "source.ts comment.block.documentation.ts markup.fenced_code.block.markdown", - "r": { - "dark_plus": "comment: #6A9955", - "light_plus": "comment: #008000", - "dark_vs": "comment: #6A9955", - "light_vs": "comment: #008000", - "hc_black": "comment: #7CA668" - } - }, - { - "c": "```", - "t": "source.ts comment.block.documentation.ts markup.fenced_code.block.markdown punctuation.definition.markdown", - "r": { - "dark_plus": "comment: #6A9955", - "light_plus": "comment: #008000", - "dark_vs": "comment: #6A9955", - "light_vs": "comment: #008000", - "hc_black": "comment: #7CA668" - } - }, - { - "c": " ", - "t": "source.ts comment.block.documentation.ts", - "r": { - "dark_plus": "comment: #6A9955", - "light_plus": "comment: #008000", - "dark_vs": "comment: #6A9955", - "light_vs": "comment: #008000", - "hc_black": "comment: #7CA668" - } - }, - { - "c": "*/", - "t": "source.ts comment.block.documentation.ts punctuation.definition.comment.ts", - "r": { - "dark_plus": "comment: #6A9955", - "light_plus": "comment: #008000", - "dark_vs": "comment: #6A9955", - "light_vs": "comment: #008000", - "hc_black": "comment: #7CA668" - } - }, - { - "c": "const", - "t": "source.ts meta.var.expr.ts storage.type.ts", - "r": { - "dark_plus": "storage.type: #569CD6", - "light_plus": "storage.type: #0000FF", - "dark_vs": "storage.type: #569CD6", - "light_vs": "storage.type: #0000FF", - "hc_black": "storage.type: #569CD6" - } - }, - { - "c": " ", - "t": "source.ts meta.var.expr.ts", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": "a", - "t": "source.ts meta.var.expr.ts meta.var-single-variable.expr.ts meta.definition.variable.ts variable.other.constant.ts", - "r": { - "dark_plus": "variable: #9CDCFE", - "light_plus": "variable: #001080", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "variable: #9CDCFE" - } - }, - { - "c": " ", - "t": "source.ts meta.var.expr.ts meta.var-single-variable.expr.ts", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": "=", - "t": "source.ts meta.var.expr.ts keyword.operator.assignment.ts", - "r": { - "dark_plus": "keyword.operator: #D4D4D4", - "light_plus": "keyword.operator: #000000", - "dark_vs": "keyword.operator: #D4D4D4", - "light_vs": "keyword.operator: #000000", - "hc_black": "keyword.operator: #D4D4D4" - } - }, - { - "c": " ", - "t": "source.ts meta.var.expr.ts", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": "1", - "t": "source.ts meta.var.expr.ts constant.numeric.decimal.ts", - "r": { - "dark_plus": "constant.numeric: #B5CEA8", - "light_plus": "constant.numeric: #09885A", - "dark_vs": "constant.numeric: #B5CEA8", - "light_vs": "constant.numeric: #09885A", - "hc_black": "constant.numeric: #B5CEA8" - } - } -] \ No newline at end of file From ab147f8b8e2af23fd61385b563c246847bc50f2b Mon Sep 17 00:00:00 2001 From: Jackson Kearl Date: Tue, 12 Nov 2019 17:09:25 -0800 Subject: [PATCH 163/352] Reduce search flicker. (#84547) * Reduce search flicker. Closes #84499. * Naming * Docs * Clean up dispose logic * Slightly delay rendering intial results in while in search on type mode, to prevent flashing localResults * Make message disappear immediately on clearning results * Dont show cancelled message while a search is running * Revert logic change, unneeded now? * Fix "Cannot read property `add` of 'null'" error. --- .../contrib/search/browser/searchView.ts | 16 +++++-- .../contrib/search/common/searchModel.ts | 44 ++++++++++++++++--- 2 files changed, 49 insertions(+), 11 deletions(-) diff --git a/src/vs/workbench/contrib/search/browser/searchView.ts b/src/vs/workbench/contrib/search/browser/searchView.ts index 150156d7dc27f..411b01d41d15a 100644 --- a/src/vs/workbench/contrib/search/browser/searchView.ts +++ b/src/vs/workbench/contrib/search/browser/searchView.ts @@ -70,6 +70,7 @@ enum SearchUIState { SlowSearch } +const SEARCH_CANCELLED_MESSAGE = nls.localize('searchCanceled', "Search was canceled before any results could be found - "); export class SearchView extends ViewletPanel { private static readonly MAX_TEXT_RESULTS = 10000; @@ -931,7 +932,7 @@ export class SearchView extends ViewletPanel { clearSearchResults(): void { this.viewModel.searchResult.clear(); - this.showEmptyStage(); + this.showEmptyStage(true); if (this.contextService.getWorkbenchState() === WorkbenchState.EMPTY) { this.showSearchWithoutFolderMessage(); } @@ -1169,6 +1170,7 @@ export class SearchView extends ViewletPanel { if (contentPattern.length === 0) { this.clearSearchResults(); + this.clearMessage(); return; } @@ -1312,7 +1314,7 @@ export class SearchView extends ViewletPanel { let message: string; if (!completed) { - message = nls.localize('searchCanceled', "Search was canceled before any results could be found - "); + message = SEARCH_CANCELLED_MESSAGE; } else if (hasIncludes && hasExcludes) { message = nls.localize('noResultsIncludesExcludes', "No results found in '{0}' excluding '{1}' - ", includePatternText, excludePatternText); } else if (hasIncludes) { @@ -1508,13 +1510,19 @@ export class SearchView extends ViewletPanel { })); } - private showEmptyStage(): void { + private showEmptyStage(forceHideMessages = false): void { // disable 'result'-actions this.updateActions(); + const showingCancelled = (this.messagesElement.firstChild?.textContent?.indexOf(SEARCH_CANCELLED_MESSAGE) ?? -1) > -1; + // clean up ui // this.replaceService.disposeAllReplacePreviews(); - dom.hide(this.messagesElement); + if (showingCancelled || forceHideMessages || !this.configurationService.getValue().search.searchOnType) { + // when in search to type, don't preemptively hide, as it causes flickering and shifting of the live results + dom.hide(this.messagesElement); + } + dom.show(this.resultsElement); this.currentSelectedFileMatch = undefined; } diff --git a/src/vs/workbench/contrib/search/common/searchModel.ts b/src/vs/workbench/contrib/search/common/searchModel.ts index a02bb04ea1c50..cdd195c17e869 100644 --- a/src/vs/workbench/contrib/search/common/searchModel.ts +++ b/src/vs/workbench/contrib/search/common/searchModel.ts @@ -639,6 +639,7 @@ export class SearchResult extends Disposable { private _query: ITextQuery | null = null; private _rangeHighlightDecorations: RangeHighlightDecorations; + private disposePastResults: () => void = () => { }; constructor( private _searchModel: SearchModel, @@ -658,8 +659,15 @@ export class SearchResult extends Disposable { } set query(query: ITextQuery | null) { - // When updating the query we could change the roots, so ensure we clean up the old roots first. - this.clear(); + // When updating the query we could change the roots, so keep a reference to them to clean up when we trigger `disposePastResults` + const oldFolderMatches = this.folderMatches(); + new Promise(resolve => this.disposePastResults = resolve) + .then(() => oldFolderMatches.forEach(match => match.clear())) + .then(() => oldFolderMatches.forEach(match => match.dispose())); + + this._rangeHighlightDecorations.removeHighlightRange(); + this._folderMatchesMap = TernarySearchTree.forPaths(); + if (!query) { return; } @@ -715,7 +723,8 @@ export class SearchResult extends Disposable { } }); - this._otherFilesMatch!.add(other, silent); + this._otherFilesMatch?.add(other, silent); + this.disposePastResults(); } clear(): void { @@ -884,6 +893,7 @@ export class SearchResult extends Disposable { } dispose(): void { + this.disposePastResults(); this.disposeMatches(); this._rangeHighlightDecorations.dispose(); super.dispose(); @@ -898,6 +908,8 @@ export class SearchModel extends Disposable { private _replaceString: string | null = null; private _replacePattern: ReplacePattern | null = null; private _preserveCase: boolean = false; + private _startStreamDelay: Promise = Promise.resolve(); + private _resultQueue: IFileMatch[] = []; private readonly _onReplaceTermChanged: Emitter = this._register(new Emitter()); readonly onReplaceTermChanged: Event = this._onReplaceTermChanged.event; @@ -954,12 +966,18 @@ export class SearchModel extends Disposable { this.cancelSearch(); this._searchQuery = query; - this.searchResult.clear(); + if (!this.searchConfig.searchOnType) { + this.searchResult.clear(); + } + this._searchResult.query = this._searchQuery; const progressEmitter = new Emitter(); this._replacePattern = new ReplacePattern(this.replaceString, this._searchQuery.contentPattern); + // In search on type case, delay the streaming of results just a bit, so that we don't flash the only "local results" fast path + this._startStreamDelay = new Promise(resolve => setTimeout(resolve, this.searchConfig.searchOnType ? 100 : 0)); + const tokenSource = this.currentCancelTokenSource = new CancellationTokenSource(); const currentRequest = this.searchService.textSearch(this._searchQuery, this.currentCancelTokenSource.token, p => { progressEmitter.fire(); @@ -1003,6 +1021,9 @@ export class SearchModel extends Disposable { throw new Error('onSearchCompleted must be called after a search is started'); } + this._searchResult.add(this._resultQueue); + this._resultQueue = []; + const options: IPatternInfo = objects.assign({}, this._searchQuery.contentPattern); delete options.pattern; @@ -1032,7 +1053,7 @@ export class SearchModel extends Disposable { duration, type: stats && stats.type, scheme, - searchOnTypeEnabled: this.configurationService.getValue('search').searchOnType + searchOnTypeEnabled: this.searchConfig.searchOnType }); return completed; } @@ -1043,12 +1064,21 @@ export class SearchModel extends Disposable { } } - private onSearchProgress(p: ISearchProgressItem): void { + private async onSearchProgress(p: ISearchProgressItem) { if ((p).resource) { - this._searchResult.add([p], true); + this._resultQueue.push(p); + await this._startStreamDelay; + if (this._resultQueue.length) { + this._searchResult.add(this._resultQueue, true); + this._resultQueue = []; + } } } + private get searchConfig() { + return this.configurationService.getValue('search'); + } + cancelSearch(): boolean { if (this.currentCancelTokenSource) { this.currentCancelTokenSource.cancel(); From 8b1e55780c3f67818d460b5e8cf5e40a607dbe3b Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Tue, 12 Nov 2019 21:13:22 -0800 Subject: [PATCH 164/352] Fix grammar pinning test --- .../test-jsdoc-multiline-type_ts.json | 130 ++---------------- 1 file changed, 10 insertions(+), 120 deletions(-) diff --git a/extensions/typescript-basics/test/colorize-results/test-jsdoc-multiline-type_ts.json b/extensions/typescript-basics/test/colorize-results/test-jsdoc-multiline-type_ts.json index cc1eba5f197d4..10a8b4c625eb1 100644 --- a/extensions/typescript-basics/test/colorize-results/test-jsdoc-multiline-type_ts.json +++ b/extensions/typescript-basics/test/colorize-results/test-jsdoc-multiline-type_ts.json @@ -77,18 +77,7 @@ } }, { - "c": " *", - "t": "source.ts comment.block.documentation.ts", - "r": { - "dark_plus": "comment: #6A9955", - "light_plus": "comment: #008000", - "dark_vs": "comment: #6A9955", - "light_vs": "comment: #008000", - "hc_black": "comment: #7CA668" - } - }, - { - "c": " id: number,", + "c": " * id: number,", "t": "source.ts comment.block.documentation.ts entity.name.type.instance.jsdoc", "r": { "dark_plus": "entity.name.type: #4EC9B0", @@ -99,18 +88,7 @@ } }, { - "c": " *", - "t": "source.ts comment.block.documentation.ts", - "r": { - "dark_plus": "comment: #6A9955", - "light_plus": "comment: #008000", - "dark_vs": "comment: #6A9955", - "light_vs": "comment: #008000", - "hc_black": "comment: #7CA668" - } - }, - { - "c": " fn: !Function,", + "c": " * fn: !Function,", "t": "source.ts comment.block.documentation.ts entity.name.type.instance.jsdoc", "r": { "dark_plus": "entity.name.type: #4EC9B0", @@ -121,18 +99,7 @@ } }, { - "c": " *", - "t": "source.ts comment.block.documentation.ts", - "r": { - "dark_plus": "comment: #6A9955", - "light_plus": "comment: #008000", - "dark_vs": "comment: #6A9955", - "light_vs": "comment: #008000", - "hc_black": "comment: #7CA668" - } - }, - { - "c": " context: (!Object|undefined)", + "c": " * context: (!Object|undefined)", "t": "source.ts comment.block.documentation.ts entity.name.type.instance.jsdoc", "r": { "dark_plus": "entity.name.type: #4EC9B0", @@ -143,18 +110,7 @@ } }, { - "c": " *", - "t": "source.ts comment.block.documentation.ts", - "r": { - "dark_plus": "comment: #6A9955", - "light_plus": "comment: #008000", - "dark_vs": "comment: #6A9955", - "light_vs": "comment: #008000", - "hc_black": "comment: #7CA668" - } - }, - { - "c": " }", + "c": " * }", "t": "source.ts comment.block.documentation.ts entity.name.type.instance.jsdoc", "r": { "dark_plus": "entity.name.type: #4EC9B0", @@ -396,18 +352,7 @@ } }, { - "c": " *", - "t": "source.ts comment.block.documentation.ts", - "r": { - "dark_plus": "comment: #6A9955", - "light_plus": "comment: #008000", - "dark_vs": "comment: #6A9955", - "light_vs": "comment: #008000", - "hc_black": "comment: #7CA668" - } - }, - { - "c": " measureTask: goog.dom.animationFrame.Task_,", + "c": " * measureTask: goog.dom.animationFrame.Task_,", "t": "source.ts comment.block.documentation.ts entity.name.type.instance.jsdoc", "r": { "dark_plus": "entity.name.type: #4EC9B0", @@ -418,18 +363,7 @@ } }, { - "c": " *", - "t": "source.ts comment.block.documentation.ts", - "r": { - "dark_plus": "comment: #6A9955", - "light_plus": "comment: #008000", - "dark_vs": "comment: #6A9955", - "light_vs": "comment: #008000", - "hc_black": "comment: #7CA668" - } - }, - { - "c": " mutateTask: goog.dom.animationFrame.Task_,", + "c": " * mutateTask: goog.dom.animationFrame.Task_,", "t": "source.ts comment.block.documentation.ts entity.name.type.instance.jsdoc", "r": { "dark_plus": "entity.name.type: #4EC9B0", @@ -440,18 +374,7 @@ } }, { - "c": " *", - "t": "source.ts comment.block.documentation.ts", - "r": { - "dark_plus": "comment: #6A9955", - "light_plus": "comment: #008000", - "dark_vs": "comment: #6A9955", - "light_vs": "comment: #008000", - "hc_black": "comment: #7CA668" - } - }, - { - "c": " state: (!Object|undefined),", + "c": " * state: (!Object|undefined),", "t": "source.ts comment.block.documentation.ts entity.name.type.instance.jsdoc", "r": { "dark_plus": "entity.name.type: #4EC9B0", @@ -462,18 +385,7 @@ } }, { - "c": " *", - "t": "source.ts comment.block.documentation.ts", - "r": { - "dark_plus": "comment: #6A9955", - "light_plus": "comment: #008000", - "dark_vs": "comment: #6A9955", - "light_vs": "comment: #008000", - "hc_black": "comment: #7CA668" - } - }, - { - "c": " args: (!Array|undefined),", + "c": " * args: (!Array|undefined),", "t": "source.ts comment.block.documentation.ts entity.name.type.instance.jsdoc", "r": { "dark_plus": "entity.name.type: #4EC9B0", @@ -484,18 +396,7 @@ } }, { - "c": " *", - "t": "source.ts comment.block.documentation.ts", - "r": { - "dark_plus": "comment: #6A9955", - "light_plus": "comment: #008000", - "dark_vs": "comment: #6A9955", - "light_vs": "comment: #008000", - "hc_black": "comment: #7CA668" - } - }, - { - "c": " isScheduled: boolean", + "c": " * isScheduled: boolean", "t": "source.ts comment.block.documentation.ts entity.name.type.instance.jsdoc", "r": { "dark_plus": "entity.name.type: #4EC9B0", @@ -506,18 +407,7 @@ } }, { - "c": " *", - "t": "source.ts comment.block.documentation.ts", - "r": { - "dark_plus": "comment: #6A9955", - "light_plus": "comment: #008000", - "dark_vs": "comment: #6A9955", - "light_vs": "comment: #008000", - "hc_black": "comment: #7CA668" - } - }, - { - "c": " }", + "c": " * }", "t": "source.ts comment.block.documentation.ts entity.name.type.instance.jsdoc", "r": { "dark_plus": "entity.name.type: #4EC9B0", From 3870d8048cda03d41281112384aab7faf07e7ab5 Mon Sep 17 00:00:00 2001 From: John Combs Date: Wed, 13 Nov 2019 00:17:54 -0500 Subject: [PATCH 165/352] Added force-device-scale-factor to command line args --- src/vs/platform/environment/common/environment.ts | 1 + src/vs/platform/environment/node/argv.ts | 1 + 2 files changed, 2 insertions(+) diff --git a/src/vs/platform/environment/common/environment.ts b/src/vs/platform/environment/common/environment.ts index eaa3bc1bae1a4..84803ede65f49 100644 --- a/src/vs/platform/environment/common/environment.ts +++ b/src/vs/platform/environment/common/environment.ts @@ -84,6 +84,7 @@ export interface ParsedArgs { 'js-flags'?: string; 'disable-gpu'?: boolean; 'nolazy'?: boolean; + 'force-device-scale-factor'?: string; } export const IEnvironmentService = createDecorator('environmentService'); diff --git a/src/vs/platform/environment/node/argv.ts b/src/vs/platform/environment/node/argv.ts index 8176898aa76b7..b97cc4b20b147 100644 --- a/src/vs/platform/environment/node/argv.ts +++ b/src/vs/platform/environment/node/argv.ts @@ -117,6 +117,7 @@ export const OPTIONS: OptionDescriptions> = { 'inspect': { type: 'string' }, 'inspect-brk': { type: 'string' }, 'nolazy': { type: 'boolean' }, // node inspect + 'force-device-scale-factor': { type: 'string' }, '_urls': { type: 'string[]' }, _: { type: 'string[]' } // main arguments From c408a2c02d78982b1f83819c587c02bb59af9f93 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Tue, 12 Nov 2019 21:52:46 -0800 Subject: [PATCH 166/352] Clarify \n\r in pseudoterminal write Fixes #84611 --- src/vs/vscode.d.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/vs/vscode.d.ts b/src/vs/vscode.d.ts index b1f5ccc6280ca..39d770789fae2 100644 --- a/src/vs/vscode.d.ts +++ b/src/vs/vscode.d.ts @@ -7487,6 +7487,9 @@ declare module 'vscode' { * [Terminal.sendText](#Terminal.sendText) which sends text to the underlying _process_ * (the pty "slave"), this will write the text to the terminal itself (the pty "master"). * + * Note writing `\n` will just move the cursor down 1 row, you need to write `\r` as well + * to move the cursor to the left-most cell. + * * **Example:** Write red text to the terminal * ```typescript * const writeEmitter = new vscode.EventEmitter(); From 0749b7aca802089907b861dd06bb7ccc329e3ed6 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Tue, 12 Nov 2019 21:58:39 -0800 Subject: [PATCH 167/352] Timebox the TSServer request used in the JS/TS task provider Fixes #84278 --- .../src/features/task.ts | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/extensions/typescript-language-features/src/features/task.ts b/extensions/typescript-language-features/src/features/task.ts index e41a4b66d0d4e..1118c660adf2b 100644 --- a/extensions/typescript-language-features/src/features/task.ts +++ b/extensions/typescript-language-features/src/features/task.ts @@ -8,7 +8,7 @@ import * as jsonc from 'jsonc-parser'; import * as path from 'path'; import * as vscode from 'vscode'; import * as nls from 'vscode-nls'; -import { ITypeScriptServiceClient } from '../typescriptService'; +import { ITypeScriptServiceClient, ServerResponse } from '../typescriptService'; import { isTsConfigFileName } from '../utils/languageDescription'; import { Lazy } from '../utils/lazy'; import { isImplicitProjectConfigFile } from '../utils/tsconfig'; @@ -36,6 +36,8 @@ interface TypeScriptTaskDefinition extends vscode.TaskDefinition { * Provides tasks for building `tsconfig.json` files in a project. */ export default class TscTaskProvider implements vscode.TaskProvider { + + private readonly projectInfoRequestTimeout = 2000; private autoDetect: AutoDetect = 'on'; private readonly tsconfigProvider: TsConfigProvider; private readonly disposables: vscode.Disposable[] = []; @@ -129,10 +131,13 @@ export default class TscTaskProvider implements vscode.TaskProvider { return []; } - const response = await this.client.value.execute( - 'projectInfo', - { file, needFileNameList: false }, - token); + const response = await Promise.race([ + this.client.value.execute( + 'projectInfo', + { file, needFileNameList: false }, + token), + new Promise(resolve => setTimeout(() => resolve(ServerResponse.NoContent), this.projectInfoRequestTimeout)) + ]); if (response.type !== 'response' || !response.body) { return []; } From cf197953d7c65b4131147d93cf0dc7766a610b70 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Tue, 12 Nov 2019 21:59:25 -0800 Subject: [PATCH 168/352] Prefer using vscode.workspace.fs over node fs --- .../src/features/task.ts | 73 +++++++++---------- .../src/utils/tsconfigProvider.ts | 7 +- 2 files changed, 39 insertions(+), 41 deletions(-) diff --git a/extensions/typescript-language-features/src/features/task.ts b/extensions/typescript-language-features/src/features/task.ts index 1118c660adf2b..59044029b69f1 100644 --- a/extensions/typescript-language-features/src/features/task.ts +++ b/extensions/typescript-language-features/src/features/task.ts @@ -3,7 +3,6 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import * as fs from 'fs'; import * as jsonc from 'jsonc-parser'; import * as path from 'path'; import * as vscode from 'vscode'; @@ -18,14 +17,14 @@ const localize = nls.loadMessageBundle(); type AutoDetect = 'on' | 'off' | 'build' | 'watch'; - -const exists = (file: string): Promise => - new Promise((resolve, _reject) => { - fs.exists(file, (value: boolean) => { - resolve(value); - }); - }); - +const exists = async (resource: vscode.Uri): Promise => { + try { + const stat = await vscode.workspace.fs.stat(resource); + return stat.type === vscode.FileType.File; + } catch { + return false; + } +}; interface TypeScriptTaskDefinition extends vscode.TaskDefinition { tsconfig: string; @@ -64,8 +63,8 @@ export default class TscTaskProvider implements vscode.TaskProvider { const configPaths: Set = new Set(); const tasks: vscode.Task[] = []; for (const project of await this.getAllTsConfigs(token)) { - if (!configPaths.has(project.path)) { - configPaths.add(project.path); + if (!configPaths.has(project.fsPath)) { + configPaths.add(project.fsPath); tasks.push(...(await this.getTasksForProject(project))); } } @@ -90,7 +89,8 @@ export default class TscTaskProvider implements vscode.TaskProvider { const kind: TypeScriptTaskDefinition = (_task.definition); const tsconfigUri: vscode.Uri = _task.scope.uri.with({ path: _task.scope.uri.path + '/' + kind.tsconfig }); const tsconfig: TSConfig = { - path: tsconfigUri.fsPath, + uri: tsconfigUri, + fsPath: tsconfigUri.fsPath, posixPath: tsconfigUri.path, workspaceFolder: _task.scope }; @@ -106,7 +106,7 @@ export default class TscTaskProvider implements vscode.TaskProvider { ...await this.getTsConfigsInWorkspace() ]; for (const config of configs) { - if (await exists(config.path)) { + if (await exists(config.uri)) { out.add(config); } } @@ -119,7 +119,8 @@ export default class TscTaskProvider implements vscode.TaskProvider { if (isTsConfigFileName(editor.document.fileName)) { const uri = editor.document.uri; return [{ - path: uri.fsPath, + uri, + fsPath: uri.fsPath, posixPath: uri.path, workspaceFolder: vscode.workspace.getWorkspaceFolder(uri) }]; @@ -148,7 +149,8 @@ export default class TscTaskProvider implements vscode.TaskProvider { const uri = vscode.Uri.file(normalizedConfigPath); const folder = vscode.workspace.getWorkspaceFolder(uri); return [{ - path: normalizedConfigPath, + uri, + fsPath: normalizedConfigPath, posixPath: uri.path, workspaceFolder: folder }]; @@ -163,7 +165,7 @@ export default class TscTaskProvider implements vscode.TaskProvider { private static async getCommand(project: TSConfig): Promise { if (project.workspaceFolder) { - const localTsc = await TscTaskProvider.getLocalTscAtPath(path.dirname(project.path)); + const localTsc = await TscTaskProvider.getLocalTscAtPath(path.dirname(project.fsPath)); if (localTsc) { return localTsc; } @@ -181,9 +183,9 @@ export default class TscTaskProvider implements vscode.TaskProvider { private static async getLocalTscAtPath(folderPath: string): Promise { const platform = process.platform; const bin = path.join(folderPath, 'node_modules', '.bin'); - if (platform === 'win32' && await exists(path.join(bin, 'tsc.cmd'))) { + if (platform === 'win32' && await exists(vscode.Uri.file(path.join(bin, 'tsc.cmd')))) { return path.join(bin, 'tsc.cmd'); - } else if ((platform === 'linux' || platform === 'darwin') && await exists(path.join(bin, 'tsc'))) { + } else if ((platform === 'linux' || platform === 'darwin') && await exists(vscode.Uri.file(path.join(bin, 'tsc')))) { return path.join(bin, 'tsc'); } return undefined; @@ -201,7 +203,7 @@ export default class TscTaskProvider implements vscode.TaskProvider { } private getBuildTask(workspaceFolder: vscode.WorkspaceFolder | undefined, label: string, command: string, args: string[], buildTaskidentifier: TypeScriptTaskDefinition): vscode.Task { - const buildTask = new vscode.Task( + const buildTask = new vscode.Task2( buildTaskidentifier, workspaceFolder || vscode.TaskScope.Workspace, localize('buildTscLabel', 'build - {0}', label), @@ -238,7 +240,6 @@ export default class TscTaskProvider implements vscode.TaskProvider { } if (this.autoDetect === 'watch' || this.autoDetect === 'on') { - tasks.push(this.getWatchTask(project.workspaceFolder, label, command, args, { type: 'typescript', tsconfig: label, option: 'watch' })); } @@ -261,25 +262,19 @@ export default class TscTaskProvider implements vscode.TaskProvider { return task; } - private getBuildShellArgs(project: TSConfig): Promise> { - const defaultArgs = ['-p', project.path]; - return new Promise>((resolve) => { - fs.readFile(project.path, (error, result) => { - if (error) { - return resolve(defaultArgs); - } - - try { - const tsconfig = jsonc.parse(result.toString()); - if (tsconfig.references) { - return resolve(['-b', project.path]); - } - } catch { - // noop - } - return resolve(defaultArgs); - }); - }); + private async getBuildShellArgs(project: TSConfig): Promise> { + const defaultArgs = ['-p', project.fsPath]; + try { + const bytes = await vscode.workspace.fs.readFile(project.uri); + const text = Buffer.from(bytes).toString('utf-8'); + const tsconfig = jsonc.parse(text); + if (tsconfig?.references) { + return ['-b', project.fsPath]; + } + } catch { + // noops + } + return defaultArgs; } private getLabelForTasks(project: TSConfig): string { diff --git a/extensions/typescript-language-features/src/utils/tsconfigProvider.ts b/extensions/typescript-language-features/src/utils/tsconfigProvider.ts index fe939032029dd..04843d0058a38 100644 --- a/extensions/typescript-language-features/src/utils/tsconfigProvider.ts +++ b/extensions/typescript-language-features/src/utils/tsconfigProvider.ts @@ -2,10 +2,12 @@ * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ + import * as vscode from 'vscode'; export interface TSConfig { - readonly path: string; + readonly uri: vscode.Uri; + readonly fsPath: string; readonly posixPath: string; readonly workspaceFolder?: vscode.WorkspaceFolder; } @@ -20,7 +22,8 @@ export default class TsConfigProvider { const root = vscode.workspace.getWorkspaceFolder(config); if (root) { configs.set(config.fsPath, { - path: config.fsPath, + uri: config, + fsPath: config.fsPath, posixPath: config.path, workspaceFolder: root }); From 0ec1207e40d3ebe55f9fd7d78bd38173bc197fbb Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Wed, 13 Nov 2019 07:38:16 +0100 Subject: [PATCH 169/352] build - compile leftover --- build/lib/compilation.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/lib/compilation.js b/build/lib/compilation.js index 170e086b35b7c..59bf1a250f61f 100644 --- a/build/lib/compilation.js +++ b/build/lib/compilation.js @@ -44,7 +44,7 @@ function createCompile(src, build, emitError) { const input = es.through(); const output = input .pipe(utf8Filter) - .pipe(bom()) + .pipe(bom()) // this is required to preserve BOM in test files that loose it otherwise .pipe(utf8Filter.restore) .pipe(tsFilter) .pipe(util.loadSourcemaps()) From d2cff74b669abc0963987dccd1a1550d7c289436 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Wed, 13 Nov 2019 07:47:20 +0100 Subject: [PATCH 170/352] web - make sure adblocker do not prevent startup Renamed workspace stats => workspace tags --- build/lib/i18n.resources.json | 2 +- .../experiments/common/experimentService.ts | 8 ++++---- .../extensions/browser/extensionTipsService.ts | 6 +++--- .../browser/workspaceTagsService.ts} | 6 +++--- .../common/workspaceTags.ts} | 4 ++-- .../electron-browser/tags.contribution.ts} | 6 +++--- .../electron-browser/workspaceTags.ts} | 16 ++++++++-------- .../electron-browser/workspaceTagsService.ts} | 12 ++++++------ .../test/workspaceTags.test.ts} | 6 +++--- src/vs/workbench/workbench.desktop.main.ts | 6 +++--- src/vs/workbench/workbench.web.main.ts | 2 +- 11 files changed, 37 insertions(+), 37 deletions(-) rename src/vs/workbench/contrib/{stats/browser/workspaceStatsService.ts => tags/browser/workspaceTagsService.ts} (78%) rename src/vs/workbench/contrib/{stats/common/workspaceStats.ts => tags/common/workspaceTags.ts} (88%) rename src/vs/workbench/contrib/{stats/electron-browser/stats.contribution.ts => tags/electron-browser/tags.contribution.ts} (75%) rename src/vs/workbench/contrib/{stats/electron-browser/workspaceStats.ts => tags/electron-browser/workspaceTags.ts} (95%) rename src/vs/workbench/contrib/{stats/electron-browser/workspaceStatsService.ts => tags/electron-browser/workspaceTagsService.ts} (98%) rename src/vs/workbench/contrib/{stats/test/workspaceStats.test.ts => tags/test/workspaceTags.test.ts} (98%) diff --git a/build/lib/i18n.resources.json b/build/lib/i18n.resources.json index 581d2badaf0a3..6a3f89dc4717a 100644 --- a/build/lib/i18n.resources.json +++ b/build/lib/i18n.resources.json @@ -143,7 +143,7 @@ "project": "vscode-workbench" }, { - "name": "vs/workbench/contrib/stats", + "name": "vs/workbench/contrib/tags", "project": "vscode-workbench" }, { diff --git a/src/vs/workbench/contrib/experiments/common/experimentService.ts b/src/vs/workbench/contrib/experiments/common/experimentService.ts index 11b6c10aa5116..f49e4ac868b21 100644 --- a/src/vs/workbench/contrib/experiments/common/experimentService.ts +++ b/src/vs/workbench/contrib/experiments/common/experimentService.ts @@ -19,7 +19,7 @@ import { CancellationToken } from 'vs/base/common/cancellation'; import { distinct } from 'vs/base/common/arrays'; import { ExtensionType } from 'vs/platform/extensions/common/extensions'; import { IProductService } from 'vs/platform/product/common/productService'; -import { IWorkspaceStatsService } from 'vs/workbench/contrib/stats/common/workspaceStats'; +import { IWorkspaceTagsService } from 'vs/workbench/contrib/tags/common/workspaceTags'; export const enum ExperimentState { Evaluating, @@ -124,7 +124,7 @@ export class ExperimentService extends Disposable implements IExperimentService @IRequestService private readonly requestService: IRequestService, @IConfigurationService private readonly configurationService: IConfigurationService, @IProductService private readonly productService: IProductService, - @IWorkspaceStatsService private readonly workspaceStatsService: IWorkspaceStatsService + @IWorkspaceTagsService private readonly workspaceTagsService: IWorkspaceTagsService ) { super(); @@ -424,11 +424,11 @@ export class ExperimentService extends Disposable implements IExperimentService filePathCheck = match(fileEdits.filePathPattern, event.resource.fsPath); } if (Array.isArray(fileEdits.workspaceIncludes) && fileEdits.workspaceIncludes.length) { - const tags = await this.workspaceStatsService.getTags(); + const tags = await this.workspaceTagsService.getTags(); workspaceCheck = !!tags && fileEdits.workspaceIncludes.some(x => !!tags[x]); } if (workspaceCheck && Array.isArray(fileEdits.workspaceExcludes) && fileEdits.workspaceExcludes.length) { - const tags = await this.workspaceStatsService.getTags(); + const tags = await this.workspaceTagsService.getTags(); workspaceCheck = !!tags && !fileEdits.workspaceExcludes.some(x => !!tags[x]); } if (filePathCheck && workspaceCheck) { diff --git a/src/vs/workbench/contrib/extensions/browser/extensionTipsService.ts b/src/vs/workbench/contrib/extensions/browser/extensionTipsService.ts index 722c6fb9e9d8e..f3cde426dd0e8 100644 --- a/src/vs/workbench/contrib/extensions/browser/extensionTipsService.ts +++ b/src/vs/workbench/contrib/extensions/browser/extensionTipsService.ts @@ -39,7 +39,7 @@ import { ExtensionType } from 'vs/platform/extensions/common/extensions'; import { extname } from 'vs/base/common/resources'; import { IExeBasedExtensionTip, IProductService } from 'vs/platform/product/common/productService'; import { timeout } from 'vs/base/common/async'; -import { IWorkspaceStatsService } from 'vs/workbench/contrib/stats/common/workspaceStats'; +import { IWorkspaceTagsService } from 'vs/workbench/contrib/tags/common/workspaceTags'; import { setImmediate, isWeb } from 'vs/base/common/platform'; import { platform, env as processEnv } from 'vs/base/common/process'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; @@ -107,7 +107,7 @@ export class ExtensionTipsService extends Disposable implements IExtensionTipsSe @IExtensionManagementService private readonly extensionManagementService: IExtensionManagementService, @IExtensionsWorkbenchService private readonly extensionWorkbenchService: IExtensionsWorkbenchService, @IExperimentService private readonly experimentService: IExperimentService, - @IWorkspaceStatsService private readonly workspaceStatsService: IWorkspaceStatsService, + @IWorkspaceTagsService private readonly workspaceTagsService: IWorkspaceTagsService, @IProductService private readonly productService: IProductService ) { super(); @@ -1114,7 +1114,7 @@ export class ExtensionTipsService extends Disposable implements IExtensionTipsSe const storageKey = 'extensionsAssistant/dynamicWorkspaceRecommendations'; const workspaceUri = this.contextService.getWorkspace().folders[0].uri; - return Promise.all([this.workspaceStatsService.getHashedRemotesFromUri(workspaceUri, false), this.workspaceStatsService.getHashedRemotesFromUri(workspaceUri, true)]).then(([hashedRemotes1, hashedRemotes2]) => { + return Promise.all([this.workspaceTagsService.getHashedRemotesFromUri(workspaceUri, false), this.workspaceTagsService.getHashedRemotesFromUri(workspaceUri, true)]).then(([hashedRemotes1, hashedRemotes2]) => { const hashedRemotes = (hashedRemotes1 || []).concat(hashedRemotes2 || []); if (!hashedRemotes.length) { return undefined; diff --git a/src/vs/workbench/contrib/stats/browser/workspaceStatsService.ts b/src/vs/workbench/contrib/tags/browser/workspaceTagsService.ts similarity index 78% rename from src/vs/workbench/contrib/stats/browser/workspaceStatsService.ts rename to src/vs/workbench/contrib/tags/browser/workspaceTagsService.ts index 14af4b898c089..d21d6688d7ac5 100644 --- a/src/vs/workbench/contrib/stats/browser/workspaceStatsService.ts +++ b/src/vs/workbench/contrib/tags/browser/workspaceTagsService.ts @@ -6,9 +6,9 @@ import { WorkbenchState, IWorkspace } from 'vs/platform/workspace/common/workspace'; import { URI } from 'vs/base/common/uri'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; -import { IWorkspaceStatsService, Tags } from 'vs/workbench/contrib/stats/common/workspaceStats'; +import { IWorkspaceTagsService, Tags } from 'vs/workbench/contrib/tags/common/workspaceTags'; -export class NoOpWorkspaceStatsService implements IWorkspaceStatsService { +export class NoOpWorkspaceTagsService implements IWorkspaceTagsService { _serviceBrand: undefined; @@ -25,4 +25,4 @@ export class NoOpWorkspaceStatsService implements IWorkspaceStatsService { } } -registerSingleton(IWorkspaceStatsService, NoOpWorkspaceStatsService, true); +registerSingleton(IWorkspaceTagsService, NoOpWorkspaceTagsService, true); diff --git a/src/vs/workbench/contrib/stats/common/workspaceStats.ts b/src/vs/workbench/contrib/tags/common/workspaceTags.ts similarity index 88% rename from src/vs/workbench/contrib/stats/common/workspaceStats.ts rename to src/vs/workbench/contrib/tags/common/workspaceTags.ts index c8205e1a07637..6814b5cdf3fd7 100644 --- a/src/vs/workbench/contrib/stats/common/workspaceStats.ts +++ b/src/vs/workbench/contrib/tags/common/workspaceTags.ts @@ -9,9 +9,9 @@ import { URI } from 'vs/base/common/uri'; export type Tags = { [index: string]: boolean | number | string | undefined }; -export const IWorkspaceStatsService = createDecorator('workspaceStatsService'); +export const IWorkspaceTagsService = createDecorator('workspaceTagsService'); -export interface IWorkspaceStatsService { +export interface IWorkspaceTagsService { _serviceBrand: undefined; getTags(): Promise; diff --git a/src/vs/workbench/contrib/stats/electron-browser/stats.contribution.ts b/src/vs/workbench/contrib/tags/electron-browser/tags.contribution.ts similarity index 75% rename from src/vs/workbench/contrib/stats/electron-browser/stats.contribution.ts rename to src/vs/workbench/contrib/tags/electron-browser/tags.contribution.ts index b2db16dac1c3d..28995ce564efb 100644 --- a/src/vs/workbench/contrib/stats/electron-browser/stats.contribution.ts +++ b/src/vs/workbench/contrib/tags/electron-browser/tags.contribution.ts @@ -5,8 +5,8 @@ import { Registry } from 'vs/platform/registry/common/platform'; import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions'; -import { WorkspaceStats } from 'vs/workbench/contrib/stats/electron-browser/workspaceStats'; +import { WorkspaceTags } from 'vs/workbench/contrib/tags/electron-browser/workspaceTags'; import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle'; -// Register Workspace Stats Contribution -Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(WorkspaceStats, LifecyclePhase.Eventually); \ No newline at end of file +// Register Workspace Tags Contribution +Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(WorkspaceTags, LifecyclePhase.Eventually); diff --git a/src/vs/workbench/contrib/stats/electron-browser/workspaceStats.ts b/src/vs/workbench/contrib/tags/electron-browser/workspaceTags.ts similarity index 95% rename from src/vs/workbench/contrib/stats/electron-browser/workspaceStats.ts rename to src/vs/workbench/contrib/tags/electron-browser/workspaceTags.ts index c72c8fb8b5f44..9faaf388fd6ad 100644 --- a/src/vs/workbench/contrib/stats/electron-browser/workspaceStats.ts +++ b/src/vs/workbench/contrib/tags/electron-browser/workspaceTags.ts @@ -13,7 +13,7 @@ import { IWorkbenchContribution } from 'vs/workbench/common/contributions'; import { endsWith } from 'vs/base/common/strings'; import { ITextFileService, } from 'vs/workbench/services/textfile/common/textfiles'; import { ISharedProcessService } from 'vs/platform/ipc/electron-browser/sharedProcessService'; -import { IWorkspaceStatsService, Tags } from 'vs/workbench/contrib/stats/common/workspaceStats'; +import { IWorkspaceTagsService, Tags } from 'vs/workbench/contrib/tags/common/workspaceTags'; import { IWorkspaceInformation } from 'vs/platform/diagnostics/common/diagnostics'; import { IRequestService } from 'vs/platform/request/common/request'; import { isWindows } from 'vs/base/common/platform'; @@ -137,7 +137,7 @@ export function getHashedRemotesFromConfig(text: string, stripEndingDotGit: bool }); } -export class WorkspaceStats implements IWorkbenchContribution { +export class WorkspaceTags implements IWorkbenchContribution { constructor( @IFileService private readonly fileService: IFileService, @@ -146,7 +146,7 @@ export class WorkspaceStats implements IWorkbenchContribution { @IRequestService private readonly requestService: IRequestService, @ITextFileService private readonly textFileService: ITextFileService, @ISharedProcessService private readonly sharedProcessService: ISharedProcessService, - @IWorkspaceStatsService private readonly workspaceStatsService: IWorkspaceStatsService + @IWorkspaceTagsService private readonly workspaceTagsService: IWorkspaceTagsService ) { if (this.telemetryService.isOptedIn) { this.report(); @@ -157,8 +157,8 @@ export class WorkspaceStats implements IWorkbenchContribution { // Windows-only Edition Event this.reportWindowsEdition(); - // Workspace Stats - this.workspaceStatsService.getTags() + // Workspace Tags + this.workspaceTagsService.getTags() .then(tags => this.reportWorkspaceTags(tags), error => onUnexpectedError(error)); // Cloud Stats @@ -192,7 +192,7 @@ export class WorkspaceStats implements IWorkbenchContribution { private async getWorkspaceInformation(): Promise { const workspace = this.contextService.getWorkspace(); const state = this.contextService.getWorkbenchState(); - const telemetryId = this.workspaceStatsService.getTelemetryWorkspaceId(workspace, state); + const telemetryId = this.workspaceTagsService.getTelemetryWorkspaceId(workspace, state); return this.telemetryService.getTelemetryInfo().then(info => { return { id: workspace.id, @@ -243,7 +243,7 @@ export class WorkspaceStats implements IWorkbenchContribution { private reportRemotes(workspaceUris: URI[]): void { Promise.all(workspaceUris.map(workspaceUri => { - return this.workspaceStatsService.getHashedRemotesFromUri(workspaceUri, true); + return this.workspaceTagsService.getHashedRemotesFromUri(workspaceUri, true); })).then(hashedRemotes => { /* __GDPR__ "workspace.hashedRemotes" : { @@ -268,7 +268,7 @@ export class WorkspaceStats implements IWorkbenchContribution { return this.fileService.resolveAll(uris.map(resource => ({ resource }))).then( results => { const names = ([]).concat(...results.map(result => result.success ? (result.stat!.children || []) : [])).map(c => c.name); - const referencesAzure = WorkspaceStats.searchArray(names, /azure/i); + const referencesAzure = WorkspaceTags.searchArray(names, /azure/i); if (referencesAzure) { tags['node'] = true; } diff --git a/src/vs/workbench/contrib/stats/electron-browser/workspaceStatsService.ts b/src/vs/workbench/contrib/tags/electron-browser/workspaceTagsService.ts similarity index 98% rename from src/vs/workbench/contrib/stats/electron-browser/workspaceStatsService.ts rename to src/vs/workbench/contrib/tags/electron-browser/workspaceTagsService.ts index f92507edb7691..fd820d40690f8 100644 --- a/src/vs/workbench/contrib/stats/electron-browser/workspaceStatsService.ts +++ b/src/vs/workbench/contrib/tags/electron-browser/workspaceTagsService.ts @@ -19,8 +19,8 @@ import { localize } from 'vs/nls'; import Severity from 'vs/base/common/severity'; import { joinPath } from 'vs/base/common/resources'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; -import { IWorkspaceStatsService, Tags } from 'vs/workbench/contrib/stats/common/workspaceStats'; -import { getHashedRemotesFromConfig } from 'vs/workbench/contrib/stats/electron-browser/workspaceStats'; +import { IWorkspaceTagsService, Tags } from 'vs/workbench/contrib/tags/common/workspaceTags'; +import { getHashedRemotesFromConfig } from 'vs/workbench/contrib/tags/electron-browser/workspaceTags'; import { IProductService } from 'vs/platform/product/common/productService'; const ModulesToLookFor = [ @@ -91,7 +91,7 @@ const PyModulesToLookFor = [ 'botframework-connector' ]; -export class WorkspaceStatsService implements IWorkspaceStatsService { +export class WorkspaceTagsService implements IWorkspaceTagsService { _serviceBrand: undefined; private _tags: Tags | undefined; @@ -106,7 +106,7 @@ export class WorkspaceStatsService implements IWorkspaceStatsService { @ITextFileService private readonly textFileService: ITextFileService ) { } - public async getTags(): Promise { + async getTags(): Promise { if (!this._tags) { this._tags = await this.resolveWorkspaceTags(this.environmentService.configuration, rootFiles => this.handleWorkspaceFiles(rootFiles)); } @@ -114,7 +114,7 @@ export class WorkspaceStatsService implements IWorkspaceStatsService { return this._tags; } - public getTelemetryWorkspaceId(workspace: IWorkspace, state: WorkbenchState): string | undefined { + getTelemetryWorkspaceId(workspace: IWorkspace, state: WorkbenchState): string | undefined { function createHash(uri: URI): string { return crypto.createHash('sha1').update(uri.scheme === Schemas.file ? uri.fsPath : uri.toString()).digest('hex'); } @@ -505,4 +505,4 @@ export class WorkspaceStatsService implements IWorkspaceStatsService { } } -registerSingleton(IWorkspaceStatsService, WorkspaceStatsService, true); +registerSingleton(IWorkspaceTagsService, WorkspaceTagsService, true); diff --git a/src/vs/workbench/contrib/stats/test/workspaceStats.test.ts b/src/vs/workbench/contrib/tags/test/workspaceTags.test.ts similarity index 98% rename from src/vs/workbench/contrib/stats/test/workspaceStats.test.ts rename to src/vs/workbench/contrib/tags/test/workspaceTags.test.ts index 3cb2162ecdb97..02591953ceb11 100644 --- a/src/vs/workbench/contrib/stats/test/workspaceStats.test.ts +++ b/src/vs/workbench/contrib/tags/test/workspaceTags.test.ts @@ -5,13 +5,13 @@ import * as assert from 'assert'; import * as crypto from 'crypto'; -import { getDomainsOfRemotes, getRemotes, getHashedRemotesFromConfig } from 'vs/workbench/contrib/stats/electron-browser/workspaceStats'; +import { getDomainsOfRemotes, getRemotes, getHashedRemotesFromConfig } from 'vs/workbench/contrib/tags/electron-browser/workspaceTags'; function hash(value: string): string { return crypto.createHash('sha1').update(value.toString()).digest('hex'); } -suite('Telemetry - WorkspaceStats', () => { +suite('Telemetry - WorkspaceTags', () => { const whitelist = [ 'github.com', @@ -163,4 +163,4 @@ suite('Telemetry - WorkspaceStats', () => { fetch = +refs/heads/*:refs/remotes/origin/* `; } -}); \ No newline at end of file +}); diff --git a/src/vs/workbench/workbench.desktop.main.ts b/src/vs/workbench/workbench.desktop.main.ts index 460c38ba63adc..7969bc1668107 100644 --- a/src/vs/workbench/workbench.desktop.main.ts +++ b/src/vs/workbench/workbench.desktop.main.ts @@ -80,9 +80,9 @@ import 'vs/workbench/contrib/localizations/browser/localizations.contribution'; // Logs import 'vs/workbench/contrib/logs/electron-browser/logs.contribution'; -// Stats -import 'vs/workbench/contrib/stats/electron-browser/workspaceStatsService'; -import 'vs/workbench/contrib/stats/electron-browser/stats.contribution'; +// Tags +import 'vs/workbench/contrib/tags/electron-browser/workspaceTagsService'; +import 'vs/workbench/contrib/tags/electron-browser/tags.contribution'; // Rapid Render Splash import 'vs/workbench/contrib/splash/electron-browser/partsSplash.contribution'; diff --git a/src/vs/workbench/workbench.web.main.ts b/src/vs/workbench/workbench.web.main.ts index 0e6601077d354..f424c87d92735 100644 --- a/src/vs/workbench/workbench.web.main.ts +++ b/src/vs/workbench/workbench.web.main.ts @@ -39,7 +39,7 @@ import 'vs/workbench/services/configurationResolver/browser/configurationResolve import 'vs/workbench/services/credentials/browser/credentialsService'; import 'vs/workbench/services/url/browser/urlService'; import 'vs/workbench/services/update/browser/updateService'; -import 'vs/workbench/contrib/stats/browser/workspaceStatsService'; +import 'vs/workbench/contrib/tags/browser/workspaceTagsService'; import 'vs/workbench/services/workspaces/browser/workspacesService'; import 'vs/workbench/services/workspaces/browser/workspaceEditingService'; import 'vs/workbench/services/dialogs/browser/dialogService'; From ef4d7e4e0171660511d27bcb60e4962141f86a23 Mon Sep 17 00:00:00 2001 From: Jean Pierre Date: Wed, 13 Nov 2019 01:51:00 -0500 Subject: [PATCH 171/352] Fixes #84197 (#84334) --- src/vs/workbench/contrib/webview/common/resourceLoader.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/webview/common/resourceLoader.ts b/src/vs/workbench/contrib/webview/common/resourceLoader.ts index ea28683ef4ba4..4b7b7cfdc443e 100644 --- a/src/vs/workbench/contrib/webview/common/resourceLoader.ts +++ b/src/vs/workbench/contrib/webview/common/resourceLoader.ts @@ -83,7 +83,7 @@ function normalizeRequestPath(requestUri: URI) { // Modern vscode-resources uris put the scheme of the requested resource as the authority if (requestUri.authority) { - return URI.parse(`${requestUri.authority}:${requestUri.path}`).with({ + return URI.parse(`${requestUri.authority}:${encodeURIComponent(requestUri.path).replace(/%2F/g, '/')}`).with({ query: requestUri.query, fragment: requestUri.fragment }); From fe7e4b231bafc034294871f4857be6f6b2c5a4df Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Tue, 12 Nov 2019 22:59:47 -0800 Subject: [PATCH 172/352] Use log service instead of console.log in extHostwebview For #84283 --- src/vs/workbench/api/common/extHost.api.impl.ts | 2 +- src/vs/workbench/api/common/extHostWebview.ts | 15 +++++++++------ .../electron-browser/api/extHostWebview.test.ts | 13 +++++++------ 3 files changed, 17 insertions(+), 13 deletions(-) diff --git a/src/vs/workbench/api/common/extHost.api.impl.ts b/src/vs/workbench/api/common/extHost.api.impl.ts index 26ef1db530a95..c872655f012c2 100644 --- a/src/vs/workbench/api/common/extHost.api.impl.ts +++ b/src/vs/workbench/api/common/extHost.api.impl.ts @@ -105,7 +105,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I const extHostOutputService = rpcProtocol.set(ExtHostContext.ExtHostOutputService, accessor.get(IExtHostOutputService)); // manually create and register addressable instances - const extHostWebviews = rpcProtocol.set(ExtHostContext.ExtHostWebviews, new ExtHostWebviews(rpcProtocol, initData.environment, extHostWorkspace)); + const extHostWebviews = rpcProtocol.set(ExtHostContext.ExtHostWebviews, new ExtHostWebviews(rpcProtocol, initData.environment, extHostWorkspace, extHostLogService)); const extHostUrls = rpcProtocol.set(ExtHostContext.ExtHostUrls, new ExtHostUrls(rpcProtocol)); const extHostDocuments = rpcProtocol.set(ExtHostContext.ExtHostDocuments, new ExtHostDocuments(rpcProtocol, extHostDocumentsAndEditors)); const extHostDocumentContentProviders = rpcProtocol.set(ExtHostContext.ExtHostDocumentContentProviders, new ExtHostDocumentContentProvider(rpcProtocol, extHostDocumentsAndEditors, extHostLogService)); diff --git a/src/vs/workbench/api/common/extHostWebview.ts b/src/vs/workbench/api/common/extHostWebview.ts index bd3b3b0daf196..e13466a070d35 100644 --- a/src/vs/workbench/api/common/extHostWebview.ts +++ b/src/vs/workbench/api/common/extHostWebview.ts @@ -5,10 +5,12 @@ import { Emitter, Event } from 'vs/base/common/event'; import { Disposable } from 'vs/base/common/lifecycle'; +import { assertIsDefined } from 'vs/base/common/types'; import { URI, UriComponents } from 'vs/base/common/uri'; import { generateUuid } from 'vs/base/common/uuid'; import * as modes from 'vs/editor/common/modes'; import { IExtensionDescription } from 'vs/platform/extensions/common/extensions'; +import { ILogService } from 'vs/platform/log/common/log'; import * as typeConverters from 'vs/workbench/api/common/extHostTypeConverters'; import { IExtHostWorkspace } from 'vs/workbench/api/common/extHostWorkspace'; import { EditorViewColumn } from 'vs/workbench/api/common/shared/editor'; @@ -16,7 +18,6 @@ import { asWebviewUri, WebviewInitData } from 'vs/workbench/api/common/shared/we import * as vscode from 'vscode'; import { ExtHostWebviewsShape, IMainContext, MainContext, MainThreadWebviewsShape, WebviewPanelHandle, WebviewPanelViewStateData } from './extHost.protocol'; import { Disposable as VSCodeDisposable } from './extHostTypes'; -import { assertIsDefined } from 'vs/base/common/types'; type IconPath = URI | { light: URI, dark: URI }; @@ -35,6 +36,7 @@ export class ExtHostWebview implements vscode.Webview { private readonly _initData: WebviewInitData, private readonly _workspace: IExtHostWorkspace | undefined, private readonly _extension: IExtensionDescription, + private readonly _logService: ILogService, ) { } public dispose() { @@ -63,7 +65,7 @@ export class ExtHostWebview implements vscode.Webview { if (this._initData.isExtensionDevelopmentDebug && !this._hasCalledAsWebviewUri) { if (/(["'])vscode-resource:([^\s'"]+?)(["'])/i.test(value)) { this._hasCalledAsWebviewUri = true; - console.warn(`${this._extension.identifier.value} created a webview that appears to use the vscode-resource scheme directly. Please migrate to use the 'webview.asWebviewUri' api instead: https://aka.ms/vscode-webview-use-aswebviewuri`); + this._logService.warn(`${this._extension.identifier.value} created a webview that appears to use the vscode-resource scheme directly. Please migrate to use the 'webview.asWebviewUri' api instead: https://aka.ms/vscode-webview-use-aswebviewuri`); } } this._proxy.$setHtml(this._handle, value); @@ -272,6 +274,7 @@ export class ExtHostWebviews implements ExtHostWebviewsShape { mainContext: IMainContext, private readonly initData: WebviewInitData, private readonly workspace: IExtHostWorkspace | undefined, + private readonly _logService: ILogService, ) { this._proxy = mainContext.getProxy(MainContext.MainThreadWebviews); } @@ -292,7 +295,7 @@ export class ExtHostWebviews implements ExtHostWebviewsShape { const handle = ExtHostWebviews.newHandle(); this._proxy.$createWebviewPanel({ id: extension.identifier, location: extension.extensionLocation }, handle, viewType, title, webviewShowOptions, convertWebviewOptions(extension, this.workspace, options)); - const webview = new ExtHostWebview(handle, this._proxy, options, this.initData, this.workspace, extension); + const webview = new ExtHostWebview(handle, this._proxy, options, this.initData, this.workspace, extension, this._logService); const panel = new ExtHostWebviewEditor(handle, this._proxy, viewType, title, viewColumn, options, webview); this._webviewPanels.set(handle, panel); return panel; @@ -349,7 +352,7 @@ export class ExtHostWebviews implements ExtHostWebviewsShape { _handle: WebviewPanelHandle, extensionId: string ): void { - console.warn(`${extensionId} created a webview without a content security policy: https://aka.ms/vscode-webview-missing-csp`); + this._logService.warn(`${extensionId} created a webview without a content security policy: https://aka.ms/vscode-webview-missing-csp`); } public $onDidChangeWebviewPanelViewStates(newStates: WebviewPanelViewStateData): void { @@ -409,7 +412,7 @@ export class ExtHostWebviews implements ExtHostWebviewsShape { } const { serializer, extension } = entry; - const webview = new ExtHostWebview(webviewHandle, this._proxy, options, this.initData, this.workspace, extension); + const webview = new ExtHostWebview(webviewHandle, this._proxy, options, this.initData, this.workspace, extension, this._logService); const revivedPanel = new ExtHostWebviewEditor(webviewHandle, this._proxy, viewType, title, typeof position === 'number' && position >= 0 ? typeConverters.ViewColumn.to(position) : undefined, options, webview); this._webviewPanels.set(webviewHandle, revivedPanel); await serializer.deserializeWebviewPanel(revivedPanel, state); @@ -429,7 +432,7 @@ export class ExtHostWebviews implements ExtHostWebviewsShape { } const { provider, extension } = entry; - const webview = new ExtHostWebview(handle, this._proxy, options, this.initData, this.workspace, extension); + const webview = new ExtHostWebview(handle, this._proxy, options, this.initData, this.workspace, extension, this._logService); const revivedPanel = new ExtHostWebviewEditor(handle, this._proxy, viewType, title, typeof position === 'number' && position >= 0 ? typeConverters.ViewColumn.to(position) : undefined, options, webview); this._webviewPanels.set(handle, revivedPanel); const capabilities = await provider.resolveWebviewEditor({ resource: URI.revive(resource) }, revivedPanel); diff --git a/src/vs/workbench/test/electron-browser/api/extHostWebview.test.ts b/src/vs/workbench/test/electron-browser/api/extHostWebview.test.ts index 37a88c04dcc65..8febbdbdf9eb7 100644 --- a/src/vs/workbench/test/electron-browser/api/extHostWebview.test.ts +++ b/src/vs/workbench/test/electron-browser/api/extHostWebview.test.ts @@ -4,14 +4,15 @@ *--------------------------------------------------------------------------------------------*/ import * as assert from 'assert'; +import { URI } from 'vs/base/common/uri'; +import { IExtensionDescription } from 'vs/platform/extensions/common/extensions'; +import { NullLogService } from 'vs/platform/log/common/log'; import { MainThreadWebviews } from 'vs/workbench/api/browser/mainThreadWebview'; import { ExtHostWebviews } from 'vs/workbench/api/common/extHostWebview'; +import { EditorViewColumn } from 'vs/workbench/api/common/shared/editor'; import { mock } from 'vs/workbench/test/electron-browser/api/mock'; import * as vscode from 'vscode'; import { SingleProxyRPCProtocol } from './testRPCProtocol'; -import { EditorViewColumn } from 'vs/workbench/api/common/shared/editor'; -import { URI } from 'vs/base/common/uri'; -import { IExtensionDescription } from 'vs/platform/extensions/common/extensions'; suite('ExtHostWebview', () => { @@ -23,7 +24,7 @@ suite('ExtHostWebview', () => { webviewCspSource: '', webviewResourceRoot: '', isExtensionDevelopmentDebug: false, - }, undefined); + }, undefined, new NullLogService()); let lastInvokedDeserializer: vscode.WebviewPanelSerializer | undefined = undefined; @@ -61,7 +62,7 @@ suite('ExtHostWebview', () => { webviewCspSource: '', webviewResourceRoot: 'vscode-resource://{{resource}}', isExtensionDevelopmentDebug: false, - }, undefined); + }, undefined, new NullLogService()); const webview = extHostWebviews.createWebviewPanel({} as any, 'type', 'title', 1, {}); assert.strictEqual( @@ -102,7 +103,7 @@ suite('ExtHostWebview', () => { webviewCspSource: '', webviewResourceRoot: `https://{{uuid}}.webview.contoso.com/commit/{{resource}}`, isExtensionDevelopmentDebug: false, - }, undefined); + }, undefined, new NullLogService()); const webview = extHostWebviews.createWebviewPanel({} as any, 'type', 'title', 1, {}); function stripEndpointUuid(input: string) { From f1dfda569cd0b48716ba51c2be48091ba6440f05 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Wed, 13 Nov 2019 08:20:57 +0100 Subject: [PATCH 173/352] Revert "web - workaround new window issue with pwa" This reverts commit 54a6229d6855fbd5b861276a3ff6eccd6b3f1cc7. --- src/vs/code/browser/workbench/workbench.ts | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/vs/code/browser/workbench/workbench.ts b/src/vs/code/browser/workbench/workbench.ts index 28b0e9a3b156c..a599f5a7ebf07 100644 --- a/src/vs/code/browser/workbench/workbench.ts +++ b/src/vs/code/browser/workbench/workbench.ts @@ -11,6 +11,7 @@ import { Disposable } from 'vs/base/common/lifecycle'; import { request } from 'vs/base/parts/request/browser/request'; import { isFolderToOpen, isWorkspaceToOpen } from 'vs/platform/windows/common/windows'; import { isEqual } from 'vs/base/common/resources'; +import { isStandalone } from 'vs/base/browser/browser'; interface ICredential { service: string; @@ -222,7 +223,7 @@ class WorkspaceProvider implements IWorkspaceProvider { if (options?.reuse) { window.location.href = targetHref; } else { - if (this.isRunningInPWA()) { // TODO@ben figure out why browser.isStandalone would not work? + if (isStandalone) { window.open(targetHref, '_blank', 'toolbar=no'); // ensures to open another 'standalone' window! } else { window.open(targetHref); @@ -231,10 +232,6 @@ class WorkspaceProvider implements IWorkspaceProvider { } } - private isRunningInPWA(): boolean { - return (window.matchMedia && window.matchMedia('(display-mode: standalone)').matches); - } - private createTargetUrl(workspace: IWorkspace, options?: { reuse?: boolean, payload?: object }): string | undefined { // Empty From 54faeeddf049aaf3e77fa6f81b761c00972da62f Mon Sep 17 00:00:00 2001 From: Alex Ross Date: Wed, 13 Nov 2019 09:46:14 +0100 Subject: [PATCH 174/352] Update title for single views (#84579) Fixes #84138 --- src/vs/workbench/browser/parts/views/panelViewlet.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/browser/parts/views/panelViewlet.ts b/src/vs/workbench/browser/parts/views/panelViewlet.ts index 7a6e3e450ce7c..b4fd837aaa6aa 100644 --- a/src/vs/workbench/browser/parts/views/panelViewlet.ts +++ b/src/vs/workbench/browser/parts/views/panelViewlet.ts @@ -65,7 +65,7 @@ export abstract class ViewletPanel extends Panel implements IView { private _isVisible: boolean = false; readonly id: string; - readonly title: string; + title: string; protected actionRunner?: IActionRunner; protected toolbar?: ToolBar; @@ -169,6 +169,7 @@ export abstract class ViewletPanel extends Panel implements IView { if (this.titleContainer) { this.titleContainer.textContent = title; } + this.title = title; this._onDidChangeTitleArea.fire(); } From b98271b76a54ccdbf6e5afa697571b343edfeed6 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Wed, 13 Nov 2019 10:07:19 +0100 Subject: [PATCH 175/352] change comment --- .../services/extensions/common/extensionHostProcessManager.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/services/extensions/common/extensionHostProcessManager.ts b/src/vs/workbench/services/extensions/common/extensionHostProcessManager.ts index 9ed5187fabe8e..dc4b8bf9690f2 100644 --- a/src/vs/workbench/services/extensions/common/extensionHostProcessManager.ts +++ b/src/vs/workbench/services/extensions/common/extensionHostProcessManager.ts @@ -185,7 +185,7 @@ export class ExtensionHostProcessManager extends Disposable { this._extensionHostProcessRPCProtocol = new RPCProtocol(protocol, logger); this._register(this._extensionHostProcessRPCProtocol.onDidChangeResponsiveState((responsiveState: ResponsiveState) => this._onDidChangeResponsiveState.fire(responsiveState))); const extHostContext: IExtHostContext = { - remoteAuthority: this._remoteAuthority! /* TODO: sandy081, remove not-null assertion */, + remoteAuthority: this._remoteAuthority! /* TODO: alexdima, remove not-null assertion */, getProxy: (identifier: ProxyIdentifier): T => this._extensionHostProcessRPCProtocol!.getProxy(identifier), set: (identifier: ProxyIdentifier, instance: R): R => this._extensionHostProcessRPCProtocol!.set(identifier, instance), assertRegistered: (identifiers: ProxyIdentifier[]): void => this._extensionHostProcessRPCProtocol!.assertRegistered(identifiers), From d8f35641fbf17540942bb79622763d72dc935b1f Mon Sep 17 00:00:00 2001 From: Alex Ross Date: Wed, 13 Nov 2019 10:22:01 +0100 Subject: [PATCH 176/352] Move remote explorer help+feedback into a ? button --- .../contrib/remote/browser/remote.ts | 366 +++++------------- .../contrib/remote/browser/remoteViewlet.css | 49 +-- .../remote/common/remoteExplorerService.ts | 72 +++- 3 files changed, 186 insertions(+), 301 deletions(-) diff --git a/src/vs/workbench/contrib/remote/browser/remote.ts b/src/vs/workbench/contrib/remote/browser/remote.ts index 5a334ade80781..5901752fe70f0 100644 --- a/src/vs/workbench/contrib/remote/browser/remote.ts +++ b/src/vs/workbench/contrib/remote/browser/remote.ts @@ -5,7 +5,6 @@ import 'vs/css!./remoteViewlet'; import * as nls from 'vs/nls'; -import * as dom from 'vs/base/browser/dom'; import { URI } from 'vs/base/common/uri'; import { IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; @@ -18,19 +17,12 @@ import { IContextMenuService } from 'vs/platform/contextview/browser/contextView import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; import { FilterViewContainerViewlet } from 'vs/workbench/browser/parts/views/viewsViewlet'; import { VIEWLET_ID, VIEW_CONTAINER } from 'vs/workbench/contrib/remote/common/remote.contribution'; -import { ViewletPanel, IViewletPanelOptions } from 'vs/workbench/browser/parts/views/panelViewlet'; -import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { IViewDescriptor, IViewsRegistry, Extensions } from 'vs/workbench/common/views'; import { Registry } from 'vs/platform/registry/common/platform'; -import { ExtensionsRegistry, IExtensionPointUser } from 'vs/workbench/services/extensions/common/extensionsRegistry'; -import { WorkbenchAsyncDataTree, TreeResourceNavigator2 } from 'vs/platform/list/browser/listService'; -import { IListVirtualDelegate } from 'vs/base/browser/ui/list/list'; -import { ITreeRenderer, ITreeNode, IAsyncDataSource } from 'vs/base/browser/ui/tree/tree'; -import { Event } from 'vs/base/common/event'; import { IExtensionDescription } from 'vs/platform/extensions/common/extensions'; import { IOpenerService } from 'vs/platform/opener/common/opener'; -import { IQuickInputService } from 'vs/platform/quickinput/common/quickInput'; +import { IQuickInputService, IQuickPickItem } from 'vs/platform/quickinput/common/quickInput'; import { ICommandService } from 'vs/platform/commands/common/commands'; import { ViewletRegistry, Extensions as ViewletExtensions, ViewletDescriptor, ShowViewletAction } from 'vs/workbench/browser/viewlet'; import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet'; @@ -49,184 +41,23 @@ import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle'; import { SwitchRemoteViewItem, SwitchRemoteAction } from 'vs/workbench/contrib/remote/browser/explorerViewItems'; import { Action, IActionViewItem, IAction } from 'vs/base/common/actions'; import { isStringArray } from 'vs/base/common/types'; -import { IRemoteExplorerService } from 'vs/workbench/services/remote/common/remoteExplorerService'; - -interface HelpInformation { - extensionDescription: IExtensionDescription; - getStarted?: string; - documentation?: string; - feedback?: string; - issues?: string; -} - -const remoteHelpExtPoint = ExtensionsRegistry.registerExtensionPoint({ - extensionPoint: 'remoteHelp', - jsonSchema: { - description: nls.localize('RemoteHelpInformationExtPoint', 'Contributes help information for Remote'), - type: 'object', - properties: { - 'getStarted': { - description: nls.localize('RemoteHelpInformationExtPoint.getStarted', "The url to your project's Getting Started page"), - type: 'string' - }, - 'documentation': { - description: nls.localize('RemoteHelpInformationExtPoint.documentation', "The url to your project's documentation page"), - type: 'string' - }, - 'feedback': { - description: nls.localize('RemoteHelpInformationExtPoint.feedback', "The url to your project's feedback reporter"), - type: 'string' - }, - 'issues': { - description: nls.localize('RemoteHelpInformationExtPoint.issues', "The url to your project's issues list"), - type: 'string' - } - } - } -}); - -interface IViewModel { - helpInformations: HelpInformation[]; -} - -class HelpTreeVirtualDelegate implements IListVirtualDelegate { - getHeight(element: IHelpItem): number { - return 22; - } - - getTemplateId(element: IHelpItem): string { - return 'HelpItemTemplate'; - } -} - -interface IHelpItemTemplateData { - parent: HTMLElement; - icon: HTMLElement; -} - -class HelpTreeRenderer implements ITreeRenderer { - templateId: string = 'HelpItemTemplate'; - - renderTemplate(container: HTMLElement): IHelpItemTemplateData { - dom.addClass(container, 'remote-help-tree-node-item'); - - const icon = dom.append(container, dom.$('.remote-help-tree-node-item-icon')); - - const data = Object.create(null); - data.parent = container; - data.icon = icon; - - return data; - } - - renderElement(element: ITreeNode, index: number, templateData: IHelpItemTemplateData, height: number | undefined): void { - const container = templateData.parent; - dom.append(container, templateData.icon); - dom.addClass(templateData.icon, element.element.key); - const labelContainer = dom.append(container, dom.$('.help-item-label')); - labelContainer.innerText = element.element.label; - } - - disposeTemplate(templateData: IHelpItemTemplateData): void { - - } -} - -class HelpDataSource implements IAsyncDataSource { - hasChildren(element: any) { - return element instanceof HelpModel; - } - - getChildren(element: any) { - if (element instanceof HelpModel && element.items) { - return element.items; - } - - return []; - } -} - -interface IHelpItem { - key: string; - label: string; - handleClick(): Promise; -} - -class HelpItem implements IHelpItem { - constructor( - public key: string, - public label: string, - public values: { extensionDescription: IExtensionDescription; url: string }[], - private openerService: IOpenerService, - private quickInputService: IQuickInputService - ) { - } - - async handleClick() { - if (this.values.length > 1) { - let actions = this.values.map(value => { - return { - label: value.extensionDescription.displayName || value.extensionDescription.identifier.value, - description: value.url - }; - }); - - const action = await this.quickInputService.pick(actions, { placeHolder: nls.localize('pickRemoteExtension', "Select url to open") }); - - if (action) { - await this.openerService.open(URI.parse(action.description)); - } - } else { - await this.openerService.open(URI.parse(this.values[0].url)); - } - } -} - -class IssueReporterItem implements IHelpItem { - constructor( - public key: string, - public label: string, - public extensionDescriptions: IExtensionDescription[], - private quickInputService: IQuickInputService, - private commandService: ICommandService - ) { - } - - async handleClick() { - if (this.extensionDescriptions.length > 1) { - let actions = this.extensionDescriptions.map(extension => { - return { - label: extension.displayName || extension.identifier.value, - identifier: extension.identifier - }; - }); - - const action = await this.quickInputService.pick(actions, { placeHolder: nls.localize('pickRemoteExtensionToReportIssue', "Select an extension to report issue") }); - - if (action) { - await this.commandService.executeCommand('workbench.action.openIssueReporter', [action.identifier.value]); - } - } else { - await this.commandService.executeCommand('workbench.action.openIssueReporter', [this.extensionDescriptions[0].identifier.value]); - } - } -} +import { IRemoteExplorerService, HelpInformation } from 'vs/workbench/services/remote/common/remoteExplorerService'; class HelpModel { items: IHelpItem[] | undefined; constructor( - viewModel: IViewModel, openerService: IOpenerService, quickInputService: IQuickInputService, - commandService: ICommandService + commandService: ICommandService, + remoteExplorerService: IRemoteExplorerService, ) { let helpItems: IHelpItem[] = []; - const getStarted = viewModel.helpInformations.filter(info => info.getStarted); + const getStarted = remoteExplorerService.helpInformation.filter(info => info.getStarted); if (getStarted.length) { helpItems.push(new HelpItem( - 'getStarted', + ['getStarted'], nls.localize('remote.help.getStarted', "Get Started"), getStarted.map((info: HelpInformation) => ({ extensionDescription: info.extensionDescription, @@ -237,11 +68,11 @@ class HelpModel { )); } - const documentation = viewModel.helpInformations.filter(info => info.documentation); + const documentation = remoteExplorerService.helpInformation.filter(info => info.documentation); if (documentation.length) { helpItems.push(new HelpItem( - 'documentation', + ['documentation'], nls.localize('remote.help.documentation', "Read Documentation"), documentation.map((info: HelpInformation) => ({ extensionDescription: info.extensionDescription, @@ -252,11 +83,11 @@ class HelpModel { )); } - const feedback = viewModel.helpInformations.filter(info => info.feedback); + const feedback = remoteExplorerService.helpInformation.filter(info => info.feedback); if (feedback.length) { helpItems.push(new HelpItem( - 'feedback', + ['feedback'], nls.localize('remote.help.feedback', "Provide Feedback"), feedback.map((info: HelpInformation) => ({ extensionDescription: info.extensionDescription, @@ -267,11 +98,11 @@ class HelpModel { )); } - const issues = viewModel.helpInformations.filter(info => info.issues); + const issues = remoteExplorerService.helpInformation.filter(info => info.issues); if (issues.length) { helpItems.push(new HelpItem( - 'issues', + ['issues'], nls.localize('remote.help.issues', "Review Issues"), issues.map((info: HelpInformation) => ({ extensionDescription: info.extensionDescription, @@ -284,9 +115,9 @@ class HelpModel { if (helpItems.length) { helpItems.push(new IssueReporterItem( - 'issueReporter', + ['issueReporter'], nls.localize('remote.help.report', "Report Issue"), - viewModel.helpInformations.map(info => info.extensionDescription), + remoteExplorerService.helpInformation.map(info => info.extensionDescription), quickInputService, commandService )); @@ -298,78 +129,104 @@ class HelpModel { } } -class HelpPanel extends ViewletPanel { - static readonly ID = '~remote.helpPanel'; - static readonly TITLE = nls.localize('remote.help', "Help and feedback"); - private tree!: WorkbenchAsyncDataTree; +interface IHelpItem extends IQuickPickItem { + label: string; + handleClick(): Promise; +} +class HelpItem implements IHelpItem { constructor( - protected viewModel: IViewModel, - options: IViewletPanelOptions, - @IKeybindingService protected keybindingService: IKeybindingService, - @IContextMenuService protected contextMenuService: IContextMenuService, - @IContextKeyService protected contextKeyService: IContextKeyService, - @IConfigurationService protected configurationService: IConfigurationService, - @IInstantiationService protected readonly instantiationService: IInstantiationService, - @IOpenerService protected openerService: IOpenerService, - @IQuickInputService protected quickInputService: IQuickInputService, - @ICommandService protected commandService: ICommandService - - + public iconClasses: string[], + public label: string, + public values: { extensionDescription: IExtensionDescription; url: string }[], + private openerService: IOpenerService, + private quickInputService: IQuickInputService ) { - super(options, keybindingService, contextMenuService, configurationService, contextKeyService); + iconClasses.push('remote-help-tree-node-item-icon'); } - protected renderBody(container: HTMLElement): void { - dom.addClass(container, 'remote-help'); - const treeContainer = document.createElement('div'); - dom.addClass(treeContainer, 'remote-help-content'); - container.appendChild(treeContainer); - - this.tree = this.instantiationService.createInstance(WorkbenchAsyncDataTree, - 'RemoteHelp', - treeContainer, - new HelpTreeVirtualDelegate(), - [new HelpTreeRenderer()], - new HelpDataSource(), - { - keyboardSupport: true, - } - ); - - const model = new HelpModel(this.viewModel, this.openerService, this.quickInputService, this.commandService); + async handleClick() { + if (this.values.length > 1) { + let actions = this.values.map(value => { + return { + label: value.extensionDescription.displayName || value.extensionDescription.identifier.value, + description: value.url + }; + }); - this.tree.setInput(model); + const action = await this.quickInputService.pick(actions, { placeHolder: nls.localize('pickRemoteExtension', "Select url to open") }); - const helpItemNavigator = this._register(new TreeResourceNavigator2(this.tree, { openOnFocus: false, openOnSelection: false })); + if (action) { + await this.openerService.open(URI.parse(action.description)); + } + } else { + await this.openerService.open(URI.parse(this.values[0].url)); + } + } +} - this._register(Event.debounce(helpItemNavigator.onDidOpenResource, (last, event) => event, 75, true)(e => { - e.element.handleClick(); - })); +class IssueReporterItem implements IHelpItem { + constructor( + public iconClasses: string[], + public label: string, + public extensionDescriptions: IExtensionDescription[], + private quickInputService: IQuickInputService, + private commandService: ICommandService + ) { + iconClasses.push('remote-help-tree-node-item-icon'); } - protected layoutBody(height: number, width: number): void { - this.tree.layout(height, width); + async handleClick() { + if (this.extensionDescriptions.length > 1) { + let actions = this.extensionDescriptions.map(extension => { + return { + label: extension.displayName || extension.identifier.value, + identifier: extension.identifier + }; + }); + + const action = await this.quickInputService.pick(actions, { placeHolder: nls.localize('pickRemoteExtensionToReportIssue', "Select an extension to report issue") }); + + if (action) { + await this.commandService.executeCommand('workbench.action.openIssueReporter', [action.identifier.value]); + } + } else { + await this.commandService.executeCommand('workbench.action.openIssueReporter', [this.extensionDescriptions[0].identifier.value]); + } } } -class HelpPanelDescriptor implements IViewDescriptor { - readonly id = HelpPanel.ID; - readonly name = HelpPanel.TITLE; - readonly ctorDescriptor: { ctor: any, arguments?: any[] }; - readonly canToggleVisibility = true; - readonly hideByDefault = false; - readonly workspace = true; +class HelpAction extends Action { + static readonly ID = 'remote.explorer.help'; + static readonly LABEL = nls.localize('remote.explorer.help', "Help and Feedback"); + private helpModel: HelpModel; + + constructor(id: string, + label: string, + @IOpenerService private readonly openerService: IOpenerService, + @IQuickInputService private readonly quickInputService: IQuickInputService, + @ICommandService private readonly commandService: ICommandService, + @IRemoteExplorerService private readonly remoteExplorerService: IRemoteExplorerService + ) { + super(id, label, 'codicon codicon-question'); + this.helpModel = new HelpModel(openerService, quickInputService, commandService, remoteExplorerService); + } - constructor(viewModel: IViewModel) { - this.ctorDescriptor = { ctor: HelpPanel, arguments: [viewModel] }; + async run(event?: any): Promise { + if (!this.helpModel.items) { + this.helpModel = new HelpModel(this.openerService, this.quickInputService, this.commandService, this.remoteExplorerService); + } + if (this.helpModel.items) { + const selection = await this.quickInputService.pick(this.helpModel.items, { placeHolder: nls.localize('remote.explorer.helpPlaceholder', "Help and Feedback") }); + if (selection) { + return selection.handleClick(); + } + } } } -export class RemoteViewlet extends FilterViewContainerViewlet implements IViewModel { - private helpPanelDescriptor = new HelpPanelDescriptor(this); +export class RemoteViewlet extends FilterViewContainerViewlet { private actions: IAction[] | undefined; - helpInformations: HelpInformation[] = []; constructor( @IWorkbenchLayoutService layoutService: IWorkbenchLayoutService, @@ -384,22 +241,6 @@ export class RemoteViewlet extends FilterViewContainerViewlet implements IViewMo @IRemoteExplorerService remoteExplorerService: IRemoteExplorerService ) { super(VIEWLET_ID, remoteExplorerService.onDidChangeTargetType, configurationService, layoutService, telemetryService, storageService, instantiationService, themeService, contextMenuService, extensionService, contextService); - this.addConstantViewDescriptors([this.helpPanelDescriptor]); - remoteHelpExtPoint.setHandler((extensions) => { - let helpInformation: HelpInformation[] = []; - for (let extension of extensions) { - this._handleRemoteInfoExtensionPoint(extension, helpInformation); - } - - this.helpInformations = helpInformation; - - const viewsRegistry = Registry.as(Extensions.ViewsRegistry); - if (this.helpInformations.length) { - viewsRegistry.registerViews([this.helpPanelDescriptor], VIEW_CONTAINER); - } else { - viewsRegistry.deregisterViews([this.helpPanelDescriptor], VIEW_CONTAINER); - } - }); } protected getFilterOn(viewDescriptor: IViewDescriptor): string | undefined { @@ -418,6 +259,7 @@ export class RemoteViewlet extends FilterViewContainerViewlet implements IViewMo if (!this.actions) { this.actions = [ this.instantiationService.createInstance(SwitchRemoteAction, SwitchRemoteAction.ID, SwitchRemoteAction.LABEL), + this.instantiationService.createInstance(HelpAction, HelpAction.ID, HelpAction.LABEL) ]; this.actions.forEach(a => { this._register(a); @@ -426,24 +268,6 @@ export class RemoteViewlet extends FilterViewContainerViewlet implements IViewMo return this.actions; } - private _handleRemoteInfoExtensionPoint(extension: IExtensionPointUser, helpInformation: HelpInformation[]) { - if (!extension.description.enableProposedApi) { - return; - } - - if (!extension.value.documentation && !extension.value.feedback && !extension.value.getStarted && !extension.value.issues) { - return; - } - - helpInformation.push({ - extensionDescription: extension.description, - getStarted: extension.value.getStarted, - documentation: extension.value.documentation, - feedback: extension.value.feedback, - issues: extension.value.issues - }); - } - getTitle(): string { const title = nls.localize('remote.explorer', "Remote Explorer"); return title; diff --git a/src/vs/workbench/contrib/remote/browser/remoteViewlet.css b/src/vs/workbench/contrib/remote/browser/remoteViewlet.css index d48d027c617d0..d95c32bbf0dc3 100644 --- a/src/vs/workbench/contrib/remote/browser/remoteViewlet.css +++ b/src/vs/workbench/contrib/remote/browser/remoteViewlet.css @@ -3,88 +3,79 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -.remote-help-content .monaco-list .monaco-list-row .remote-help-tree-node-item { - display: flex; - height: 22px; - line-height: 22px; - flex: 1; - text-overflow: ellipsis; - overflow: hidden; - flex-wrap: nowrap; -} - -.remote-help-content .monaco-list .monaco-list-row .remote-help-tree-node-item>.remote-help-tree-node-item-icon { +.remote-help-tree-node-item-icon { background-size: 16px; background-position: left center; background-repeat: no-repeat; - padding-right: 6px; - width: 16px; - height: 22px; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; } +.remote-help-tree-node-item-icon .monaco-icon-label-description-container { + padding-left: 22px; +} + .remote-help-content .monaco-list .monaco-list-row .monaco-tl-twistie { width: 0px !important; } -.vs .monaco-list .monaco-list-row .remote-help-tree-node-item>.remote-help-tree-node-item-icon.getStarted { +.vs .remote-help-tree-node-item-icon.getStarted { background-image: url('help-getting-started-light.svg') } -.vs .monaco-list .monaco-list-row .remote-help-tree-node-item>.remote-help-tree-node-item-icon.documentation { +.vs .remote-help-tree-node-item-icon.documentation { background-image: url('help-documentation-light.svg') } -.vs .monaco-list .monaco-list-row .remote-help-tree-node-item>.remote-help-tree-node-item-icon.feedback { +.vs .remote-help-tree-node-item-icon.feedback { background-image: url('help-feedback-light.svg') } -.vs .monaco-list .monaco-list-row .remote-help-tree-node-item>.remote-help-tree-node-item-icon.issues { +.vs .remote-help-tree-node-item-icon.issues { background-image: url('help-review-issues-light.svg') } -.vs .monaco-list .monaco-list-row .remote-help-tree-node-item>.remote-help-tree-node-item-icon.issueReporter { +.vs .remote-help-tree-node-item-icon.issueReporter { background-image: url('help-report-issue-light.svg') } -.vs-dark .monaco-list .monaco-list-row .remote-help-tree-node-item>.remote-help-tree-node-item-icon.getStarted { +.vs-dark .remote-help-tree-node-item-icon.getStarted { background-image: url('help-getting-started-dark.svg') } -.vs-dark .monaco-list .monaco-list-row .remote-help-tree-node-item>.remote-help-tree-node-item-icon.documentation { +.vs-dark .remote-help-tree-node-item-icon.documentation { background-image: url('help-documentation-dark.svg') } -.vs-dark .monaco-list .monaco-list-row .remote-help-tree-node-item>.remote-help-tree-node-item-icon.feedback { +.vs-dark .remote-help-tree-node-item-icon.feedback { background-image: url('help-feedback-dark.svg') } -.vs-dark .monaco-list .monaco-list-row .remote-help-tree-node-item>.remote-help-tree-node-item-icon.issues { +.vs-dark .remote-help-tree-node-item-icon.issues { background-image: url('help-review-issues-dark.svg') } -.vs-dark .monaco-list .monaco-list-row .remote-help-tree-node-item>.remote-help-tree-node-item-icon.issueReporter { +.vs-dark .remote-help-tree-node-item-icon.issueReporter { background-image: url('help-report-issue-dark.svg') } -.hc-black .monaco-list .monaco-list-row .remote-help-tree-node-item>.remote-help-tree-node-item-icon.getStarted { +.hc-black .remote-help-tree-node-item-icon.getStarted { background-image: url('help-getting-started-hc.svg') } -.hc-black .monaco-list .monaco-list-row .remote-help-tree-node-item>.remote-help-tree-node-item-icon.documentation { +.hc-black .remote-help-tree-node-item-icon.documentation { background-image: url('help-documentation-hc.svg') } -.hc-black .monaco-list .monaco-list-row .remote-help-tree-node-item>.remote-help-tree-node-item-icon.feedback { +.hc-black .remote-help-tree-node-item-icon.feedback { background-image: url('help-feedback-hc.svg') } -.hc-black .monaco-list .monaco-list-row .remote-help-tree-node-item>.remote-help-tree-node-item-icon.issues { +.hc-black .remote-help-tree-node-item-icon.issues { background-image: url('help-review-issues-hc.svg') } -.hc-black .monaco-list .monaco-list-row .remote-help-tree-node-item>.remote-help-tree-node-item-icon.issueReporter { +.hc-black .remote-help-tree-node-item-icon.issueReporter { background-image: url('help-report-issue-hc.svg') } diff --git a/src/vs/workbench/services/remote/common/remoteExplorerService.ts b/src/vs/workbench/services/remote/common/remoteExplorerService.ts index 7aec6e576894a..fa368290b5b2e 100644 --- a/src/vs/workbench/services/remote/common/remoteExplorerService.ts +++ b/src/vs/workbench/services/remote/common/remoteExplorerService.ts @@ -3,10 +3,13 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +import * as nls from 'vs/nls'; import { Event, Emitter } from 'vs/base/common/event'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; +import { IExtensionDescription } from 'vs/platform/extensions/common/extensions'; +import { ExtensionsRegistry, IExtensionPointUser } from 'vs/workbench/services/extensions/common/extensionsRegistry'; export const IRemoteExplorerService = createDecorator('remoteExplorerService'); export const REMOTE_EXPLORER_TYPE_KEY: string = 'remote.explorerType'; @@ -15,15 +18,60 @@ export interface IRemoteExplorerService { _serviceBrand: undefined; onDidChangeTargetType: Event; targetType: string; + readonly helpInformation: HelpInformation[]; } +export interface HelpInformation { + extensionDescription: IExtensionDescription; + getStarted?: string; + documentation?: string; + feedback?: string; + issues?: string; +} + +const remoteHelpExtPoint = ExtensionsRegistry.registerExtensionPoint({ + extensionPoint: 'remoteHelp', + jsonSchema: { + description: nls.localize('RemoteHelpInformationExtPoint', 'Contributes help information for Remote'), + type: 'object', + properties: { + 'getStarted': { + description: nls.localize('RemoteHelpInformationExtPoint.getStarted', "The url to your project's Getting Started page"), + type: 'string' + }, + 'documentation': { + description: nls.localize('RemoteHelpInformationExtPoint.documentation', "The url to your project's documentation page"), + type: 'string' + }, + 'feedback': { + description: nls.localize('RemoteHelpInformationExtPoint.feedback', "The url to your project's feedback reporter"), + type: 'string' + }, + 'issues': { + description: nls.localize('RemoteHelpInformationExtPoint.issues', "The url to your project's issues list"), + type: 'string' + } + } + } +}); + class RemoteExplorerService implements IRemoteExplorerService { public _serviceBrand: undefined; private _targetType: string = ''; private _onDidChangeTargetType: Emitter = new Emitter(); public onDidChangeTargetType: Event = this._onDidChangeTargetType.event; + private _helpInformation: HelpInformation[] = []; + + constructor(@IStorageService private readonly storageService: IStorageService) { + remoteHelpExtPoint.setHandler((extensions) => { + let helpInformation: HelpInformation[] = []; + for (let extension of extensions) { + this._handleRemoteInfoExtensionPoint(extension, helpInformation); + } - constructor(@IStorageService private readonly storageService: IStorageService) { } + this._helpInformation = helpInformation; + }); + } set targetType(name: string) { if (this._targetType !== name) { @@ -36,6 +84,28 @@ class RemoteExplorerService implements IRemoteExplorerService { get targetType(): string { return this._targetType; } + + private _handleRemoteInfoExtensionPoint(extension: IExtensionPointUser, helpInformation: HelpInformation[]) { + if (!extension.description.enableProposedApi) { + return; + } + + if (!extension.value.documentation && !extension.value.feedback && !extension.value.getStarted && !extension.value.issues) { + return; + } + + helpInformation.push({ + extensionDescription: extension.description, + getStarted: extension.value.getStarted, + documentation: extension.value.documentation, + feedback: extension.value.feedback, + issues: extension.value.issues + }); + } + + get helpInformation(): HelpInformation[] { + return this._helpInformation; + } } registerSingleton(IRemoteExplorerService, RemoteExplorerService, true); From 48af7ba677933e0d710b192c0fba2491b78afea9 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Wed, 13 Nov 2019 10:39:47 +0100 Subject: [PATCH 177/352] fixes #84455 --- test/electron/renderer.html | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/test/electron/renderer.html b/test/electron/renderer.html index 38005b2d6094a..49cfa95c65786 100644 --- a/test/electron/renderer.html +++ b/test/electron/renderer.html @@ -23,6 +23,16 @@ window.alert = function () { throw new Error('window.alert() is not supported in tests!'); } window.confirm = function () { throw new Error('window.confirm() is not supported in tests!'); } + // Ignore uncaught cancelled promise errors + window.addEventListener('unhandledrejection', e => { + const name = e && e.reason && e.reason.name; + + if (name === 'Canceled') { + e.preventDefault(); + e.stopPropagation(); + } + }); + mocha.setup({ ui: 'tdd', timeout: 5000 From 44a7079ed16dfc64870aa61f02d310289d6c1676 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Wed, 13 Nov 2019 10:41:46 +0100 Subject: [PATCH 178/352] fix console.warn related to #84283 --- src/vs/workbench/api/common/extHostSCM.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/vs/workbench/api/common/extHostSCM.ts b/src/vs/workbench/api/common/extHostSCM.ts index 2cca3f54ca509..3b2943ff281f7 100644 --- a/src/vs/workbench/api/common/extHostSCM.ts +++ b/src/vs/workbench/api/common/extHostSCM.ts @@ -180,8 +180,7 @@ export class ExtHostSCMInputBox implements vscode.SourceControlInputBox { } if (fn && typeof fn !== 'function') { - console.warn('Invalid SCM input box validation function'); - return; + throw new Error(`[${this._extension.identifier.value}]: Invalid SCM input box validation function`); } this._validateInput = fn; From 557d444fe5f8f9fc11b2770632956b9df54072a2 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Wed, 13 Nov 2019 10:45:41 +0100 Subject: [PATCH 179/352] open editors - adopt working copy service and track unsaved properly (#84672) --- .../files/browser/views/openEditorsView.ts | 31 ++++++++++--------- .../browser/testCustomEditors.ts | 3 +- 2 files changed, 19 insertions(+), 15 deletions(-) diff --git a/src/vs/workbench/contrib/files/browser/views/openEditorsView.ts b/src/vs/workbench/contrib/files/browser/views/openEditorsView.ts index a182f6f962cad..2304fbb4d742d 100644 --- a/src/vs/workbench/contrib/files/browser/views/openEditorsView.ts +++ b/src/vs/workbench/contrib/files/browser/views/openEditorsView.ts @@ -15,8 +15,6 @@ import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { IEditorInput, Verbosity } from 'vs/workbench/common/editor'; import { SaveAllAction, SaveAllInGroupAction, CloseGroupAction } from 'vs/workbench/contrib/files/browser/fileActions'; import { OpenEditorsFocusedContext, ExplorerFocusedContext, IFilesConfiguration, OpenEditor } from 'vs/workbench/contrib/files/common/files'; -import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; -import { IUntitledTextEditorService } from 'vs/workbench/services/untitled/common/untitledTextEditorService'; import { CloseAllEditorsAction, CloseEditorAction } from 'vs/workbench/browser/parts/editor/editorActions'; import { ToggleEditorLayoutAction } from 'vs/workbench/browser/actions/layoutActions'; import { IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey'; @@ -43,7 +41,7 @@ import { ElementsDragAndDropData, DesktopDragAndDropData } from 'vs/base/browser import { URI } from 'vs/base/common/uri'; import { withNullAsUndefined, withUndefinedAsNull } from 'vs/base/common/types'; import { isWeb } from 'vs/base/common/platform'; -import { IAutoSaveConfigurationService, AutoSaveMode } from 'vs/workbench/services/autoSaveConfiguration/common/autoSaveConfigurationService'; +import { IWorkingCopyService } from 'vs/workbench/services/workingCopy/common/workingCopyService'; const $ = dom.$; @@ -68,17 +66,15 @@ export class OpenEditorsView extends ViewletPanel { options: IViewletViewOptions, @IInstantiationService private readonly instantiationService: IInstantiationService, @IContextMenuService contextMenuService: IContextMenuService, - @ITextFileService private readonly textFileService: ITextFileService, @IEditorService private readonly editorService: IEditorService, @IEditorGroupsService private readonly editorGroupService: IEditorGroupsService, @IConfigurationService configurationService: IConfigurationService, @IKeybindingService keybindingService: IKeybindingService, - @IUntitledTextEditorService private readonly untitledTextEditorService: IUntitledTextEditorService, @IContextKeyService private readonly contextKeyService: IContextKeyService, @IThemeService private readonly themeService: IThemeService, @ITelemetryService private readonly telemetryService: ITelemetryService, @IMenuService private readonly menuService: IMenuService, - @IAutoSaveConfigurationService private readonly autoSaveConfigurationService: IAutoSaveConfigurationService + @IWorkingCopyService private readonly workingCopyService: IWorkingCopyService ) { super({ ...(options as IViewletPanelOptions), @@ -102,11 +98,7 @@ export class OpenEditorsView extends ViewletPanel { this._register(this.configurationService.onDidChangeConfiguration(e => this.onConfigurationChange(e))); // Handle dirty counter - this._register(this.untitledTextEditorService.onDidChangeDirty(() => this.updateDirtyIndicator())); - this._register(this.textFileService.models.onModelsDirty(() => this.updateDirtyIndicator())); - this._register(this.textFileService.models.onModelsSaved(() => this.updateDirtyIndicator())); - this._register(this.textFileService.models.onModelsSaveError(() => this.updateDirtyIndicator())); - this._register(this.textFileService.models.onModelsReverted(() => this.updateDirtyIndicator())); + this._register(this.workingCopyService.onDidChangeDirty(() => this.updateDirtyIndicator())); } private registerUpdateEvents(): void { @@ -248,7 +240,7 @@ export class OpenEditorsView extends ViewletPanel { const element = e.elements.length ? e.elements[0] : undefined; if (element instanceof OpenEditor) { const resource = element.getResource(); - this.dirtyEditorFocusedContext.set(this.textFileService.isDirty(resource)); + this.dirtyEditorFocusedContext.set(element.editor.isDirty()); this.resourceContext.set(withUndefinedAsNull(resource)); } else if (!!element) { this.groupFocusedContext.set(true); @@ -415,8 +407,7 @@ export class OpenEditorsView extends ViewletPanel { } private updateDirtyIndicator(): void { - let dirty = this.autoSaveConfigurationService.getAutoSaveMode() !== AutoSaveMode.AFTER_SHORT_DELAY ? this.textFileService.getDirty().length - : this.untitledTextEditorService.getDirty().length; + let dirty = this.dirtyCount; if (dirty === 0) { dom.addClass(this.dirtyCountElement, 'hidden'); } else { @@ -425,6 +416,18 @@ export class OpenEditorsView extends ViewletPanel { } } + private get dirtyCount(): number { + let dirtyCount = 0; + + for (const element of this.elements) { + if (element instanceof OpenEditor && element.editor.isDirty()) { + dirtyCount++; + } + } + + return dirtyCount; + } + private get elementCount(): number { return this.editorGroupService.groups.map(g => g.count) .reduce((first, second) => first + second, this.showGroups ? this.editorGroupService.groups.length : 0); diff --git a/src/vs/workbench/contrib/testCustomEditors/browser/testCustomEditors.ts b/src/vs/workbench/contrib/testCustomEditors/browser/testCustomEditors.ts index 6a038352e2d60..62711b74fc8b2 100644 --- a/src/vs/workbench/contrib/testCustomEditors/browser/testCustomEditors.ts +++ b/src/vs/workbench/contrib/testCustomEditors/browser/testCustomEditors.ts @@ -25,9 +25,10 @@ import { generateUuid } from 'vs/base/common/uuid'; import { CancellationToken } from 'vs/base/common/cancellation'; import { editorBackground, editorForeground } from 'vs/platform/theme/common/colorRegistry'; import { IWorkingCopy, IWorkingCopyService } from 'vs/workbench/services/workingCopy/common/workingCopyService'; +import { env } from 'vs/base/common/process'; const CUSTOM_SCHEME = 'testCustomEditor'; -const ENABLE = false; +const ENABLE = !!env['VSCODE_DEV']; class TestCustomEditorsAction extends Action { From 711ed6c850bc10d966b6adebe8323540fd4d2c70 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Wed, 13 Nov 2019 10:53:25 +0100 Subject: [PATCH 180/352] remove more output --- src/vs/base/common/cache.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/vs/base/common/cache.ts b/src/vs/base/common/cache.ts index bc585927f03b8..3269508e02bbf 100644 --- a/src/vs/base/common/cache.ts +++ b/src/vs/base/common/cache.ts @@ -22,7 +22,6 @@ export class Cache { const cts = new CancellationTokenSource(); const promise = this.task(cts.token); - promise.finally(() => cts.dispose()); this.result = { promise, From f6b6a978073e7a1c102ec8f1ae2eb41d3a369ffb Mon Sep 17 00:00:00 2001 From: Alexandru Dima Date: Wed, 13 Nov 2019 09:59:15 +0100 Subject: [PATCH 181/352] Take typings from tsconfig.monaco.json --- build/gulpfile.editor.js | 8 -------- build/lib/standalone.js | 2 ++ build/lib/standalone.ts | 3 +++ 3 files changed, 5 insertions(+), 8 deletions(-) diff --git a/build/gulpfile.editor.js b/build/gulpfile.editor.js index 6734a820cf181..77e512bdc561d 100644 --- a/build/gulpfile.editor.js +++ b/build/gulpfile.editor.js @@ -71,14 +71,6 @@ const extractEditorSrcTask = task.define('extract-editor-src', () => { apiusages, extrausages ], - typings: [ - 'typings/lib.ie11_safe_es6.d.ts', - 'typings/thenable.d.ts', - 'typings/es6-promise.d.ts', - 'typings/require-monaco.d.ts', - "typings/lib.es2018.promise.d.ts", - 'vs/monaco.d.ts' - ], libs: [ `lib.es5.d.ts`, `lib.dom.d.ts`, diff --git a/build/lib/standalone.js b/build/lib/standalone.js index 56f89544dac98..4457e1a56d1c1 100644 --- a/build/lib/standalone.js +++ b/build/lib/standalone.js @@ -44,6 +44,8 @@ function extractEditor(options) { compilerOptions.moduleResolution = ts.ModuleResolutionKind.Classic; options.compilerOptions = compilerOptions; console.log(`Running with shakeLevel ${tss.toStringShakeLevel(options.shakeLevel)}`); + // Take the extra included .d.ts files from `tsconfig.monaco.json` + options.typings = tsConfig.include.filter(includedFile => /\.d\.ts$/.test(includedFile)); let result = tss.shake(options); for (let fileName in result) { if (result.hasOwnProperty(fileName)) { diff --git a/build/lib/standalone.ts b/build/lib/standalone.ts index 07000331ad2b6..8ec71bfae5d60 100644 --- a/build/lib/standalone.ts +++ b/build/lib/standalone.ts @@ -52,6 +52,9 @@ export function extractEditor(options: tss.ITreeShakingOptions & { destRoot: str console.log(`Running with shakeLevel ${tss.toStringShakeLevel(options.shakeLevel)}`); + // Take the extra included .d.ts files from `tsconfig.monaco.json` + options.typings = (tsConfig.include).filter(includedFile => /\.d\.ts$/.test(includedFile)); + let result = tss.shake(options); for (let fileName in result) { if (result.hasOwnProperty(fileName)) { From 032925e74e35faa6b79c737e15c9ddedd7e6a306 Mon Sep 17 00:00:00 2001 From: Alexandru Dima Date: Wed, 13 Nov 2019 09:59:51 +0100 Subject: [PATCH 182/352] Improve error reporting during treeshaking --- build/lib/treeshaking.js | 14 +++++++------- build/lib/treeshaking.ts | 14 +++++++------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/build/lib/treeshaking.js b/build/lib/treeshaking.js index 50ff7caa01d3b..cec07007bbe4b 100644 --- a/build/lib/treeshaking.js +++ b/build/lib/treeshaking.js @@ -25,17 +25,17 @@ function toStringShakeLevel(shakeLevel) { } } exports.toStringShakeLevel = toStringShakeLevel; -function printDiagnostics(diagnostics) { +function printDiagnostics(options, diagnostics) { for (const diag of diagnostics) { let result = ''; if (diag.file) { - result += `${diag.file.fileName}: `; + result += `${path.join(options.sourcesRoot, diag.file.fileName)}`; } if (diag.file && diag.start) { let location = diag.file.getLineAndCharacterOfPosition(diag.start); - result += `- ${location.line + 1},${location.character} - `; + result += `:${location.line + 1}:${location.character}`; } - result += JSON.stringify(diag.messageText); + result += ` - ` + JSON.stringify(diag.messageText); console.log(result); } } @@ -44,17 +44,17 @@ function shake(options) { const program = languageService.getProgram(); const globalDiagnostics = program.getGlobalDiagnostics(); if (globalDiagnostics.length > 0) { - printDiagnostics(globalDiagnostics); + printDiagnostics(options, globalDiagnostics); throw new Error(`Compilation Errors encountered.`); } const syntacticDiagnostics = program.getSyntacticDiagnostics(); if (syntacticDiagnostics.length > 0) { - printDiagnostics(syntacticDiagnostics); + printDiagnostics(options, syntacticDiagnostics); throw new Error(`Compilation Errors encountered.`); } const semanticDiagnostics = program.getSemanticDiagnostics(); if (semanticDiagnostics.length > 0) { - printDiagnostics(semanticDiagnostics); + printDiagnostics(options, semanticDiagnostics); throw new Error(`Compilation Errors encountered.`); } markNodes(languageService, options); diff --git a/build/lib/treeshaking.ts b/build/lib/treeshaking.ts index f096963365582..58f3c878495c1 100644 --- a/build/lib/treeshaking.ts +++ b/build/lib/treeshaking.ts @@ -71,17 +71,17 @@ export interface ITreeShakingResult { [file: string]: string; } -function printDiagnostics(diagnostics: ReadonlyArray): void { +function printDiagnostics(options: ITreeShakingOptions, diagnostics: ReadonlyArray): void { for (const diag of diagnostics) { let result = ''; if (diag.file) { - result += `${diag.file.fileName}: `; + result += `${path.join(options.sourcesRoot, diag.file.fileName)}`; } if (diag.file && diag.start) { let location = diag.file.getLineAndCharacterOfPosition(diag.start); - result += `- ${location.line + 1},${location.character} - `; + result += `:${location.line + 1}:${location.character}`; } - result += JSON.stringify(diag.messageText); + result += ` - ` + JSON.stringify(diag.messageText); console.log(result); } } @@ -92,19 +92,19 @@ export function shake(options: ITreeShakingOptions): ITreeShakingResult { const globalDiagnostics = program.getGlobalDiagnostics(); if (globalDiagnostics.length > 0) { - printDiagnostics(globalDiagnostics); + printDiagnostics(options, globalDiagnostics); throw new Error(`Compilation Errors encountered.`); } const syntacticDiagnostics = program.getSyntacticDiagnostics(); if (syntacticDiagnostics.length > 0) { - printDiagnostics(syntacticDiagnostics); + printDiagnostics(options, syntacticDiagnostics); throw new Error(`Compilation Errors encountered.`); } const semanticDiagnostics = program.getSemanticDiagnostics(); if (semanticDiagnostics.length > 0) { - printDiagnostics(semanticDiagnostics); + printDiagnostics(options, semanticDiagnostics); throw new Error(`Compilation Errors encountered.`); } From 898fbafa5b70868bb2576ae84f95bedf6ab9031d Mon Sep 17 00:00:00 2001 From: Alexandru Dima Date: Wed, 13 Nov 2019 10:18:21 +0100 Subject: [PATCH 183/352] Make implements type relationships more explicit to help treeshaking --- build/monaco/monaco.usage.recipe | 13 ------------- src/vs/base/browser/ui/countBadge/countBadge.ts | 3 ++- src/vs/base/browser/ui/tree/asyncDataTree.ts | 3 ++- src/vs/base/common/styler.ts | 12 ++++++++++++ .../base/parts/quickopen/browser/quickOpenWidget.ts | 3 ++- .../editor/contrib/codeAction/codeActionWidget.ts | 4 +++- src/vs/platform/contextview/browser/contextView.ts | 6 +++--- src/vs/platform/environment/common/environment.ts | 3 ++- src/vs/platform/theme/common/styler.ts | 7 +------ src/vs/platform/workspace/common/workspace.ts | 3 ++- .../suggestEnabledInput/suggestEnabledInput.ts | 3 ++- 11 files changed, 31 insertions(+), 29 deletions(-) create mode 100644 src/vs/base/common/styler.ts diff --git a/build/monaco/monaco.usage.recipe b/build/monaco/monaco.usage.recipe index f1a74a25e3013..b0b1842c1b0dc 100644 --- a/build/monaco/monaco.usage.recipe +++ b/build/monaco/monaco.usage.recipe @@ -2,15 +2,9 @@ // This file is adding references to various symbols which should not be removed via tree shaking import { ServiceIdentifier } from './vs/platform/instantiation/common/instantiation'; -import { IContextViewService } from './vs/platform/contextview/browser/contextView'; import { IHighlight } from './vs/base/parts/quickopen/browser/quickOpenModel'; -import { IWorkspaceContextService } from './vs/platform/workspace/common/workspace'; -import { IEnvironmentService } from './vs/platform/environment/common/environment'; -import { CountBadge } from './vs/base/browser/ui/countBadge/countBadge'; import { SimpleWorkerClient, create as create1 } from './vs/base/common/worker/simpleWorker'; import { create as create2 } from './vs/editor/common/services/editorSimpleWorker'; -import { QuickOpenWidget } from './vs/base/parts/quickopen/browser/quickOpenWidget'; -import { WorkbenchAsyncDataTree } from './vs/platform/list/browser/listService'; import { SyncDescriptor0, SyncDescriptor1, SyncDescriptor2, SyncDescriptor3, SyncDescriptor4, SyncDescriptor5, SyncDescriptor6, SyncDescriptor7, SyncDescriptor8 } from './vs/platform/instantiation/common/descriptors'; import { DiffNavigator } from './vs/editor/browser/widget/diffNavigator'; import { DocumentRangeFormattingEditProvider } from './vs/editor/common/modes'; @@ -19,13 +13,6 @@ import * as editorAPI from './vs/editor/editor.api'; (function () { var a: any; var b: any; - a = (b).layout; // IContextViewProvider - a = (b).getWorkspaceFolder; // IWorkspaceFolderProvider - a = (b).getWorkspace; // IWorkspaceFolderProvider - a = (b).style; // IThemable - a = (b).style; // IThemable - a = (>b).style; // IThemable - a = (b).userHome; // IUserHomeProvider a = (b).previous; // IDiffNavigator a = (>b).type; a = (b).start; diff --git a/src/vs/base/browser/ui/countBadge/countBadge.ts b/src/vs/base/browser/ui/countBadge/countBadge.ts index cb04c5099f351..95d56cd3ed3ef 100644 --- a/src/vs/base/browser/ui/countBadge/countBadge.ts +++ b/src/vs/base/browser/ui/countBadge/countBadge.ts @@ -8,6 +8,7 @@ import { $, append } from 'vs/base/browser/dom'; import { format } from 'vs/base/common/strings'; import { Color } from 'vs/base/common/color'; import { mixin } from 'vs/base/common/objects'; +import { IThemable } from 'vs/base/common/styler'; export interface ICountBadgeOptions extends ICountBadgetyles { count?: number; @@ -26,7 +27,7 @@ const defaultOpts = { badgeForeground: Color.fromHex('#FFFFFF') }; -export class CountBadge { +export class CountBadge implements IThemable { private element: HTMLElement; private count: number = 0; diff --git a/src/vs/base/browser/ui/tree/asyncDataTree.ts b/src/vs/base/browser/ui/tree/asyncDataTree.ts index 9a5dd74b4f530..19c5c94724fa9 100644 --- a/src/vs/base/browser/ui/tree/asyncDataTree.ts +++ b/src/vs/base/browser/ui/tree/asyncDataTree.ts @@ -19,6 +19,7 @@ import { toggleClass } from 'vs/base/browser/dom'; import { values } from 'vs/base/common/map'; import { ScrollEvent } from 'vs/base/common/scrollable'; import { ICompressedTreeNode, ICompressedTreeElement } from 'vs/base/browser/ui/tree/compressedObjectTreeModel'; +import { IThemable } from 'vs/base/common/styler'; interface IAsyncDataTreeNode { element: TInput | T; @@ -261,7 +262,7 @@ function dfs(node: IAsyncDataTreeNode, fn: (node: IAsyncDa node.children.forEach(child => dfs(child, fn)); } -export class AsyncDataTree implements IDisposable { +export class AsyncDataTree implements IDisposable, IThemable { protected readonly tree: ObjectTree, TFilterData>; protected readonly root: IAsyncDataTreeNode; diff --git a/src/vs/base/common/styler.ts b/src/vs/base/common/styler.ts new file mode 100644 index 0000000000000..6ed9d019f75f1 --- /dev/null +++ b/src/vs/base/common/styler.ts @@ -0,0 +1,12 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { Color } from 'vs/base/common/color'; + +export type styleFn = (colors: { [name: string]: Color | undefined }) => void; + +export interface IThemable { + style: styleFn; +} diff --git a/src/vs/base/parts/quickopen/browser/quickOpenWidget.ts b/src/vs/base/parts/quickopen/browser/quickOpenWidget.ts index dc7df956ff2c4..8a5414833f5cd 100644 --- a/src/vs/base/parts/quickopen/browser/quickOpenWidget.ts +++ b/src/vs/base/parts/quickopen/browser/quickOpenWidget.ts @@ -23,6 +23,7 @@ import { ScrollbarVisibility } from 'vs/base/common/scrollable'; import { Color } from 'vs/base/common/color'; import { mixin } from 'vs/base/common/objects'; import { StandardMouseEvent, IMouseEvent } from 'vs/base/browser/mouseEvent'; +import { IThemable } from 'vs/base/common/styler'; export interface IQuickOpenCallbacks { onOk: () => void; @@ -92,7 +93,7 @@ const defaultStyles = { const DEFAULT_INPUT_ARIA_LABEL = nls.localize('quickOpenAriaLabel', "Quick picker. Type to narrow down results."); -export class QuickOpenWidget extends Disposable implements IModelProvider { +export class QuickOpenWidget extends Disposable implements IModelProvider, IThemable { private static readonly MAX_WIDTH = 600; // Max total width of quick open widget private static readonly MAX_ITEMS_HEIGHT = 20 * 22; // Max height of item list below input field diff --git a/src/vs/editor/contrib/codeAction/codeActionWidget.ts b/src/vs/editor/contrib/codeAction/codeActionWidget.ts index 5cfc01cbfbe24..a40ffdfa45c2a 100644 --- a/src/vs/editor/contrib/codeAction/codeActionWidget.ts +++ b/src/vs/editor/contrib/codeAction/codeActionWidget.ts @@ -54,7 +54,9 @@ export class CodeActionWidget extends Disposable { ) { super(); - this._keybindingResolver = new CodeActionKeybindingResolver(keybindingService); + this._keybindingResolver = new CodeActionKeybindingResolver({ + getKeybindings: () => keybindingService.getKeybindings() + }); } get isVisible(): boolean { diff --git a/src/vs/platform/contextview/browser/contextView.ts b/src/vs/platform/contextview/browser/contextView.ts index f5d1e81a5695c..2104e66c0b4e4 100644 --- a/src/vs/platform/contextview/browser/contextView.ts +++ b/src/vs/platform/contextview/browser/contextView.ts @@ -7,11 +7,11 @@ import { IDisposable } from 'vs/base/common/lifecycle'; import { Event } from 'vs/base/common/event'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { IContextMenuDelegate } from 'vs/base/browser/contextmenu'; -import { AnchorAlignment } from 'vs/base/browser/ui/contextview/contextview'; +import { AnchorAlignment, IContextViewProvider } from 'vs/base/browser/ui/contextview/contextview'; export const IContextViewService = createDecorator('contextViewService'); -export interface IContextViewService { +export interface IContextViewService extends IContextViewProvider { _serviceBrand: undefined; @@ -41,4 +41,4 @@ export interface IContextMenuService { showContextMenu(delegate: IContextMenuDelegate): void; onDidContextMenu: Event; // TODO@isidor these event should be removed once we get async context menus -} \ No newline at end of file +} diff --git a/src/vs/platform/environment/common/environment.ts b/src/vs/platform/environment/common/environment.ts index eaa3bc1bae1a4..c5aac80a5c54e 100644 --- a/src/vs/platform/environment/common/environment.ts +++ b/src/vs/platform/environment/common/environment.ts @@ -5,6 +5,7 @@ import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { URI } from 'vs/base/common/uri'; +import { IUserHomeProvider } from 'vs/base/common/labels'; export interface ParsedArgs { _: string[]; @@ -99,7 +100,7 @@ export interface IExtensionHostDebugParams extends IDebugParams { export const BACKUPS = 'Backups'; -export interface IEnvironmentService { +export interface IEnvironmentService extends IUserHomeProvider { _serviceBrand: undefined; diff --git a/src/vs/platform/theme/common/styler.ts b/src/vs/platform/theme/common/styler.ts index 56f0deef22987..7a3decaa26e87 100644 --- a/src/vs/platform/theme/common/styler.ts +++ b/src/vs/platform/theme/common/styler.ts @@ -8,17 +8,12 @@ import { focusBorder, inputBackground, inputForeground, ColorIdentifier, selectF import { IDisposable } from 'vs/base/common/lifecycle'; import { Color } from 'vs/base/common/color'; import { mixin } from 'vs/base/common/objects'; - -export type styleFn = (colors: { [name: string]: Color | undefined }) => void; +import { IThemable, styleFn } from 'vs/base/common/styler'; export interface IStyleOverrides { [color: string]: ColorIdentifier | undefined; } -export interface IThemable { - style: styleFn; -} - export interface IColorMapping { [optionsKey: string]: ColorValue | undefined; } diff --git a/src/vs/platform/workspace/common/workspace.ts b/src/vs/platform/workspace/common/workspace.ts index 6ab9770b32fa6..7e31738058d00 100644 --- a/src/vs/platform/workspace/common/workspace.ts +++ b/src/vs/platform/workspace/common/workspace.ts @@ -9,10 +9,11 @@ import { createDecorator } from 'vs/platform/instantiation/common/instantiation' import { TernarySearchTree } from 'vs/base/common/map'; import { Event } from 'vs/base/common/event'; import { IWorkspaceIdentifier, IStoredWorkspaceFolder, isRawFileWorkspaceFolder, isRawUriWorkspaceFolder, ISingleFolderWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; +import { IWorkspaceFolderProvider } from 'vs/base/common/labels'; export const IWorkspaceContextService = createDecorator('contextService'); -export interface IWorkspaceContextService { +export interface IWorkspaceContextService extends IWorkspaceFolderProvider { _serviceBrand: undefined; /** diff --git a/src/vs/workbench/contrib/codeEditor/browser/suggestEnabledInput/suggestEnabledInput.ts b/src/vs/workbench/contrib/codeEditor/browser/suggestEnabledInput/suggestEnabledInput.ts index 19f19686a3d69..223949c9ac683 100644 --- a/src/vs/workbench/contrib/codeEditor/browser/suggestEnabledInput/suggestEnabledInput.ts +++ b/src/vs/workbench/contrib/codeEditor/browser/suggestEnabledInput/suggestEnabledInput.ts @@ -27,12 +27,13 @@ import { SuggestController } from 'vs/editor/contrib/suggest/suggestController'; import { IContextKey } from 'vs/platform/contextkey/common/contextkey'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { ColorIdentifier, editorSelectionBackground, inputBackground, inputBorder, inputForeground, inputPlaceholderForeground, selectionBackground } from 'vs/platform/theme/common/colorRegistry'; -import { IStyleOverrides, IThemable, attachStyler } from 'vs/platform/theme/common/styler'; +import { IStyleOverrides, attachStyler } from 'vs/platform/theme/common/styler'; import { IThemeService, registerThemingParticipant } from 'vs/platform/theme/common/themeService'; import { MenuPreventer } from 'vs/workbench/contrib/codeEditor/browser/menuPreventer'; import { getSimpleEditorOptions } from 'vs/workbench/contrib/codeEditor/browser/simpleEditorOptions'; import { SelectionClipboardContributionID } from 'vs/workbench/contrib/codeEditor/browser/selectionClipboard'; import { EditorExtensionsRegistry } from 'vs/editor/browser/editorExtensions'; +import { IThemable } from 'vs/base/common/styler'; interface SuggestResultsProvider { /** From 27770ed1b52617d16c671f1909f9d759cdebcdf1 Mon Sep 17 00:00:00 2001 From: Alexandru Dima Date: Wed, 13 Nov 2019 11:07:31 +0100 Subject: [PATCH 184/352] Make type relationships more explicit to help the tree shaker --- build/monaco/monaco.d.ts.recipe | 2 +- build/monaco/monaco.usage.recipe | 10 +--------- .../base/parts/quickopen/browser/quickOpenModel.ts | 3 ++- src/vs/editor/browser/widget/diffNavigator.ts | 9 ++++++++- .../editor/standalone/browser/standaloneEditor.ts | 9 +-------- src/vs/monaco.d.ts | 13 ++++++------- 6 files changed, 19 insertions(+), 27 deletions(-) diff --git a/build/monaco/monaco.d.ts.recipe b/build/monaco/monaco.d.ts.recipe index 900b1bcce6064..0c49fac1c369e 100644 --- a/build/monaco/monaco.d.ts.recipe +++ b/build/monaco/monaco.d.ts.recipe @@ -43,7 +43,7 @@ declare namespace monaco { } declare namespace monaco.editor { - +#include(vs/editor/browser/widget/diffNavigator): IDiffNavigator #includeAll(vs/editor/standalone/browser/standaloneEditor;modes.=>languages.;editorCommon.=>): #include(vs/editor/standalone/common/standaloneThemeService): BuiltinTheme, IStandaloneThemeData, IColors #include(vs/editor/common/modes/supports/tokenization): ITokenThemeRule diff --git a/build/monaco/monaco.usage.recipe b/build/monaco/monaco.usage.recipe index b0b1842c1b0dc..3c48da8d85a71 100644 --- a/build/monaco/monaco.usage.recipe +++ b/build/monaco/monaco.usage.recipe @@ -2,25 +2,17 @@ // This file is adding references to various symbols which should not be removed via tree shaking import { ServiceIdentifier } from './vs/platform/instantiation/common/instantiation'; -import { IHighlight } from './vs/base/parts/quickopen/browser/quickOpenModel'; -import { SimpleWorkerClient, create as create1 } from './vs/base/common/worker/simpleWorker'; +import { create as create1 } from './vs/base/common/worker/simpleWorker'; import { create as create2 } from './vs/editor/common/services/editorSimpleWorker'; import { SyncDescriptor0, SyncDescriptor1, SyncDescriptor2, SyncDescriptor3, SyncDescriptor4, SyncDescriptor5, SyncDescriptor6, SyncDescriptor7, SyncDescriptor8 } from './vs/platform/instantiation/common/descriptors'; -import { DiffNavigator } from './vs/editor/browser/widget/diffNavigator'; -import { DocumentRangeFormattingEditProvider } from './vs/editor/common/modes'; import * as editorAPI from './vs/editor/editor.api'; (function () { var a: any; var b: any; - a = (b).previous; // IDiffNavigator a = (>b).type; - a = (b).start; - a = (b).end; - a = (>b).getProxyObject; // IWorkerClient a = create1; a = create2; - a = (b).extensionId; // injection madness a = (>b).ctor; diff --git a/src/vs/base/parts/quickopen/browser/quickOpenModel.ts b/src/vs/base/parts/quickopen/browser/quickOpenModel.ts index 463323c236361..8bb7da3ff4f2f 100644 --- a/src/vs/base/parts/quickopen/browser/quickOpenModel.ts +++ b/src/vs/base/parts/quickopen/browser/quickOpenModel.ts @@ -19,13 +19,14 @@ import { OS } from 'vs/base/common/platform'; import { ResolvedKeybinding } from 'vs/base/common/keyCodes'; import { IItemAccessor } from 'vs/base/parts/quickopen/common/quickOpenScorer'; import { coalesce } from 'vs/base/common/arrays'; +import { IMatch } from 'vs/base/common/filters'; export interface IContext { event: any; quickNavigateConfiguration: IQuickNavigateConfiguration; } -export interface IHighlight { +export interface IHighlight extends IMatch { start: number; end: number; } diff --git a/src/vs/editor/browser/widget/diffNavigator.ts b/src/vs/editor/browser/widget/diffNavigator.ts index 1c941ed0facf3..f341549a1dc21 100644 --- a/src/vs/editor/browser/widget/diffNavigator.ts +++ b/src/vs/editor/browser/widget/diffNavigator.ts @@ -30,10 +30,17 @@ const defaultOptions: Options = { alwaysRevealFirst: true }; +export interface IDiffNavigator { + canNavigate(): boolean; + next(): void; + previous(): void; + dispose(): void; +} + /** * Create a new diff navigator for the provided diff editor. */ -export class DiffNavigator extends Disposable { +export class DiffNavigator extends Disposable implements IDiffNavigator { private readonly _editor: IDiffEditor; private readonly _options: Options; diff --git a/src/vs/editor/standalone/browser/standaloneEditor.ts b/src/vs/editor/standalone/browser/standaloneEditor.ts index 14fe6f67a5fb5..82b29c68eb850 100644 --- a/src/vs/editor/standalone/browser/standaloneEditor.ts +++ b/src/vs/editor/standalone/browser/standaloneEditor.ts @@ -9,7 +9,7 @@ import { URI } from 'vs/base/common/uri'; import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService'; import { OpenerService } from 'vs/editor/browser/services/openerService'; -import { DiffNavigator } from 'vs/editor/browser/widget/diffNavigator'; +import { DiffNavigator, IDiffNavigator } from 'vs/editor/browser/widget/diffNavigator'; import { ConfigurationChangedEvent } from 'vs/editor/common/config/editorOptions'; import { BareFontInfo, FontInfo } from 'vs/editor/common/config/fontInfo'; import { Token } from 'vs/editor/common/core/token'; @@ -127,13 +127,6 @@ export function createDiffEditor(domElement: HTMLElement, options?: IDiffEditorC }); } -export interface IDiffNavigator { - canNavigate(): boolean; - next(): void; - previous(): void; - dispose(): void; -} - export interface IDiffNavigatorOptions { readonly followsCaret?: boolean; readonly ignoreCharChanges?: boolean; diff --git a/src/vs/monaco.d.ts b/src/vs/monaco.d.ts index 6e453de295906..bcfe1121ecbc7 100644 --- a/src/vs/monaco.d.ts +++ b/src/vs/monaco.d.ts @@ -802,6 +802,12 @@ declare namespace monaco { declare namespace monaco.editor { + export interface IDiffNavigator { + canNavigate(): boolean; + next(): void; + previous(): void; + dispose(): void; + } /** * Create a new editor under `domElement`. @@ -824,13 +830,6 @@ declare namespace monaco.editor { */ export function createDiffEditor(domElement: HTMLElement, options?: IDiffEditorConstructionOptions, override?: IEditorOverrideServices): IStandaloneDiffEditor; - export interface IDiffNavigator { - canNavigate(): boolean; - next(): void; - previous(): void; - dispose(): void; - } - export interface IDiffNavigatorOptions { readonly followsCaret?: boolean; readonly ignoreCharChanges?: boolean; From b5ce6014d759c8ea3d3ee283b4c9cdb3b00c31a9 Mon Sep 17 00:00:00 2001 From: Alexandru Dima Date: Wed, 13 Nov 2019 11:14:45 +0100 Subject: [PATCH 185/352] Improve output in case of errors and generate an analysis folder with the source content (for easy diffing) --- build/gulpfile.editor.js | 65 +++++++++++++++++++++++++++++++++++----- build/lib/standalone.js | 2 +- build/lib/standalone.ts | 2 +- build/lib/treeshaking.js | 2 +- build/lib/treeshaking.ts | 2 +- build/lib/util.js | 25 ++++++++++++++++ build/lib/util.ts | 25 ++++++++++++++++ 7 files changed, 112 insertions(+), 11 deletions(-) diff --git a/build/gulpfile.editor.js b/build/gulpfile.editor.js index 77e512bdc561d..938c82f57beab 100644 --- a/build/gulpfile.editor.js +++ b/build/gulpfile.editor.js @@ -57,7 +57,6 @@ var BUNDLED_FILE_HEADER = [ const languages = i18n.defaultLanguages.concat([]); // i18n.defaultLanguages.concat(process.env.VSCODE_QUALITY !== 'stable' ? i18n.extraLanguages : []); const extractEditorSrcTask = task.define('extract-editor-src', () => { - console.log(`If the build fails, consider tweaking shakeLevel below to a lower value.`); const apiusages = monacoapi.execute().usageContent; const extrausages = fs.readFileSync(path.join(root, 'build', 'monaco', 'monaco.usage.recipe')).toString(); standalone.extractEditor({ @@ -130,18 +129,70 @@ const createESMSourcesAndResourcesTask = task.define('extract-editor-esm', () => }); const compileEditorESMTask = task.define('compile-editor-esm', () => { + console.log(`Launching the TS compiler at ${path.join(__dirname, '../out-editor-esm')}...`); + let result; if (process.platform === 'win32') { - const result = cp.spawnSync(`..\\node_modules\\.bin\\tsc.cmd`, { + result = cp.spawnSync(`..\\node_modules\\.bin\\tsc.cmd`, { cwd: path.join(__dirname, '../out-editor-esm') }); - console.log(result.stdout.toString()); - console.log(result.stderr.toString()); } else { - const result = cp.spawnSync(`node`, [`../node_modules/.bin/tsc`], { + result = cp.spawnSync(`node`, [`../node_modules/.bin/tsc`], { cwd: path.join(__dirname, '../out-editor-esm') }); - console.log(result.stdout.toString()); - console.log(result.stderr.toString()); + } + + console.log(result.stdout.toString()); + console.log(result.stderr.toString()); + + if (result.status !== 0) { + console.log(`The TS Compilation failed, preparing analysis folder...`); + const destPath = path.join(__dirname, '../../vscode-monaco-editor-esm-analysis'); + return util.rimraf(destPath)().then(() => { + fs.mkdirSync(destPath); + + // initialize a new repository + cp.spawnSync(`git`, [`init`], { + cwd: destPath + }); + + // build a list of files to copy + const files = util.rreddir(path.join(__dirname, '../out-editor-esm')); + + // copy files from src + for (const file of files) { + const srcFilePath = path.join(__dirname, '../src', file); + const dstFilePath = path.join(destPath, file); + if (fs.existsSync(srcFilePath)) { + util.ensureDir(path.dirname(dstFilePath)); + const contents = fs.readFileSync(srcFilePath).toString().replace(/\r\n|\r|\n/g, '\n'); + fs.writeFileSync(dstFilePath, contents); + } + } + + // create an initial commit to diff against + cp.spawnSync(`git`, [`add`, `.`], { + cwd: destPath + }); + + // create the commit + cp.spawnSync(`git`, [`commit`, `-m`, `"original sources"`, `--no-gpg-sign`], { + cwd: destPath + }); + + // copy files from esm + for (const file of files) { + const srcFilePath = path.join(__dirname, '../out-editor-esm', file); + const dstFilePath = path.join(destPath, file); + if (fs.existsSync(srcFilePath)) { + util.ensureDir(path.dirname(dstFilePath)); + const contents = fs.readFileSync(srcFilePath).toString().replace(/\r\n|\r|\n/g, '\n'); + fs.writeFileSync(dstFilePath, contents); + } + } + + console.log(`Open in VS Code the folder at '${destPath}' and you can alayze the compilation error`); + throw new Error('Standalone Editor compilation failed. If this is the build machine, simply launch `yarn run gulp editor-distro` on your machine to further analyze the compilation problem.'); + }); } }); diff --git a/build/lib/standalone.js b/build/lib/standalone.js index 4457e1a56d1c1..ccfd7b45d23e6 100644 --- a/build/lib/standalone.js +++ b/build/lib/standalone.js @@ -43,7 +43,7 @@ function extractEditor(options) { compilerOptions.declaration = false; compilerOptions.moduleResolution = ts.ModuleResolutionKind.Classic; options.compilerOptions = compilerOptions; - console.log(`Running with shakeLevel ${tss.toStringShakeLevel(options.shakeLevel)}`); + console.log(`Running tree shaker with shakeLevel ${tss.toStringShakeLevel(options.shakeLevel)}`); // Take the extra included .d.ts files from `tsconfig.monaco.json` options.typings = tsConfig.include.filter(includedFile => /\.d\.ts$/.test(includedFile)); let result = tss.shake(options); diff --git a/build/lib/standalone.ts b/build/lib/standalone.ts index 8ec71bfae5d60..f80c611e6fc7b 100644 --- a/build/lib/standalone.ts +++ b/build/lib/standalone.ts @@ -50,7 +50,7 @@ export function extractEditor(options: tss.ITreeShakingOptions & { destRoot: str options.compilerOptions = compilerOptions; - console.log(`Running with shakeLevel ${tss.toStringShakeLevel(options.shakeLevel)}`); + console.log(`Running tree shaker with shakeLevel ${tss.toStringShakeLevel(options.shakeLevel)}`); // Take the extra included .d.ts files from `tsconfig.monaco.json` options.typings = (tsConfig.include).filter(includedFile => /\.d\.ts$/.test(includedFile)); diff --git a/build/lib/treeshaking.js b/build/lib/treeshaking.js index cec07007bbe4b..65dd88f585c06 100644 --- a/build/lib/treeshaking.js +++ b/build/lib/treeshaking.js @@ -358,7 +358,7 @@ function markNodes(languageService, options) { ++step; let node; if (step % 100 === 0) { - console.log(`${step}/${step + black_queue.length + gray_queue.length} (${black_queue.length}, ${gray_queue.length})`); + console.log(`Treeshaking - ${Math.floor(100 * step / (step + black_queue.length + gray_queue.length))}% - ${step}/${step + black_queue.length + gray_queue.length} (${black_queue.length}, ${gray_queue.length})`); } if (black_queue.length === 0) { for (let i = 0; i < gray_queue.length; i++) { diff --git a/build/lib/treeshaking.ts b/build/lib/treeshaking.ts index 58f3c878495c1..89f562ad1b80c 100644 --- a/build/lib/treeshaking.ts +++ b/build/lib/treeshaking.ts @@ -471,7 +471,7 @@ function markNodes(languageService: ts.LanguageService, options: ITreeShakingOpt let node: ts.Node; if (step % 100 === 0) { - console.log(`${step}/${step + black_queue.length + gray_queue.length} (${black_queue.length}, ${gray_queue.length})`); + console.log(`Treeshaking - ${Math.floor(100 * step / (step + black_queue.length + gray_queue.length))}% - ${step}/${step + black_queue.length + gray_queue.length} (${black_queue.length}, ${gray_queue.length})`); } if (black_queue.length === 0) { diff --git a/build/lib/util.js b/build/lib/util.js index 1888bfed2e448..752d9fb63f08f 100644 --- a/build/lib/util.js +++ b/build/lib/util.js @@ -185,6 +185,31 @@ function rimraf(dir) { return result; } exports.rimraf = rimraf; +function _rreaddir(dirPath, prepend, result) { + const entries = fs.readdirSync(dirPath, { withFileTypes: true }); + for (const entry of entries) { + if (entry.isDirectory()) { + _rreaddir(path.join(dirPath, entry.name), `${prepend}/${entry.name}`, result); + } + else { + result.push(`${prepend}/${entry.name}`); + } + } +} +function rreddir(dirPath) { + let result = []; + _rreaddir(dirPath, '', result); + return result; +} +exports.rreddir = rreddir; +function ensureDir(dirPath) { + if (fs.existsSync(dirPath)) { + return; + } + ensureDir(path.dirname(dirPath)); + fs.mkdirSync(dirPath); +} +exports.ensureDir = ensureDir; function getVersion(root) { let version = process.env['BUILD_SOURCEVERSION']; if (!version || !/^[0-9a-f]{40}$/i.test(version)) { diff --git a/build/lib/util.ts b/build/lib/util.ts index ae598d5f2cfd0..45b6c9e1b82f6 100644 --- a/build/lib/util.ts +++ b/build/lib/util.ts @@ -243,6 +243,31 @@ export function rimraf(dir: string): () => Promise { return result; } +function _rreaddir(dirPath: string, prepend: string, result: string[]): void { + const entries = fs.readdirSync(dirPath, { withFileTypes: true }); + for (const entry of entries) { + if (entry.isDirectory()) { + _rreaddir(path.join(dirPath, entry.name), `${prepend}/${entry.name}`, result); + } else { + result.push(`${prepend}/${entry.name}`); + } + } +} + +export function rreddir(dirPath: string): string[] { + let result: string[] = []; + _rreaddir(dirPath, '', result); + return result; +} + +export function ensureDir(dirPath: string): void { + if (fs.existsSync(dirPath)) { + return; + } + ensureDir(path.dirname(dirPath)); + fs.mkdirSync(dirPath); +} + export function getVersion(root: string): string | undefined { let version = process.env['BUILD_SOURCEVERSION']; From 5e7b7820a95dd2d7ae65d98a1280c65f5aa25e48 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Wed, 13 Nov 2019 11:38:32 +0100 Subject: [PATCH 186/352] fixes #83726 --- src/vs/base/browser/ui/splitview/splitview.ts | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/vs/base/browser/ui/splitview/splitview.ts b/src/vs/base/browser/ui/splitview/splitview.ts index 8b9333782667b..c3603f5c5cfb5 100644 --- a/src/vs/base/browser/ui/splitview/splitview.ts +++ b/src/vs/base/browser/ui/splitview/splitview.ts @@ -109,6 +109,10 @@ abstract class ViewItem { get priority(): LayoutPriority | undefined { return this.view.priority; } get snap(): boolean { return !!this.view.snap; } + set enabled(enabled: boolean) { + this.container.style.pointerEvents = enabled ? null : 'none'; + } + constructor( protected container: HTMLElement, private view: IView, @@ -430,6 +434,10 @@ export class SplitView extends Disposable { } private onSashStart({ sash, start, alt }: ISashEvent): void { + for (const item of this.viewItems) { + item.enabled = false; + } + const index = firstIndex(this.sashItems, item => item.sash === sash); // This way, we can press Alt while we resize a sash, macOS style! @@ -535,6 +543,10 @@ export class SplitView extends Disposable { this._onDidSashChange.fire(index); this.sashDragState!.disposable.dispose(); this.saveProportions(); + + for (const item of this.viewItems) { + item.enabled = true; + } } private onViewChange(item: ViewItem, size: number | undefined): void { From f91e3ee213d7179b42b7f265708a45908bd6033d Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Wed, 13 Nov 2019 11:38:51 +0100 Subject: [PATCH 187/352] working copy - reduce dirty listeners and support "save all" action enablement (#84672) --- .../browser/parts/editor/editorActions.ts | 2 -- .../contrib/files/browser/fileActions.ts | 34 +++++-------------- .../contrib/search/browser/searchView.ts | 14 ++++---- .../common/untitledTextEditorService.ts | 16 ++++----- 4 files changed, 23 insertions(+), 43 deletions(-) diff --git a/src/vs/workbench/browser/parts/editor/editorActions.ts b/src/vs/workbench/browser/parts/editor/editorActions.ts index 5968708814a8f..178c61b28b67c 100644 --- a/src/vs/workbench/browser/parts/editor/editorActions.ts +++ b/src/vs/workbench/browser/parts/editor/editorActions.ts @@ -1274,8 +1274,6 @@ export class BaseQuickOpenEditorInGroupAction extends Action { run(): Promise { const keys = this.keybindingService.lookupKeybindings(this.id); - - this.quickOpenService.show(NAVIGATE_IN_ACTIVE_GROUP_PREFIX, { quickNavigateConfiguration: { keybindings: keys } }); return Promise.resolve(true); diff --git a/src/vs/workbench/contrib/files/browser/fileActions.ts b/src/vs/workbench/contrib/files/browser/fileActions.ts index 38d7fbac179e1..ad24df30607bb 100644 --- a/src/vs/workbench/contrib/files/browser/fileActions.ts +++ b/src/vs/workbench/contrib/files/browser/fileActions.ts @@ -19,7 +19,6 @@ import { ITextFileService } from 'vs/workbench/services/textfile/common/textfile import { IFileService } from 'vs/platform/files/common/files'; import { toResource, SideBySideEditor } from 'vs/workbench/common/editor'; import { ExplorerViewlet } from 'vs/workbench/contrib/files/browser/explorerViewlet'; -import { IUntitledTextEditorService } from 'vs/workbench/services/untitled/common/untitledTextEditorService'; import { IQuickOpenService } from 'vs/platform/quickOpen/common/quickOpen'; import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet'; import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; @@ -47,6 +46,7 @@ import { onUnexpectedError, getErrorMessage } from 'vs/base/common/errors'; import { asDomUri, triggerDownload } from 'vs/base/browser/dom'; import { mnemonicButtonLabel } from 'vs/base/common/labels'; import { IAutoSaveConfigurationService } from 'vs/workbench/services/autoSaveConfiguration/common/autoSaveConfigurationService'; +import { IWorkingCopyService } from 'vs/workbench/services/workingCopy/common/workingCopyService'; export const NEW_FILE_COMMAND_ID = 'explorer.newFile'; export const NEW_FILE_LABEL = nls.localize('newFile', "New File"); @@ -512,38 +512,30 @@ export abstract class BaseSaveAllAction extends Action { constructor( id: string, label: string, - @ITextFileService private readonly textFileService: ITextFileService, - @IUntitledTextEditorService private readonly untitledTextEditorService: IUntitledTextEditorService, @ICommandService protected commandService: ICommandService, @INotificationService private notificationService: INotificationService, + @IWorkingCopyService private readonly workingCopyService: IWorkingCopyService ) { super(id, label); - this.lastIsDirty = this.textFileService.isDirty(); + this.lastIsDirty = this.workingCopyService.hasDirty; this.enabled = this.lastIsDirty; this.registerListeners(); } - protected abstract includeUntitled(): boolean; protected abstract doRun(context: any): Promise; private registerListeners(): void { - // listen to files being changed locally - this._register(this.textFileService.models.onModelsDirty(e => this.updateEnablement(true))); - this._register(this.textFileService.models.onModelsSaved(e => this.updateEnablement(false))); - this._register(this.textFileService.models.onModelsReverted(e => this.updateEnablement(false))); - this._register(this.textFileService.models.onModelsSaveError(e => this.updateEnablement(true))); - - if (this.includeUntitled()) { - this._register(this.untitledTextEditorService.onDidChangeDirty(resource => this.updateEnablement(this.untitledTextEditorService.isDirty(resource)))); - } + // update enablement based on working copy changes + this._register(this.workingCopyService.onDidChangeDirty(() => this.updateEnablement())); } - private updateEnablement(isDirty: boolean): void { - if (this.lastIsDirty !== isDirty) { - this.enabled = this.textFileService.isDirty(); + private updateEnablement(): void { + const hasDirty = this.workingCopyService.hasDirty; + if (this.lastIsDirty !== hasDirty) { + this.enabled = hasDirty; this.lastIsDirty = this.enabled; } } @@ -569,10 +561,6 @@ export class SaveAllAction extends BaseSaveAllAction { protected doRun(context: any): Promise { return this.commandService.executeCommand(SAVE_ALL_COMMAND_ID); } - - protected includeUntitled(): boolean { - return true; - } } export class SaveAllInGroupAction extends BaseSaveAllAction { @@ -587,10 +575,6 @@ export class SaveAllInGroupAction extends BaseSaveAllAction { protected doRun(context: any): Promise { return this.commandService.executeCommand(SAVE_ALL_IN_GROUP_COMMAND_ID, {}, context); } - - protected includeUntitled(): boolean { - return true; - } } export class CloseGroupAction extends Action { diff --git a/src/vs/workbench/contrib/search/browser/searchView.ts b/src/vs/workbench/contrib/search/browser/searchView.ts index 411b01d41d15a..48f78ae2f79d9 100644 --- a/src/vs/workbench/contrib/search/browser/searchView.ts +++ b/src/vs/workbench/contrib/search/browser/searchView.ts @@ -178,7 +178,7 @@ export class SearchView extends ViewletPanel { this.viewletState = this.memento.getMemento(StorageScope.WORKSPACE); this._register(this.fileService.onFileChanges(e => this.onFilesChanged(e))); - this._register(this.untitledTextEditorService.onDidChangeDirty(e => this.onUntitledDidChangeDirty(e))); + this._register(this.untitledTextEditorService.onDidDisposeModel(e => this.onUntitledDidDispose(e))); this._register(this.contextService.onDidChangeWorkbenchState(() => this.onDidChangeWorkbenchState())); this._register(this.searchHistoryService.onDidClearHistory(() => this.clearHistory())); @@ -1581,18 +1581,16 @@ export class SearchView extends ViewletPanel { return undefined; } - private onUntitledDidChangeDirty(resource: URI): void { + private onUntitledDidDispose(resource: URI): void { if (!this.viewModel) { return; } // remove search results from this resource as it got disposed - if (!this.untitledTextEditorService.isDirty(resource)) { - const matches = this.viewModel.searchResult.matches(); - for (let i = 0, len = matches.length; i < len; i++) { - if (resource.toString() === matches[i].resource.toString()) { - this.viewModel.searchResult.remove(matches[i]); - } + const matches = this.viewModel.searchResult.matches(); + for (let i = 0, len = matches.length; i < len; i++) { + if (resource.toString() === matches[i].resource.toString()) { + this.viewModel.searchResult.remove(matches[i]); } } } diff --git a/src/vs/workbench/services/untitled/common/untitledTextEditorService.ts b/src/vs/workbench/services/untitled/common/untitledTextEditorService.ts index 696b628c7ed09..fcb13e5c16cb4 100644 --- a/src/vs/workbench/services/untitled/common/untitledTextEditorService.ts +++ b/src/vs/workbench/services/untitled/common/untitledTextEditorService.ts @@ -117,17 +117,17 @@ export class UntitledTextEditorService extends Disposable implements IUntitledTe private mapResourceToInput = new ResourceMap(); private mapResourceToAssociatedFilePath = new ResourceMap(); - private readonly _onDidChangeContent: Emitter = this._register(new Emitter()); - readonly onDidChangeContent: Event = this._onDidChangeContent.event; + private readonly _onDidChangeContent = this._register(new Emitter()); + readonly onDidChangeContent = this._onDidChangeContent.event; - private readonly _onDidChangeDirty: Emitter = this._register(new Emitter()); - readonly onDidChangeDirty: Event = this._onDidChangeDirty.event; + private readonly _onDidChangeDirty = this._register(new Emitter()); + readonly onDidChangeDirty = this._onDidChangeDirty.event; - private readonly _onDidChangeEncoding: Emitter = this._register(new Emitter()); - readonly onDidChangeEncoding: Event = this._onDidChangeEncoding.event; + private readonly _onDidChangeEncoding = this._register(new Emitter()); + readonly onDidChangeEncoding = this._onDidChangeEncoding.event; - private readonly _onDidDisposeModel: Emitter = this._register(new Emitter()); - readonly onDidDisposeModel: Event = this._onDidDisposeModel.event; + private readonly _onDidDisposeModel = this._register(new Emitter()); + readonly onDidDisposeModel = this._onDidDisposeModel.event; constructor( @IInstantiationService private readonly instantiationService: IInstantiationService, From 6b8c4b04f3b35f1e80d65fbd04ab7405ddd89e5c Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Wed, 13 Nov 2019 11:46:02 +0100 Subject: [PATCH 188/352] Revert "Only QuickNav if there was a keyDown since shown (fixes #83013)" This reverts commit 8faa1d52f1a17bbce681a6d7d00a739a73c27e75. --- src/vs/base/parts/quickopen/browser/quickOpenWidget.ts | 7 +------ src/vs/workbench/browser/parts/quickinput/quickInput.ts | 7 +------ 2 files changed, 2 insertions(+), 12 deletions(-) diff --git a/src/vs/base/parts/quickopen/browser/quickOpenWidget.ts b/src/vs/base/parts/quickopen/browser/quickOpenWidget.ts index 8a5414833f5cd..25399d91d9515 100644 --- a/src/vs/base/parts/quickopen/browser/quickOpenWidget.ts +++ b/src/vs/base/parts/quickopen/browser/quickOpenWidget.ts @@ -135,7 +135,6 @@ export class QuickOpenWidget extends Disposable implements IModelProvider, IThem private styles: IQuickOpenStyles; // @ts-ignore (legacy widget - to be replaced with quick input) private renderer: Renderer; - private keyDownSeenSinceShown = false; constructor(container: HTMLElement, callbacks: IQuickOpenCallbacks, options: IQuickOpenOptions) { super(); @@ -172,7 +171,6 @@ export class QuickOpenWidget extends Disposable implements IModelProvider, IThem this._register(DOM.addDisposableListener(this.element, DOM.EventType.FOCUS, e => this.gainingFocus(), true)); this._register(DOM.addDisposableListener(this.element, DOM.EventType.BLUR, e => this.loosingFocus(e), true)); this._register(DOM.addDisposableListener(this.element, DOM.EventType.KEY_DOWN, e => { - this.keyDownSeenSinceShown = true; const keyboardEvent: StandardKeyboardEvent = new StandardKeyboardEvent(e); if (keyboardEvent.keyCode === KeyCode.Escape) { DOM.EventHelper.stop(e, true); @@ -223,7 +221,6 @@ export class QuickOpenWidget extends Disposable implements IModelProvider, IThem this._register(DOM.addDisposableListener(this.inputBox.inputElement, DOM.EventType.INPUT, (e: Event) => this.onType())); this._register(DOM.addDisposableListener(this.inputBox.inputElement, DOM.EventType.KEY_DOWN, (e: KeyboardEvent) => { - this.keyDownSeenSinceShown = true; const keyboardEvent: StandardKeyboardEvent = new StandardKeyboardEvent(e); const shouldOpenInBackground = this.shouldOpenInBackground(keyboardEvent); @@ -304,7 +301,6 @@ export class QuickOpenWidget extends Disposable implements IModelProvider, IThem })); this._register(DOM.addDisposableListener(this.treeContainer, DOM.EventType.KEY_DOWN, e => { - this.keyDownSeenSinceShown = true; const keyboardEvent: StandardKeyboardEvent = new StandardKeyboardEvent(e); // Only handle when in quick navigation mode @@ -325,7 +321,7 @@ export class QuickOpenWidget extends Disposable implements IModelProvider, IThem const keyCode = keyboardEvent.keyCode; // Only handle when in quick navigation mode - if (!this.quickNavigateConfiguration || !this.keyDownSeenSinceShown) { + if (!this.quickNavigateConfiguration) { return; } @@ -600,7 +596,6 @@ export class QuickOpenWidget extends Disposable implements IModelProvider, IThem this.visible = true; this.isLoosingFocus = false; this.quickNavigateConfiguration = options ? options.quickNavigateConfiguration : undefined; - this.keyDownSeenSinceShown = false; // Adjust UI for quick navigate mode if (this.quickNavigateConfiguration) { diff --git a/src/vs/workbench/browser/parts/quickinput/quickInput.ts b/src/vs/workbench/browser/parts/quickinput/quickInput.ts index 4b365e66ae144..033a66cc27423 100644 --- a/src/vs/workbench/browser/parts/quickinput/quickInput.ts +++ b/src/vs/workbench/browser/parts/quickinput/quickInput.ts @@ -84,7 +84,6 @@ interface QuickInputUI { onDidTriggerButton: Event; ignoreFocusOut: boolean; keyMods: Writeable; - keyDownSeenSinceShown: boolean; isScreenReaderOptimized(): boolean; show(controller: QuickInput): void; setVisibilities(visibilities: Visibilities): void; @@ -217,7 +216,6 @@ class QuickInput extends Disposable implements IQuickInput { } }), ); - this.ui.keyDownSeenSinceShown = false; this.ui.show(this); this.visible = true; this.update(); @@ -556,7 +554,6 @@ class QuickPick extends QuickInput implements IQuickPi } })); this.visibleDisposables.add(this.ui.inputBox.onKeyDown(event => { - this.ui.keyDownSeenSinceShown = true; switch (event.keyCode) { case KeyCode.DownArrow: this.ui.list.focus('Next'); @@ -655,7 +652,7 @@ class QuickPick extends QuickInput implements IQuickPi private registerQuickNavigation() { return dom.addDisposableListener(this.ui.container, dom.EventType.KEY_UP, e => { - if (this.canSelectMany || !this.quickNavigate || !this.ui.keyDownSeenSinceShown) { + if (this.canSelectMany || !this.quickNavigate) { return; } @@ -1114,7 +1111,6 @@ export class QuickInputService extends Component implements IQuickInputService { inputBox.setFocus(); })); this._register(dom.addDisposableListener(container, dom.EventType.KEY_DOWN, (e: KeyboardEvent) => { - this.getUI().keyDownSeenSinceShown = true; const event = new StandardKeyboardEvent(e); switch (event.keyCode) { case KeyCode.Enter: @@ -1176,7 +1172,6 @@ export class QuickInputService extends Component implements IQuickInputService { onDidTriggerButton: this.onDidTriggerButtonEmitter.event, ignoreFocusOut: false, keyMods: this.keyMods, - keyDownSeenSinceShown: false, isScreenReaderOptimized: () => this.isScreenReaderOptimized(), show: controller => this.show(controller), hide: () => this.hide(), From 701c0739da149839baecbc6acd95463b88b5bd0b Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Wed, 13 Nov 2019 11:49:11 +0100 Subject: [PATCH 189/352] better fix #83013 --- .../base/parts/quickopen/browser/quickOpenWidget.ts | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/vs/base/parts/quickopen/browser/quickOpenWidget.ts b/src/vs/base/parts/quickopen/browser/quickOpenWidget.ts index 25399d91d9515..965e30332134d 100644 --- a/src/vs/base/parts/quickopen/browser/quickOpenWidget.ts +++ b/src/vs/base/parts/quickopen/browser/quickOpenWidget.ts @@ -314,6 +314,16 @@ export class QuickOpenWidget extends Disposable implements IModelProvider, IThem this.navigateInTree(keyboardEvent.keyCode); } + + // Support to open item with Enter still even in quick nav mode + else if (keyboardEvent.keyCode === KeyCode.Enter) { + DOM.EventHelper.stop(e, true); + + const focus = this.tree.getFocus(); + if (focus) { + this.elementSelected(focus, e); + } + } })); this._register(DOM.addDisposableListener(this.treeContainer, DOM.EventType.KEY_UP, e => { @@ -327,7 +337,7 @@ export class QuickOpenWidget extends Disposable implements IModelProvider, IThem // Select element when keys are pressed that signal it const quickNavKeys = this.quickNavigateConfiguration.keybindings; - const wasTriggerKeyPressed = keyCode === KeyCode.Enter || quickNavKeys.some(k => { + const wasTriggerKeyPressed = quickNavKeys.some(k => { const [firstPart, chordPart] = k.getParts(); if (chordPart) { return false; From 2054549c99941d3f67a0ce722ae8dccc18ef5bab Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Wed, 13 Nov 2019 11:49:09 +0100 Subject: [PATCH 190/352] Add isEntryVisible api to statusbar service --- .../browser/parts/statusbar/statusbarPart.ts | 4 ++++ .../workbench/services/statusbar/common/statusbar.ts | 12 ++++++++++-- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/browser/parts/statusbar/statusbarPart.ts b/src/vs/workbench/browser/parts/statusbar/statusbarPart.ts index 3fe32716b3018..425e82cf37b9d 100644 --- a/src/vs/workbench/browser/parts/statusbar/statusbarPart.ts +++ b/src/vs/workbench/browser/parts/statusbar/statusbarPart.ts @@ -433,6 +433,10 @@ export class StatusbarPart extends Part implements IStatusbarService { }; } + isEntryVisible(id: string): boolean { + return !this.viewModel.isHidden(id); + } + updateEntryVisibility(id: string, visible: boolean): void { if (visible) { this.viewModel.show(id); diff --git a/src/vs/workbench/services/statusbar/common/statusbar.ts b/src/vs/workbench/services/statusbar/common/statusbar.ts index 95e43cdc5fba1..cd91a975bda2e 100644 --- a/src/vs/workbench/services/statusbar/common/statusbar.ts +++ b/src/vs/workbench/services/statusbar/common/statusbar.ts @@ -62,8 +62,6 @@ export interface IStatusbarService { _serviceBrand: undefined; - readonly onDidChangeEntryVisibility: Event<{ id: string, visible: boolean }>; - /** * Adds an entry to the statusbar with the given alignment and priority. Use the returned accessor * to update or remove the statusbar entry. @@ -76,6 +74,16 @@ export interface IStatusbarService { */ addEntry(entry: IStatusbarEntry, id: string, name: string, alignment: StatusbarAlignment, priority?: number): IStatusbarEntryAccessor; + /** + * An event that is triggered when an entry's visibility is changed. + */ + readonly onDidChangeEntryVisibility: Event<{ id: string, visible: boolean }>; + + /** + * Return if an entry is visible or not. + */ + isEntryVisible(id: string): boolean; + /** * Allows to update an entry's visibility with the provided ID. */ From bf4c91571a9ac80fb5fca38006180c7f365d1efe Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Wed, 13 Nov 2019 12:01:08 +0100 Subject: [PATCH 191/352] simpler navigation --- .../outline/browser/outlineNavigation.ts | 128 +++++++----------- 1 file changed, 49 insertions(+), 79 deletions(-) diff --git a/src/vs/workbench/contrib/outline/browser/outlineNavigation.ts b/src/vs/workbench/contrib/outline/browser/outlineNavigation.ts index 4caed47d6cf58..b5bc5f1a97b06 100644 --- a/src/vs/workbench/contrib/outline/browser/outlineNavigation.ts +++ b/src/vs/workbench/contrib/outline/browser/outlineNavigation.ts @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { Range } from 'vs/editor/common/core/range'; +import { IPosition, Position } from 'vs/editor/common/core/position'; import { OutlineElement, OutlineModel, TreeElement } from 'vs/editor/contrib/documentSymbols/outlineModel'; import { localize } from 'vs/nls'; import { IEditorContribution, ScrollType } from 'vs/editor/common/editorCommon'; @@ -13,74 +14,36 @@ import { EditorStateCancellationTokenSource, CodeEditorStateFlag } from 'vs/edit import { EditorAction, registerEditorAction, registerEditorContribution } from 'vs/editor/browser/editorExtensions'; import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { EditorContextKeys } from 'vs/editor/common/editorContextKeys'; -import { values } from 'vs/base/common/collections'; +import { forEach } from 'vs/base/common/collections'; import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; import { KeyCode, KeyMod } from 'vs/base/common/keyCodes'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { OutlineFilter } from 'vs/editor/contrib/documentSymbols/outlineTree'; +import { binarySearch } from 'vs/base/common/arrays'; -class Navigator { +class FlatOutline { - private readonly _children: TreeElement[] = []; + readonly elements: OutlineElement[] = []; + readonly _positions: IPosition[]; - constructor( - readonly element: TreeElement, - private readonly _filter: OutlineFilter - ) { - this._children = values(element.children) - .filter(entry => !(entry instanceof OutlineElement) || _filter.filter(entry)) - .sort(Navigator._compare); - } + constructor(model: OutlineModel, filter: OutlineFilter) { - navigate(up: boolean): TreeElement | undefined { - return up ? this._up() : this._down(); - } - - private _up(): TreeElement | undefined { - const sibling = this._sibling(true); - if (!sibling) { - return this.element.parent; - } - let nav: Navigator = sibling; - while (nav) { - let next = nav._child(true); - if (!next) { - return nav.element; + const walk = (element: TreeElement) => { + if (element instanceof OutlineElement && !filter.filter(element)) { + return; } - nav = new Navigator(next, this._filter); - } - return undefined; - } - - private _down(): TreeElement | undefined { - const firstChild = this._child(false); - if (firstChild) { - return firstChild; - } - let nav: Navigator | undefined = this; - while (nav) { - const next = nav._sibling(false); - if (next) { - return next.element; + if (element instanceof OutlineElement) { + this.elements.push(element); } - nav = nav.element.parent && new Navigator(nav.element.parent, this._filter); - } - return undefined; - } - - private _sibling(up: boolean): Navigator | undefined { - if (!this.element.parent) { - return undefined; - } - const parent = new Navigator(this.element.parent, this._filter); - const idx = parent._children.indexOf(this.element); - const nexIdx = idx + (up ? -1 : +1); - const element = parent._children[nexIdx]; - return element && new Navigator(element, this._filter); - } - - private _child(last: boolean): TreeElement | undefined { - return this._children[last ? this._children.length - 1 : 0]; + forEach(element.children, entry => walk(entry.value)); + }; + + walk(model); + this.elements.sort(FlatOutline._compare); + this._positions = this.elements.map(element => ({ + lineNumber: element.symbol.range.startLineNumber, + column: element.symbol.range.startColumn + })); } private static _compare(a: TreeElement, b: TreeElement): number { @@ -88,6 +51,17 @@ class Navigator { ? Range.compareRangesUsingStarts(a.symbol.range, b.symbol.range) : 0; } + + find(position: IPosition, preferAfter: boolean): number { + const idx = binarySearch(this._positions, position, Position.compare); + if (idx >= 0) { + return idx; + } else if (preferAfter) { + return ~idx; + } else { + return ~idx - 1; + } + } } export class OutlineNavigation implements IEditorContribution { @@ -133,34 +107,30 @@ export class OutlineNavigation implements IEditorContribution { const filter = new OutlineFilter('outline', this._configService); const outlineModel = await OutlineModel.create(textModel, this._cts.token); - let element: TreeElement | undefined = outlineModel.getItemEnclosingPosition(position); - if (!(element instanceof OutlineElement) || this._cts.token.isCancellationRequested) { + if (this._cts.token.isCancellationRequested) { return; } - // don't start in a filtered element - let stack: OutlineElement[] = [element]; - while (element instanceof OutlineElement) { - if (!filter.filter(element)) { - stack.length = 0; + const symbols = new FlatOutline(outlineModel, filter); + const idx = symbols.find(position, !up); + const element = symbols.elements[idx]; + + if (element) { + if (Range.containsPosition(element.symbol.selectionRange, position)) { + // at the "name" of a symbol -> move + const nextElement = symbols.elements[idx + (up ? -1 : +1)]; + this._revealElement(nextElement); + } else { - stack.push(element); + // enclosing, lastBefore, or firstAfter element + this._revealElement(element); } - element = element.parent; - } - element = stack[0]; - if (!(element instanceof OutlineElement)) { - return; - } - - // reveal container first (unless already at its range) - let nextElement: TreeElement | undefined = element; - if (!up || Range.containsPosition(element.symbol.selectionRange, position)) { - nextElement = new Navigator(element, filter).navigate(up); } + } - if (nextElement instanceof OutlineElement) { - const pos = Range.lift(nextElement.symbol.selectionRange).getStartPosition(); + private _revealElement(element: OutlineElement | undefined): void { + if (element) { + const pos = Range.lift(element.symbol.selectionRange).getStartPosition(); this._editor.setPosition(pos); this._editor.revealPosition(pos, ScrollType.Smooth); } From c6388baf2b155f4e90fd8bf58167a7511395f27e Mon Sep 17 00:00:00 2001 From: Alexandru Dima Date: Wed, 13 Nov 2019 12:04:27 +0100 Subject: [PATCH 192/352] Replace layer hinting using `will-change: transform` with `transform: translate3d(0px, 0px, 0px)` (#84214) --- src/vs/base/browser/fastDomNode.ts | 2 +- src/vs/base/browser/ui/list/listView.ts | 2 +- src/vs/base/browser/ui/progressbar/progressbar.css | 2 +- src/vs/editor/common/config/editorOptions.ts | 4 ++-- src/vs/monaco.d.ts | 4 ++-- .../workbench/browser/parts/editor/media/tabstitlecontrol.css | 2 +- .../browser/parts/notifications/media/notificationsToasts.css | 4 ++-- 7 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/vs/base/browser/fastDomNode.ts b/src/vs/base/browser/fastDomNode.ts index 180eacdbd0ff8..5c688bd34964b 100644 --- a/src/vs/base/browser/fastDomNode.ts +++ b/src/vs/base/browser/fastDomNode.ts @@ -205,7 +205,7 @@ export class FastDomNode { return; } this._layerHint = layerHint; - (this.domNode.style).willChange = this._layerHint ? 'transform' : 'auto'; + this.domNode.style.transform = this._layerHint ? 'translate3d(0px, 0px, 0px)' : ''; } public setContain(contain: 'none' | 'strict' | 'content' | 'size' | 'layout' | 'style' | 'paint'): void { diff --git a/src/vs/base/browser/ui/list/listView.ts b/src/vs/base/browser/ui/list/listView.ts index 620974cd757ed..770bd8c4c3411 100644 --- a/src/vs/base/browser/ui/list/listView.ts +++ b/src/vs/base/browser/ui/list/listView.ts @@ -234,7 +234,7 @@ export class ListView implements ISpliceable, IDisposable { this.rowsContainer = document.createElement('div'); this.rowsContainer.className = 'monaco-list-rows'; - this.rowsContainer.style.willChange = 'transform'; + this.rowsContainer.style.transform = 'translate3d(0px, 0px, 0px)'; this.disposables.add(Gesture.addTarget(this.rowsContainer)); this.scrollableElement = this.disposables.add(new ScrollableElement(this.rowsContainer, { diff --git a/src/vs/base/browser/ui/progressbar/progressbar.css b/src/vs/base/browser/ui/progressbar/progressbar.css index 5d1e8b3f76258..64368d699b0f1 100644 --- a/src/vs/base/browser/ui/progressbar/progressbar.css +++ b/src/vs/base/browser/ui/progressbar/progressbar.css @@ -35,7 +35,7 @@ animation-duration: 4s; animation-iteration-count: infinite; animation-timing-function: linear; - will-change: transform; + transform: translate3d(0px, 0px, 0px); } /** diff --git a/src/vs/editor/common/config/editorOptions.ts b/src/vs/editor/common/config/editorOptions.ts index de2c41dddd370..ac610aa562696 100644 --- a/src/vs/editor/common/config/editorOptions.ts +++ b/src/vs/editor/common/config/editorOptions.ts @@ -186,8 +186,8 @@ export interface IEditorOptions { */ fontLigatures?: boolean | string; /** - * Disable the use of `will-change` for the editor margin and lines layers. - * The usage of `will-change` acts as a hint for browsers to create an extra layer. + * Disable the use of `transform: translate3d(0px, 0px, 0px)` for the editor margin and lines layers. + * The usage of `transform: translate3d(0px, 0px, 0px)` acts as a hint for browsers to create an extra layer. * Defaults to false. */ disableLayerHinting?: boolean; diff --git a/src/vs/monaco.d.ts b/src/vs/monaco.d.ts index bcfe1121ecbc7..2fa74f0ac351d 100644 --- a/src/vs/monaco.d.ts +++ b/src/vs/monaco.d.ts @@ -2597,8 +2597,8 @@ declare namespace monaco.editor { */ fontLigatures?: boolean | string; /** - * Disable the use of `will-change` for the editor margin and lines layers. - * The usage of `will-change` acts as a hint for browsers to create an extra layer. + * Disable the use of `transform: translate3d(0px, 0px, 0px)` for the editor margin and lines layers. + * The usage of `transform: translate3d(0px, 0px, 0px)` acts as a hint for browsers to create an extra layer. * Defaults to false. */ disableLayerHinting?: boolean; diff --git a/src/vs/workbench/browser/parts/editor/media/tabstitlecontrol.css b/src/vs/workbench/browser/parts/editor/media/tabstitlecontrol.css index c772839b16065..cfde439545707 100644 --- a/src/vs/workbench/browser/parts/editor/media/tabstitlecontrol.css +++ b/src/vs/workbench/browser/parts/editor/media/tabstitlecontrol.css @@ -84,7 +84,7 @@ } .monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.dragged { - will-change: transform; /* forces tab to be drawn on a separate layer (fixes https://github.com/Microsoft/vscode/issues/18733) */ + transform: translate3d(0px, 0px, 0px); /* forces tab to be drawn on a separate layer (fixes https://github.com/Microsoft/vscode/issues/18733) */ } .monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.dragged-over div { diff --git a/src/vs/workbench/browser/parts/notifications/media/notificationsToasts.css b/src/vs/workbench/browser/parts/notifications/media/notificationsToasts.css index bd99129c7434b..3f07c0123abc9 100644 --- a/src/vs/workbench/browser/parts/notifications/media/notificationsToasts.css +++ b/src/vs/workbench/browser/parts/notifications/media/notificationsToasts.css @@ -30,7 +30,7 @@ transform: translateY(100%); /* move the notification 50px to the bottom (to prevent bleed through) */ opacity: 0; /* fade the toast in */ transition: transform 300ms ease-out, opacity 300ms ease-out; - will-change: transform, opacity; /* force a separate layer for the toast to speed things up */ + transform: translate3d(0px, 0px, 0px); /* force a separate layer for the toast to speed things up */ } .monaco-workbench > .notifications-toasts .notification-toast-container > .notification-toast.notification-fade-in { @@ -42,4 +42,4 @@ opacity: 1; transform: none; transition: none; -} \ No newline at end of file +} From 14513cc382ab46c364d419e7393a253de6650678 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Wed, 13 Nov 2019 12:10:16 +0100 Subject: [PATCH 193/352] enable auth token service --- src/vs/platform/auth/common/auth.ts | 1 - .../auth/electron-browser/authTokenService.ts | 30 ++++--------------- .../common/userDataSyncService.ts | 9 +----- .../common/userDataSyncStoreService.ts | 18 +++++------ .../authToken/browser/authTokenService.ts | 30 +++++-------------- .../electron-browser/authTokenService.ts | 2 +- 6 files changed, 22 insertions(+), 68 deletions(-) diff --git a/src/vs/platform/auth/common/auth.ts b/src/vs/platform/auth/common/auth.ts index 99102a0fe9396..1f4e643c62e0b 100644 --- a/src/vs/platform/auth/common/auth.ts +++ b/src/vs/platform/auth/common/auth.ts @@ -8,7 +8,6 @@ import { Event, Emitter } from 'vs/base/common/event'; import { URI } from 'vs/base/common/uri'; export const enum AuthTokenStatus { - Disabled = 'Disabled', Inactive = 'Inactive', Active = 'Active' } diff --git a/src/vs/platform/auth/electron-browser/authTokenService.ts b/src/vs/platform/auth/electron-browser/authTokenService.ts index 9b70de53d72f5..00a35957be51b 100644 --- a/src/vs/platform/auth/electron-browser/authTokenService.ts +++ b/src/vs/platform/auth/electron-browser/authTokenService.ts @@ -9,8 +9,6 @@ import { Event, Emitter } from 'vs/base/common/event'; import { IAuthTokenService, AuthTokenStatus } from 'vs/platform/auth/common/auth'; import { ICredentialsService } from 'vs/platform/credentials/common/credentials'; import { Disposable, IDisposable } from 'vs/base/common/lifecycle'; -import { IProductService } from 'vs/platform/product/common/productService'; -import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { URI } from 'vs/base/common/uri'; import { generateUuid } from 'vs/base/common/uuid'; import { shell } from 'electron'; @@ -51,7 +49,7 @@ export interface IToken { export class AuthTokenService extends Disposable implements IAuthTokenService { _serviceBrand: undefined; - private _status: AuthTokenStatus = AuthTokenStatus.Disabled; + private _status: AuthTokenStatus = AuthTokenStatus.Inactive; get status(): AuthTokenStatus { return this._status; } private _onDidChangeStatus: Emitter = this._register(new Emitter()); readonly onDidChangeStatus: Event = this._onDidChangeStatus.event; @@ -63,19 +61,13 @@ export class AuthTokenService extends Disposable implements IAuthTokenService { constructor( @ICredentialsService private readonly credentialsService: ICredentialsService, - @IProductService productService: IProductService, - @IConfigurationService configurationService: IConfigurationService, ) { super(); - if (productService.settingsSyncStoreUrl && configurationService.getValue('configurationSync.enableAuth')) { - this.credentialsService.getPassword(SERVICE_NAME, ACCOUNT).then(storedRefreshToken => { - if (storedRefreshToken) { - this.refresh(storedRefreshToken); - } else { - this._status = AuthTokenStatus.Inactive; - } - }); - } + this.credentialsService.getPassword(SERVICE_NAME, ACCOUNT).then(storedRefreshToken => { + if (storedRefreshToken) { + this.refresh(storedRefreshToken); + } + }); } public async login(callbackUri: URI): Promise { @@ -107,17 +99,10 @@ export class AuthTokenService extends Disposable implements IAuthTokenService { } public getToken(): Promise { - if (this.status === AuthTokenStatus.Disabled) { - throw new Error('Not enabled'); - } return Promise.resolve(this._activeToken?.accessToken); } public async refreshToken(): Promise { - if (this.status === AuthTokenStatus.Disabled) { - throw new Error('Not enabled'); - } - if (!this._activeToken) { throw new Error('No token to refresh'); } @@ -247,9 +232,6 @@ export class AuthTokenService extends Disposable implements IAuthTokenService { } async logout(): Promise { - if (this.status === AuthTokenStatus.Disabled) { - throw new Error('Not enabled'); - } await this.credentialsService.deletePassword(SERVICE_NAME, ACCOUNT); this._activeToken = undefined; this.setStatus(AuthTokenStatus.Inactive); diff --git a/src/vs/platform/userDataSync/common/userDataSyncService.ts b/src/vs/platform/userDataSync/common/userDataSyncService.ts index a4908dabe2220..85b8a9ee1520d 100644 --- a/src/vs/platform/userDataSync/common/userDataSyncService.ts +++ b/src/vs/platform/userDataSync/common/userDataSyncService.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { IUserDataSyncService, SyncStatus, ISynchroniser, IUserDataSyncStoreService, SyncSource, IUserDataSyncLogService, UserDataSyncStoreError, UserDataSyncStoreErrorCode } from 'vs/platform/userDataSync/common/userDataSync'; +import { IUserDataSyncService, SyncStatus, ISynchroniser, IUserDataSyncStoreService, SyncSource, IUserDataSyncLogService } from 'vs/platform/userDataSync/common/userDataSync'; import { Disposable } from 'vs/base/common/lifecycle'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { SettingsSynchroniser } from 'vs/platform/userDataSync/common/settingsSync'; @@ -164,13 +164,6 @@ export class UserDataAutoSync extends Disposable { try { await this.userDataSyncService.sync(); } catch (e) { - if (e instanceof UserDataSyncStoreError && e.code === UserDataSyncStoreErrorCode.Unauthroized) { - if (e instanceof UserDataSyncStoreError && e.code === UserDataSyncStoreErrorCode.Unauthroized && this.authTokenService.status === AuthTokenStatus.Disabled) { - this.logService.error('Sync failed because the server requires authorization. Please enable authorization.'); - } else { - this.logService.error(e); - } - } this.logService.error(e); } if (loop) { diff --git a/src/vs/platform/userDataSync/common/userDataSyncStoreService.ts b/src/vs/platform/userDataSync/common/userDataSyncStoreService.ts index 5910b86817c0f..faf1ec0c400b1 100644 --- a/src/vs/platform/userDataSync/common/userDataSyncStoreService.ts +++ b/src/vs/platform/userDataSync/common/userDataSyncStoreService.ts @@ -11,7 +11,7 @@ import { URI } from 'vs/base/common/uri'; import { joinPath } from 'vs/base/common/resources'; import { CancellationToken } from 'vs/base/common/cancellation'; import { IHeaders, IRequestOptions, IRequestContext } from 'vs/base/parts/request/common/request'; -import { IAuthTokenService, AuthTokenStatus } from 'vs/platform/auth/common/auth'; +import { IAuthTokenService } from 'vs/platform/auth/common/auth'; export class UserDataSyncStoreService extends Disposable implements IUserDataSyncStoreService { @@ -87,21 +87,17 @@ export class UserDataSyncStoreService extends Disposable implements IUserDataSyn } private async request(options: IRequestOptions, token: CancellationToken): Promise { - if (this.authTokenService.status !== AuthTokenStatus.Disabled) { - const authToken = await this.authTokenService.getToken(); - if (!authToken) { - throw new Error('No Auth Token Available.'); - } - options.headers = options.headers || {}; - options.headers['authorization'] = `Bearer ${authToken}`; + const authToken = await this.authTokenService.getToken(); + if (!authToken) { + throw new Error('No Auth Token Available.'); } + options.headers = options.headers || {}; + options.headers['authorization'] = `Bearer ${authToken}`; const context = await this.requestService.request(options, token); if (context.res.statusCode === 401) { - if (this.authTokenService.status !== AuthTokenStatus.Disabled) { - this.authTokenService.refreshToken(); - } + this.authTokenService.refreshToken(); // Throw Unauthorized Error throw new UserDataSyncStoreError('Unauthorized', UserDataSyncStoreErrorCode.Unauthroized); } diff --git a/src/vs/workbench/services/authToken/browser/authTokenService.ts b/src/vs/workbench/services/authToken/browser/authTokenService.ts index 430a11f7bd896..77ba08b94fa77 100644 --- a/src/vs/workbench/services/authToken/browser/authTokenService.ts +++ b/src/vs/workbench/services/authToken/browser/authTokenService.ts @@ -8,8 +8,6 @@ import { Event, Emitter } from 'vs/base/common/event'; import { IAuthTokenService, AuthTokenStatus } from 'vs/platform/auth/common/auth'; import { ICredentialsService } from 'vs/platform/credentials/common/credentials'; import { Disposable } from 'vs/base/common/lifecycle'; -import { IProductService } from 'vs/platform/product/common/productService'; -import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IQuickInputService } from 'vs/platform/quickinput/common/quickInput'; import { URI } from 'vs/base/common/uri'; @@ -19,7 +17,7 @@ const ACCOUNT = 'MyAccount'; export class AuthTokenService extends Disposable implements IAuthTokenService { _serviceBrand: undefined; - private _status: AuthTokenStatus = AuthTokenStatus.Disabled; + private _status: AuthTokenStatus = AuthTokenStatus.Inactive; get status(): AuthTokenStatus { return this._status; } private _onDidChangeStatus: Emitter = this._register(new Emitter()); readonly onDidChangeStatus: Event = this._onDidChangeStatus.event; @@ -28,26 +26,18 @@ export class AuthTokenService extends Disposable implements IAuthTokenService { constructor( @ICredentialsService private readonly credentialsService: ICredentialsService, - @IProductService productService: IProductService, - @IConfigurationService configurationService: IConfigurationService, @IQuickInputService private readonly quickInputService: IQuickInputService ) { super(); - if (productService.settingsSyncStoreUrl && configurationService.getValue('configurationSync.enableAuth')) { - this._status = AuthTokenStatus.Inactive; - this.getToken().then(token => { - if (token) { - this.setStatus(AuthTokenStatus.Active); - } - }); - } + this._status = AuthTokenStatus.Inactive; + this.getToken().then(token => { + if (token) { + this.setStatus(AuthTokenStatus.Active); + } + }); } async getToken(): Promise { - if (this.status === AuthTokenStatus.Disabled) { - throw new Error('Not enabled'); - } - const token = await this.credentialsService.getPassword(SERVICE_NAME, ACCOUNT); if (token) { return token; @@ -65,16 +55,10 @@ export class AuthTokenService extends Disposable implements IAuthTokenService { } async refreshToken(): Promise { - if (this.status === AuthTokenStatus.Disabled) { - throw new Error('Not enabled'); - } await this.logout(); } async logout(): Promise { - if (this.status === AuthTokenStatus.Disabled) { - throw new Error('Not enabled'); - } await this.credentialsService.deletePassword(SERVICE_NAME, ACCOUNT); this.setStatus(AuthTokenStatus.Inactive); } diff --git a/src/vs/workbench/services/authToken/electron-browser/authTokenService.ts b/src/vs/workbench/services/authToken/electron-browser/authTokenService.ts index 7a06e375569a7..e29e1727aff95 100644 --- a/src/vs/workbench/services/authToken/electron-browser/authTokenService.ts +++ b/src/vs/workbench/services/authToken/electron-browser/authTokenService.ts @@ -18,7 +18,7 @@ export class AuthTokenService extends Disposable implements IAuthTokenService { private readonly channel: IChannel; - private _status: AuthTokenStatus = AuthTokenStatus.Disabled; + private _status: AuthTokenStatus = AuthTokenStatus.Inactive; get status(): AuthTokenStatus { return this._status; } private _onDidChangeStatus: Emitter = this._register(new Emitter()); readonly onDidChangeStatus: Event = this._onDidChangeStatus.event; From 0872b0037889b932dce5a8eede2b01103305692b Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Wed, 13 Nov 2019 12:17:13 +0100 Subject: [PATCH 194/352] Enable sign in only when sync is initialized --- .../workbench/contrib/userDataSync/browser/userDataSync.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts b/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts index 476d3ab6ce9c6..17218a393304c 100644 --- a/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts +++ b/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts @@ -63,7 +63,7 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo this.registerActions(); timeout(2000).then(() => { - if (this.authTokenService.status === AuthTokenStatus.Inactive && configurationService.getValue('configurationSync.enable')) { + if (this.authTokenService.status === AuthTokenStatus.Inactive && this.userDataSyncService.status !== SyncStatus.Uninitialized && configurationService.getValue('configurationSync.enable')) { this.showSignInNotification(); } }); @@ -109,7 +109,7 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo let badge: IBadge | undefined = undefined; let clazz: string | undefined; - if (this.authTokenService.status === AuthTokenStatus.Inactive && this.configurationService.getValue('configurationSync.enable')) { + if (this.authTokenService.status === AuthTokenStatus.Inactive && this.userDataSyncService.status !== SyncStatus.Uninitialized && this.configurationService.getValue('configurationSync.enable')) { badge = new NumberBadge(1, () => localize('sign in', "Sign in...")); } else if (this.userDataSyncService.status === SyncStatus.HasConflicts) { badge = new NumberBadge(1, () => localize('resolve conflicts', "Resolve Conflicts")); @@ -200,7 +200,7 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo id: 'workbench.userData.actions.login', title: localize('sign in', "Sign in...") }, - when: ContextKeyExpr.and(CONTEXT_AUTH_TOKEN_STATE.isEqualTo(AuthTokenStatus.Inactive), ContextKeyExpr.has('config.configurationSync.enable')), + when: ContextKeyExpr.and(CONTEXT_SYNC_STATE.notEqualsTo(SyncStatus.Uninitialized), CONTEXT_AUTH_TOKEN_STATE.isEqualTo(AuthTokenStatus.Inactive), ContextKeyExpr.has('config.configurationSync.enable')), }; CommandsRegistry.registerCommand(signInMenuItem.command.id, () => this.signIn()); MenuRegistry.appendMenuItem(MenuId.GlobalActivity, signInMenuItem); From 2580bacd65b519ae4a1857ecf413841916e1ce68 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Wed, 13 Nov 2019 12:25:27 +0100 Subject: [PATCH 195/352] show short highlight --- .../outline/browser/outlineNavigation.ts | 28 ++++++++++++++----- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/src/vs/workbench/contrib/outline/browser/outlineNavigation.ts b/src/vs/workbench/contrib/outline/browser/outlineNavigation.ts index b5bc5f1a97b06..8362d0f7ad7b9 100644 --- a/src/vs/workbench/contrib/outline/browser/outlineNavigation.ts +++ b/src/vs/workbench/contrib/outline/browser/outlineNavigation.ts @@ -24,7 +24,7 @@ import { binarySearch } from 'vs/base/common/arrays'; class FlatOutline { readonly elements: OutlineElement[] = []; - readonly _positions: IPosition[]; + readonly _elementPositions: IPosition[]; constructor(model: OutlineModel, filter: OutlineFilter) { @@ -40,7 +40,7 @@ class FlatOutline { walk(model); this.elements.sort(FlatOutline._compare); - this._positions = this.elements.map(element => ({ + this._elementPositions = this.elements.map(element => ({ lineNumber: element.symbol.range.startLineNumber, column: element.symbol.range.startColumn })); @@ -53,7 +53,7 @@ class FlatOutline { } find(position: IPosition, preferAfter: boolean): number { - const idx = binarySearch(this._positions, position, Position.compare); + const idx = binarySearch(this._elementPositions, position, Position.compare); if (idx >= 0) { return idx; } else if (preferAfter) { @@ -129,11 +129,25 @@ export class OutlineNavigation implements IEditorContribution { } private _revealElement(element: OutlineElement | undefined): void { - if (element) { - const pos = Range.lift(element.symbol.selectionRange).getStartPosition(); - this._editor.setPosition(pos); - this._editor.revealPosition(pos, ScrollType.Smooth); + if (!element) { + return; } + const pos = Range.lift(element.symbol.selectionRange).getStartPosition(); + this._editor.setPosition(pos); + this._editor.revealPosition(pos, ScrollType.Smooth); + + const modelNow = this._editor.getModel(); + const ids = this._editor.deltaDecorations([], [{ + range: element.symbol.selectionRange, + options: { + className: 'rangeHighlight', + } + }]); + setTimeout(() => { + if (modelNow === this._editor.getModel()) { + this._editor.deltaDecorations(ids, []); + } + }, 250); } } From 4c5dd3bc93dde01d80a7718e2aabb5de0328db14 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Wed, 13 Nov 2019 15:20:09 +0100 Subject: [PATCH 196/352] debt - add more configuration related things from textfiles to files config service --- .../parts/editor/editor.contribution.ts | 7 +- .../browser/parts/editor/textDiffEditor.ts | 6 +- .../browser/parts/editor/textEditor.ts | 6 +- .../parts/editor/textResourceEditor.ts | 10 +-- .../parts/quickopen/quickOpenController.ts | 6 +- .../backup/common/backupModelTracker.ts | 6 +- .../files/browser/editors/textFileEditor.ts | 6 +- .../files/browser/fileActions.contribution.ts | 2 +- .../contrib/files/browser/fileActions.ts | 6 +- .../files/common/dirtyFilesIndicator.ts | 6 +- .../files/common/editors/fileEditorInput.ts | 6 +- .../files/electron-browser/textFileEditor.ts | 6 +- .../contrib/output/browser/logViewer.ts | 6 +- .../contrib/output/browser/outputPanel.ts | 6 +- .../preferences/browser/preferencesEditor.ts | 6 +- .../common/filesConfigurationService.ts} | 63 ++++++++++++++++-- .../browser/browserTextFileService.ts | 2 +- .../textfile/browser/textFileService.ts | 64 +++---------------- .../textfile/common/textFileEditorModel.ts | 10 +-- .../services/textfile/common/textfiles.ts | 4 -- .../electron-browser/nativeTextFileService.ts | 8 +-- .../textfile/test/textFileService.test.ts | 10 +-- .../workbench/test/workbenchTestServices.ts | 21 +++--- src/vs/workbench/workbench.common.main.ts | 2 +- 24 files changed, 138 insertions(+), 137 deletions(-) rename src/vs/workbench/services/{autoSaveConfiguration/common/autoSaveConfigurationService.ts => filesConfiguration/common/filesConfigurationService.ts} (69%) diff --git a/src/vs/workbench/browser/parts/editor/editor.contribution.ts b/src/vs/workbench/browser/parts/editor/editor.contribution.ts index 7de63db891a07..fe4d6da6b5881 100644 --- a/src/vs/workbench/browser/parts/editor/editor.contribution.ts +++ b/src/vs/workbench/browser/parts/editor/editor.contribution.ts @@ -17,7 +17,7 @@ import { UntitledTextEditorInput } from 'vs/workbench/common/editor/untitledText import { ResourceEditorInput } from 'vs/workbench/common/editor/resourceEditorInput'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { TextDiffEditor } from 'vs/workbench/browser/parts/editor/textDiffEditor'; -import { ITextFileService, SUPPORTED_ENCODINGS } from 'vs/workbench/services/textfile/common/textfiles'; +import { SUPPORTED_ENCODINGS } from 'vs/workbench/services/textfile/common/textfiles'; import { BinaryResourceDiffEditor } from 'vs/workbench/browser/parts/editor/binaryDiffEditor'; import { ChangeEncodingAction, ChangeEOLAction, ChangeModeAction, EditorStatus } from 'vs/workbench/browser/parts/editor/editorStatus'; import { IWorkbenchActionRegistry, Extensions as ActionExtensions } from 'vs/workbench/common/actions'; @@ -53,6 +53,7 @@ import { Extensions as WorkbenchExtensions, IWorkbenchContributionsRegistry } fr import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle'; import { withNullAsUndefined } from 'vs/base/common/types'; import { registerAndGetAmdImageURL } from 'vs/base/common/amd'; +import { IFilesConfigurationService } from 'vs/workbench/services/filesConfiguration/common/filesConfigurationService'; // Register String Editor Registry.as(EditorExtensions.Editors).registerEditor( @@ -113,12 +114,12 @@ interface ISerializedUntitledTextEditorInput { class UntitledTextEditorInputFactory implements IEditorInputFactory { constructor( - @ITextFileService private readonly textFileService: ITextFileService, + @IFilesConfigurationService private readonly filesConfigurationService: IFilesConfigurationService, @IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService ) { } serialize(editorInput: EditorInput): string | undefined { - if (!this.textFileService.isHotExitEnabled) { + if (!this.filesConfigurationService.isHotExitEnabled) { return undefined; // never restore untitled unless hot exit is enabled } diff --git a/src/vs/workbench/browser/parts/editor/textDiffEditor.ts b/src/vs/workbench/browser/parts/editor/textDiffEditor.ts index 8d4f411c71c54..889d9c678adcb 100644 --- a/src/vs/workbench/browser/parts/editor/textDiffEditor.ts +++ b/src/vs/workbench/browser/parts/editor/textDiffEditor.ts @@ -33,7 +33,7 @@ import { EditorMemento } from 'vs/workbench/browser/parts/editor/baseEditor'; import { IHostService } from 'vs/workbench/services/host/browser/host'; import { EditorActivation, IEditorOptions } from 'vs/platform/editor/common/editor'; import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService'; -import { IAutoSaveConfigurationService } from 'vs/workbench/services/autoSaveConfiguration/common/autoSaveConfigurationService'; +import { IFilesConfigurationService } from 'vs/workbench/services/filesConfiguration/common/filesConfigurationService'; /** * The text editor that leverages the diff text editor for the editing experience. @@ -56,9 +56,9 @@ export class TextDiffEditor extends BaseTextEditor implements ITextDiffEditor { @ITextFileService textFileService: ITextFileService, @IHostService hostService: IHostService, @IClipboardService private _clipboardService: IClipboardService, - @IAutoSaveConfigurationService autoSaveConfigurationService: IAutoSaveConfigurationService + @IFilesConfigurationService filesConfigurationService: IFilesConfigurationService ) { - super(TextDiffEditor.ID, telemetryService, instantiationService, storageService, configurationService, themeService, textFileService, editorService, editorGroupService, hostService, autoSaveConfigurationService); + super(TextDiffEditor.ID, telemetryService, instantiationService, storageService, configurationService, themeService, textFileService, editorService, editorGroupService, hostService, filesConfigurationService); } protected getEditorMemento(editorGroupService: IEditorGroupsService, key: string, limit: number = 10): IEditorMemento { diff --git a/src/vs/workbench/browser/parts/editor/textEditor.ts b/src/vs/workbench/browser/parts/editor/textEditor.ts index d7042a433102c..cb3930fa43ad4 100644 --- a/src/vs/workbench/browser/parts/editor/textEditor.ts +++ b/src/vs/workbench/browser/parts/editor/textEditor.ts @@ -24,7 +24,7 @@ import { IEditorGroupsService, IEditorGroup } from 'vs/workbench/services/editor import { CancellationToken } from 'vs/base/common/cancellation'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IHostService } from 'vs/workbench/services/host/browser/host'; -import { IAutoSaveConfigurationService, AutoSaveMode } from 'vs/workbench/services/autoSaveConfiguration/common/autoSaveConfigurationService'; +import { IFilesConfigurationService, AutoSaveMode } from 'vs/workbench/services/filesConfiguration/common/filesConfigurationService'; const TEXT_EDITOR_VIEW_STATE_PREFERENCE_KEY = 'textEditorViewState'; @@ -55,7 +55,7 @@ export abstract class BaseTextEditor extends BaseEditor implements ITextEditor { @IEditorService protected editorService: IEditorService, @IEditorGroupsService protected editorGroupService: IEditorGroupsService, @IHostService private readonly hostService: IHostService, - @IAutoSaveConfigurationService private readonly autoSaveConfigurationService: IAutoSaveConfigurationService + @IFilesConfigurationService private readonly filesConfigurationService: IFilesConfigurationService ) { super(id, telemetryService, themeService, storageService); @@ -167,7 +167,7 @@ export abstract class BaseTextEditor extends BaseEditor implements ITextEditor { } private maybeTriggerSaveAll(reason: SaveReason): void { - const mode = this.autoSaveConfigurationService.getAutoSaveMode(); + const mode = this.filesConfigurationService.getAutoSaveMode(); // Determine if we need to save all. In case of a window focus change we also save if auto save mode // is configured to be ON_FOCUS_CHANGE (editor focus change) diff --git a/src/vs/workbench/browser/parts/editor/textResourceEditor.ts b/src/vs/workbench/browser/parts/editor/textResourceEditor.ts index b4e50ce6a8f1a..78c0c9ab54b20 100644 --- a/src/vs/workbench/browser/parts/editor/textResourceEditor.ts +++ b/src/vs/workbench/browser/parts/editor/textResourceEditor.ts @@ -24,7 +24,7 @@ import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editor import { CancellationToken } from 'vs/base/common/cancellation'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IHostService } from 'vs/workbench/services/host/browser/host'; -import { IAutoSaveConfigurationService } from 'vs/workbench/services/autoSaveConfiguration/common/autoSaveConfigurationService'; +import { IFilesConfigurationService } from 'vs/workbench/services/filesConfiguration/common/filesConfigurationService'; /** * An editor implementation that is capable of showing the contents of resource inputs. Uses @@ -43,9 +43,9 @@ export class AbstractTextResourceEditor extends BaseTextEditor { @ITextFileService textFileService: ITextFileService, @IEditorService editorService: IEditorService, @IHostService hostService: IHostService, - @IAutoSaveConfigurationService autoSaveConfigurationService: IAutoSaveConfigurationService + @IFilesConfigurationService filesConfigurationService: IFilesConfigurationService ) { - super(id, telemetryService, instantiationService, storageService, configurationService, themeService, textFileService, editorService, editorGroupService, hostService, autoSaveConfigurationService); + super(id, telemetryService, instantiationService, storageService, configurationService, themeService, textFileService, editorService, editorGroupService, hostService, filesConfigurationService); } getTitle(): string | undefined { @@ -208,8 +208,8 @@ export class TextResourceEditor extends AbstractTextResourceEditor { @IEditorService editorService: IEditorService, @IEditorGroupsService editorGroupService: IEditorGroupsService, @IHostService hostService: IHostService, - @IAutoSaveConfigurationService autoSaveConfigurationService: IAutoSaveConfigurationService + @IFilesConfigurationService filesConfigurationService: IFilesConfigurationService ) { - super(TextResourceEditor.ID, telemetryService, instantiationService, storageService, configurationService, themeService, editorGroupService, textFileService, editorService, hostService, autoSaveConfigurationService); + super(TextResourceEditor.ID, telemetryService, instantiationService, storageService, configurationService, themeService, editorGroupService, textFileService, editorService, hostService, filesConfigurationService); } } diff --git a/src/vs/workbench/browser/parts/quickopen/quickOpenController.ts b/src/vs/workbench/browser/parts/quickopen/quickOpenController.ts index 80aab18b2592f..6f7e2254a6ae3 100644 --- a/src/vs/workbench/browser/parts/quickopen/quickOpenController.ts +++ b/src/vs/workbench/browser/parts/quickopen/quickOpenController.ts @@ -51,7 +51,7 @@ import { IQuickInputService, IQuickPickItem } from 'vs/platform/quickinput/commo import { CancellationTokenSource, CancellationToken } from 'vs/base/common/cancellation'; import { IStorageService } from 'vs/platform/storage/common/storage'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; -import { IAutoSaveConfigurationService, AutoSaveMode } from 'vs/workbench/services/autoSaveConfiguration/common/autoSaveConfigurationService'; +import { IFilesConfigurationService, AutoSaveMode } from 'vs/workbench/services/filesConfiguration/common/filesConfigurationService'; const HELP_PREFIX = '?'; @@ -737,7 +737,7 @@ export class EditorHistoryEntry extends EditorQuickOpenEntry { @IConfigurationService private readonly configurationService: IConfigurationService, @ILabelService labelService: ILabelService, @IFileService fileService: IFileService, - @IAutoSaveConfigurationService private readonly autoSaveConfigurationService: IAutoSaveConfigurationService + @IFilesConfigurationService private readonly filesConfigurationService: IFilesConfigurationService ) { super(editorService); @@ -755,7 +755,7 @@ export class EditorHistoryEntry extends EditorQuickOpenEntry { this.description = labelService.getUriLabel(resources.dirname(this.resource), { relative: true }); this.dirty = this.resource && this.textFileService.isDirty(this.resource); - if (this.dirty && this.autoSaveConfigurationService.getAutoSaveMode() === AutoSaveMode.AFTER_SHORT_DELAY) { + if (this.dirty && this.filesConfigurationService.getAutoSaveMode() === AutoSaveMode.AFTER_SHORT_DELAY) { this.dirty = false; // no dirty decoration if auto save is on with a short timeout } } diff --git a/src/vs/workbench/contrib/backup/common/backupModelTracker.ts b/src/vs/workbench/contrib/backup/common/backupModelTracker.ts index 21d022ec1b72c..e7dee7bcfbdf1 100644 --- a/src/vs/workbench/contrib/backup/common/backupModelTracker.ts +++ b/src/vs/workbench/contrib/backup/common/backupModelTracker.ts @@ -10,7 +10,7 @@ import { ITextFileService, TextFileModelChangeEvent, StateChange } from 'vs/work import { IUntitledTextEditorService } from 'vs/workbench/services/untitled/common/untitledTextEditorService'; import { IWorkbenchContribution } from 'vs/workbench/common/contributions'; import { CONTENT_CHANGE_EVENT_BUFFER_DELAY } from 'vs/platform/files/common/files'; -import { IAutoSaveConfigurationService, IAutoSaveConfiguration } from 'vs/workbench/services/autoSaveConfiguration/common/autoSaveConfigurationService'; +import { IFilesConfigurationService, IAutoSaveConfiguration } from 'vs/workbench/services/filesConfiguration/common/filesConfigurationService'; const AUTO_SAVE_AFTER_DELAY_DISABLED_TIME = CONTENT_CHANGE_EVENT_BUFFER_DELAY + 500; @@ -22,7 +22,7 @@ export class BackupModelTracker extends Disposable implements IWorkbenchContribu @IBackupFileService private readonly backupFileService: IBackupFileService, @ITextFileService private readonly textFileService: ITextFileService, @IUntitledTextEditorService private readonly untitledTextEditorService: IUntitledTextEditorService, - @IAutoSaveConfigurationService private readonly autoSaveConfigurationService: IAutoSaveConfigurationService + @IFilesConfigurationService private readonly filesConfigurationService: IFilesConfigurationService ) { super(); @@ -41,7 +41,7 @@ export class BackupModelTracker extends Disposable implements IWorkbenchContribu this._register(this.untitledTextEditorService.onDidDisposeModel(e => this.discardBackup(e))); // Listen to auto save config changes - this._register(this.autoSaveConfigurationService.onAutoSaveConfigurationChange(c => this.onAutoSaveConfigurationChange(c))); + this._register(this.filesConfigurationService.onAutoSaveConfigurationChange(c => this.onAutoSaveConfigurationChange(c))); } private onAutoSaveConfigurationChange(configuration: IAutoSaveConfiguration): void { diff --git a/src/vs/workbench/contrib/files/browser/editors/textFileEditor.ts b/src/vs/workbench/contrib/files/browser/editors/textFileEditor.ts index b683a64070aeb..cfb489c9d7c45 100644 --- a/src/vs/workbench/contrib/files/browser/editors/textFileEditor.ts +++ b/src/vs/workbench/contrib/files/browser/editors/textFileEditor.ts @@ -32,7 +32,7 @@ import { IEditorGroupView } from 'vs/workbench/browser/parts/editor/editor'; import { createErrorWithActions } from 'vs/base/common/errorsWithActions'; import { MutableDisposable } from 'vs/base/common/lifecycle'; import { EditorActivation, IEditorOptions } from 'vs/platform/editor/common/editor'; -import { IAutoSaveConfigurationService } from 'vs/workbench/services/autoSaveConfiguration/common/autoSaveConfigurationService'; +import { IFilesConfigurationService } from 'vs/workbench/services/filesConfiguration/common/filesConfigurationService'; /** * An implementation of editor for file system resources. @@ -58,9 +58,9 @@ export class TextFileEditor extends BaseTextEditor { @ITextFileService textFileService: ITextFileService, @IHostService hostService: IHostService, @IExplorerService private readonly explorerService: IExplorerService, - @IAutoSaveConfigurationService autoSaveConfigurationService: IAutoSaveConfigurationService + @IFilesConfigurationService filesConfigurationService: IFilesConfigurationService ) { - super(TextFileEditor.ID, telemetryService, instantiationService, storageService, configurationService, themeService, textFileService, editorService, editorGroupService, hostService, autoSaveConfigurationService); + super(TextFileEditor.ID, telemetryService, instantiationService, storageService, configurationService, themeService, textFileService, editorService, editorGroupService, hostService, filesConfigurationService); this.updateRestoreViewStateConfiguration(); diff --git a/src/vs/workbench/contrib/files/browser/fileActions.contribution.ts b/src/vs/workbench/contrib/files/browser/fileActions.contribution.ts index 1fb26f4e7639d..54c80ed215879 100644 --- a/src/vs/workbench/contrib/files/browser/fileActions.contribution.ts +++ b/src/vs/workbench/contrib/files/browser/fileActions.contribution.ts @@ -18,7 +18,7 @@ import { isMacintosh } from 'vs/base/common/platform'; import { FilesExplorerFocusCondition, ExplorerRootContext, ExplorerFolderContext, ExplorerResourceNotReadonlyContext, ExplorerResourceCut, IExplorerService, ExplorerResourceMoveableToTrash, ExplorerViewletVisibleContext } from 'vs/workbench/contrib/files/common/files'; import { ADD_ROOT_FOLDER_COMMAND_ID, ADD_ROOT_FOLDER_LABEL } from 'vs/workbench/browser/actions/workspaceCommands'; import { CLOSE_SAVED_EDITORS_COMMAND_ID, CLOSE_EDITORS_IN_GROUP_COMMAND_ID, CLOSE_EDITOR_COMMAND_ID, CLOSE_OTHER_EDITORS_IN_GROUP_COMMAND_ID } from 'vs/workbench/browser/parts/editor/editorCommands'; -import { AutoSaveContext } from 'vs/workbench/services/autoSaveConfiguration/common/autoSaveConfigurationService'; +import { AutoSaveContext } from 'vs/workbench/services/filesConfiguration/common/filesConfigurationService'; import { ResourceContextKey } from 'vs/workbench/common/resources'; import { WorkbenchListDoubleSelection } from 'vs/platform/list/browser/listService'; import { URI } from 'vs/base/common/uri'; diff --git a/src/vs/workbench/contrib/files/browser/fileActions.ts b/src/vs/workbench/contrib/files/browser/fileActions.ts index ad24df30607bb..6386b86db0ccc 100644 --- a/src/vs/workbench/contrib/files/browser/fileActions.ts +++ b/src/vs/workbench/contrib/files/browser/fileActions.ts @@ -45,7 +45,7 @@ import { ExplorerItem, NewExplorerItem } from 'vs/workbench/contrib/files/common import { onUnexpectedError, getErrorMessage } from 'vs/base/common/errors'; import { asDomUri, triggerDownload } from 'vs/base/browser/dom'; import { mnemonicButtonLabel } from 'vs/base/common/labels'; -import { IAutoSaveConfigurationService } from 'vs/workbench/services/autoSaveConfiguration/common/autoSaveConfigurationService'; +import { IFilesConfigurationService } from 'vs/workbench/services/filesConfiguration/common/filesConfigurationService'; import { IWorkingCopyService } from 'vs/workbench/services/workingCopy/common/workingCopyService'; export const NEW_FILE_COMMAND_ID = 'explorer.newFile'; @@ -496,13 +496,13 @@ export class ToggleAutoSaveAction extends Action { constructor( id: string, label: string, - @IAutoSaveConfigurationService private readonly autoSaveConfigurationService: IAutoSaveConfigurationService + @IFilesConfigurationService private readonly filesConfigurationService: IFilesConfigurationService ) { super(id, label); } run(): Promise { - return this.autoSaveConfigurationService.toggleAutoSave(); + return this.filesConfigurationService.toggleAutoSave(); } } diff --git a/src/vs/workbench/contrib/files/common/dirtyFilesIndicator.ts b/src/vs/workbench/contrib/files/common/dirtyFilesIndicator.ts index edb4a75e829c6..cbbc586cbebd5 100644 --- a/src/vs/workbench/contrib/files/common/dirtyFilesIndicator.ts +++ b/src/vs/workbench/contrib/files/common/dirtyFilesIndicator.ts @@ -10,7 +10,7 @@ import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle'; import { Disposable, MutableDisposable } from 'vs/base/common/lifecycle'; import { IActivityService, NumberBadge } from 'vs/workbench/services/activity/common/activity'; import { IWorkingCopyService, IWorkingCopy, WorkingCopyCapabilities } from 'vs/workbench/services/workingCopy/common/workingCopyService'; -import { IAutoSaveConfigurationService, AutoSaveMode } from 'vs/workbench/services/autoSaveConfiguration/common/autoSaveConfigurationService'; +import { IFilesConfigurationService, AutoSaveMode } from 'vs/workbench/services/filesConfiguration/common/filesConfigurationService'; export class DirtyFilesIndicator extends Disposable implements IWorkbenchContribution { private readonly badgeHandle = this._register(new MutableDisposable()); @@ -25,7 +25,7 @@ export class DirtyFilesIndicator extends Disposable implements IWorkbenchContrib @ILifecycleService private readonly lifecycleService: ILifecycleService, @IActivityService private readonly activityService: IActivityService, @IWorkingCopyService private readonly workingCopyService: IWorkingCopyService, - @IAutoSaveConfigurationService private readonly autoSaveConfigurationService: IAutoSaveConfigurationService + @IFilesConfigurationService private readonly filesConfigurationService: IFilesConfigurationService ) { super(); @@ -43,7 +43,7 @@ export class DirtyFilesIndicator extends Disposable implements IWorkbenchContrib private onWorkingCopyDidChangeDirty(copy: IWorkingCopy): void { const gotDirty = copy.isDirty(); - if (gotDirty && !!(copy.capabilities & WorkingCopyCapabilities.AutoSave) && this.autoSaveConfigurationService.getAutoSaveMode() === AutoSaveMode.AFTER_SHORT_DELAY) { + if (gotDirty && !!(copy.capabilities & WorkingCopyCapabilities.AutoSave) && this.filesConfigurationService.getAutoSaveMode() === AutoSaveMode.AFTER_SHORT_DELAY) { return; // do not indicate dirty of working copies that are auto saved after short delay } diff --git a/src/vs/workbench/contrib/files/common/editors/fileEditorInput.ts b/src/vs/workbench/contrib/files/common/editors/fileEditorInput.ts index d4efe1d008479..2695c40d587c9 100644 --- a/src/vs/workbench/contrib/files/common/editors/fileEditorInput.ts +++ b/src/vs/workbench/contrib/files/common/editors/fileEditorInput.ts @@ -17,7 +17,7 @@ import { IReference } from 'vs/base/common/lifecycle'; import { ITextModelService } from 'vs/editor/common/services/resolverService'; import { FILE_EDITOR_INPUT_ID, TEXT_FILE_EDITOR_ID, BINARY_FILE_EDITOR_ID } from 'vs/workbench/contrib/files/common/files'; import { ILabelService } from 'vs/platform/label/common/label'; -import { IAutoSaveConfigurationService, AutoSaveMode } from 'vs/workbench/services/autoSaveConfiguration/common/autoSaveConfigurationService'; +import { IFilesConfigurationService, AutoSaveMode } from 'vs/workbench/services/filesConfiguration/common/filesConfigurationService'; const enum ForceOpenAs { None, @@ -51,7 +51,7 @@ export class FileEditorInput extends EditorInput implements IFileEditorInput { @ITextModelService private readonly textModelResolverService: ITextModelService, @ILabelService private readonly labelService: ILabelService, @IFileService private readonly fileService: IFileService, - @IAutoSaveConfigurationService private readonly autoSaveConfigurationService: IAutoSaveConfigurationService + @IFilesConfigurationService private readonly filesConfigurationService: IFilesConfigurationService ) { super(); @@ -236,7 +236,7 @@ export class FileEditorInput extends EditorInput implements IFileEditorInput { return true; // always indicate dirty state if we are in conflict or error state } - if (this.autoSaveConfigurationService.getAutoSaveMode() === AutoSaveMode.AFTER_SHORT_DELAY) { + if (this.filesConfigurationService.getAutoSaveMode() === AutoSaveMode.AFTER_SHORT_DELAY) { return false; // fast auto save enabled so we do not declare dirty } diff --git a/src/vs/workbench/contrib/files/electron-browser/textFileEditor.ts b/src/vs/workbench/contrib/files/electron-browser/textFileEditor.ts index d2b5d4aa360c9..2afebd9cbe20e 100644 --- a/src/vs/workbench/contrib/files/electron-browser/textFileEditor.ts +++ b/src/vs/workbench/contrib/files/electron-browser/textFileEditor.ts @@ -25,7 +25,7 @@ import { IHostService } from 'vs/workbench/services/host/browser/host'; import { IPreferencesService } from 'vs/workbench/services/preferences/common/preferences'; import { IExplorerService } from 'vs/workbench/contrib/files/common/files'; import { IElectronService } from 'vs/platform/electron/node/electron'; -import { IAutoSaveConfigurationService } from 'vs/workbench/services/autoSaveConfiguration/common/autoSaveConfigurationService'; +import { IFilesConfigurationService } from 'vs/workbench/services/filesConfiguration/common/filesConfigurationService'; /** * An implementation of editor for file system resources. @@ -48,9 +48,9 @@ export class NativeTextFileEditor extends TextFileEditor { @IPreferencesService private readonly preferencesService: IPreferencesService, @IHostService hostService: IHostService, @IExplorerService explorerService: IExplorerService, - @IAutoSaveConfigurationService autoSaveConfigurationService: IAutoSaveConfigurationService + @IFilesConfigurationService filesConfigurationService: IFilesConfigurationService ) { - super(telemetryService, fileService, viewletService, instantiationService, contextService, storageService, configurationService, editorService, themeService, editorGroupService, textFileService, hostService, explorerService, autoSaveConfigurationService); + super(telemetryService, fileService, viewletService, instantiationService, contextService, storageService, configurationService, editorService, themeService, editorGroupService, textFileService, hostService, explorerService, filesConfigurationService); } protected handleSetInputError(error: Error, input: FileEditorInput, options: EditorOptions | undefined): void { diff --git a/src/vs/workbench/contrib/output/browser/logViewer.ts b/src/vs/workbench/contrib/output/browser/logViewer.ts index 31ee5aac46210..4f192347a5d51 100644 --- a/src/vs/workbench/contrib/output/browser/logViewer.ts +++ b/src/vs/workbench/contrib/output/browser/logViewer.ts @@ -20,7 +20,7 @@ import { LOG_SCHEME, IFileOutputChannelDescriptor } from 'vs/workbench/contrib/o import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IHostService } from 'vs/workbench/services/host/browser/host'; -import { IAutoSaveConfigurationService } from 'vs/workbench/services/autoSaveConfiguration/common/autoSaveConfigurationService'; +import { IFilesConfigurationService } from 'vs/workbench/services/filesConfiguration/common/filesConfigurationService'; export class LogViewerInput extends ResourceEditorInput { @@ -56,9 +56,9 @@ export class LogViewer extends AbstractTextResourceEditor { @ITextFileService textFileService: ITextFileService, @IEditorService editorService: IEditorService, @IHostService hostService: IHostService, - @IAutoSaveConfigurationService autoSaveConfigurationService: IAutoSaveConfigurationService + @IFilesConfigurationService filesConfigurationService: IFilesConfigurationService ) { - super(LogViewer.LOG_VIEWER_EDITOR_ID, telemetryService, instantiationService, storageService, textResourceConfigurationService, themeService, editorGroupService, textFileService, editorService, hostService, autoSaveConfigurationService); + super(LogViewer.LOG_VIEWER_EDITOR_ID, telemetryService, instantiationService, storageService, textResourceConfigurationService, themeService, editorGroupService, textFileService, editorService, hostService, filesConfigurationService); } protected getConfigurationOverrides(): IEditorOptions { diff --git a/src/vs/workbench/contrib/output/browser/outputPanel.ts b/src/vs/workbench/contrib/output/browser/outputPanel.ts index c2e14e0763a25..9ecc2c1d47c56 100644 --- a/src/vs/workbench/contrib/output/browser/outputPanel.ts +++ b/src/vs/workbench/contrib/output/browser/outputPanel.ts @@ -26,7 +26,7 @@ import { CancellationToken } from 'vs/base/common/cancellation'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IHostService } from 'vs/workbench/services/host/browser/host'; import { CursorChangeReason } from 'vs/editor/common/controller/cursorEvents'; -import { IAutoSaveConfigurationService } from 'vs/workbench/services/autoSaveConfiguration/common/autoSaveConfigurationService'; +import { IFilesConfigurationService } from 'vs/workbench/services/filesConfiguration/common/filesConfigurationService'; export class OutputPanel extends AbstractTextResourceEditor { private actions: IAction[] | undefined; @@ -46,9 +46,9 @@ export class OutputPanel extends AbstractTextResourceEditor { @ITextFileService textFileService: ITextFileService, @IEditorService editorService: IEditorService, @IHostService hostService: IHostService, - @IAutoSaveConfigurationService autoSaveConfigurationService: IAutoSaveConfigurationService + @IFilesConfigurationService filesConfigurationService: IFilesConfigurationService ) { - super(OUTPUT_PANEL_ID, telemetryService, instantiationService, storageService, textResourceConfigurationService, themeService, editorGroupService, textFileService, editorService, hostService, autoSaveConfigurationService); + super(OUTPUT_PANEL_ID, telemetryService, instantiationService, storageService, textResourceConfigurationService, themeService, editorGroupService, textFileService, editorService, hostService, filesConfigurationService); this.scopedInstantiationService = instantiationService; } diff --git a/src/vs/workbench/contrib/preferences/browser/preferencesEditor.ts b/src/vs/workbench/contrib/preferences/browser/preferencesEditor.ts index 8c5d0468c3e15..144a775d045fc 100644 --- a/src/vs/workbench/contrib/preferences/browser/preferencesEditor.ts +++ b/src/vs/workbench/contrib/preferences/browser/preferencesEditor.ts @@ -55,7 +55,7 @@ import { DefaultSettingsEditorModel, SettingsEditorModel } from 'vs/workbench/se import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; import { IHostService } from 'vs/workbench/services/host/browser/host'; import { withNullAsUndefined, withUndefinedAsNull, assertIsDefined } from 'vs/base/common/types'; -import { IAutoSaveConfigurationService } from 'vs/workbench/services/autoSaveConfiguration/common/autoSaveConfigurationService'; +import { IFilesConfigurationService } from 'vs/workbench/services/filesConfiguration/common/filesConfigurationService'; export class PreferencesEditor extends BaseEditor { @@ -983,9 +983,9 @@ export class DefaultPreferencesEditor extends BaseTextEditor { @IEditorGroupsService editorGroupService: IEditorGroupsService, @IEditorService editorService: IEditorService, @IHostService hostService: IHostService, - @IAutoSaveConfigurationService autoSaveConfigurationService: IAutoSaveConfigurationService + @IFilesConfigurationService filesConfigurationService: IFilesConfigurationService ) { - super(DefaultPreferencesEditor.ID, telemetryService, instantiationService, storageService, configurationService, themeService, textFileService, editorService, editorGroupService, hostService, autoSaveConfigurationService); + super(DefaultPreferencesEditor.ID, telemetryService, instantiationService, storageService, configurationService, themeService, textFileService, editorService, editorGroupService, hostService, filesConfigurationService); } private static _getContributions(): IEditorContributionDescription[] { diff --git a/src/vs/workbench/services/autoSaveConfiguration/common/autoSaveConfigurationService.ts b/src/vs/workbench/services/filesConfiguration/common/filesConfigurationService.ts similarity index 69% rename from src/vs/workbench/services/autoSaveConfiguration/common/autoSaveConfigurationService.ts rename to src/vs/workbench/services/filesConfiguration/common/filesConfigurationService.ts index 9e7ac720a44bc..a982e0161fc3d 100644 --- a/src/vs/workbench/services/autoSaveConfiguration/common/autoSaveConfigurationService.ts +++ b/src/vs/workbench/services/filesConfiguration/common/filesConfigurationService.ts @@ -9,8 +9,10 @@ import { Event, Emitter } from 'vs/base/common/event'; import { Disposable } from 'vs/base/common/lifecycle'; import { RawContextKey, IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { IConfigurationService, ConfigurationTarget } from 'vs/platform/configuration/common/configuration'; -import { IFilesConfiguration, AutoSaveConfiguration } from 'vs/platform/files/common/files'; +import { IFilesConfiguration, AutoSaveConfiguration, HotExitConfiguration } from 'vs/platform/files/common/files'; import { isUndefinedOrNull } from 'vs/base/common/types'; +import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; +import { equals } from 'vs/base/common/objects'; export const AutoSaveContext = new RawContextKey('config.files.autoSave', undefined); @@ -28,12 +30,14 @@ export const enum AutoSaveMode { ON_WINDOW_CHANGE } -export const IAutoSaveConfigurationService = createDecorator('autoSaveConfigurationService'); +export const IFilesConfigurationService = createDecorator('filesConfigurationService'); -export interface IAutoSaveConfigurationService { +export interface IFilesConfigurationService { _serviceBrand: undefined; + //#region Auto Save + readonly onAutoSaveConfigurationChange: Event; getAutoSaveMode(): AutoSaveMode; @@ -41,30 +45,50 @@ export interface IAutoSaveConfigurationService { getAutoSaveConfiguration(): IAutoSaveConfiguration; toggleAutoSave(): Promise; + + //#endregion + + readonly onFilesAssociationChange: Event; + + readonly isHotExitEnabled: boolean; + + readonly hotExitConfiguration: string | undefined; } -export class AutoSaveConfigurationService extends Disposable implements IAutoSaveConfigurationService { +export class FilesConfigurationService extends Disposable implements IFilesConfigurationService { _serviceBrand: undefined; private readonly _onAutoSaveConfigurationChange = this._register(new Emitter()); readonly onAutoSaveConfigurationChange = this._onAutoSaveConfigurationChange.event; + private readonly _onFilesAssociationChange = this._register(new Emitter()); + readonly onFilesAssociationChange = this._onFilesAssociationChange.event; + private configuredAutoSaveDelay?: number; private configuredAutoSaveOnFocusChange: boolean | undefined; private configuredAutoSaveOnWindowChange: boolean | undefined; private autoSaveContext: IContextKey; + private currentFilesAssociationConfig: { [key: string]: string; }; + + private currentHotExitConfig: string; + constructor( @IContextKeyService contextKeyService: IContextKeyService, - @IConfigurationService private readonly configurationService: IConfigurationService + @IConfigurationService private readonly configurationService: IConfigurationService, + @IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService ) { super(); this.autoSaveContext = AutoSaveContext.bindTo(contextKeyService); const configuration = configurationService.getValue(); + + this.currentFilesAssociationConfig = configuration?.files?.associations; + this.currentHotExitConfig = configuration?.files?.hotExit || HotExitConfiguration.ON_EXIT; + this.onFilesConfigurationChange(configuration); this.registerListeners(); @@ -80,7 +104,9 @@ export class AutoSaveConfigurationService extends Disposable implements IAutoSav })); } - private onFilesConfigurationChange(configuration: IFilesConfiguration): void { + protected onFilesConfigurationChange(configuration: IFilesConfiguration): void { + + // Auto Save const autoSaveMode = configuration?.files?.autoSave || AutoSaveConfiguration.OFF; this.autoSaveContext.set(autoSaveMode); switch (autoSaveMode) { @@ -111,6 +137,21 @@ export class AutoSaveConfigurationService extends Disposable implements IAutoSav // Emit as event this._onAutoSaveConfigurationChange.fire(this.getAutoSaveConfiguration()); + + // Check for change in files associations + const filesAssociation = configuration?.files?.associations; + if (!equals(this.currentFilesAssociationConfig, filesAssociation)) { + this.currentFilesAssociationConfig = filesAssociation; + this._onFilesAssociationChange.fire(); + } + + // Hot exit + const hotExitMode = configuration?.files?.hotExit; + if (hotExitMode === HotExitConfiguration.OFF || hotExitMode === HotExitConfiguration.ON_EXIT_AND_WINDOW_CLOSE) { + this.currentHotExitConfig = hotExitMode; + } else { + this.currentHotExitConfig = HotExitConfiguration.ON_EXIT; + } } getAutoSaveMode(): AutoSaveMode { @@ -153,6 +194,14 @@ export class AutoSaveConfigurationService extends Disposable implements IAutoSav return this.configurationService.updateValue('files.autoSave', newAutoSaveValue, ConfigurationTarget.USER); } + + get isHotExitEnabled(): boolean { + return !this.environmentService.isExtensionDevelopment && this.currentHotExitConfig !== HotExitConfiguration.OFF; + } + + get hotExitConfiguration(): string { + return this.currentHotExitConfig; + } } -registerSingleton(IAutoSaveConfigurationService, AutoSaveConfigurationService); +registerSingleton(IFilesConfigurationService, FilesConfigurationService); diff --git a/src/vs/workbench/services/textfile/browser/browserTextFileService.ts b/src/vs/workbench/services/textfile/browser/browserTextFileService.ts index 39e02d196e31e..858552d31c3b9 100644 --- a/src/vs/workbench/services/textfile/browser/browserTextFileService.ts +++ b/src/vs/workbench/services/textfile/browser/browserTextFileService.ts @@ -35,7 +35,7 @@ export class BrowserTextFileService extends AbstractTextFileService { return false; // no dirty: no veto } - if (!this.isHotExitEnabled) { + if (!this.filesConfigurationService.isHotExitEnabled) { return true; // dirty without backup: veto } diff --git a/src/vs/workbench/services/textfile/browser/textFileService.ts b/src/vs/workbench/services/textfile/browser/textFileService.ts index ea66d626d2e31..3534496d5e622 100644 --- a/src/vs/workbench/services/textfile/browser/textFileService.ts +++ b/src/vs/workbench/services/textfile/browser/textFileService.ts @@ -5,7 +5,6 @@ import * as nls from 'vs/nls'; import { URI } from 'vs/base/common/uri'; -import * as objects from 'vs/base/common/objects'; import { Emitter, AsyncEmitter } from 'vs/base/common/event'; import * as platform from 'vs/base/common/platform'; import { IBackupFileService } from 'vs/workbench/services/backup/common/backup'; @@ -13,8 +12,7 @@ import { IResult, ITextFileOperationResult, ITextFileService, ITextFileStreamCon import { ConfirmResult, IRevertOptions } from 'vs/workbench/common/editor'; import { ILifecycleService, ShutdownReason, LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle'; import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; -import { IFileService, IFilesConfiguration, FileOperationError, FileOperationResult, HotExitConfiguration, IFileStatWithMetadata, ICreateFileOptions, FileOperation } from 'vs/platform/files/common/files'; -import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { IFileService, FileOperationError, FileOperationResult, HotExitConfiguration, IFileStatWithMetadata, ICreateFileOptions, FileOperation } from 'vs/platform/files/common/files'; import { Disposable } from 'vs/base/common/lifecycle'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; import { IUntitledTextEditorService } from 'vs/workbench/services/untitled/common/untitledTextEditorService'; @@ -37,7 +35,7 @@ import { VSBuffer } from 'vs/base/common/buffer'; import { ITextSnapshot } from 'vs/editor/common/model'; import { ITextResourceConfigurationService } from 'vs/editor/common/services/resourceConfiguration'; import { PLAINTEXT_MODE_ID } from 'vs/editor/common/modes/modesRegistry'; -import { IAutoSaveConfigurationService, AutoSaveMode } from 'vs/workbench/services/autoSaveConfiguration/common/autoSaveConfigurationService'; +import { IFilesConfigurationService, AutoSaveMode } from 'vs/workbench/services/filesConfiguration/common/filesConfigurationService'; /** * The workbench file service implementation implements the raw file service spec and adds additional methods on top. @@ -48,9 +46,6 @@ export abstract class AbstractTextFileService extends Disposable implements ITex //#region events - private readonly _onFilesAssociationChange = this._register(new Emitter()); - readonly onFilesAssociationChange = this._onFilesAssociationChange.event; - private _onWillRunOperation = this._register(new AsyncEmitter()); readonly onWillRunOperation = this._onWillRunOperation.event; @@ -64,17 +59,12 @@ export abstract class AbstractTextFileService extends Disposable implements ITex abstract get encoding(): IResourceEncodings; - private currentFilesAssociationConfig: { [key: string]: string; }; - - private configuredHotExit: string | undefined; - constructor( @IWorkspaceContextService private readonly contextService: IWorkspaceContextService, @IFileService protected readonly fileService: IFileService, @IUntitledTextEditorService protected readonly untitledTextEditorService: IUntitledTextEditorService, @ILifecycleService private readonly lifecycleService: ILifecycleService, @IInstantiationService protected readonly instantiationService: IInstantiationService, - @IConfigurationService private readonly configurationService: IConfigurationService, @IModeService private readonly modeService: IModeService, @IModelService private readonly modelService: IModelService, @IWorkbenchEnvironmentService protected readonly environmentService: IWorkbenchEnvironmentService, @@ -85,15 +75,12 @@ export abstract class AbstractTextFileService extends Disposable implements ITex @IFileDialogService private readonly fileDialogService: IFileDialogService, @IEditorService private readonly editorService: IEditorService, @ITextResourceConfigurationService protected readonly textResourceConfigurationService: ITextResourceConfigurationService, - @IAutoSaveConfigurationService private readonly autoSaveConfigurationService: IAutoSaveConfigurationService + @IFilesConfigurationService protected readonly filesConfigurationService: IFilesConfigurationService ) { super(); this._models = this._register(instantiationService.createInstance(TextFileEditorModelManager)); - const configuration = configurationService.getValue(); - this.currentFilesAssociationConfig = configuration?.files?.associations; - this.registerListeners(); } @@ -105,21 +92,14 @@ export abstract class AbstractTextFileService extends Disposable implements ITex this.lifecycleService.onBeforeShutdown(event => event.veto(this.onBeforeShutdown(event.reason))); this.lifecycleService.onShutdown(this.dispose, this); - // Files configuration changes - this._register(this.configurationService.onDidChangeConfiguration(e => { - if (e.affectsConfiguration('files')) { - this.onFilesConfigurationChange(this.configurationService.getValue()); - } - })); - // Auto save changes - this._register(this.autoSaveConfigurationService.onAutoSaveConfigurationChange(() => this.onAutoSaveConfigurationChange())); + this._register(this.filesConfigurationService.onAutoSaveConfigurationChange(() => this.onAutoSaveConfigurationChange())); } private onAutoSaveConfigurationChange(): void { // save all dirty when enabling auto save - if (this.autoSaveConfigurationService.getAutoSaveMode() !== AutoSaveMode.OFF) { + if (this.filesConfigurationService.getAutoSaveMode() !== AutoSaveMode.OFF) { this.saveAll(); } } @@ -132,7 +112,7 @@ export abstract class AbstractTextFileService extends Disposable implements ITex // If auto save is enabled, save all files and then check again for dirty files // We DO NOT run any save participant if we are in the shutdown phase for performance reasons - if (this.autoSaveConfigurationService.getAutoSaveMode() !== AutoSaveMode.OFF) { + if (this.filesConfigurationService.getAutoSaveMode() !== AutoSaveMode.OFF) { return this.saveAll(false /* files only */, { skipSaveParticipants: true }).then(() => { // If we still have dirty files, we either have untitled ones or files that cannot be saved @@ -156,7 +136,7 @@ export abstract class AbstractTextFileService extends Disposable implements ITex private handleDirtyBeforeShutdown(dirty: URI[], reason: ShutdownReason): boolean | Promise { // If hot exit is enabled, backup dirty files and allow to exit without confirmation - if (this.isHotExitEnabled) { + if (this.filesConfigurationService.isHotExitEnabled) { return this.backupBeforeShutdown(dirty, reason).then(didBackup => { if (didBackup) { return this.noVeto({ cleanUpBackups: false }); // no veto and no backup cleanup (since backup was successful) @@ -184,7 +164,7 @@ export abstract class AbstractTextFileService extends Disposable implements ITex let doBackup: boolean | undefined; switch (reason) { case ShutdownReason.CLOSE: - if (this.contextService.getWorkbenchState() !== WorkbenchState.EMPTY && this.configuredHotExit === HotExitConfiguration.ON_EXIT_AND_WINDOW_CLOSE) { + if (this.contextService.getWorkbenchState() !== WorkbenchState.EMPTY && this.filesConfigurationService.hotExitConfiguration === HotExitConfiguration.ON_EXIT_AND_WINDOW_CLOSE) { doBackup = true; // backup if a folder is open and onExitAndWindowClose is configured } else if (await this.getWindowCount() > 1 || platform.isMacintosh) { doBackup = false; // do not backup if a window is closed that does not cause quitting of the application @@ -202,7 +182,7 @@ export abstract class AbstractTextFileService extends Disposable implements ITex break; case ShutdownReason.LOAD: - if (this.contextService.getWorkbenchState() !== WorkbenchState.EMPTY && this.configuredHotExit === HotExitConfiguration.ON_EXIT_AND_WINDOW_CLOSE) { + if (this.contextService.getWorkbenchState() !== WorkbenchState.EMPTY && this.filesConfigurationService.hotExitConfiguration === HotExitConfiguration.ON_EXIT_AND_WINDOW_CLOSE) { doBackup = true; // backup if a folder is open and onExitAndWindowClose is configured } else { doBackup = false; // do not backup because we are switching contexts @@ -303,24 +283,6 @@ export abstract class AbstractTextFileService extends Disposable implements ITex await this.backupFileService.discardAllWorkspaceBackups(); } - protected onFilesConfigurationChange(configuration: IFilesConfiguration): void { - - // Check for change in files associations - const filesAssociation = configuration?.files?.associations; - if (!objects.equals(this.currentFilesAssociationConfig, filesAssociation)) { - this.currentFilesAssociationConfig = filesAssociation; - this._onFilesAssociationChange.fire(); - } - - // Hot exit - const hotExitMode = configuration?.files?.hotExit; - if (hotExitMode === HotExitConfiguration.OFF || hotExitMode === HotExitConfiguration.ON_EXIT_AND_WINDOW_CLOSE) { - this.configuredHotExit = hotExitMode; - } else { - this.configuredHotExit = HotExitConfiguration.ON_EXIT; - } - } - //#endregion //#region primitives (read, create, move, delete, update) @@ -969,14 +931,6 @@ export abstract class AbstractTextFileService extends Disposable implements ITex //#endregion - //#region config - - get isHotExitEnabled(): boolean { - return !this.environmentService.isExtensionDevelopment && this.configuredHotExit !== HotExitConfiguration.OFF; - } - - //#endregion - dispose(): void { // Clear all caches diff --git a/src/vs/workbench/services/textfile/common/textFileEditorModel.ts b/src/vs/workbench/services/textfile/common/textFileEditorModel.ts index c50d7ea04042e..7dba20135d723 100644 --- a/src/vs/workbench/services/textfile/common/textFileEditorModel.ts +++ b/src/vs/workbench/services/textfile/common/textFileEditorModel.ts @@ -30,7 +30,7 @@ import { isEqual, isEqualOrParent, extname, basename, joinPath } from 'vs/base/c import { onUnexpectedError } from 'vs/base/common/errors'; import { Schemas } from 'vs/base/common/network'; import { IWorkingCopyService, WorkingCopyCapabilities } from 'vs/workbench/services/workingCopy/common/workingCopyService'; -import { IAutoSaveConfigurationService, IAutoSaveConfiguration } from 'vs/workbench/services/autoSaveConfiguration/common/autoSaveConfigurationService'; +import { IFilesConfigurationService, IAutoSaveConfiguration } from 'vs/workbench/services/filesConfiguration/common/filesConfigurationService'; export interface IBackupMetaData { mtime: number; @@ -123,11 +123,11 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil @IWorkspaceContextService private readonly contextService: IWorkspaceContextService, @ILogService private readonly logService: ILogService, @IWorkingCopyService private readonly workingCopyService: IWorkingCopyService, - @IAutoSaveConfigurationService private readonly autoSaveConfigurationService: IAutoSaveConfigurationService + @IFilesConfigurationService private readonly filesConfigurationService: IFilesConfigurationService ) { super(modelService, modeService); - this.updateAutoSaveConfiguration(autoSaveConfigurationService.getAutoSaveConfiguration()); + this.updateAutoSaveConfiguration(filesConfigurationService.getAutoSaveConfiguration()); // Make known to working copy service this._register(this.workingCopyService.registerWorkingCopy(this)); @@ -137,8 +137,8 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil private registerListeners(): void { this._register(this.fileService.onFileChanges(e => this.onFileChanges(e))); - this._register(this.autoSaveConfigurationService.onAutoSaveConfigurationChange(config => this.updateAutoSaveConfiguration(config))); - this._register(this.textFileService.onFilesAssociationChange(e => this.onFilesAssociationChange())); + this._register(this.filesConfigurationService.onAutoSaveConfigurationChange(config => this.updateAutoSaveConfiguration(config))); + this._register(this.filesConfigurationService.onFilesAssociationChange(e => this.onFilesAssociationChange())); this._register(this.onDidStateChange(e => this.onStateChange(e))); } diff --git a/src/vs/workbench/services/textfile/common/textfiles.ts b/src/vs/workbench/services/textfile/common/textfiles.ts index 9341412702050..a77cb9386dbe4 100644 --- a/src/vs/workbench/services/textfile/common/textfiles.ts +++ b/src/vs/workbench/services/textfile/common/textfiles.ts @@ -22,10 +22,6 @@ export interface ITextFileService extends IDisposable { _serviceBrand: undefined; - readonly onFilesAssociationChange: Event; - - readonly isHotExitEnabled: boolean; - /** * An event that is fired before attempting a certain file operation. */ diff --git a/src/vs/workbench/services/textfile/electron-browser/nativeTextFileService.ts b/src/vs/workbench/services/textfile/electron-browser/nativeTextFileService.ts index 3a1487ec77965..7a37e7ca8abc1 100644 --- a/src/vs/workbench/services/textfile/electron-browser/nativeTextFileService.ts +++ b/src/vs/workbench/services/textfile/electron-browser/nativeTextFileService.ts @@ -31,7 +31,6 @@ import { IElectronService } from 'vs/platform/electron/node/electron'; import { IUntitledTextEditorService } from 'vs/workbench/services/untitled/common/untitledTextEditorService'; import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IModeService } from 'vs/editor/common/services/modeService'; import { IModelService } from 'vs/editor/common/services/modelService'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; @@ -42,7 +41,7 @@ import { IDialogService, IFileDialogService } from 'vs/platform/dialogs/common/d import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { ConfirmResult } from 'vs/workbench/common/editor'; import { assign } from 'vs/base/common/objects'; -import { IAutoSaveConfigurationService } from 'vs/workbench/services/autoSaveConfiguration/common/autoSaveConfigurationService'; +import { IFilesConfigurationService } from 'vs/workbench/services/filesConfiguration/common/filesConfigurationService'; export class NativeTextFileService extends AbstractTextFileService { @@ -52,7 +51,6 @@ export class NativeTextFileService extends AbstractTextFileService { @IUntitledTextEditorService untitledTextEditorService: IUntitledTextEditorService, @ILifecycleService lifecycleService: ILifecycleService, @IInstantiationService instantiationService: IInstantiationService, - @IConfigurationService configurationService: IConfigurationService, @IModeService modeService: IModeService, @IModelService modelService: IModelService, @IWorkbenchEnvironmentService environmentService: IWorkbenchEnvironmentService, @@ -65,9 +63,9 @@ export class NativeTextFileService extends AbstractTextFileService { @ITextResourceConfigurationService textResourceConfigurationService: ITextResourceConfigurationService, @IElectronService private readonly electronService: IElectronService, @IProductService private readonly productService: IProductService, - @IAutoSaveConfigurationService autoSaveConfigurationService: IAutoSaveConfigurationService + @IFilesConfigurationService filesConfigurationService: IFilesConfigurationService ) { - super(contextService, fileService, untitledTextEditorService, lifecycleService, instantiationService, configurationService, modeService, modelService, environmentService, notificationService, backupFileService, historyService, dialogService, fileDialogService, editorService, textResourceConfigurationService, autoSaveConfigurationService); + super(contextService, fileService, untitledTextEditorService, lifecycleService, instantiationService, modeService, modelService, environmentService, notificationService, backupFileService, historyService, dialogService, fileDialogService, editorService, textResourceConfigurationService, filesConfigurationService); } private _encoding: EncodingOracle | undefined; diff --git a/src/vs/workbench/services/textfile/test/textFileService.test.ts b/src/vs/workbench/services/textfile/test/textFileService.test.ts index fc486b3c0b7c8..152212b71a2bc 100644 --- a/src/vs/workbench/services/textfile/test/textFileService.test.ts +++ b/src/vs/workbench/services/textfile/test/textFileService.test.ts @@ -7,7 +7,7 @@ import * as sinon from 'sinon'; import * as platform from 'vs/base/common/platform'; import { URI } from 'vs/base/common/uri'; import { ILifecycleService, BeforeShutdownEvent, ShutdownReason } from 'vs/platform/lifecycle/common/lifecycle'; -import { workbenchInstantiationService, TestLifecycleService, TestTextFileService, TestContextService, TestFileService, TestElectronService } from 'vs/workbench/test/workbenchTestServices'; +import { workbenchInstantiationService, TestLifecycleService, TestTextFileService, TestContextService, TestFileService, TestElectronService, TestFilesConfigurationService } from 'vs/workbench/test/workbenchTestServices'; import { toResource } from 'vs/base/test/common/utils'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { TextFileEditorModel } from 'vs/workbench/services/textfile/common/textFileEditorModel'; @@ -21,11 +21,13 @@ import { IModelService } from 'vs/editor/common/services/modelService'; import { ModelServiceImpl } from 'vs/editor/common/services/modelServiceImpl'; import { Schemas } from 'vs/base/common/network'; import { IElectronService } from 'vs/platform/electron/node/electron'; +import { IFilesConfigurationService } from 'vs/workbench/services/filesConfiguration/common/filesConfigurationService'; class ServiceAccessor { constructor( @ILifecycleService public lifecycleService: TestLifecycleService, @ITextFileService public textFileService: TestTextFileService, + @IFilesConfigurationService public filesConfigurationService: TestFilesConfigurationService, @IUntitledTextEditorService public untitledTextEditorService: IUntitledTextEditorService, @IWorkspaceContextService public contextService: TestContextService, @IModelService public modelService: ModelServiceImpl, @@ -102,7 +104,7 @@ suite('Files - TextFileService', () => { const service = accessor.textFileService; service.setConfirmResult(ConfirmResult.DONT_SAVE); - service.onFilesConfigurationChange({ files: { hotExit: 'off' } }); + accessor.filesConfigurationService.onFilesConfigurationChange({ files: { hotExit: 'off' } }); await model.load(); model.textEditorModel!.setValue('foo'); @@ -128,7 +130,7 @@ suite('Files - TextFileService', () => { const service = accessor.textFileService; service.setConfirmResult(ConfirmResult.SAVE); - service.onFilesConfigurationChange({ files: { hotExit: 'off' } }); + accessor.filesConfigurationService.onFilesConfigurationChange({ files: { hotExit: 'off' } }); await model.load(); model.textEditorModel!.setValue('foo'); @@ -417,7 +419,7 @@ suite('Files - TextFileService', () => { const service = accessor.textFileService; // Set hot exit config - service.onFilesConfigurationChange({ files: { hotExit: setting } }); + accessor.filesConfigurationService.onFilesConfigurationChange({ files: { hotExit: setting } }); // Set empty workspace if required if (!workspace) { accessor.contextService.setWorkspace(new Workspace('empty:1508317022751')); diff --git a/src/vs/workbench/test/workbenchTestServices.ts b/src/vs/workbench/test/workbenchTestServices.ts index b1e238cb5d5f0..c150c035c6f84 100644 --- a/src/vs/workbench/test/workbenchTestServices.ts +++ b/src/vs/workbench/test/workbenchTestServices.ts @@ -93,7 +93,7 @@ import { IEmptyWindowBackupInfo } from 'vs/platform/backup/node/backup'; import { IDialogMainService } from 'vs/platform/dialogs/electron-main/dialogs'; import { find } from 'vs/base/common/arrays'; import { WorkingCopyService, IWorkingCopyService } from 'vs/workbench/services/workingCopy/common/workingCopyService'; -import { IAutoSaveConfigurationService, AutoSaveConfigurationService } from 'vs/workbench/services/autoSaveConfiguration/common/autoSaveConfigurationService'; +import { IFilesConfigurationService, FilesConfigurationService } from 'vs/workbench/services/filesConfiguration/common/filesConfigurationService'; export function createFileInput(instantiationService: IInstantiationService, resource: URI): FileEditorInput { return instantiationService.createInstance(FileEditorInput, resource, undefined, undefined); @@ -201,7 +201,6 @@ export class TestTextFileService extends NativeTextFileService { @IUntitledTextEditorService untitledTextEditorService: IUntitledTextEditorService, @ILifecycleService lifecycleService: ILifecycleService, @IInstantiationService instantiationService: IInstantiationService, - @IConfigurationService configurationService: IConfigurationService, @IModeService modeService: IModeService, @IModelService modelService: IModelService, @IWorkbenchEnvironmentService environmentService: IWorkbenchEnvironmentService, @@ -214,7 +213,7 @@ export class TestTextFileService extends NativeTextFileService { @ITextResourceConfigurationService textResourceConfigurationService: ITextResourceConfigurationService, @IElectronService electronService: IElectronService, @IProductService productService: IProductService, - @IAutoSaveConfigurationService autoSaveConfigurationService: IAutoSaveConfigurationService + @IFilesConfigurationService filesConfigurationService: IFilesConfigurationService ) { super( contextService, @@ -222,7 +221,6 @@ export class TestTextFileService extends NativeTextFileService { untitledTextEditorService, lifecycleService, instantiationService, - configurationService, modeService, modelService, environmentService, @@ -235,7 +233,7 @@ export class TestTextFileService extends NativeTextFileService { textResourceConfigurationService, electronService, productService, - autoSaveConfigurationService + filesConfigurationService ); } @@ -285,10 +283,6 @@ export class TestTextFileService extends NativeTextFileService { return Promise.resolve(true); } - public onFilesConfigurationChange(configuration: any): void { - super.onFilesConfigurationChange(configuration); - } - protected cleanupBackupsBeforeShutdown(): Promise { this.cleanupBackupsBeforeShutdownCalled = true; return Promise.resolve(); @@ -304,7 +298,7 @@ export function workbenchInstantiationService(): IInstantiationService { instantiationService.stub(IWorkspaceContextService, workspaceContextService); const configService = new TestConfigurationService(); instantiationService.stub(IConfigurationService, configService); - instantiationService.stub(IAutoSaveConfigurationService, new AutoSaveConfigurationService(contextKeyService, configService)); + instantiationService.stub(IFilesConfigurationService, new TestFilesConfigurationService(contextKeyService, configService, TestEnvironmentService)); instantiationService.stub(ITextResourceConfigurationService, new TestTextResourceConfigurationService(configService)); instantiationService.stub(IUntitledTextEditorService, instantiationService.createInstance(UntitledTextEditorService)); instantiationService.stub(IStorageService, new TestStorageService()); @@ -1471,3 +1465,10 @@ export class TestDialogMainService implements IDialogMainService { } export class TestWorkingCopyService extends WorkingCopyService { } + +export class TestFilesConfigurationService extends FilesConfigurationService { + + onFilesConfigurationChange(configuration: any): void { + super.onFilesConfigurationChange(configuration); + } +} diff --git a/src/vs/workbench/workbench.common.main.ts b/src/vs/workbench/workbench.common.main.ts index 3c0ed98e54e72..5e499d4aa4173 100644 --- a/src/vs/workbench/workbench.common.main.ts +++ b/src/vs/workbench/workbench.common.main.ts @@ -83,7 +83,7 @@ import 'vs/workbench/services/userDataSync/common/settingsMergeService'; import 'vs/workbench/services/path/common/remotePathService'; import 'vs/workbench/services/remote/common/remoteExplorerService'; import 'vs/workbench/services/workingCopy/common/workingCopyService'; -import 'vs/workbench/services/autoSaveConfiguration/common/autoSaveConfigurationService'; +import 'vs/workbench/services/filesConfiguration/common/filesConfigurationService'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { ExtensionGalleryService } from 'vs/platform/extensionManagement/common/extensionGalleryService'; From 3440bc01c8700aa146592874890fa23e1e54af64 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Wed, 13 Nov 2019 11:44:30 +0100 Subject: [PATCH 197/352] fixes #84658 --- .../contrib/files/browser/views/explorerViewer.ts | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/files/browser/views/explorerViewer.ts b/src/vs/workbench/contrib/files/browser/views/explorerViewer.ts index 2a1d6e7a9d676..1186a19c258ee 100644 --- a/src/vs/workbench/contrib/files/browser/views/explorerViewer.ts +++ b/src/vs/workbench/contrib/files/browser/views/explorerViewer.ts @@ -176,8 +176,19 @@ export class FilesRenderer implements ICompressibleTreeRenderer e.name).join('/'); + const editableData = this.explorerService.getEditableData(stat); + + // File Label + if (!editableData) { + templateData.label.element.style.display = 'flex'; + templateData.elementDisposable = this.renderStat(stat, label, node.filterData, templateData); + } - templateData.elementDisposable = this.renderStat(stat, label, node.filterData, templateData); + // Input Box + else { + templateData.label.element.style.display = 'none'; + templateData.elementDisposable = this.renderInputBox(templateData.container, stat, editableData); + } } private renderStat(stat: ExplorerItem, label: string, filterData: FuzzyScore | undefined, templateData: IFileTemplateData): IDisposable { From 65b57bcda2bf738841d3de058516649f6808cf61 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Wed, 13 Nov 2019 12:37:15 +0100 Subject: [PATCH 198/352] remove optional argument from iconlabel --- src/vs/base/browser/ui/iconLabel/iconLabel.ts | 2 +- src/vs/base/parts/quickopen/browser/quickOpenModel.ts | 2 +- src/vs/workbench/browser/labels.ts | 6 +++--- src/vs/workbench/browser/parts/editor/breadcrumbsControl.ts | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/vs/base/browser/ui/iconLabel/iconLabel.ts b/src/vs/base/browser/ui/iconLabel/iconLabel.ts index 69315ea919a24..3fded36de5683 100644 --- a/src/vs/base/browser/ui/iconLabel/iconLabel.ts +++ b/src/vs/base/browser/ui/iconLabel/iconLabel.ts @@ -116,7 +116,7 @@ export class IconLabel extends Disposable { return this.domNode.element; } - setLabel(label?: string, description?: string, options?: IIconLabelValueOptions): void { + setLabel(label: string, description?: string, options?: IIconLabelValueOptions): void { const classes = ['monaco-icon-label']; if (options) { if (options.extraClasses) { diff --git a/src/vs/base/parts/quickopen/browser/quickOpenModel.ts b/src/vs/base/parts/quickopen/browser/quickOpenModel.ts index 8bb7da3ff4f2f..b846129db466e 100644 --- a/src/vs/base/parts/quickopen/browser/quickOpenModel.ts +++ b/src/vs/base/parts/quickopen/browser/quickOpenModel.ts @@ -462,7 +462,7 @@ class Renderer implements IRenderer { options.title = entry.getTooltip(); options.descriptionTitle = entry.getDescriptionTooltip() || entry.getDescription(); // tooltip over description because it could overflow options.descriptionMatches = descriptionHighlights || []; - data.label.setLabel(types.withNullAsUndefined(entry.getLabel()), entry.getDescription(), options); + data.label.setLabel(entry.getLabel() || '', entry.getDescription(), options); // Meta data.detail.set(entry.getDetail(), detailHighlights); diff --git a/src/vs/workbench/browser/labels.ts b/src/vs/workbench/browser/labels.ts index ecb0b7fbf9a55..fa66a47103461 100644 --- a/src/vs/workbench/browser/labels.ts +++ b/src/vs/workbench/browser/labels.ts @@ -164,7 +164,7 @@ export class ResourceLabels extends Disposable { const label: IResourceLabel = { element: widget.element, onDidRender: widget.onDidRender, - setLabel: (label?: string, description?: string, options?: IIconLabelValueOptions) => widget.setLabel(label, description, options), + setLabel: (label: string, description?: string, options?: IIconLabelValueOptions) => widget.setLabel(label, description, options), setResource: (label: IResourceLabelProps, options?: IResourceLabelOptions) => widget.setResource(label, options), setEditor: (editor: IEditorInput, options?: IResourceLabelOptions) => widget.setEditor(editor, options), setFile: (resource: URI, options?: IFileLabelOptions) => widget.setFile(resource, options), @@ -404,7 +404,7 @@ class ResourceLabelWidget extends IconLabel { this.computedIconClasses = undefined; this.computedPathLabel = undefined; - this.setLabel(); + this.setLabel(''); } private render(clearIconCache: boolean): void { @@ -493,7 +493,7 @@ class ResourceLabelWidget extends IconLabel { } } - this.setLabel(label, this.label.description, iconLabelOptions); + this.setLabel(label || '', this.label.description, iconLabelOptions); this._onDidRender.fire(); } diff --git a/src/vs/workbench/browser/parts/editor/breadcrumbsControl.ts b/src/vs/workbench/browser/parts/editor/breadcrumbsControl.ts index 375f8a2274e94..7aab9754619dc 100644 --- a/src/vs/workbench/browser/parts/editor/breadcrumbsControl.ts +++ b/src/vs/workbench/browser/parts/editor/breadcrumbsControl.ts @@ -102,7 +102,7 @@ class Item extends BreadcrumbsItem { } else if (this.element instanceof OutlineGroup) { // provider let label = new IconLabel(container); - label.setLabel(this.element.provider.displayName); + label.setLabel(this.element.provider.displayName || ''); this._disposables.add(label); } else if (this.element instanceof OutlineElement) { From f654e24f03ea8f9421d5ffd9ed151977e51a119d Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Wed, 13 Nov 2019 13:04:03 +0100 Subject: [PATCH 199/352] proper sign in flow for settings sync --- .../userDataSync/common/userDataSync.ts | 8 +- .../browser/relauncher.contribution.ts | 7 - .../userDataSync/browser/userDataSync.ts | 129 +++++++++++------- 3 files changed, 77 insertions(+), 67 deletions(-) diff --git a/src/vs/platform/userDataSync/common/userDataSync.ts b/src/vs/platform/userDataSync/common/userDataSync.ts index 18377cfac58e0..7f8d907a42176 100644 --- a/src/vs/platform/userDataSync/common/userDataSync.ts +++ b/src/vs/platform/userDataSync/common/userDataSync.ts @@ -33,7 +33,7 @@ export function registerConfiguration(): IDisposable { 'configurationSync.enable': { type: 'boolean', description: localize('configurationSync.enable', "When enabled, synchronizes configuration that includes Settings and Extensions."), - default: true, + default: false, scope: ConfigurationScope.APPLICATION }, 'configurationSync.enableSettings': { @@ -63,12 +63,6 @@ export function registerConfiguration(): IDisposable { $ref: ignoredSettingsSchemaId, additionalProperties: true, uniqueItems: true - }, - 'configurationSync.enableAuth': { - 'type': 'boolean', - description: localize('configurationSync.enableAuth', "Enables authentication and requires VS Code restart when changed"), - 'default': false, - 'scope': ConfigurationScope.APPLICATION } } }); diff --git a/src/vs/workbench/contrib/relauncher/browser/relauncher.contribution.ts b/src/vs/workbench/contrib/relauncher/browser/relauncher.contribution.ts index dbdd3ef369c8a..d5447f83cfc49 100644 --- a/src/vs/workbench/contrib/relauncher/browser/relauncher.contribution.ts +++ b/src/vs/workbench/contrib/relauncher/browser/relauncher.contribution.ts @@ -39,7 +39,6 @@ export class SettingsChangeRelauncher extends Disposable implements IWorkbenchCo private enableCrashReporter: boolean | undefined; private treeHorizontalScrolling: boolean | undefined; private debugConsoleWordWrap: boolean | undefined; - private enableConfigSyncAuth: boolean | undefined; constructor( @IHostService private readonly hostService: IHostService, @@ -107,12 +106,6 @@ export class SettingsChangeRelauncher extends Disposable implements IWorkbenchCo } } - // Configuration Sync Auth - if (typeof config.configurationSync?.enableAuth === 'boolean' && config.configurationSync.enableAuth !== this.enableConfigSyncAuth) { - this.enableConfigSyncAuth = config.configurationSync.enableAuth; - changed = true; - } - // Notify only when changed and we are the focused window (avoids notification spam across windows) if (notify && changed) { this.doConfirm( diff --git a/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts b/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts index 17218a393304c..03dc1b2a2b9df 100644 --- a/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts +++ b/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts @@ -25,7 +25,7 @@ import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/ import { isEqual } from 'vs/base/common/resources'; import { IEditorInput } from 'vs/workbench/common/editor'; import { IAuthTokenService, AuthTokenStatus } from 'vs/platform/auth/common/auth'; -import { timeout } from 'vs/base/common/async'; +import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; const CONTEXT_AUTH_TOKEN_STATE = new RawContextKey('authTokenStatus', AuthTokenStatus.Inactive); const SYNC_PUSH_LIGHT_ICON_URI = URI.parse(registerAndGetAmdImageURL(`vs/workbench/contrib/userDataSync/browser/media/check-light.svg`)); @@ -33,6 +33,8 @@ const SYNC_PUSH_DARK_ICON_URI = URI.parse(registerAndGetAmdImageURL(`vs/workbenc export class UserDataSyncWorkbenchContribution extends Disposable implements IWorkbenchContribution { + private static readonly ENABLEMENT_SETTING = 'configurationSync.enable'; + private readonly syncStatusContext: IContextKey; private readonly authTokenContext: IContextKey; private readonly badgeDisposable = this._register(new MutableDisposable()); @@ -50,6 +52,7 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo @ITextFileService private readonly textFileService: ITextFileService, @IHistoryService private readonly historyService: IHistoryService, @IWorkbenchEnvironmentService private readonly workbenchEnvironmentService: IWorkbenchEnvironmentService, + @IDialogService private readonly dialogService: IDialogService, ) { super(); this.syncStatusContext = CONTEXT_SYNC_STATE.bindTo(contextKeyService); @@ -59,14 +62,8 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo this.onDidChangeSyncStatus(this.userDataSyncService.status); this._register(Event.debounce(authTokenService.onDidChangeStatus, () => undefined, 500)(() => this.onDidChangeAuthTokenStatus(this.authTokenService.status))); this._register(Event.debounce(userDataSyncService.onDidChangeStatus, () => undefined, 500)(() => this.onDidChangeSyncStatus(this.userDataSyncService.status))); - this._register(Event.filter(this.configurationService.onDidChangeConfiguration, e => e.affectsConfiguration('configurationSync.enable'))(() => this.updateBadge())); + this._register(Event.filter(this.configurationService.onDidChangeConfiguration, e => e.affectsConfiguration(UserDataSyncWorkbenchContribution.ENABLEMENT_SETTING))(() => this.onDidChangeEnablement())); this.registerActions(); - - timeout(2000).then(() => { - if (this.authTokenService.status === AuthTokenStatus.Inactive && this.userDataSyncService.status !== SyncStatus.Uninitialized && configurationService.getValue('configurationSync.enable')) { - this.showSignInNotification(); - } - }); } private onDidChangeAuthTokenStatus(status: AuthTokenStatus) { @@ -103,14 +100,34 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo } } + private onDidChangeEnablement() { + this.updateBadge(); + const enabled = this.configurationService.getValue(UserDataSyncWorkbenchContribution.ENABLEMENT_SETTING); + if (enabled) { + if (this.authTokenService.status === AuthTokenStatus.Inactive) { + const handle = this.notificationService.prompt(Severity.Info, localize('ask to sign in', "Please sign in to '{0}' to turn on configuration sync", "{ACCOUNT_NAME}"), + [ + { + label: localize('Sign in', "Sign in"), + run: () => this.signIn() + } + ]); + this.signInNotificationDisposable.value = toDisposable(() => handle.close()); + handle.onDidClose(() => this.signInNotificationDisposable.clear()); + } + } else { + this.signInNotificationDisposable.clear(); + } + } + private updateBadge(): void { this.badgeDisposable.clear(); let badge: IBadge | undefined = undefined; let clazz: string | undefined; - if (this.authTokenService.status === AuthTokenStatus.Inactive && this.userDataSyncService.status !== SyncStatus.Uninitialized && this.configurationService.getValue('configurationSync.enable')) { - badge = new NumberBadge(1, () => localize('sign in', "Sign in...")); + if (this.userDataSyncService.status !== SyncStatus.Uninitialized && this.configurationService.getValue(UserDataSyncWorkbenchContribution.ENABLEMENT_SETTING) && this.authTokenService.status === AuthTokenStatus.Inactive) { + badge = new NumberBadge(1, () => localize('sign in', "Configuration Sync: Sign in...")); } else if (this.userDataSyncService.status === SyncStatus.HasConflicts) { badge = new NumberBadge(1, () => localize('resolve conflicts', "Resolve Conflicts")); } else if (this.userDataSyncService.status === SyncStatus.Syncing) { @@ -123,16 +140,24 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo } } - private showSignInNotification(): void { - const handle = this.notificationService.prompt(Severity.Info, localize('show sign in', "Please sign in to Settings Sync service to start syncing configuration."), - [ - { - label: localize('sign in', "Sign in..."), - run: () => this.signIn() - } - ]); - this.signInNotificationDisposable.value = toDisposable(() => handle.close()); - handle.onDidClose(() => this.signInNotificationDisposable.clear()); + private async turnOn(): Promise { + if (this.authTokenService.status === AuthTokenStatus.Inactive) { + const result = await this.dialogService.confirm({ + type: 'info', + message: localize('turn on', "Turn on Configuration Sync"), + detail: localize('ask to sign in', "Please sign in to '{0}' to turn on configuration sync", "{ACCOUNT_NAME}"), + primaryButton: localize('Sign in', "Sign in") + }); + if (!result.confirmed) { + return; + } + await this.signIn(); + } + await this.configurationService.updateValue(UserDataSyncWorkbenchContribution.ENABLEMENT_SETTING, true); + } + + private async turnOff(): Promise { + await this.configurationService.updateValue(UserDataSyncWorkbenchContribution.ENABLEMENT_SETTING, false); } private async signIn(): Promise { @@ -194,53 +219,29 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo private registerActions(): void { - const signInMenuItem: IMenuItem = { - group: '5_sync', - command: { - id: 'workbench.userData.actions.login', - title: localize('sign in', "Sign in...") - }, - when: ContextKeyExpr.and(CONTEXT_SYNC_STATE.notEqualsTo(SyncStatus.Uninitialized), CONTEXT_AUTH_TOKEN_STATE.isEqualTo(AuthTokenStatus.Inactive), ContextKeyExpr.has('config.configurationSync.enable')), - }; - CommandsRegistry.registerCommand(signInMenuItem.command.id, () => this.signIn()); - MenuRegistry.appendMenuItem(MenuId.GlobalActivity, signInMenuItem); - MenuRegistry.appendMenuItem(MenuId.CommandPalette, signInMenuItem); - - const signOutMenuItem: IMenuItem = { - group: '5_sync', - command: { - id: 'workbench.userData.actions.logout', - title: localize('sign out', "Sign Out") - }, - when: ContextKeyExpr.and(CONTEXT_AUTH_TOKEN_STATE.isEqualTo(AuthTokenStatus.Active)), - }; - CommandsRegistry.registerCommand(signOutMenuItem.command.id, () => this.signOut()); - MenuRegistry.appendMenuItem(MenuId.GlobalActivity, signOutMenuItem); - MenuRegistry.appendMenuItem(MenuId.CommandPalette, signOutMenuItem); - const startSyncMenuItem: IMenuItem = { group: '5_sync', command: { id: 'workbench.userData.actions.syncStart', title: localize('start sync', "Configuration Sync: Turn On") }, - when: ContextKeyExpr.and(CONTEXT_SYNC_STATE.notEqualsTo(SyncStatus.Uninitialized), ContextKeyExpr.not('config.configurationSync.enable')), + when: ContextKeyExpr.and(CONTEXT_SYNC_STATE.notEqualsTo(SyncStatus.Uninitialized), ContextKeyExpr.not(`config.${UserDataSyncWorkbenchContribution.ENABLEMENT_SETTING}`)), }; - CommandsRegistry.registerCommand(startSyncMenuItem.command.id, () => this.configurationService.updateValue('configurationSync.enable', true)); + CommandsRegistry.registerCommand(startSyncMenuItem.command.id, () => this.turnOn()); MenuRegistry.appendMenuItem(MenuId.GlobalActivity, startSyncMenuItem); MenuRegistry.appendMenuItem(MenuId.CommandPalette, startSyncMenuItem); - const stopSyncMenuItem: IMenuItem = { + const signInMenuItem: IMenuItem = { group: '5_sync', command: { - id: 'workbench.userData.actions.stopSync', - title: localize('stop sync', "Configuration Sync: Turn Off") + id: 'workbench.userData.actions.login', + title: localize('sign in', "Configuration Sync: Sign in...") }, - when: ContextKeyExpr.and(CONTEXT_SYNC_STATE.notEqualsTo(SyncStatus.Uninitialized), ContextKeyExpr.has('config.configurationSync.enable')), + when: ContextKeyExpr.and(CONTEXT_SYNC_STATE.notEqualsTo(SyncStatus.Uninitialized), ContextKeyExpr.has(`config.${UserDataSyncWorkbenchContribution.ENABLEMENT_SETTING}`), CONTEXT_AUTH_TOKEN_STATE.isEqualTo(AuthTokenStatus.Inactive)), }; - CommandsRegistry.registerCommand(stopSyncMenuItem.command.id, () => this.configurationService.updateValue('configurationSync.enable', false)); - MenuRegistry.appendMenuItem(MenuId.GlobalActivity, stopSyncMenuItem); - MenuRegistry.appendMenuItem(MenuId.CommandPalette, stopSyncMenuItem); + CommandsRegistry.registerCommand(signInMenuItem.command.id, () => this.signIn()); + MenuRegistry.appendMenuItem(MenuId.GlobalActivity, signInMenuItem); + MenuRegistry.appendMenuItem(MenuId.CommandPalette, signInMenuItem); const resolveConflictsMenuItem: IMenuItem = { group: '5_sync', @@ -276,5 +277,27 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo order: 1, when: ContextKeyExpr.and(CONTEXT_SYNC_STATE.isEqualTo(SyncStatus.HasConflicts), ResourceContextKey.Resource.isEqualTo(this.workbenchEnvironmentService.settingsSyncPreviewResource.toString())), }); + + const stopSyncMenuItem: IMenuItem = { + group: '5_sync', + command: { + id: 'workbench.userData.actions.stopSync', + title: localize('stop sync', "Configuration Sync: Turn Off") + }, + when: ContextKeyExpr.and(CONTEXT_SYNC_STATE.notEqualsTo(SyncStatus.Uninitialized), ContextKeyExpr.has(`config.${UserDataSyncWorkbenchContribution.ENABLEMENT_SETTING}`)), + }; + CommandsRegistry.registerCommand(stopSyncMenuItem.command.id, () => this.turnOff()); + MenuRegistry.appendMenuItem(MenuId.CommandPalette, stopSyncMenuItem); + + const signOutMenuItem: IMenuItem = { + group: '5_sync', + command: { + id: 'workbench.userData.actions.logout', + title: localize('sign out', "Sign Out") + }, + when: ContextKeyExpr.and(CONTEXT_AUTH_TOKEN_STATE.isEqualTo(AuthTokenStatus.Active)), + }; + CommandsRegistry.registerCommand(signOutMenuItem.command.id, () => this.signOut()); + MenuRegistry.appendMenuItem(MenuId.CommandPalette, signOutMenuItem); } } From 3f80872c182b3463cc734d5ce0d3a086eea6acd4 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Wed, 13 Nov 2019 15:19:06 +0100 Subject: [PATCH 200/352] Show turn off action --- .../userDataSync/browser/userDataSync.ts | 23 ++++++++++--------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts b/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts index 03dc1b2a2b9df..f787581a5ee96 100644 --- a/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts +++ b/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts @@ -243,6 +243,18 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo MenuRegistry.appendMenuItem(MenuId.GlobalActivity, signInMenuItem); MenuRegistry.appendMenuItem(MenuId.CommandPalette, signInMenuItem); + const stopSyncMenuItem: IMenuItem = { + group: '5_sync', + command: { + id: 'workbench.userData.actions.stopSync', + title: localize('stop sync', "Configuration Sync: Turn Off") + }, + when: ContextKeyExpr.and(CONTEXT_SYNC_STATE.notEqualsTo(SyncStatus.Uninitialized), ContextKeyExpr.has(`config.${UserDataSyncWorkbenchContribution.ENABLEMENT_SETTING}`)), + }; + CommandsRegistry.registerCommand(stopSyncMenuItem.command.id, () => this.turnOff()); + MenuRegistry.appendMenuItem(MenuId.GlobalActivity, stopSyncMenuItem); + MenuRegistry.appendMenuItem(MenuId.CommandPalette, stopSyncMenuItem); + const resolveConflictsMenuItem: IMenuItem = { group: '5_sync', command: { @@ -278,17 +290,6 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo when: ContextKeyExpr.and(CONTEXT_SYNC_STATE.isEqualTo(SyncStatus.HasConflicts), ResourceContextKey.Resource.isEqualTo(this.workbenchEnvironmentService.settingsSyncPreviewResource.toString())), }); - const stopSyncMenuItem: IMenuItem = { - group: '5_sync', - command: { - id: 'workbench.userData.actions.stopSync', - title: localize('stop sync', "Configuration Sync: Turn Off") - }, - when: ContextKeyExpr.and(CONTEXT_SYNC_STATE.notEqualsTo(SyncStatus.Uninitialized), ContextKeyExpr.has(`config.${UserDataSyncWorkbenchContribution.ENABLEMENT_SETTING}`)), - }; - CommandsRegistry.registerCommand(stopSyncMenuItem.command.id, () => this.turnOff()); - MenuRegistry.appendMenuItem(MenuId.CommandPalette, stopSyncMenuItem); - const signOutMenuItem: IMenuItem = { group: '5_sync', command: { From 49d286b04464a03b55076e8fd0a949f2bb99570b Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Wed, 13 Nov 2019 15:25:42 +0100 Subject: [PATCH 201/352] Show number for global activity actions that has number badge --- src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts b/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts index f787581a5ee96..c8e3f5c636f28 100644 --- a/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts +++ b/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts @@ -235,7 +235,7 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo group: '5_sync', command: { id: 'workbench.userData.actions.login', - title: localize('sign in', "Configuration Sync: Sign in...") + title: localize('global activity sign in', "Configuration Sync: Sign in... (1)") }, when: ContextKeyExpr.and(CONTEXT_SYNC_STATE.notEqualsTo(SyncStatus.Uninitialized), ContextKeyExpr.has(`config.${UserDataSyncWorkbenchContribution.ENABLEMENT_SETTING}`), CONTEXT_AUTH_TOKEN_STATE.isEqualTo(AuthTokenStatus.Inactive)), }; @@ -259,7 +259,7 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo group: '5_sync', command: { id: 'sync.resolveConflicts', - title: localize('resolveConflicts', "Configuration Sync: Resolve Conflicts"), + title: localize('resolveConflicts', "Configuration Sync: Resolve Conflicts (1)"), }, when: CONTEXT_SYNC_STATE.isEqualTo(SyncStatus.HasConflicts), }; From 33dd2401f5535b8431b743019185428ef24ff1f3 Mon Sep 17 00:00:00 2001 From: Christof Marti Date: Wed, 13 Nov 2019 15:36:57 +0100 Subject: [PATCH 202/352] fix #83013 --- src/vs/workbench/browser/parts/quickinput/quickInput.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/browser/parts/quickinput/quickInput.ts b/src/vs/workbench/browser/parts/quickinput/quickInput.ts index 033a66cc27423..36f7c6eb674b6 100644 --- a/src/vs/workbench/browser/parts/quickinput/quickInput.ts +++ b/src/vs/workbench/browser/parts/quickinput/quickInput.ts @@ -661,7 +661,7 @@ class QuickPick extends QuickInput implements IQuickPi // Select element when keys are pressed that signal it const quickNavKeys = this.quickNavigate.keybindings; - const wasTriggerKeyPressed = keyCode === KeyCode.Enter || quickNavKeys.some(k => { + const wasTriggerKeyPressed = quickNavKeys.some(k => { const [firstPart, chordPart] = k.getParts(); if (chordPart) { return false; From 11a213a5c1b11a58b6220f1962c7735097e1cd25 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Wed, 13 Nov 2019 15:45:10 +0100 Subject: [PATCH 203/352] Show only one configuration sync action in global activity --- .../userDataSync/browser/userDataSync.ts | 21 +++++++++++-------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts b/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts index c8e3f5c636f28..d3a24fc66f32a 100644 --- a/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts +++ b/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts @@ -243,17 +243,20 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo MenuRegistry.appendMenuItem(MenuId.GlobalActivity, signInMenuItem); MenuRegistry.appendMenuItem(MenuId.CommandPalette, signInMenuItem); - const stopSyncMenuItem: IMenuItem = { + const stopSycCommand = { + id: 'workbench.userData.actions.stopSync', + title: localize('stop sync', "Configuration Sync: Turn Off") + }; + CommandsRegistry.registerCommand(stopSycCommand.id, () => this.turnOff()); + MenuRegistry.appendMenuItem(MenuId.GlobalActivity, { group: '5_sync', - command: { - id: 'workbench.userData.actions.stopSync', - title: localize('stop sync', "Configuration Sync: Turn Off") - }, + command: stopSycCommand, + when: ContextKeyExpr.and(ContextKeyExpr.has(`config.${UserDataSyncWorkbenchContribution.ENABLEMENT_SETTING}`), CONTEXT_AUTH_TOKEN_STATE.isEqualTo(AuthTokenStatus.Active), CONTEXT_SYNC_STATE.notEqualsTo(SyncStatus.Uninitialized), CONTEXT_SYNC_STATE.notEqualsTo(SyncStatus.HasConflicts)) + }); + MenuRegistry.appendMenuItem(MenuId.CommandPalette, { + command: stopSycCommand, when: ContextKeyExpr.and(CONTEXT_SYNC_STATE.notEqualsTo(SyncStatus.Uninitialized), ContextKeyExpr.has(`config.${UserDataSyncWorkbenchContribution.ENABLEMENT_SETTING}`)), - }; - CommandsRegistry.registerCommand(stopSyncMenuItem.command.id, () => this.turnOff()); - MenuRegistry.appendMenuItem(MenuId.GlobalActivity, stopSyncMenuItem); - MenuRegistry.appendMenuItem(MenuId.CommandPalette, stopSyncMenuItem); + }); const resolveConflictsMenuItem: IMenuItem = { group: '5_sync', From bd4f9e84801b5769c3df24bbc387117429874ef2 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Wed, 13 Nov 2019 15:38:48 +0100 Subject: [PATCH 204/352] update reference view extension --- build/builtInExtensions.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/builtInExtensions.json b/build/builtInExtensions.json index 3c85dd690d5ab..29c39c9b5e4a6 100644 --- a/build/builtInExtensions.json +++ b/build/builtInExtensions.json @@ -31,7 +31,7 @@ }, { "name": "ms-vscode.references-view", - "version": "0.0.35", + "version": "0.0.36", "repo": "https://github.com/Microsoft/vscode-reference-view", "metadata": { "id": "dc489f46-520d-4556-ae85-1f9eab3c412d", From 93e87cabe5083930120d51e202b63efd4f36b73a Mon Sep 17 00:00:00 2001 From: Greg Van Liew Date: Wed, 13 Nov 2019 07:29:04 -0800 Subject: [PATCH 205/352] Another nit in settings comment --- extensions/npm/package.nls.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/npm/package.nls.json b/extensions/npm/package.nls.json index 014010a8425d1..51756d241f14a 100644 --- a/extensions/npm/package.nls.json +++ b/extensions/npm/package.nls.json @@ -7,7 +7,7 @@ "config.npm.exclude": "Configure glob patterns for folders that should be excluded from automatic script detection.", "config.npm.enableScriptExplorer": "Enable an explorer view for npm scripts when there is no top-level 'package.json' file.", "config.npm.scriptExplorerAction": "The default click action used in the npm scripts explorer: `open` or `run`, the default is `open`.", - "config.npm.enableRunFromFolder": "Enable running NPM scripts contained in a folder from the Explorer context menu.", + "config.npm.enableRunFromFolder": "Enable running npm scripts contained in a folder from the Explorer context menu.", "config.npm.fetchOnlinePackageInfo": "Fetch data from https://registry.npmjs.org and https://registry.bower.io to provide auto-completion and information on hover features on npm dependencies.", "npm.parseError": "Npm task detection: failed to parse the file {0}", "taskdef.script": "The npm script to customize.", From 7225d02a7cc31a18bb21a8bd682536ac64f596ea Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Wed, 13 Nov 2019 17:59:27 +0100 Subject: [PATCH 206/352] fix tests --- src/vs/platform/dialogs/common/dialogs.ts | 1 - src/vs/platform/files/test/node/diskFileService.test.ts | 2 +- src/vs/workbench/services/textfile/common/textfiles.ts | 3 --- 3 files changed, 1 insertion(+), 5 deletions(-) diff --git a/src/vs/platform/dialogs/common/dialogs.ts b/src/vs/platform/dialogs/common/dialogs.ts index a01a721267f41..0258fa407dd8e 100644 --- a/src/vs/platform/dialogs/common/dialogs.ts +++ b/src/vs/platform/dialogs/common/dialogs.ts @@ -141,7 +141,6 @@ export interface IOpenDialogOptions { availableFileSystems?: readonly string[]; } - export const IDialogService = createDecorator('dialogService'); export interface IDialogOptions { diff --git a/src/vs/platform/files/test/node/diskFileService.test.ts b/src/vs/platform/files/test/node/diskFileService.test.ts index 0b5b1ecf8bc00..0caf7ec7a45b8 100644 --- a/src/vs/platform/files/test/node/diskFileService.test.ts +++ b/src/vs/platform/files/test/node/diskFileService.test.ts @@ -134,7 +134,7 @@ suite('Disk File Service', function () { // we see random test failures when accessing the native file system. To // diagnose further, we retry node.js file access tests up to 3 times to // rule out any random disk issue. - // this.retries(3); + this.retries(3); setup(async () => { const logService = new NullLogService(); diff --git a/src/vs/workbench/services/textfile/common/textfiles.ts b/src/vs/workbench/services/textfile/common/textfiles.ts index a77cb9386dbe4..bfc329ca941fe 100644 --- a/src/vs/workbench/services/textfile/common/textfiles.ts +++ b/src/vs/workbench/services/textfile/common/textfiles.ts @@ -139,7 +139,6 @@ export interface ITextFileService extends IDisposable { confirmSave(resources?: URI[]): Promise; } - export class FileOperationWillRunEvent implements IWaitUntil { constructor( @@ -157,7 +156,6 @@ export class FileOperationWillRunEvent implements IWaitUntil { } } - export class FileOperationDidRunEvent { constructor( @@ -167,7 +165,6 @@ export class FileOperationDidRunEvent { ) { } } - export interface IReadTextFileOptions extends IReadFileOptions { /** From 09324ffcf269f608fe5ca91b93ecba1f4433556d Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Wed, 13 Nov 2019 18:02:34 +0100 Subject: [PATCH 207/352] files - do not indicate document edited when auto save is on --- .../contrib/files/common/dirtyFilesIndicator.ts | 6 +++--- src/vs/workbench/electron-browser/window.ts | 10 ++++++++-- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/vs/workbench/contrib/files/common/dirtyFilesIndicator.ts b/src/vs/workbench/contrib/files/common/dirtyFilesIndicator.ts index cbbc586cbebd5..040c1bb45ad02 100644 --- a/src/vs/workbench/contrib/files/common/dirtyFilesIndicator.ts +++ b/src/vs/workbench/contrib/files/common/dirtyFilesIndicator.ts @@ -41,9 +41,9 @@ export class DirtyFilesIndicator extends Disposable implements IWorkbenchContrib this.lifecycleService.onShutdown(this.dispose, this); } - private onWorkingCopyDidChangeDirty(copy: IWorkingCopy): void { - const gotDirty = copy.isDirty(); - if (gotDirty && !!(copy.capabilities & WorkingCopyCapabilities.AutoSave) && this.filesConfigurationService.getAutoSaveMode() === AutoSaveMode.AFTER_SHORT_DELAY) { + private onWorkingCopyDidChangeDirty(workingCopy: IWorkingCopy): void { + const gotDirty = workingCopy.isDirty(); + if (gotDirty && !!(workingCopy.capabilities & WorkingCopyCapabilities.AutoSave) && this.filesConfigurationService.getAutoSaveMode() === AutoSaveMode.AFTER_SHORT_DELAY) { return; // do not indicate dirty of working copies that are auto saved after short delay } diff --git a/src/vs/workbench/electron-browser/window.ts b/src/vs/workbench/electron-browser/window.ts index d7f2c37ac7fba..1272f66f0a6c6 100644 --- a/src/vs/workbench/electron-browser/window.ts +++ b/src/vs/workbench/electron-browser/window.ts @@ -60,7 +60,8 @@ import { ITunnelService, extractLocalHostUriMetaDataForPortMapping } from 'vs/pl import { IWorkbenchLayoutService, Parts } from 'vs/workbench/services/layout/browser/layoutService'; import { IHostService } from 'vs/workbench/services/host/browser/host'; import { IElectronEnvironmentService } from 'vs/workbench/services/electron/electron-browser/electronEnvironmentService'; -import { IWorkingCopyService } from 'vs/workbench/services/workingCopy/common/workingCopyService'; +import { IWorkingCopyService, WorkingCopyCapabilities } from 'vs/workbench/services/workingCopy/common/workingCopyService'; +import { AutoSaveMode, IFilesConfigurationService } from 'vs/workbench/services/filesConfiguration/common/filesConfigurationService'; export class ElectronWindow extends Disposable { @@ -103,7 +104,8 @@ export class ElectronWindow extends Disposable { @ITunnelService private readonly tunnelService: ITunnelService, @IWorkbenchLayoutService private readonly layoutService: IWorkbenchLayoutService, @IElectronEnvironmentService private readonly electronEnvironmentService: IElectronEnvironmentService, - @IWorkingCopyService private readonly workingCopyService: IWorkingCopyService + @IWorkingCopyService private readonly workingCopyService: IWorkingCopyService, + @IFilesConfigurationService private readonly filesConfigurationService: IFilesConfigurationService ) { super(); @@ -267,6 +269,10 @@ export class ElectronWindow extends Disposable { if (isMacintosh) { this._register(this.workingCopyService.onDidChangeDirty(workingCopy => { const gotDirty = workingCopy.isDirty(); + if (gotDirty && !!(workingCopy.capabilities & WorkingCopyCapabilities.AutoSave) && this.filesConfigurationService.getAutoSaveMode() === AutoSaveMode.AFTER_SHORT_DELAY) { + return; // do not indicate dirty of working copies that are auto saved after short delay + } + if ((!this.isDocumentedEdited && gotDirty) || (this.isDocumentedEdited && !gotDirty)) { const hasDirtyFiles = this.workingCopyService.hasDirty; this.isDocumentedEdited = hasDirtyFiles; From c4a5657ec19ed34e5393b0bb803e29545122cbab Mon Sep 17 00:00:00 2001 From: Martin Aeschlimann Date: Wed, 13 Nov 2019 18:06:14 +0100 Subject: [PATCH 208/352] update onigasm. Fixes #82606 --- package.json | 2 +- remote/package.json | 2 +- remote/web/package.json | 2 +- remote/web/yarn.lock | 8 ++++---- remote/yarn.lock | 8 ++++---- yarn.lock | 8 ++++---- 6 files changed, 15 insertions(+), 15 deletions(-) diff --git a/package.json b/package.json index ba04b1cf11b30..7ec46913bfc60 100644 --- a/package.json +++ b/package.json @@ -42,7 +42,7 @@ "native-keymap": "2.0.0", "native-watchdog": "1.2.0", "node-pty": "^0.10.0-beta2", - "onigasm-umd": "^2.2.2", + "onigasm-umd": "^2.2.4", "semver-umd": "^5.5.3", "spdlog": "^0.11.1", "sudo-prompt": "9.0.0", diff --git a/remote/package.json b/remote/package.json index ec299bfed0cdf..446f54ff57ed0 100644 --- a/remote/package.json +++ b/remote/package.json @@ -12,7 +12,7 @@ "jschardet": "2.1.1", "native-watchdog": "1.2.0", "node-pty": "^0.10.0-beta2", - "onigasm-umd": "^2.2.2", + "onigasm-umd": "^2.2.4", "semver-umd": "^5.5.3", "spdlog": "^0.11.1", "vscode-minimist": "^1.2.1", diff --git a/remote/web/package.json b/remote/web/package.json index 9889d010fab87..9fcdaa00992c9 100644 --- a/remote/web/package.json +++ b/remote/web/package.json @@ -2,7 +2,7 @@ "name": "vscode-web", "version": "0.0.0", "dependencies": { - "onigasm-umd": "^2.2.2", + "onigasm-umd": "^2.2.4", "semver-umd": "^5.5.3", "vscode-textmate": "^4.3.0", "xterm": "4.3.0-beta17", diff --git a/remote/web/yarn.lock b/remote/web/yarn.lock index 45a2296934f01..1ecb4b7cb52d8 100644 --- a/remote/web/yarn.lock +++ b/remote/web/yarn.lock @@ -7,10 +7,10 @@ nan@^2.14.0: resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.0.tgz#7818f722027b2459a86f0295d434d1fc2336c52c" integrity sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg== -onigasm-umd@^2.2.2: - version "2.2.2" - resolved "https://registry.yarnpkg.com/onigasm-umd/-/onigasm-umd-2.2.2.tgz#b989d762df61f899a3052ac794a50bd93fe20257" - integrity sha512-v2eMOJu7iE444L2iJN+U6s6s5S0y7oj/N0DAkrd6wokRtTVoq/v/yaDI1lIqFrTeJbNtqNzYvguDF5yNzW3Rvw== +onigasm-umd@^2.2.4: + version "2.2.4" + resolved "https://registry.yarnpkg.com/onigasm-umd/-/onigasm-umd-2.2.4.tgz#27ee87f7496c66ad40cebfbc0d418c19bb7db5ec" + integrity sha512-N9VqCUhl9KBuzm47vcK8T/xUnbYylIhMN45Rwltlo1sZc3QUDda6SxIlyVB8r0SJQwURv8JOHjyXjjCriGvzRg== oniguruma@^7.2.0: version "7.2.0" diff --git a/remote/yarn.lock b/remote/yarn.lock index 1aab9f6a9c0ef..99fb10b59c3a8 100644 --- a/remote/yarn.lock +++ b/remote/yarn.lock @@ -283,10 +283,10 @@ normalize-path@^3.0.0, normalize-path@~3.0.0: resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== -onigasm-umd@^2.2.2: - version "2.2.2" - resolved "https://registry.yarnpkg.com/onigasm-umd/-/onigasm-umd-2.2.2.tgz#b989d762df61f899a3052ac794a50bd93fe20257" - integrity sha512-v2eMOJu7iE444L2iJN+U6s6s5S0y7oj/N0DAkrd6wokRtTVoq/v/yaDI1lIqFrTeJbNtqNzYvguDF5yNzW3Rvw== +onigasm-umd@^2.2.4: + version "2.2.4" + resolved "https://registry.yarnpkg.com/onigasm-umd/-/onigasm-umd-2.2.4.tgz#27ee87f7496c66ad40cebfbc0d418c19bb7db5ec" + integrity sha512-N9VqCUhl9KBuzm47vcK8T/xUnbYylIhMN45Rwltlo1sZc3QUDda6SxIlyVB8r0SJQwURv8JOHjyXjjCriGvzRg== oniguruma@^7.2.0: version "7.2.0" diff --git a/yarn.lock b/yarn.lock index 25111e8c9c3b4..8bd5a9e0fb38f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6068,10 +6068,10 @@ onetime@^2.0.0: dependencies: mimic-fn "^1.0.0" -onigasm-umd@^2.2.2: - version "2.2.2" - resolved "https://registry.yarnpkg.com/onigasm-umd/-/onigasm-umd-2.2.2.tgz#b989d762df61f899a3052ac794a50bd93fe20257" - integrity sha512-v2eMOJu7iE444L2iJN+U6s6s5S0y7oj/N0DAkrd6wokRtTVoq/v/yaDI1lIqFrTeJbNtqNzYvguDF5yNzW3Rvw== +onigasm-umd@^2.2.4: + version "2.2.4" + resolved "https://registry.yarnpkg.com/onigasm-umd/-/onigasm-umd-2.2.4.tgz#27ee87f7496c66ad40cebfbc0d418c19bb7db5ec" + integrity sha512-N9VqCUhl9KBuzm47vcK8T/xUnbYylIhMN45Rwltlo1sZc3QUDda6SxIlyVB8r0SJQwURv8JOHjyXjjCriGvzRg== oniguruma@^7.2.0: version "7.2.0" From 4a61f3399415587fb166bbed751d0b23458a3c2c Mon Sep 17 00:00:00 2001 From: Andre Weinand Date: Wed, 13 Nov 2019 18:17:42 +0100 Subject: [PATCH 209/352] proposed API for creating debug uri --- src/vs/vscode.proposed.d.ts | 21 +++++++++++++++ .../workbench/api/common/extHost.api.impl.ts | 5 +++- .../api/common/extHostDebugService.ts | 1 + .../workbench/api/node/extHostDebugService.ts | 26 +++++++++++++++++++ 4 files changed, 52 insertions(+), 1 deletion(-) diff --git a/src/vs/vscode.proposed.d.ts b/src/vs/vscode.proposed.d.ts index b89290d05fad0..d139918f061ed 100644 --- a/src/vs/vscode.proposed.d.ts +++ b/src/vs/vscode.proposed.d.ts @@ -523,6 +523,27 @@ declare module 'vscode' { //#region André: debug + /** + * A DebugSource is an opaque stand-in type for the type [Source](https://microsoft.github.io/debug-adapter-protocol/specification#Types_Source) defined in the Debug Adapter Protocol. + */ + export interface DebugSource { + // opaque contents + } + + export namespace debug { + + /** + * Converts a "Source" object received via the Debug Adapter Protocol into a Uri that can be used to load its contents. + * + * If the "Source" object has insufficient information to create a uri, an error is thrown. + * + * @param source An object conforming to the [Source](https://microsoft.github.io/debug-adapter-protocol/specification#Types_Source) type defined in the Debug Adapter Protocol. + * @param session An optional debug session that will be used to locate the Debug Adapter Protocol. + * @return A uri that can be used to load the contents of the source. + */ + function asDebugSourceUri(source: DebugSource, session?: DebugSession): Uri; + } + // deprecated export interface DebugConfigurationProvider { diff --git a/src/vs/workbench/api/common/extHost.api.impl.ts b/src/vs/workbench/api/common/extHost.api.impl.ts index c872655f012c2..448923b104465 100644 --- a/src/vs/workbench/api/common/extHost.api.impl.ts +++ b/src/vs/workbench/api/common/extHost.api.impl.ts @@ -778,7 +778,6 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I if (!parentSessionOrOptions || (typeof parentSessionOrOptions === 'object' && 'configuration' in parentSessionOrOptions)) { return extHostDebugService.startDebugging(folder, nameOrConfig, { parentSession: parentSessionOrOptions }); } - checkProposedApiEnabled(extension); return extHostDebugService.startDebugging(folder, nameOrConfig, parentSessionOrOptions || {}); }, addBreakpoints(breakpoints: vscode.Breakpoint[]) { @@ -786,6 +785,10 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I }, removeBreakpoints(breakpoints: vscode.Breakpoint[]) { return extHostDebugService.removeBreakpoints(breakpoints); + }, + asDebugSourceUri(source: vscode.DebugSource, session?: vscode.DebugSession): vscode.Uri { + checkProposedApiEnabled(extension); + return extHostDebugService.asDebugSourceUri(source, session); } }; diff --git a/src/vs/workbench/api/common/extHostDebugService.ts b/src/vs/workbench/api/common/extHostDebugService.ts index f079be622eeef..a80504d6c0f44 100644 --- a/src/vs/workbench/api/common/extHostDebugService.ts +++ b/src/vs/workbench/api/common/extHostDebugService.ts @@ -30,5 +30,6 @@ export interface IExtHostDebugService extends ExtHostDebugServiceShape { registerDebugConfigurationProvider(type: string, provider: vscode.DebugConfigurationProvider): vscode.Disposable; registerDebugAdapterDescriptorFactory(extension: IExtensionDescription, type: string, factory: vscode.DebugAdapterDescriptorFactory): vscode.Disposable; registerDebugAdapterTrackerFactory(type: string, factory: vscode.DebugAdapterTrackerFactory): vscode.Disposable; + asDebugSourceUri(source: vscode.DebugSource, session?: vscode.DebugSession): vscode.Uri; } diff --git a/src/vs/workbench/api/node/extHostDebugService.ts b/src/vs/workbench/api/node/extHostDebugService.ts index 1b9b233961a84..82d87ead7998f 100644 --- a/src/vs/workbench/api/node/extHostDebugService.ts +++ b/src/vs/workbench/api/node/extHostDebugService.ts @@ -138,6 +138,32 @@ export class ExtHostDebugService implements IExtHostDebugService, ExtHostDebugSe }); } + public asDebugSourceUri(src: vscode.DebugSource, session?: vscode.DebugSession): URI { + + const source = src; + + if (typeof source.sourceReference === 'number') { + // src can be retrieved via DAP's "source" request + + let debug = `debug:${encodeURIComponent(source.path || '')}`; + let sep = '?'; + + if (session) { + debug += `${sep}session=${encodeURIComponent(session.id)}`; + sep = '&'; + } + + debug += `${sep}ref=${source.sourceReference}`; + + return vscode.Uri.parse(debug); + } else if (source.path) { + // src is just a local file path + return vscode.Uri.file(source.path); + } else { + throw new Error(`cannot create uri from DAP 'source' object; properties 'path' and 'sourceReference' are both missing.`); + } + } + private registerAllDebugTypes(extensionRegistry: ExtensionDescriptionRegistry) { const debugTypes: string[] = []; From 283c952d3f9baade691bb4a0f4477774174cf7dc Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Wed, 13 Nov 2019 18:18:55 +0100 Subject: [PATCH 210/352] opener service uses IOpener for its built-in openers --- .../editor/browser/services/openerService.ts | 142 ++++++++++-------- 1 file changed, 80 insertions(+), 62 deletions(-) diff --git a/src/vs/editor/browser/services/openerService.ts b/src/vs/editor/browser/services/openerService.ts index 48175adfb4272..476f10ecf001a 100644 --- a/src/vs/editor/browser/services/openerService.ts +++ b/src/vs/editor/browser/services/openerService.ts @@ -16,6 +16,69 @@ import { CommandsRegistry, ICommandService } from 'vs/platform/commands/common/c import { IOpener, IOpenerService, IValidator, IExternalUriResolver, OpenOptions, ResolveExternalUriOptions, IResolvedExternalUri, IExternalOpener } from 'vs/platform/opener/common/opener'; import { EditorOpenContext } from 'vs/platform/editor/common/editor'; +class CommandOpener implements IOpener { + + constructor(@ICommandService private readonly _commandService: ICommandService) { } + + async open(uri: URI, ) { + // run command or bail out if command isn't known + if (!equalsIgnoreCase(uri.scheme, Schemas.command)) { + return false; + } + + if (!CommandsRegistry.getCommand(uri.path)) { + throw new Error(`command '${uri.path}' NOT known`); + } + + // execute as command + let args: any = []; + try { + args = parse(uri.query); + if (!Array.isArray(args)) { + args = [args]; + } + } catch (e) { + // ignore error + } + await this._commandService.executeCommand(uri.path, ...args); + return true; + } +} + +class EditorOpener implements IOpener { + + constructor(@ICodeEditorService private readonly _editorService: ICodeEditorService) { } + + async open(uri: URI, options?: OpenOptions): Promise { + + // finally open in editor + let selection: { startLineNumber: number; startColumn: number; } | undefined = undefined; + const match = /^L?(\d+)(?:,(\d+))?/.exec(uri.fragment); + if (match) { + // support file:///some/file.js#73,84 + // support file:///some/file.js#L73 + selection = { + startLineNumber: parseInt(match[1]), + startColumn: match[2] ? parseInt(match[2]) : 1 + }; + // remove fragment + uri = uri.with({ fragment: '' }); + } + + if (uri.scheme === Schemas.file) { + uri = resources.normalizePath(uri); // workaround for non-normalized paths (https://github.com/Microsoft/vscode/issues/12954) + } + + await this._editorService.openCodeEditor( + { resource: uri, options: { selection, context: options?.fromUserGesture ? EditorOpenContext.USER : EditorOpenContext.API } }, + this._editorService.getFocusedCodeEditor(), + options?.openToSide + ); + + return true; + } +} + export class OpenerService extends Disposable implements IOpenerService { _serviceBrand: undefined; @@ -26,8 +89,8 @@ export class OpenerService extends Disposable implements IOpenerService { private _externalOpener: IExternalOpener; constructor( - @ICodeEditorService private readonly _editorService: ICodeEditorService, - @ICommandService private readonly _commandService: ICommandService, + @ICodeEditorService editorService: ICodeEditorService, + @ICommandService commandService: ICommandService, ) { super(); @@ -35,14 +98,26 @@ export class OpenerService extends Disposable implements IOpenerService { this._externalOpener = { openExternal: href => { dom.windowOpenNoOpener(href); - return Promise.resolve(true); } }; + + // + this._openers.push({ // default: open externally + open: async (uri: URI, options: OpenOptions | undefined): Promise => { + const { scheme } = uri; + if (options?.openExternal || equalsIgnoreCase(scheme, Schemas.mailto) || equalsIgnoreCase(scheme, Schemas.http) || equalsIgnoreCase(scheme, Schemas.https)) { + return this._doOpenExternal(uri, options); + } + return false; + } + }); + this._openers.push(new CommandOpener(commandService)); // default: run command + this._openers.push(new EditorOpener(editorService)); // default: open editor } registerOpener(opener: IOpener): IDisposable { - const remove = this._openers.push(opener); + const remove = this._openers.unshift(opener); return { dispose: remove }; } @@ -85,8 +160,7 @@ export class OpenerService extends Disposable implements IOpenerService { } } - // use default openers - return this._doOpen(resource, options); + return false; } async resolveExternalUri(resource: URI, options?: ResolveExternalUriOptions): Promise { @@ -100,62 +174,6 @@ export class OpenerService extends Disposable implements IOpenerService { return { resolved: resource, dispose: () => { } }; } - private async _doOpen(resource: URI, options: OpenOptions | undefined): Promise { - const { scheme, path, query, fragment } = resource; - - if (options?.openExternal || equalsIgnoreCase(scheme, Schemas.mailto) || equalsIgnoreCase(scheme, Schemas.http) || equalsIgnoreCase(scheme, Schemas.https)) { - // open externally - return this._doOpenExternal(resource, options); - } - - if (equalsIgnoreCase(scheme, Schemas.command)) { - // run command or bail out if command isn't known - if (!CommandsRegistry.getCommand(path)) { - throw new Error(`command '${path}' NOT known`); - } - // execute as command - let args: any = []; - try { - args = parse(query); - if (!Array.isArray(args)) { - args = [args]; - } - } catch (e) { - // ignore error - } - - await this._commandService.executeCommand(path, ...args); - - return true; - } - - // finally open in editor - let selection: { startLineNumber: number; startColumn: number; } | undefined = undefined; - const match = /^L?(\d+)(?:,(\d+))?/.exec(fragment); - if (match) { - // support file:///some/file.js#73,84 - // support file:///some/file.js#L73 - selection = { - startLineNumber: parseInt(match[1]), - startColumn: match[2] ? parseInt(match[2]) : 1 - }; - // remove fragment - resource = resource.with({ fragment: '' }); - } - - if (resource.scheme === Schemas.file) { - resource = resources.normalizePath(resource); // workaround for non-normalized paths (https://github.com/Microsoft/vscode/issues/12954) - } - - await this._editorService.openCodeEditor( - { resource, options: { selection, context: options?.fromUserGesture ? EditorOpenContext.USER : EditorOpenContext.API } }, - this._editorService.getFocusedCodeEditor(), - options?.openToSide - ); - - return true; - } - private async _doOpenExternal(resource: URI, options: OpenOptions | undefined): Promise { const { resolved } = await this.resolveExternalUri(resource, options); From 60188e277c9538e47dd3894aa6d4e9957d401581 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Wed, 13 Nov 2019 16:08:09 +0100 Subject: [PATCH 211/352] wordings --- .../workbench/contrib/userDataSync/browser/userDataSync.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts b/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts index d3a24fc66f32a..1459d13fc9b1e 100644 --- a/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts +++ b/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts @@ -105,7 +105,7 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo const enabled = this.configurationService.getValue(UserDataSyncWorkbenchContribution.ENABLEMENT_SETTING); if (enabled) { if (this.authTokenService.status === AuthTokenStatus.Inactive) { - const handle = this.notificationService.prompt(Severity.Info, localize('ask to sign in', "Please sign in to '{0}' to turn on configuration sync", "{ACCOUNT_NAME}"), + const handle = this.notificationService.prompt(Severity.Info, localize('ask to sign in', "Please sign in with your '{0}' account to sync configuration", "{ACCOUNT_NAME}"), [ { label: localize('Sign in', "Sign in"), @@ -144,8 +144,8 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo if (this.authTokenService.status === AuthTokenStatus.Inactive) { const result = await this.dialogService.confirm({ type: 'info', - message: localize('turn on', "Turn on Configuration Sync"), - detail: localize('ask to sign in', "Please sign in to '{0}' to turn on configuration sync", "{ACCOUNT_NAME}"), + message: localize('sign in to account', "Sign in to {0}", "{ACCOUNT_NAME}"), + detail: localize('ask to sign in', "Please sign in with your '{0}' account to sync configuration", "{ACCOUNT_NAME}"), primaryButton: localize('Sign in', "Sign in") }); if (!result.confirmed) { From 6910af0be9c329aa817bf9105b83d495a926c163 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Wed, 13 Nov 2019 18:19:20 +0100 Subject: [PATCH 212/352] :lipstick: change labels --- .../userDataSync/browser/userDataSync.ts | 56 ++++++++++++------- 1 file changed, 35 insertions(+), 21 deletions(-) diff --git a/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts b/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts index 1459d13fc9b1e..7d72356a6f02b 100644 --- a/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts +++ b/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts @@ -127,7 +127,7 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo let clazz: string | undefined; if (this.userDataSyncService.status !== SyncStatus.Uninitialized && this.configurationService.getValue(UserDataSyncWorkbenchContribution.ENABLEMENT_SETTING) && this.authTokenService.status === AuthTokenStatus.Inactive) { - badge = new NumberBadge(1, () => localize('sign in', "Configuration Sync: Sign in...")); + badge = new NumberBadge(1, () => localize('sign in', "Sync: Sign in...")); } else if (this.userDataSyncService.status === SyncStatus.HasConflicts) { badge = new NumberBadge(1, () => localize('resolve conflicts', "Resolve Conflicts")); } else if (this.userDataSyncService.status === SyncStatus.Syncing) { @@ -223,7 +223,7 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo group: '5_sync', command: { id: 'workbench.userData.actions.syncStart', - title: localize('start sync', "Configuration Sync: Turn On") + title: localize('start sync', "Sync: Turn On") }, when: ContextKeyExpr.and(CONTEXT_SYNC_STATE.notEqualsTo(SyncStatus.Uninitialized), ContextKeyExpr.not(`config.${UserDataSyncWorkbenchContribution.ENABLEMENT_SETTING}`)), }; @@ -231,21 +231,28 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo MenuRegistry.appendMenuItem(MenuId.GlobalActivity, startSyncMenuItem); MenuRegistry.appendMenuItem(MenuId.CommandPalette, startSyncMenuItem); - const signInMenuItem: IMenuItem = { + const signInCommandId = 'workbench.userData.actions.login'; + const signInWhenContext = ContextKeyExpr.and(CONTEXT_SYNC_STATE.notEqualsTo(SyncStatus.Uninitialized), ContextKeyExpr.has(`config.${UserDataSyncWorkbenchContribution.ENABLEMENT_SETTING}`), CONTEXT_AUTH_TOKEN_STATE.isEqualTo(AuthTokenStatus.Inactive)); + CommandsRegistry.registerCommand(signInCommandId, () => this.signIn()); + MenuRegistry.appendMenuItem(MenuId.GlobalActivity, { group: '5_sync', command: { - id: 'workbench.userData.actions.login', - title: localize('global activity sign in', "Configuration Sync: Sign in... (1)") + id: signInCommandId, + title: localize('global activity sign in', "Sync: Sign in... (1)") }, - when: ContextKeyExpr.and(CONTEXT_SYNC_STATE.notEqualsTo(SyncStatus.Uninitialized), ContextKeyExpr.has(`config.${UserDataSyncWorkbenchContribution.ENABLEMENT_SETTING}`), CONTEXT_AUTH_TOKEN_STATE.isEqualTo(AuthTokenStatus.Inactive)), - }; - CommandsRegistry.registerCommand(signInMenuItem.command.id, () => this.signIn()); - MenuRegistry.appendMenuItem(MenuId.GlobalActivity, signInMenuItem); - MenuRegistry.appendMenuItem(MenuId.CommandPalette, signInMenuItem); + when: signInWhenContext, + }); + MenuRegistry.appendMenuItem(MenuId.CommandPalette, { + command: { + id: signInCommandId, + title: localize('sign in', "Sync: Sign in...") + }, + when: signInWhenContext, + }); const stopSycCommand = { id: 'workbench.userData.actions.stopSync', - title: localize('stop sync', "Configuration Sync: Turn Off") + title: localize('stop sync', "Sync: Turn Off") }; CommandsRegistry.registerCommand(stopSycCommand.id, () => this.turnOff()); MenuRegistry.appendMenuItem(MenuId.GlobalActivity, { @@ -258,31 +265,38 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo when: ContextKeyExpr.and(CONTEXT_SYNC_STATE.notEqualsTo(SyncStatus.Uninitialized), ContextKeyExpr.has(`config.${UserDataSyncWorkbenchContribution.ENABLEMENT_SETTING}`)), }); - const resolveConflictsMenuItem: IMenuItem = { + const resolveConflictsCommandId = 'workbench.userData.actions.resolveConflicts'; + const resolveConflictsWhenContext = CONTEXT_SYNC_STATE.isEqualTo(SyncStatus.HasConflicts); + CommandsRegistry.registerCommand(resolveConflictsCommandId, () => this.handleConflicts()); + MenuRegistry.appendMenuItem(MenuId.GlobalActivity, { group: '5_sync', command: { - id: 'sync.resolveConflicts', - title: localize('resolveConflicts', "Configuration Sync: Resolve Conflicts (1)"), + id: resolveConflictsCommandId, + title: localize('resolveConflicts_global', "Sync: Resolve Conflicts (1)"), }, - when: CONTEXT_SYNC_STATE.isEqualTo(SyncStatus.HasConflicts), - }; - CommandsRegistry.registerCommand(resolveConflictsMenuItem.command.id, () => this.handleConflicts()); - MenuRegistry.appendMenuItem(MenuId.GlobalActivity, resolveConflictsMenuItem); - MenuRegistry.appendMenuItem(MenuId.CommandPalette, resolveConflictsMenuItem); + when: resolveConflictsWhenContext, + }); + MenuRegistry.appendMenuItem(MenuId.CommandPalette, { + command: { + id: resolveConflictsCommandId, + title: localize('resolveConflicts', "Sync: Resolve Conflicts"), + }, + when: resolveConflictsWhenContext, + }); const continueSyncCommandId = 'workbench.userData.actions.continueSync'; CommandsRegistry.registerCommand(continueSyncCommandId, () => this.continueSync()); MenuRegistry.appendMenuItem(MenuId.CommandPalette, { command: { id: continueSyncCommandId, - title: localize('continue sync', "Configuration Sync: Continue") + title: localize('continue sync', "Sync: Continue") }, when: ContextKeyExpr.and(CONTEXT_SYNC_STATE.isEqualTo(SyncStatus.HasConflicts)), }); MenuRegistry.appendMenuItem(MenuId.EditorTitle, { command: { id: continueSyncCommandId, - title: localize('continue sync', "Configuration Sync: Continue"), + title: localize('continue sync', "Sync: Continue"), iconLocation: { light: SYNC_PUSH_LIGHT_ICON_URI, dark: SYNC_PUSH_DARK_ICON_URI From 216187d14ab01bc002819a2e229c1d7860807c54 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Wed, 13 Nov 2019 18:15:28 +0100 Subject: [PATCH 213/352] textfiles - inline confirmSave --- .../textfile/browser/textFileService.ts | 44 +++++++++---------- 1 file changed, 20 insertions(+), 24 deletions(-) diff --git a/src/vs/workbench/services/textfile/browser/textFileService.ts b/src/vs/workbench/services/textfile/browser/textFileService.ts index 3534496d5e622..f7409aa72ca81 100644 --- a/src/vs/workbench/services/textfile/browser/textFileService.ts +++ b/src/vs/workbench/services/textfile/browser/textFileService.ts @@ -506,7 +506,26 @@ export abstract class AbstractTextFileService extends Disposable implements ITex return ConfirmResult.DONT_SAVE; } - return promptSave(this.dialogService, resourcesToConfirm); + const message = resourcesToConfirm.length === 1 + ? nls.localize('saveChangesMessage', "Do you want to save the changes you made to {0}?", basename(resourcesToConfirm[0])) + : getConfirmMessage(nls.localize('saveChangesMessages', "Do you want to save the changes to the following {0} files?", resourcesToConfirm.length), resourcesToConfirm); + + const buttons: string[] = [ + resourcesToConfirm.length > 1 ? nls.localize({ key: 'saveAll', comment: ['&& denotes a mnemonic'] }, "&&Save All") : nls.localize({ key: 'save', comment: ['&& denotes a mnemonic'] }, "&&Save"), + nls.localize({ key: 'dontSave', comment: ['&& denotes a mnemonic'] }, "Do&&n't Save"), + nls.localize('cancel', "Cancel") + ]; + + const { choice } = await this.dialogService.show(Severity.Warning, message, buttons, { + cancelId: 2, + detail: nls.localize('saveChangesDetail', "Your changes will be lost if you don't save them.") + }); + + switch (choice) { + case 0: return ConfirmResult.SAVE; + case 1: return ConfirmResult.DONT_SAVE; + default: return ConfirmResult.CANCEL; + } } async confirmOverwrite(resource: URI): Promise { @@ -939,26 +958,3 @@ export abstract class AbstractTextFileService extends Disposable implements ITex super.dispose(); } } - -export async function promptSave(dialogService: IDialogService, resourcesToConfirm: readonly URI[]) { - const message = resourcesToConfirm.length === 1 - ? nls.localize('saveChangesMessage', "Do you want to save the changes you made to {0}?", basename(resourcesToConfirm[0])) - : getConfirmMessage(nls.localize('saveChangesMessages', "Do you want to save the changes to the following {0} files?", resourcesToConfirm.length), resourcesToConfirm); - - const buttons: string[] = [ - resourcesToConfirm.length > 1 ? nls.localize({ key: 'saveAll', comment: ['&& denotes a mnemonic'] }, "&&Save All") : nls.localize({ key: 'save', comment: ['&& denotes a mnemonic'] }, "&&Save"), - nls.localize({ key: 'dontSave', comment: ['&& denotes a mnemonic'] }, "Do&&n't Save"), - nls.localize('cancel', "Cancel") - ]; - - const { choice } = await dialogService.show(Severity.Warning, message, buttons, { - cancelId: 2, - detail: nls.localize('saveChangesDetail', "Your changes will be lost if you don't save them.") - }); - - switch (choice) { - case 0: return ConfirmResult.SAVE; - case 1: return ConfirmResult.DONT_SAVE; - default: return ConfirmResult.CANCEL; - } -} From 877f5625058c957cc5a1f6dbf41d11721c7638e2 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Wed, 13 Nov 2019 18:21:33 +0100 Subject: [PATCH 214/352] working copy - allow to get dirty copies --- .../workingCopy/common/workingCopyService.ts | 30 +++++++++++++++++++ .../test/common/workingCopyService.test.ts | 20 +++++++++++++ 2 files changed, 50 insertions(+) diff --git a/src/vs/workbench/services/workingCopy/common/workingCopyService.ts b/src/vs/workbench/services/workingCopy/common/workingCopyService.ts index 074a783029151..fe2f33adfa318 100644 --- a/src/vs/workbench/services/workingCopy/common/workingCopyService.ts +++ b/src/vs/workbench/services/workingCopy/common/workingCopyService.ts @@ -50,6 +50,8 @@ export interface IWorkingCopyService { isDirty(resource: URI): boolean; + getDirty(...resources: URI[]): IWorkingCopy[]; + //#endregion @@ -69,6 +71,34 @@ export class WorkingCopyService extends Disposable implements IWorkingCopyServic private readonly _onDidChangeDirty = this._register(new Emitter()); readonly onDidChangeDirty = this._onDidChangeDirty.event; + getDirty(...resources: URI[]): IWorkingCopy[] { + const dirtyWorkingCopies: IWorkingCopy[] = []; + + // Specific resource(s) + if (resources.length > 0) { + for (const resource of resources) { + this.fillDirty(this.mapResourceToWorkingCopy.get(resource.toString()), dirtyWorkingCopies); + } + } + + // All resources + else { + this.fillDirty(this.workingCopies, dirtyWorkingCopies); + } + + return dirtyWorkingCopies; + } + + private fillDirty(workingCopies: Set | undefined, target: IWorkingCopy[]): void { + if (workingCopies) { + for (const workingCopy of workingCopies) { + if (workingCopy.isDirty()) { + target.push(workingCopy); + } + } + } + } + isDirty(resource: URI): boolean { const workingCopies = this.mapResourceToWorkingCopy.get(resource.toString()); if (workingCopies) { diff --git a/src/vs/workbench/services/workingCopy/test/common/workingCopyService.test.ts b/src/vs/workbench/services/workingCopy/test/common/workingCopyService.test.ts index a7797845a1755..7110cd285820e 100644 --- a/src/vs/workbench/services/workingCopy/test/common/workingCopyService.test.ts +++ b/src/vs/workbench/services/workingCopy/test/common/workingCopyService.test.ts @@ -56,6 +56,8 @@ suite('WorkingCopyService', () => { assert.equal(service.hasDirty, false); assert.equal(service.dirtyCount, 0); + assert.equal(service.getDirty().length, 0); + assert.equal(service.getDirty(URI.file('/'), URI.file('/some')).length, 0); assert.equal(service.isDirty(URI.file('/')), false); // resource 1 @@ -66,6 +68,8 @@ suite('WorkingCopyService', () => { assert.equal(service.dirtyCount, 0); assert.equal(service.isDirty(resource1), false); assert.equal(service.hasDirty, false); + assert.equal(service.getDirty(resource1).length, 0); + assert.equal(service.getDirty().length, 0); copy1.setDirty(true); @@ -74,6 +78,8 @@ suite('WorkingCopyService', () => { assert.equal(service.hasDirty, true); assert.equal(onDidChangeDirty.length, 1); assert.equal(onDidChangeDirty[0], copy1); + assert.equal(service.getDirty(resource1).length, 1); + assert.equal(service.getDirty().length, 1); copy1.setDirty(false); @@ -82,6 +88,8 @@ suite('WorkingCopyService', () => { assert.equal(service.hasDirty, false); assert.equal(onDidChangeDirty.length, 2); assert.equal(onDidChangeDirty[1], copy1); + assert.equal(service.getDirty(resource1).length, 0); + assert.equal(service.getDirty().length, 0); unregister1.dispose(); @@ -93,6 +101,8 @@ suite('WorkingCopyService', () => { assert.equal(service.dirtyCount, 1); assert.equal(service.isDirty(resource2), true); assert.equal(service.hasDirty, true); + assert.equal(service.getDirty(resource1, resource2).length, 1); + assert.equal(service.getDirty().length, 1); assert.equal(onDidChangeDirty.length, 3); assert.equal(onDidChangeDirty[2], copy2); @@ -102,6 +112,8 @@ suite('WorkingCopyService', () => { assert.equal(service.hasDirty, false); assert.equal(onDidChangeDirty.length, 4); assert.equal(onDidChangeDirty[3], copy2); + assert.equal(service.getDirty(resource1, resource2).length, 0); + assert.equal(service.getDirty().length, 0); }); test('registry - multiple copies on same resource', () => { @@ -123,23 +135,31 @@ suite('WorkingCopyService', () => { assert.equal(service.dirtyCount, 1); assert.equal(onDidChangeDirty.length, 1); assert.equal(service.isDirty(resource), true); + assert.equal(service.getDirty(resource).length, 1); + assert.equal(service.getDirty().length, 1); copy2.setDirty(true); assert.equal(service.dirtyCount, 2); assert.equal(onDidChangeDirty.length, 2); assert.equal(service.isDirty(resource), true); + assert.equal(service.getDirty(resource).length, 2); + assert.equal(service.getDirty().length, 2); unregister1.dispose(); assert.equal(service.dirtyCount, 1); assert.equal(onDidChangeDirty.length, 3); assert.equal(service.isDirty(resource), true); + assert.equal(service.getDirty(resource).length, 1); + assert.equal(service.getDirty().length, 1); unregister2.dispose(); assert.equal(service.dirtyCount, 0); assert.equal(onDidChangeDirty.length, 4); assert.equal(service.isDirty(resource), false); + assert.equal(service.getDirty(resource).length, 0); + assert.equal(service.getDirty().length, 0); }); }); From 8e7877bdc442f1e83a7fec51920d82b696139129 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Wed, 13 Nov 2019 19:04:14 +0100 Subject: [PATCH 215/352] Revert "opener service uses IOpener for its built-in openers" This reverts commit 283c952d3f9baade691bb4a0f4477774174cf7dc. --- .../editor/browser/services/openerService.ts | 142 ++++++++---------- 1 file changed, 62 insertions(+), 80 deletions(-) diff --git a/src/vs/editor/browser/services/openerService.ts b/src/vs/editor/browser/services/openerService.ts index 476f10ecf001a..48175adfb4272 100644 --- a/src/vs/editor/browser/services/openerService.ts +++ b/src/vs/editor/browser/services/openerService.ts @@ -16,69 +16,6 @@ import { CommandsRegistry, ICommandService } from 'vs/platform/commands/common/c import { IOpener, IOpenerService, IValidator, IExternalUriResolver, OpenOptions, ResolveExternalUriOptions, IResolvedExternalUri, IExternalOpener } from 'vs/platform/opener/common/opener'; import { EditorOpenContext } from 'vs/platform/editor/common/editor'; -class CommandOpener implements IOpener { - - constructor(@ICommandService private readonly _commandService: ICommandService) { } - - async open(uri: URI, ) { - // run command or bail out if command isn't known - if (!equalsIgnoreCase(uri.scheme, Schemas.command)) { - return false; - } - - if (!CommandsRegistry.getCommand(uri.path)) { - throw new Error(`command '${uri.path}' NOT known`); - } - - // execute as command - let args: any = []; - try { - args = parse(uri.query); - if (!Array.isArray(args)) { - args = [args]; - } - } catch (e) { - // ignore error - } - await this._commandService.executeCommand(uri.path, ...args); - return true; - } -} - -class EditorOpener implements IOpener { - - constructor(@ICodeEditorService private readonly _editorService: ICodeEditorService) { } - - async open(uri: URI, options?: OpenOptions): Promise { - - // finally open in editor - let selection: { startLineNumber: number; startColumn: number; } | undefined = undefined; - const match = /^L?(\d+)(?:,(\d+))?/.exec(uri.fragment); - if (match) { - // support file:///some/file.js#73,84 - // support file:///some/file.js#L73 - selection = { - startLineNumber: parseInt(match[1]), - startColumn: match[2] ? parseInt(match[2]) : 1 - }; - // remove fragment - uri = uri.with({ fragment: '' }); - } - - if (uri.scheme === Schemas.file) { - uri = resources.normalizePath(uri); // workaround for non-normalized paths (https://github.com/Microsoft/vscode/issues/12954) - } - - await this._editorService.openCodeEditor( - { resource: uri, options: { selection, context: options?.fromUserGesture ? EditorOpenContext.USER : EditorOpenContext.API } }, - this._editorService.getFocusedCodeEditor(), - options?.openToSide - ); - - return true; - } -} - export class OpenerService extends Disposable implements IOpenerService { _serviceBrand: undefined; @@ -89,8 +26,8 @@ export class OpenerService extends Disposable implements IOpenerService { private _externalOpener: IExternalOpener; constructor( - @ICodeEditorService editorService: ICodeEditorService, - @ICommandService commandService: ICommandService, + @ICodeEditorService private readonly _editorService: ICodeEditorService, + @ICommandService private readonly _commandService: ICommandService, ) { super(); @@ -98,26 +35,14 @@ export class OpenerService extends Disposable implements IOpenerService { this._externalOpener = { openExternal: href => { dom.windowOpenNoOpener(href); + return Promise.resolve(true); } }; - - // - this._openers.push({ // default: open externally - open: async (uri: URI, options: OpenOptions | undefined): Promise => { - const { scheme } = uri; - if (options?.openExternal || equalsIgnoreCase(scheme, Schemas.mailto) || equalsIgnoreCase(scheme, Schemas.http) || equalsIgnoreCase(scheme, Schemas.https)) { - return this._doOpenExternal(uri, options); - } - return false; - } - }); - this._openers.push(new CommandOpener(commandService)); // default: run command - this._openers.push(new EditorOpener(editorService)); // default: open editor } registerOpener(opener: IOpener): IDisposable { - const remove = this._openers.unshift(opener); + const remove = this._openers.push(opener); return { dispose: remove }; } @@ -160,7 +85,8 @@ export class OpenerService extends Disposable implements IOpenerService { } } - return false; + // use default openers + return this._doOpen(resource, options); } async resolveExternalUri(resource: URI, options?: ResolveExternalUriOptions): Promise { @@ -174,6 +100,62 @@ export class OpenerService extends Disposable implements IOpenerService { return { resolved: resource, dispose: () => { } }; } + private async _doOpen(resource: URI, options: OpenOptions | undefined): Promise { + const { scheme, path, query, fragment } = resource; + + if (options?.openExternal || equalsIgnoreCase(scheme, Schemas.mailto) || equalsIgnoreCase(scheme, Schemas.http) || equalsIgnoreCase(scheme, Schemas.https)) { + // open externally + return this._doOpenExternal(resource, options); + } + + if (equalsIgnoreCase(scheme, Schemas.command)) { + // run command or bail out if command isn't known + if (!CommandsRegistry.getCommand(path)) { + throw new Error(`command '${path}' NOT known`); + } + // execute as command + let args: any = []; + try { + args = parse(query); + if (!Array.isArray(args)) { + args = [args]; + } + } catch (e) { + // ignore error + } + + await this._commandService.executeCommand(path, ...args); + + return true; + } + + // finally open in editor + let selection: { startLineNumber: number; startColumn: number; } | undefined = undefined; + const match = /^L?(\d+)(?:,(\d+))?/.exec(fragment); + if (match) { + // support file:///some/file.js#73,84 + // support file:///some/file.js#L73 + selection = { + startLineNumber: parseInt(match[1]), + startColumn: match[2] ? parseInt(match[2]) : 1 + }; + // remove fragment + resource = resource.with({ fragment: '' }); + } + + if (resource.scheme === Schemas.file) { + resource = resources.normalizePath(resource); // workaround for non-normalized paths (https://github.com/Microsoft/vscode/issues/12954) + } + + await this._editorService.openCodeEditor( + { resource, options: { selection, context: options?.fromUserGesture ? EditorOpenContext.USER : EditorOpenContext.API } }, + this._editorService.getFocusedCodeEditor(), + options?.openToSide + ); + + return true; + } + private async _doOpenExternal(resource: URI, options: OpenOptions | undefined): Promise { const { resolved } = await this.resolveExternalUri(resource, options); From b9ca01d9c2aa7d958d1635c675087eedf97e5648 Mon Sep 17 00:00:00 2001 From: Jackson Kearl Date: Wed, 13 Nov 2019 11:09:37 -0800 Subject: [PATCH 216/352] Only delay progress indicator when triggered on type --- .../search/browser/patternInputWidget.ts | 8 +++---- .../contrib/search/browser/searchActions.ts | 2 +- .../contrib/search/browser/searchView.ts | 24 +++++++++---------- .../contrib/search/browser/searchWidget.ts | 10 ++++---- 4 files changed, 22 insertions(+), 22 deletions(-) diff --git a/src/vs/workbench/contrib/search/browser/patternInputWidget.ts b/src/vs/workbench/contrib/search/browser/patternInputWidget.ts index 0dd3066c394aa..014d39c99bdd9 100644 --- a/src/vs/workbench/contrib/search/browser/patternInputWidget.ts +++ b/src/vs/workbench/contrib/search/browser/patternInputWidget.ts @@ -43,8 +43,8 @@ export class PatternInputWidget extends Widget { private domNode!: HTMLElement; protected inputBox!: HistoryInputBox; - private _onSubmit = this._register(new Emitter()); - onSubmit: CommonEvent = this._onSubmit.event; + private _onSubmit = this._register(new Emitter()); + onSubmit: CommonEvent = this._onSubmit.event; private _onCancel = this._register(new Emitter()); onCancel: CommonEvent = this._onCancel.event; @@ -152,7 +152,7 @@ export class PatternInputWidget extends Widget { this._register(this.inputBox.onDidChange(() => { if (this.searchConfig.searchOnType) { this._onCancel.fire(); - this.searchOnTypeDelayer.trigger(() => this._onSubmit.fire(), this.searchConfig.searchOnTypeDebouncePeriod); + this.searchOnTypeDelayer.trigger(() => this._onSubmit.fire(false), this.searchConfig.searchOnTypeDebouncePeriod); } })); @@ -170,7 +170,7 @@ export class PatternInputWidget extends Widget { private onInputKeyUp(keyboardEvent: IKeyboardEvent) { switch (keyboardEvent.keyCode) { case KeyCode.Enter: - this._onSubmit.fire(); + this._onSubmit.fire(true); return; case KeyCode.Escape: this._onCancel.fire(); diff --git a/src/vs/workbench/contrib/search/browser/searchActions.ts b/src/vs/workbench/contrib/search/browser/searchActions.ts index 669a16aa3b997..b6fe2c25e12c2 100644 --- a/src/vs/workbench/contrib/search/browser/searchActions.ts +++ b/src/vs/workbench/contrib/search/browser/searchActions.ts @@ -275,7 +275,7 @@ export class RefreshAction extends Action { run(): Promise { const searchView = getSearchView(this.viewletService, this.panelService); if (searchView) { - searchView.onQueryChanged(); + searchView.onQueryChanged(false); } return Promise.resolve(); diff --git a/src/vs/workbench/contrib/search/browser/searchView.ts b/src/vs/workbench/contrib/search/browser/searchView.ts index 48f78ae2f79d9..bd2d3c226e44d 100644 --- a/src/vs/workbench/contrib/search/browser/searchView.ts +++ b/src/vs/workbench/contrib/search/browser/searchView.ts @@ -268,7 +268,7 @@ export class SearchView extends ViewletPanel { this.inputPatternIncludes.setValue(patternIncludes); - this.inputPatternIncludes.onSubmit(() => this.onQueryChanged(true)); + this.inputPatternIncludes.onSubmit(triggeredOnType => this.onQueryChanged(true, triggeredOnType)); this.inputPatternIncludes.onCancel(() => this.cancelSearch(false)); this.trackInputBox(this.inputPatternIncludes.inputFocusTracker, this.inputPatternIncludesFocused); @@ -284,7 +284,7 @@ export class SearchView extends ViewletPanel { this.inputPatternExcludes.setValue(patternExclusions); this.inputPatternExcludes.setUseExcludesAndIgnoreFiles(useExcludesAndIgnoreFiles); - this.inputPatternExcludes.onSubmit(() => this.onQueryChanged(true)); + this.inputPatternExcludes.onSubmit(triggeredOnType => this.onQueryChanged(true, triggeredOnType)); this.inputPatternExcludes.onCancel(() => this.cancelSearch(false)); this.inputPatternExcludes.onChangeIgnoreBox(() => this.onQueryChanged(true)); this.trackInputBox(this.inputPatternExcludes.inputFocusTracker, this.inputPatternExclusionsFocused); @@ -386,7 +386,7 @@ export class SearchView extends ViewletPanel { this.searchWidget.toggleReplace(true); } - this._register(this.searchWidget.onSearchSubmit(() => this.onQueryChanged())); + this._register(this.searchWidget.onSearchSubmit(triggeredOnType => this.onQueryChanged(false, triggeredOnType))); this._register(this.searchWidget.onSearchCancel(({ focus }) => this.cancelSearch(focus))); this._register(this.searchWidget.searchInput.onDidOptionChange(() => this.onQueryChanged(true))); @@ -800,7 +800,7 @@ export class SearchView extends ViewletPanel { } this.searchWidget.setValue(selectedText, true); updatedText = true; - this.onQueryChanged(); + this.onQueryChanged(false); } } @@ -1155,7 +1155,7 @@ export class SearchView extends ViewletPanel { this.searchWidget.focus(false); } - onQueryChanged(preserveFocus?: boolean): void { + onQueryChanged(preserveFocus: boolean, triggeredOnType = false): void { if (!this.searchWidget.searchInput.inputBox.isInputValid()) { return; } @@ -1221,7 +1221,7 @@ export class SearchView extends ViewletPanel { } this.validateQuery(query).then(() => { - this.onQueryTriggered(query, options, excludePatternText, includePatternText); + this.onQueryTriggered(query, options, excludePatternText, includePatternText, triggeredOnType); if (!preserveFocus) { this.searchWidget.focus(false); // focus back to input field @@ -1251,7 +1251,7 @@ export class SearchView extends ViewletPanel { }); } - private onQueryTriggered(query: ITextQuery, options: ITextQueryBuilderOptions, excludePatternText: string, includePatternText: string): void { + private onQueryTriggered(query: ITextQuery, options: ITextQueryBuilderOptions, excludePatternText: string, includePatternText: string, triggeredOnType: boolean): void { this.addToSearchHistoryDelayer.trigger(() => this.searchWidget.searchInput.onSearchSubmit()); this.inputPatternExcludes.onSearchSubmit(); this.inputPatternIncludes.onSearchSubmit(); @@ -1259,13 +1259,13 @@ export class SearchView extends ViewletPanel { this.viewModel.cancelSearch(); this.currentSearchQ = this.currentSearchQ - .then(() => this.doSearch(query, options, excludePatternText, includePatternText)) + .then(() => this.doSearch(query, options, excludePatternText, includePatternText, triggeredOnType)) .then(() => undefined, () => undefined); } - private doSearch(query: ITextQuery, options: ITextQueryBuilderOptions, excludePatternText: string, includePatternText: string): Thenable { + private doSearch(query: ITextQuery, options: ITextQueryBuilderOptions, excludePatternText: string, includePatternText: string, triggeredOnType: boolean): Thenable { let progressComplete: () => void; - this.progressService.withProgress({ location: VIEWLET_ID, delay: 300 }, _progress => { + this.progressService.withProgress({ location: VIEWLET_ID, delay: triggeredOnType ? 300 : 0 }, _progress => { return new Promise(resolve => progressComplete = resolve); }); @@ -1335,7 +1335,7 @@ export class SearchView extends ViewletPanel { const searchAgainLink = dom.append(p, $('a.pointer.prominent', undefined, nls.localize('rerunSearch.message', "Search again"))); this.messageDisposables.push(dom.addDisposableListener(searchAgainLink, dom.EventType.CLICK, (e: MouseEvent) => { dom.EventHelper.stop(e, false); - this.onQueryChanged(); + this.onQueryChanged(false); })); } else if (hasIncludes || hasExcludes) { const searchAgainLink = dom.append(p, $('a.pointer.prominent', { tabindex: 0 }, nls.localize('rerunSearchInAll.message', "Search again in all files"))); @@ -1345,7 +1345,7 @@ export class SearchView extends ViewletPanel { this.inputPatternExcludes.setValue(''); this.inputPatternIncludes.setValue(''); - this.onQueryChanged(); + this.onQueryChanged(false); })); } else { const openSettingsLink = dom.append(p, $('a.pointer.prominent', { tabindex: 0 }, nls.localize('openSettings.message', "Open Settings"))); diff --git a/src/vs/workbench/contrib/search/browser/searchWidget.ts b/src/vs/workbench/contrib/search/browser/searchWidget.ts index d3c846bd0dd74..a7ebbd9cb1909 100644 --- a/src/vs/workbench/contrib/search/browser/searchWidget.ts +++ b/src/vs/workbench/contrib/search/browser/searchWidget.ts @@ -121,8 +121,8 @@ export class SearchWidget extends Widget { private ignoreGlobalFindBufferOnNextFocus = false; private previousGlobalFindBufferValue: string | null = null; - private _onSearchSubmit = this._register(new Emitter()); - readonly onSearchSubmit: Event = this._onSearchSubmit.event; + private _onSearchSubmit = this._register(new Emitter()); + readonly onSearchSubmit: Event = this._onSearchSubmit.event; private _onSearchCancel = this._register(new Emitter<{ focus: boolean }>()); readonly onSearchCancel: Event<{ focus: boolean }> = this._onSearchCancel.event; @@ -454,7 +454,7 @@ export class SearchWidget extends Widget { this.temporarilySkipSearchOnChange = false; } else { this._onSearchCancel.fire({ focus: false }); - this._searchDelayer.trigger((() => this.submitSearch()), this.searchConfiguration.searchOnTypeDebouncePeriod); + this._searchDelayer.trigger((() => this.submitSearch(true)), this.searchConfiguration.searchOnTypeDebouncePeriod); } } } @@ -563,7 +563,7 @@ export class SearchWidget extends Widget { } } - private submitSearch(): void { + private submitSearch(triggeredOnType = false): void { this.searchInput.validate(); if (!this.searchInput.inputBox.isInputValid()) { return; @@ -574,7 +574,7 @@ export class SearchWidget extends Widget { if (value && useGlobalFindBuffer) { this.clipboardServce.writeFindText(value); } - this._onSearchSubmit.fire(); + this._onSearchSubmit.fire(triggeredOnType); } dispose(): void { From 607df9880f3ddfa949422b7e76aa58be9fb582a7 Mon Sep 17 00:00:00 2001 From: Jackson Kearl Date: Wed, 13 Nov 2019 11:30:46 -0800 Subject: [PATCH 217/352] Add action to toggle search on type --- .../search/browser/search.contribution.ts | 3 ++- .../contrib/search/browser/searchActions.ts | 24 +++++++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/search/browser/search.contribution.ts b/src/vs/workbench/contrib/search/browser/search.contribution.ts index e6b8aea934658..7343939e042ad 100644 --- a/src/vs/workbench/contrib/search/browser/search.contribution.ts +++ b/src/vs/workbench/contrib/search/browser/search.contribution.ts @@ -41,7 +41,7 @@ import { ExplorerFolderContext, ExplorerRootContext, FilesExplorerFocusCondition import { OpenAnythingHandler } from 'vs/workbench/contrib/search/browser/openAnythingHandler'; import { OpenSymbolHandler } from 'vs/workbench/contrib/search/browser/openSymbolHandler'; import { registerContributions as replaceContributions } from 'vs/workbench/contrib/search/browser/replaceContributions'; -import { clearHistoryCommand, ClearSearchResultsAction, CloseReplaceAction, CollapseDeepestExpandedLevelAction, copyAllCommand, copyMatchCommand, copyPathCommand, FocusNextInputAction, FocusNextSearchResultAction, FocusPreviousInputAction, FocusPreviousSearchResultAction, focusSearchListCommand, getSearchView, openSearchView, OpenSearchViewletAction, RefreshAction, RemoveAction, ReplaceAction, ReplaceAllAction, ReplaceAllInFolderAction, ReplaceInFilesAction, toggleCaseSensitiveCommand, toggleRegexCommand, toggleWholeWordCommand, FindInFilesCommand } from 'vs/workbench/contrib/search/browser/searchActions'; +import { clearHistoryCommand, ClearSearchResultsAction, CloseReplaceAction, CollapseDeepestExpandedLevelAction, copyAllCommand, copyMatchCommand, copyPathCommand, FocusNextInputAction, FocusNextSearchResultAction, FocusPreviousInputAction, FocusPreviousSearchResultAction, focusSearchListCommand, getSearchView, openSearchView, OpenSearchViewletAction, RefreshAction, RemoveAction, ReplaceAction, ReplaceAllAction, ReplaceAllInFolderAction, ReplaceInFilesAction, toggleCaseSensitiveCommand, toggleRegexCommand, toggleWholeWordCommand, FindInFilesCommand, ToggleSearchOnTypeAction } from 'vs/workbench/contrib/search/browser/searchActions'; import { SearchPanel } from 'vs/workbench/contrib/search/browser/searchPanel'; import { SearchView } from 'vs/workbench/contrib/search/browser/searchView'; import { SearchViewlet } from 'vs/workbench/contrib/search/browser/searchViewlet'; @@ -619,6 +619,7 @@ KeybindingsRegistry.registerCommandAndKeybindingRule(objects.assign({ registry.registerWorkbenchAction(new SyncActionDescriptor(CollapseDeepestExpandedLevelAction, CollapseDeepestExpandedLevelAction.ID, CollapseDeepestExpandedLevelAction.LABEL), 'Search: Collapse All', category); registry.registerWorkbenchAction(new SyncActionDescriptor(ShowAllSymbolsAction, ShowAllSymbolsAction.ID, ShowAllSymbolsAction.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.KEY_T }), 'Go to Symbol in Workspace...'); +registry.registerWorkbenchAction(new SyncActionDescriptor(ToggleSearchOnTypeAction, ToggleSearchOnTypeAction.ID, ToggleSearchOnTypeAction.LABEL), 'Search: Toggle Search on Type', category); registry.registerWorkbenchAction(new SyncActionDescriptor(RefreshAction, RefreshAction.ID, RefreshAction.LABEL), 'Search: Refresh', category); registry.registerWorkbenchAction(new SyncActionDescriptor(ClearSearchResultsAction, ClearSearchResultsAction.ID, ClearSearchResultsAction.LABEL), 'Search: Clear Search Results', category); diff --git a/src/vs/workbench/contrib/search/browser/searchActions.ts b/src/vs/workbench/contrib/search/browser/searchActions.ts index b6fe2c25e12c2..8cb3ff896bef1 100644 --- a/src/vs/workbench/contrib/search/browser/searchActions.ts +++ b/src/vs/workbench/contrib/search/browser/searchActions.ts @@ -251,6 +251,30 @@ export class CloseReplaceAction extends Action { } } +// --- Toggle Search On Type + +export class ToggleSearchOnTypeAction extends Action { + + static readonly ID = 'workbench.action.toggleSearchOnType'; + static readonly LABEL = nls.localize('toggleTabs', "Toggle Search on Type"); + + private static readonly searchOnTypeKey = 'search.searchOnType'; + + constructor( + id: string, + label: string, + @IConfigurationService private readonly configurationService: IConfigurationService + ) { + super(id, label); + } + + run(): Promise { + const searchOnType = this.configurationService.getValue(ToggleSearchOnTypeAction.searchOnTypeKey); + return this.configurationService.updateValue(ToggleSearchOnTypeAction.searchOnTypeKey, !searchOnType); + } +} + + export class RefreshAction extends Action { static readonly ID: string = 'search.action.refreshSearchResults'; From 92caa97a1af10de2f371c21c8c84c94d4dacb658 Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Wed, 13 Nov 2019 12:33:52 -0800 Subject: [PATCH 218/352] Update distro --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 7ec46913bfc60..28c243771debd 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "code-oss-dev", "version": "1.41.0", - "distro": "be6ad88ea0214dfdb03b943bef28e7a5c9fc2e4b", + "distro": "403ab44be562c63a0cde1969fd8f5b45ff51709c", "author": { "name": "Microsoft Corporation" }, From a77da1b1d88ce377d6a189a60b40030fee4569b1 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Wed, 13 Nov 2019 14:42:42 -0800 Subject: [PATCH 219/352] For #81574 (#84669) Our code currently uses the `IConstructorSignature` types in a two main ways: - As argument types in functions that take a service constructor. - As return types or property types when we expose a service constructor in the API This first usage is not valid with strict function types. The reason is that the `IConstructorSignature` types takes a rest array of `...services: BrandedService[]` , while the concrete constructors you pass in use actual services. With strict function types, you cannot convert the concrete constructor type to an `IConstructorSignature` because this would drop important type information that the implementation needs. As an example ```ts class Foo { constructor(@ILogService service: ILogService) {} } registerFoo(Foo); // The type of `ctor` inlines `IConstructorSignature0` function registerFoo(ctor: { new(....serivces: BrandedService[]): Foo}) { // When registerFoo(Foo) is called, the implementation here would need to know that // ctor needs to be invoked with exactly one `ILogService`. However the type of `IConstructorSignature0` // does not express this. Strict function types therefore disallows this conversion } ``` To fix this, I have converted a few places were we were taking `IConstructorSignature` arguments so that they preserve the full type of the constructor. This fixed over half of our 900 strict function type errors. Unfortunatly I can not figure out a more elegant way to express this besides inlining the types However, even after this change, we still need to figure out how to deal with: - Places in the code where `IConstructorSignature` is exposed as a return type or object property - How to deal with all of our descriptor types (such as `SyncActionDescriptor`) --- src/vs/editor/browser/editorExtensions.ts | 6 +++--- src/vs/platform/instantiation/common/extensions.ts | 4 ++-- src/vs/platform/instantiation/common/instantiation.ts | 5 +++-- src/vs/workbench/api/common/extHostCustomers.ts | 6 +++--- src/vs/workbench/browser/actions.ts | 4 ++-- src/vs/workbench/common/contributions.ts | 9 ++++----- 6 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/vs/editor/browser/editorExtensions.ts b/src/vs/editor/browser/editorExtensions.ts index 8f2d7c90482f3..1b81608b01366 100644 --- a/src/vs/editor/browser/editorExtensions.ts +++ b/src/vs/editor/browser/editorExtensions.ts @@ -16,7 +16,7 @@ import { ITextModelService } from 'vs/editor/common/services/resolverService'; import { MenuId, MenuRegistry } from 'vs/platform/actions/common/actions'; import { CommandsRegistry, ICommandHandlerDescription } from 'vs/platform/commands/common/commands'; import { ContextKeyExpr, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; -import { IConstructorSignature1, ServicesAccessor as InstantiationServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; +import { IConstructorSignature1, ServicesAccessor as InstantiationServicesAccessor, BrandedService } from 'vs/platform/instantiation/common/instantiation'; import { IKeybindings, KeybindingsRegistry } from 'vs/platform/keybinding/common/keybindingsRegistry'; import { Registry } from 'vs/platform/registry/common/platform'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; @@ -303,7 +303,7 @@ export function registerInstantiatedEditorAction(editorAction: EditorAction): vo EditorContributionRegistry.INSTANCE.registerEditorAction(editorAction); } -export function registerEditorContribution(id: string, ctor: IEditorContributionCtor): void { +export function registerEditorContribution(id: string, ctor: { new(editor: ICodeEditor, ...services: Services): IEditorContribution }): void { EditorContributionRegistry.INSTANCE.registerEditorContribution(id, ctor); } @@ -355,7 +355,7 @@ class EditorContributionRegistry { this.editorCommands = Object.create(null); } - public registerEditorContribution(id: string, ctor: IEditorContributionCtor): void { + public registerEditorContribution(id: string, ctor: { new(editor: ICodeEditor, ...services: Services): IEditorContribution }): void { this.editorContributions.push({ id, ctor }); } diff --git a/src/vs/platform/instantiation/common/extensions.ts b/src/vs/platform/instantiation/common/extensions.ts index 5957b7924f51b..938b18b2938b0 100644 --- a/src/vs/platform/instantiation/common/extensions.ts +++ b/src/vs/platform/instantiation/common/extensions.ts @@ -4,11 +4,11 @@ *--------------------------------------------------------------------------------------------*/ import { SyncDescriptor } from './descriptors'; -import { ServiceIdentifier, IConstructorSignature0 } from './instantiation'; +import { ServiceIdentifier, BrandedService } from './instantiation'; const _registry: [ServiceIdentifier, SyncDescriptor][] = []; -export function registerSingleton(id: ServiceIdentifier, ctor: IConstructorSignature0, supportsDelayedInstantiation?: boolean): void { +export function registerSingleton(id: ServiceIdentifier, ctor: { new(...services: Services): T }, supportsDelayedInstantiation?: boolean): void { _registry.push([id, new SyncDescriptor(ctor, [], supportsDelayedInstantiation)]); } diff --git a/src/vs/platform/instantiation/common/instantiation.ts b/src/vs/platform/instantiation/common/instantiation.ts index 926d3c4653f7d..10ff5a25051df 100644 --- a/src/vs/platform/instantiation/common/instantiation.ts +++ b/src/vs/platform/instantiation/common/instantiation.ts @@ -22,7 +22,7 @@ export namespace _util { // --- interfaces ------ -type BrandedService = { _serviceBrand: undefined }; +export type BrandedService = { _serviceBrand: undefined }; export interface IConstructorSignature0 { new(...services: BrandedService[]): T; @@ -101,7 +101,8 @@ export interface IInstantiationService { createInstance(descriptor: descriptors.SyncDescriptor7, a1: A1, a2: A2, a3: A3, a4: A4, a5: A5, a6: A6, a7: A7): T; createInstance(descriptor: descriptors.SyncDescriptor8, a1: A1, a2: A2, a3: A3, a4: A4, a5: A5, a6: A6, a7: A7, a8: A8): T; - createInstance any, R extends InstanceType>(t: Ctor, ...args: GetLeadingNonServiceArgs>): R; + createInstance any, R extends InstanceType>(t: Ctor, ...args: GetLeadingNonServiceArgs>): R; + createInstance any, R extends InstanceType>(t: Ctor): R; /** * diff --git a/src/vs/workbench/api/common/extHostCustomers.ts b/src/vs/workbench/api/common/extHostCustomers.ts index 1ce450c4c2a08..298b2354972a1 100644 --- a/src/vs/workbench/api/common/extHostCustomers.ts +++ b/src/vs/workbench/api/common/extHostCustomers.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { IDisposable } from 'vs/base/common/lifecycle'; -import { IConstructorSignature1 } from 'vs/platform/instantiation/common/instantiation'; +import { IConstructorSignature1, BrandedService } from 'vs/platform/instantiation/common/instantiation'; import { IExtHostContext } from 'vs/workbench/api/common/extHost.protocol'; import { ProxyIdentifier } from 'vs/workbench/services/extensions/common/proxyIdentifier'; @@ -13,12 +13,12 @@ export type IExtHostNamedCustomer = [ProxyIdentifier, export type IExtHostCustomerCtor = IConstructorSignature1; export function extHostNamedCustomer(id: ProxyIdentifier) { - return function (ctor: IExtHostCustomerCtor): void { + return function (ctor: { new(context: IExtHostContext, ...services: Services): T }): void { ExtHostCustomersRegistryImpl.INSTANCE.registerNamedCustomer(id, ctor); }; } -export function extHostCustomer(ctor: IExtHostCustomerCtor): void { +export function extHostCustomer(ctor: { new(context: IExtHostContext, ...services: Services): T }): void { ExtHostCustomersRegistryImpl.INSTANCE.registerCustomer(ctor); } diff --git a/src/vs/workbench/browser/actions.ts b/src/vs/workbench/browser/actions.ts index 2cf27b60ae674..eaa70be455d6a 100644 --- a/src/vs/workbench/browser/actions.ts +++ b/src/vs/workbench/browser/actions.ts @@ -7,7 +7,7 @@ import { Registry } from 'vs/platform/registry/common/platform'; import { IAction } from 'vs/base/common/actions'; import { Separator } from 'vs/base/browser/ui/actionbar/actionbar'; import { ITree, IActionProvider } from 'vs/base/parts/tree/browser/tree'; -import { IInstantiationService, IConstructorSignature0, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; +import { IInstantiationService, IConstructorSignature0, ServicesAccessor, BrandedService } from 'vs/platform/instantiation/common/instantiation'; /** * The action bar contributor allows to add actions to an actionbar in a given context. @@ -134,7 +134,7 @@ export interface IActionBarRegistry { * Registers an Actionbar contributor. It will be called to contribute actions to all the action bars * that are used in the Workbench in the given scope. */ - registerActionBarContributor(scope: string, ctor: IConstructorSignature0): void; + registerActionBarContributor(scope: string, ctor: { new(...services: Services): ActionBarContributor }): void; /** * Returns an array of registered action bar contributors known to the workbench for the given scope. diff --git a/src/vs/workbench/common/contributions.ts b/src/vs/workbench/common/contributions.ts index e2a4ca4d3214c..e5b8cbc867990 100644 --- a/src/vs/workbench/common/contributions.ts +++ b/src/vs/workbench/common/contributions.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { IInstantiationService, IConstructorSignature0, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; +import { IInstantiationService, IConstructorSignature0, ServicesAccessor, BrandedService } from 'vs/platform/instantiation/common/instantiation'; import { ILifecycleService, LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle'; import { Registry } from 'vs/platform/registry/common/platform'; import { runWhenIdle, IdleDeadline } from 'vs/base/common/async'; @@ -19,7 +19,7 @@ export namespace Extensions { export const Workbench = 'workbench.contributions.kind'; } -export type IWorkbenchContributionSignature = IConstructorSignature0; +type IWorkbenchContributionSignature = new (...services: Service) => IWorkbenchContribution; export interface IWorkbenchContributionsRegistry { @@ -29,7 +29,7 @@ export interface IWorkbenchContributionsRegistry { * * @param phase the lifecycle phase when to instantiate the contribution. */ - registerWorkbenchContribution(contribution: IWorkbenchContributionSignature, phase: LifecyclePhase): void; + registerWorkbenchContribution(contribution: IWorkbenchContributionSignature, phase: LifecyclePhase): void; /** * Starts the registry by providing the required services. @@ -43,8 +43,7 @@ class WorkbenchContributionsRegistry implements IWorkbenchContributionsRegistry private readonly toBeInstantiated: Map[]> = new Map[]>(); - registerWorkbenchContribution(ctor: IWorkbenchContributionSignature, phase: LifecyclePhase = LifecyclePhase.Starting): void { - + registerWorkbenchContribution(ctor: { new(...services: Services): IWorkbenchContribution }, phase: LifecyclePhase = LifecyclePhase.Starting): void { // Instantiate directly if we are already matching the provided phase if (this.instantiationService && this.lifecycleService && this.lifecycleService.phase >= phase) { this.instantiationService.createInstance(ctor); From 84c882df686a1045158ea3b3a3245aead8dad888 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Wed, 13 Nov 2019 14:51:06 -0800 Subject: [PATCH 220/352] Fix extHost crashing due to using `vscode` as a value (instead of only as types) --- src/vs/workbench/api/node/extHostDebugService.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/api/node/extHostDebugService.ts b/src/vs/workbench/api/node/extHostDebugService.ts index 82d87ead7998f..bffcbcddd2b36 100644 --- a/src/vs/workbench/api/node/extHostDebugService.ts +++ b/src/vs/workbench/api/node/extHostDebugService.ts @@ -155,10 +155,10 @@ export class ExtHostDebugService implements IExtHostDebugService, ExtHostDebugSe debug += `${sep}ref=${source.sourceReference}`; - return vscode.Uri.parse(debug); + return URI.parse(debug); } else if (source.path) { // src is just a local file path - return vscode.Uri.file(source.path); + return URI.file(source.path); } else { throw new Error(`cannot create uri from DAP 'source' object; properties 'path' and 'sourceReference' are both missing.`); } From 3091f55e3e1fb8d198192377d322afff33d3b44b Mon Sep 17 00:00:00 2001 From: Miguel Solorio Date: Wed, 13 Nov 2019 15:20:02 -0800 Subject: [PATCH 221/352] Add breakpoint color tokens --- .../ui/codiconLabel/codicon/codicon.css | 31 ++++-- .../ui/codiconLabel/codicon/codicon.ttf | Bin 46380 -> 46836 bytes .../browser/breakpointEditorContribution.ts | 9 +- .../contrib/debug/browser/breakpointsView.ts | 30 ++--- .../browser/debugCallStackContribution.ts | 90 ++++++++++++++- .../browser/media/debug.contribution.css | 103 +++--------------- .../debug/browser/media/debugViewlet.css | 13 ++- 7 files changed, 158 insertions(+), 118 deletions(-) diff --git a/src/vs/base/browser/ui/codiconLabel/codicon/codicon.css b/src/vs/base/browser/ui/codiconLabel/codicon/codicon.css index 753d70792994e..5fe22758599cc 100644 --- a/src/vs/base/browser/ui/codiconLabel/codicon/codicon.css +++ b/src/vs/base/browser/ui/codiconLabel/codicon/codicon.css @@ -5,7 +5,7 @@ @font-face { font-family: "codicon"; - src: url("./codicon.ttf?3443fb4013ab5a04c23a30f912dd6627") format("truetype"); + src: url("./codicon.ttf?d02baa177e0c5b865597b4e28fca9e07") format("truetype"); } .codicon[class*='codicon-'] { @@ -69,6 +69,9 @@ .codicon-eye-watch:before { content: "\ea70" } .codicon-circle-filled:before { content: "\ea71" } .codicon-primitive-dot:before { content: "\ea71" } +.codicon-debug-breakpoint:before { content: "\ea71" } +.codicon-debug-breakpoint-disabled:before { content: "\ea71" } +.codicon-debug-hint:before { content: "\ea71" } .codicon-primitive-square:before { content: "\ea72" } .codicon-edit:before { content: "\ea73" } .codicon-pencil:before { content: "\ea73" } @@ -162,12 +165,15 @@ .codicon-bold:before { content: "\eaa3" } .codicon-book:before { content: "\eaa4" } .codicon-bookmark:before { content: "\eaa5" } -.codicon-breakpoint-conditional-unverified:before { content: "\eaa6" } -.codicon-breakpoint-conditional:before { content: "\eaa7" } -.codicon-breakpoint-data-unverified:before { content: "\eaa8" } -.codicon-breakpoint-data:before { content: "\eaa9" } -.codicon-breakpoint-log-unverified:before { content: "\eaaa" } -.codicon-breakpoint-log:before { content: "\eaab" } +.codicon-debug-breakpoint-conditional-unverified:before { content: "\eaa6" } +.codicon-debug-breakpoint-conditional:before { content: "\eaa7" } +.codicon-debug-breakpoint-conditional-disabled:before { content: "\eaa7" } +.codicon-debug-breakpoint-data-unverified:before { content: "\eaa8" } +.codicon-debug-breakpoint-data:before { content: "\eaa9" } +.codicon-debug-breakpoint-data-disabled:before { content: "\eaa9" } +.codicon-debug-breakpoint-log-unverified:before { content: "\eaaa" } +.codicon-debug-breakpoint-log:before { content: "\eaab" } +.codicon-debug-breakpoint-log-disabled:before { content: "\eaab" } .codicon-briefcase:before { content: "\eaac" } .codicon-broadcast:before { content: "\eaad" } .codicon-browser:before { content: "\eaae" } @@ -185,6 +191,7 @@ .codicon-chrome-minimize:before { content: "\eaba" } .codicon-chrome-restore:before { content: "\eabb" } .codicon-circle-outline:before { content: "\eabc" } +.codicon-debug-breakpoint-unverified:before { content: "\eabc" } .codicon-circle-slash:before { content: "\eabd" } .codicon-circuit-board:before { content: "\eabe" } .codicon-clear-all:before { content: "\eabf" } @@ -198,8 +205,6 @@ .codicon-comment-discussion:before { content: "\eac7" } .codicon-compare-changes:before { content: "\eac8" } .codicon-credit-card:before { content: "\eac9" } -.codicon-current-and-breakpoint:before { content: "\eaca" } -.codicon-current:before { content: "\eacb" } .codicon-dash:before { content: "\eacc" } .codicon-dashboard:before { content: "\eacd" } .codicon-database:before { content: "\eace" } @@ -386,3 +391,11 @@ .codicon-list-flat:before { content: "\eb84" } .codicon-list-selection:before { content: "\eb85" } .codicon-list-tree:before { content: "\eb86" } +.codicon-debug-breakpoint-function-unverified:before { content: "\eb87" } +.codicon-debug-breakpoint-function:before { content: "\eb88" } +.codicon-debug-breakpoint-function-disabled:before { content: "\eb88" } +.codicon-debug-breakpoint-stackframe-active:before { content: "\eb89" } +.codicon-debug-breakpoint-stackframe-dot:before { content: "\eb8a" } +.codicon-debug-breakpoint-stackframe:before { content: "\eb8b" } +.codicon-debug-breakpoint-stackframe-focused:before { content: "\eb8b" } +.codicon-debug-breakpoint-unsupported:before { content: "\eb8c" } diff --git a/src/vs/base/browser/ui/codiconLabel/codicon/codicon.ttf b/src/vs/base/browser/ui/codiconLabel/codicon/codicon.ttf index ba3474205da690928d1da0baa9f557ae33a5b1d3..3af3dbb97c51f3979947e67df2d63717f4e4dd77 100644 GIT binary patch delta 5435 zcmaLb3s{s@8VB(I8E(VC0K#x_800d*fPxoLKt)6}GqSQWGcW1jfS?EjNM`1!l^MBZ z(Zy}sUALQ;tW3(x%*<}qcCj+EyP1`p)5VO+?V|hteBFI~9-rO8-}lZp^UdHlbIy7H z9~-r;=Udw;Bn|SJgcb(XtD0w*#F$^|k&$LfeA1 zJoW&U)bjxxRCn?IcFL}w*S=uMniD7Zeuse2dm5W(`IoM`Zx4`?4cI2k^Dk(zRbd04 zPvP+yP5ybcnd{x7mI4pd^8iOnb6fkg6TVM@wfu##!CSX`NBW?6EM5B1SMC|Hq8Phbn4#8y0or#aT1!45o&o!Euv@d94NOL!T(G2<2d6R+V7yotB)Hr~Nryo-H! z5Bu>xKEQ|g2p{894&Bdi5MSU+9LCqs_y*tN2!6m({D`0N3y$Ge{Ep)a%BJipQaMzV zidIe)({;q2Sm;)%%A?X$hRRe~%B!+fj>^TIxC?*A-58E?j6@|yp^Aeq{JzXc70*$@ z83i~wC#)OCy2f+Guhw%{0p=H#((v_Urr zjyvc%f+G-muE0RnMj&WyI4q&(2@X)`Cc&W!-7Gk0p*i6!9KO(;WEKu&=vIMktZjm0 z8=AA%!ch)AUvRubcL?Nji0CW1L!1QA3k0VFv~|`5C+kANDFS`9;ADYbBsguLuMwO; z(2E795_C{-Qb8{f*vPun!Y4V?pqB~GIp|Y3`=GBAoQKfY3(iRB<$`k)`Ub)24{e<( zalS%#3eH^Un*;|w^h&|m3_bl8Zio{bdX>N*thWkIcIev#r#-YaUWf|-^zDL60rVXL zJ*;;ME)Q#>pAD9BZ>``$0liLe$$(xjxOhNs5L`x}t3!D@Y0gm~761rk^v5pc0S zDv-#!Ng#=ppMTKWAelRx1yWeM1$whSF5qT;LLilOi-3pqNr5!htpe6ycuF9hb(=s2 z>(c_6)(G3q9fFtj8NnqIdWYa*3H_|#vI)IYZ~=w3<{NP-h2AB&s6sz4xV%EYAh^&% zzbLrmLce6;2;=Gt{j%UX482=$MTUMwaBYTuO>mWleqC_AhJHhE<%WJ!a1DpvBe_fjR*Z`pS3AO_0_XL{)^nSti0R6sTqk#TEuw_7h zDA+upKN4&s&>xE+I|}qCg1rU$Q^76+eL%3^Kz}CKd7uvp_8{ob1-lXSA;G=`{e@tM zg8ovlS3!Rz*tMV!Ti^d-p1q$tUkkP=Xf4>(pp9UAgZ@Ua(LsMJ*z%yi6KsCa-wU=u z=p%v+5&8$g)(Cx6ppoCd{!y@BLiY%EPUxQmdnokJ!U{F|7hwe%eN3>!LjOy!*Fyg) z*ma?Q6DLpXcity2?hk1Xu+re;}i@HFfoGh0VY;h z>#2zoj1(}v1j7YP{7L-p-^x1)f{6phC73;65(QHTOp;(8fk_rjCNL?283m@dU|NB3 z3+5J>RDm_D9>FXFlV*K+A)mS7Nq@d`#Fm~3H1 zXp$CVaf&LU=U^mcL=YrRtQE!n2~~E5vEcwHo}Y&43IEYf>9D?v|y-&86y}k zVa^f^nlNJpBPYz+7JmOspD^PDb12L?f{7HSS}>c!oGX}8Va5yQRhaVxlPk>mf*BTO zf?%43xlrH$>qUYI7bbWyH^i_DGf^=1!dxO4fMF&HMq!vs1w%2+WWjh0bD3aJhM6K5 znPH|1hG&>*f-xFqx(G5+!(1+ytzl*erfis*f_WRpFPOYxY6LSl%q+n)4igYK&RQ!J z&&|{cWn-N!l%2KS`u^(~$RfGZAe4i3j!;pobA^g#Z4}DMI!~w=)+V9iSeu3F#o8jQ zd~dE0DuK0CC>Otf(>1Docd27L}z!<*+UjysUw_R`3D`<~qSk9hmC{FM42> z3ts-f+#q-%gkfd{cZk-8RI=VAc*O*>QlP49Z?Z4AI>a4P60$nf5gG{X z2;C97C-h)wPgr85-Vy#n`0yYj-ydAQAJVXqP9l88ue>*baYYlX3Wir<^yN?4GvAz^<)k87rDk!!W<@kCoCoN^uUaP9Rv3bDjGCp(BeT`2OTT&6iq1VEILpeSG=(J z$l$WUYXfU!OJ|lYFMY6df0?IjUD>NcLx)xk4Gdj1bo0xLgHA6MQ|zF|blh>0UskJww`si>^ztk_cV+DOmH#*s%V`&JeX ztE{e^QaPt`*C_j_qEU-S9jmIYT2!^Qs%P}z(Gy3vkKR1`lQ9)zri?j$R^?d>yFKnF zLc4os>~?lH^lwq!Z}oAg;6x@(8^VCnVqZkD&r{}cx}DxZc}eo;A3ke6kJ4l>|F;td za-?#Px2gOIK?E>TB}WV?^+hCly>E;?ctKdWGu9btZDJyM%ZoU*7a4Aki1B#3-y5)_L;1Szd~mGIZp*Rd z+I+UWu8-Dj>-KI~q0&PG{z~`w+|blsIIFoS(9qt{+~jY}ICbEj_3mkjXB=p~UG^D|*3EC4Wxcv^ep5$nYeQW_ zZJ_u6JShFtFZgYJ@1X09qZ*rMXPxn2Tf2YO+`3l&IkC{sU(`{1>OD?7gVPQPG`FYz epSL*e?Bh?J{`{u4`7JHYt?jje?t>3iNB$d8jo42B delta 5014 zcmYk=4SbIE8VB&-|JnQdtG$`M+h)cLdoi;OBb6MLBtH145X?2S8yIq~nX+GckdhYG^czq6Sw9+WGSsUY}G~F~2%_ zbKJ<~z{VP0;NMWcped-On&*!;0m0AR+nHLL3d3uu>XVikH-;4dhyd`_0Y}a}IPQP- z0>5w*{{X&lIp5_M|Bgv*OE6EFl^qAnWRH$~uW81;?c(#n)eet~kFr_)0gr9)bS>rI z^1t{DE?Fflc7k2$+>OkT)pC!W=sf=Y%ka9Xm~M{p+=Y9v4{zdTyl6bI4PW44e1&|| z8z1xc^cikICZ5G4tia!qGsU=YDS}KKsxcX_;|V;5O(p&p74Su6k%;keUjZNNJSd@A{`m%hb;6*HU?lI z1|b)NF$6=AhXM>k5r(4}BT#};lwl-BVKmAy24isv#^Ewtj`6qx6YwWY#Fe-TSK}I7 zi|csH*JB!{<3`Lt1u8KURhWg@sKFe}#XL7^F(37Oe{SMMjaYytEW|BXj9YOVZpTtA z!*Vp^4%~^AxC^WBXWr=DXu)6bSG3|@tij*#03O6cSciXLJ^qOe_!l0*M*JI(Vl&sy z?#ap22h2f#;pc zALDEMjK2vqK_=LQm{1dD!c9cm&c}jc<4qrvU=mG|Nj53C4{f*~Yq=D?9~tRq!ns}o zoi!A+-8o)dp%eY1-S=>nRVuC}$V|mm1*uY8Uyy2r7g=X1t~tnT#nlJlR&sD1Lgpy0 zNXT5pwF#N0kk48RxSazREQFie!KDkSQ_g0Wdd1}o;r4TIVMDm(99-g%M#aSrS)jP= zA>7LjZUBgL6U40mS*Vc1)i1a3gt$E*ixf8sWU)dJ>k`Gy1G!ak8$oVU+)$9)6}J|I z``N)w25~EHH^?%DO{~iu{2})sq*?LxK<-f7mk{Tb6L%=&PQ|?nS*f^dA$KWEVO^!T zlOd}W_cY{g#YGQkQQYT{Y0mpk-13lCg`ZjPReT=EeToeM!k+73Yk;g#Y!ZEju|BR4&ALS)hSm9f5@K1mDmd@SlM2p4 z+NKcC`joT6ct9VXJgtzx+M$rhx?LfO^%;d^)@Kz`Sf5kua*!R0{SNZHV&{YGRP2F} z7Zkf8S6C-ch>a2A>>px_gzQpmmXMbe+a_eUVgrS|tk_B+uP8QE$g7I&6|zUM(L!ER zY`G9;CBDuT#qJAvL$MD-_9}K{$eW728S<85mxjEp*sme`6gxNM9mO6F*{|5mA@3^o zb;tpQGFJC{JP?~bWpDb66s=Zez^(ycg`AYUj>D9CZeSq1r0 zacV(MIPd=n-u+abe5E+bASV@v8suxm$psO`K?ku4Ggwb44nN2@ienIRT5%vkzEvEJ zkTVLi`2Ndxit`fkz2fAA{Gd2PA!ik*Ddb0md93FY2Q1_##Ze3CQ5?FEpOq7jKgECm>#rCUU;`9G18ksTe1Hv73=*)xije{~L^*xd zhF-+q|J{5LrkFTj!xgg!Y=mM8fsItmBe1;`lL>5;Vn%_DR!l3f?1&EL7T8$D1OpqV zm}Ovl^WV3M4XjCuK?pWkF%rS1D25~0RK=JCo2D3; zVEZb#H}gTdauT@BP|Q=XnTp8@wx43gg3VG)Td@5Va~Ev3VgiF5pqRyA2P&pA*c`=t z20O@k|9N0kgUwY8ZLotC;~VS{#UKYeR58-Q<|*eRhRs(@d9VeFc@MTwVK?hA#S92r zq?iWXu)}#m42H19iV+cZgko5PEm4e(u%(It61Ge+O2Up*43)5>6yqiAXvLrjTdo*6 zVaGV!{D%+l!C1u{3VVrSB845Nm`!0XRZOX{mnr5|*vl1@E9`j13=4aOVw#1WpqOi6 zCn_dfSof7Y5W_C)Rf@3}_G-ld3_D3N3d3Hb7>Z#hE5>8kYZZes>=ebw411koc!r&- z7^7jYS8gV1*c%kHHS9FSlnpywF>k}(sF=KAXDDWH*b2oo4qK_1%VB3KCUn>;#jFln zt(e+jXF2cxEZ+Tjp3GLpleI<}FV;EAc(cw`#)oyDGQO;}%J{L)SH_>UPMJW~dS!xG z8B(W}6CYiNa@golG9f}`zU{@%9?18;g z@dFV2?Mj{y*0!a^WVl;h+gf?f;R^53+@R? z3TX;C8=4)uFtk0)GpsnQHSBD7armGOnDwzSv8}NOV!Pu~;>N{ojO*$h*n52MO}!7tC&X9AZ;L1E%iNK9AhV}mOuxo{8?v&q zTCz^{pV+^-|EB&u*^${v+4~0!957+Pu7REd8wb9h6Q46TXKl{DK`Dcp-GjPvy>qj2 zt8zEy?#=ymaQ@(y!JR|WhpZcNeCYV0D~5LFMdjU)_j+D;-ue7J`R57(3kDZlRj{I9 zZ{eiEg@xM+PY(+nRy=I_u-2mRqVl4KqU}Xp!zT@I9e%brzIbx+o)H*PK4RI3y(3PQ z&mv5b&bp#xpCyVQJJHvMr{~%Y&1qEjh;Sw z^=K*gE^jYCH732IDef81j*5Z)ruZ7>I}iT92TDz}PhLTWPdvXuLqiK$0$I6QxwgR1 zo0E7Q3Zi{7oF7dhbYvvH71Z{5&cwFs1{HREm)&4GjtuHtXi_`YJ~r0Xc6{?rliW6D zOL9z9Wn*>4yoUNYbxi|i*4I_dX_`}CS5X_+wt7okSjZoKSXI$f5qsYgu_3{K_-1YW z?2h&At4u-E%$pk this.getContextMenuActions(candidate.breakpoint ? [candidate.breakpoint] : [], activeCodeEditor.getModel().uri, candidate.range.startLineNumber, candidate.range.startColumn); const inlineWidget = new InlineBreakpointWidget(activeCodeEditor, decorationId, cssClass, candidate.breakpoint, this.debugService, this.contextMenuService, contextMenuActions); @@ -543,6 +543,7 @@ class InlineBreakpointWidget implements IContentWidget, IDisposable { private create(cssClass: string | null | undefined): void { this.domNode = $('.inline-breakpoint-widget'); + this.domNode.classList.add('codicon'); if (cssClass) { this.domNode.classList.add(cssClass); } diff --git a/src/vs/workbench/contrib/debug/browser/breakpointsView.ts b/src/vs/workbench/contrib/debug/browser/breakpointsView.ts index 66102bb84fc84..a23fddadbb61a 100644 --- a/src/vs/workbench/contrib/debug/browser/breakpointsView.ts +++ b/src/vs/workbench/contrib/debug/browser/breakpointsView.ts @@ -346,7 +346,7 @@ class BreakpointsRenderer implements IListRenderer { if (focusedStackFrame) { collector.addRule(`.monaco-editor .view-overlays .debug-focused-stack-frame-line { background: ${focusedStackFrame}; }`); } + + const debugIconBreakpointColor = theme.getColor(debugIconBreakpointForeground); + if (debugIconBreakpointColor) { + collector.addRule(` + .monaco-workbench .codicon-debug-breakpoint, + .monaco-workbench .codicon-debug-hint:not(*[class*='codicon-debug-breakpoint']) , + .monaco-workbench .codicon-debug-breakpoint-stackframe-dot, + .monaco-workbench .codicon-debug-breakpoint.codicon-debug-breakpoint-stackframe-focused::after { + color: ${debugIconBreakpointColor} !important; + } + `); + } + + const debugIconBreakpointDisabledColor = theme.getColor(debugIconBreakpointDisabledForeground); + if (debugIconBreakpointDisabledColor) { + collector.addRule(` + .monaco-workbench .codicon[class*='-disabled'] { + color: ${debugIconBreakpointDisabledColor} !important; + } + `); + } + + const debugIconBreakpointUnverifiedColor = theme.getColor(debugIconBreakpointUnverifiedForeground); + if (debugIconBreakpointUnverifiedColor) { + collector.addRule(` + .monaco-workbench .codicon[class*='-unverified'] { + color: ${debugIconBreakpointUnverifiedColor} !important; + } + `); + } + + const debugIconBreakpointConditionalColor = theme.getColor(debugIconBreakpointConditionalForeground); + if (debugIconBreakpointConditionalColor) { + collector.addRule(` + .monaco-workbench .codicon-debug-breakpoint-conditional { + color: ${debugIconBreakpointConditionalColor} !important; + } + `); + } + + const debugIconBreakpointLogColor = theme.getColor(debugIconBreakpointLogForeground); + if (debugIconBreakpointLogColor) { + collector.addRule(` + .monaco-workbench .codicon-debug-breakpoint-log { + color: ${debugIconBreakpointLogColor} !important; + } + `); + } + + const debugIconBreakpointFunctionColor = theme.getColor(debugIconBreakpointFunctionForeground); + if (debugIconBreakpointFunctionColor) { + collector.addRule(` + .monaco-workbench .codicon-debug-breakpoint-function { + color: ${debugIconBreakpointFunctionColor} !important; + } + `); + } + + const debugIconBreakpointStackframeColor = theme.getColor(debugIconBreakpointStackframeForeground); + if (debugIconBreakpointStackframeColor) { + collector.addRule(` + .monaco-workbench .codicon-debug-breakpoint-stackframe, + .monaco-workbench .codicon-debug-breakpoint-stackframe-dot::after { + color: ${debugIconBreakpointStackframeColor} !important; + } + `); + } + + const debugIconBreakpointStackframeFocusedColor = theme.getColor(debugIconBreakpointStackframeFocusedForeground); + if (debugIconBreakpointStackframeFocusedColor) { + collector.addRule(` + .monaco-workbench .codicon-debug-breakpoint-stackframe-focused { + color: ${debugIconBreakpointStackframeFocusedColor} !important; + } + `); + } + }); const topStackFrameColor = registerColor('editor.stackFrameHighlightBackground', { dark: '#ffff0033', light: '#ffff6673', hc: '#fff600' }, localize('topStackFrameLineHighlight', 'Background color for the highlight of line at the top stack frame position.')); const focusedStackFrameColor = registerColor('editor.focusedStackFrameHighlightBackground', { dark: '#7abd7a4d', light: '#cee7ce73', hc: '#cee7ce' }, localize('focusedStackFrameLineHighlight', 'Background color for the highlight of line at focused stack frame position.')); + +const debugIconBreakpointForeground = registerColor('debugIcon.breakpointForeground', { dark: '#E51400', light: '#E51400', hc: '#E51400' }, localize('debugIcon.breakpointForeground', 'Icon color for breakpoints.')); +const debugIconBreakpointDisabledForeground = registerColor('debugIcon.breakpointDisabledForeground', { dark: '#848484', light: '#848484', hc: '#848484' }, localize('debugIcon.breakpointDisabledForeground', 'Icon color for disabled breakpoints.')); +const debugIconBreakpointUnverifiedForeground = registerColor('debugIcon.breakpointUnverifiedForeground', { dark: '#848484', light: '#848484', hc: '#848484' }, localize('debugIcon.breakpointUnverifiedForeground', 'Icon color for unverified breakpoints.')); +const debugIconBreakpointConditionalForeground = registerColor('debugIcon.breakpointConditionalForeground', { dark: debugIconBreakpointForeground, light: debugIconBreakpointForeground, hc: debugIconBreakpointForeground }, localize('debugIcon.breakpointConditionalForeground', 'Icon color for conditional breakpoints.')); +const debugIconBreakpointLogForeground = registerColor('debugIcon.breakpointLogForeground', { dark: debugIconBreakpointForeground, light: debugIconBreakpointForeground, hc: debugIconBreakpointForeground }, localize('debugIcon.breakpointLogForeground', 'Icon color for log breakpoints.')); +const debugIconBreakpointFunctionForeground = registerColor('debugIcon.breakpointFunctionForeground', { dark: debugIconBreakpointForeground, light: debugIconBreakpointForeground, hc: debugIconBreakpointForeground }, localize('debugIcon.breakpointFunctionForeground', 'Icon color for function breakpoints.')); +const debugIconBreakpointStackframeForeground = registerColor('debugIcon.breakpointStackframeForeground', { dark: '#FFCC00', light: '#FFCC00', hc: '#FFCC00' }, localize('debugIcon.breakpointStackframeForeground', 'Icon color for breakpoints.')); +const debugIconBreakpointStackframeFocusedForeground = registerColor('debugIcon.breakpointStackframeFocusedForeground', { dark: '#89D185', light: '#89D185', hc: '#89D185' }, localize('debugIcon.breakpointStackframeFocusedForeground', 'Icon color for breakpoints.')); diff --git a/src/vs/workbench/contrib/debug/browser/media/debug.contribution.css b/src/vs/workbench/contrib/debug/browser/media/debug.contribution.css index fd184092abdc8..b712940078246 100644 --- a/src/vs/workbench/contrib/debug/browser/media/debug.contribution.css +++ b/src/vs/workbench/contrib/debug/browser/media/debug.contribution.css @@ -3,45 +3,35 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -/* Activity Bar */ -.monaco-editor .debug-top-stack-frame-column::before { - background: url('current-arrow.svg') center center no-repeat; -} - -.debug-breakpoint-hint { - background: url('breakpoint-hint.svg') center center no-repeat; +.codicon-debug-hint { cursor: pointer; } -.debug-breakpoint-disabled, -.monaco-editor .inline-breakpoint-widget.debug-breakpoint-disabled { - background: url('breakpoint-disabled.svg') center center no-repeat; +.codicon-debug-hint:not(*[class*='codicon-debug-breakpoint']) { + opacity: .4 !important; } -.monaco-editor .inline-breakpoint-widget.debug-breakpoint-disabled:hover { - background: url('breakpoint-hint.svg') center center no-repeat; +/* overlapped icons */ +.inline-breakpoint-widget.codicon-debug-breakpoint-stackframe-dot::after { + position: absolute; + top: 0; + left: 0; } -.monaco-editor .inline-breakpoint-widget.line-start { - left: -0.45em !important; +.codicon-debug-breakpoint.codicon-debug-breakpoint-stackframe-focused::after { + position: absolute; } -.debug-breakpoint-unverified, -.monaco-editor .inline-breakpoint-widget.debug-breakpoint-unverified { - background: url('breakpoint-unverified.svg') center center no-repeat; +.inline-breakpoint-widget.codicon-debug-breakpoint-stackframe-dot::after { + content: "\eb8b"; } -.monaco-editor .debug-top-stack-frame { - background: url('current-arrow.svg') center center no-repeat; +.codicon-debug-breakpoint.codicon-debug-breakpoint-stackframe-focused::after { + content: "\eb8a"; } -.monaco-editor .debug-focused-stack-frame { - background: url('stackframe-arrow.svg') center center no-repeat; -} - -.debug-breakpoint, -.monaco-editor .inline-breakpoint-widget { - background: url('breakpoint.svg') center center no-repeat; +.monaco-editor .inline-breakpoint-widget.line-start { + left: -0.45em !important; } .monaco-editor .debug-breakpoint-placeholder::before, @@ -70,67 +60,6 @@ cursor: pointer; } -.debug-function-breakpoint { - background: url('breakpoint-function.svg') center center no-repeat; -} - -.debug-function-breakpoint-unverified { - background: url('breakpoint-function-unverified.svg') center center no-repeat; -} - -.debug-function-breakpoint-disabled { - background: url('breakpoint-function-disabled.svg') center center no-repeat; -} - -.debug-data-breakpoint { - background: url('breakpoint-data.svg') center center no-repeat; -} - -.debug-data-breakpoint-unverified { - background: url('breakpoint-data-unverified.svg') center center no-repeat; -} - -.debug-data-breakpoint-disabled { - background: url('breakpoint-data-disabled.svg') center center no-repeat; -} - -.debug-breakpoint-conditional, -.monaco-editor .inline-breakpoint-widget.debug-breakpoint-conditional { - background: url('breakpoint-conditional.svg') center center no-repeat; -} - -.debug-breakpoint-log, -.monaco-editor .inline-breakpoint-widget.debug-breakpoint-log { - background: url('breakpoint-log.svg') center center no-repeat; -} - -.debug-breakpoint-log-disabled, -.monaco-editor .inline-breakpoint-widget.debug-breakpoint-log-disabled { - background: url('breakpoint-log-disabled.svg') center center no-repeat; -} - -.debug-breakpoint-log-unverified, -.monaco-editor .inline-breakpoint-widget.debug-breakpoint-log-unverified { - background: url('breakpoint-log-unverified.svg') center center no-repeat; -} - -.debug-breakpoint-unsupported, -.monaco-editor .inline-breakpoint-widget.debug-breakpoint-unsupported { - background: url('breakpoint-unsupported.svg') center center no-repeat; -} - -.monaco-editor .debug-top-stack-frame.debug-breakpoint-and-top-stack-frame, -.monaco-editor .debug-breakpoint.debug-top-stack-frame, -.monaco-editor .debug-breakpoint-and-top-stack-frame-at-column { - background: url('current-and-breakpoint.svg') center center no-repeat; -} - -.monaco-editor .debug-focused-stack-frame.debug-breakpoint, -.monaco-editor .debug-focused-stack-frame.debug-breakpoint-conditional, -.monaco-editor .debug-focused-stack-frame.debug-breakpoint-log { - background: url('stackframe-and-breakpoint.svg') center center no-repeat; -} - /* Error editor */ .debug-error-editor:focus { outline: none !important; diff --git a/src/vs/workbench/contrib/debug/browser/media/debugViewlet.css b/src/vs/workbench/contrib/debug/browser/media/debugViewlet.css index 9847a8b1d06ac..185b8187d413a 100644 --- a/src/vs/workbench/contrib/debug/browser/media/debugViewlet.css +++ b/src/vs/workbench/contrib/debug/browser/media/debugViewlet.css @@ -78,6 +78,10 @@ color: #666; } +.debug-viewlet .monaco-list:focus .monaco-list-row.selected.focused .codicon { + color: inherit !important; +} + .debug-viewlet .disabled { opacity: 0.35; } @@ -333,10 +337,17 @@ flex-shrink: 0; } -.debug-viewlet .debug-breakpoints .breakpoint > .icon { +.debug-viewlet .debug-breakpoints .breakpoint > .codicon { width: 19px; height: 19px; min-width: 19px; + display: flex; + align-items: center; + justify-content: center; +} + +.debug-viewlet .debug-breakpoints .breakpoint > .codicon-debug-breakpoint-stackframe-dot::before { + content: "\ea71"; } .debug-viewlet .debug-breakpoints .breakpoint > .file-path { From 4fa83458cfefe8aa6f5eb505b0d6ecd4bfc1daba Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Wed, 13 Nov 2019 11:56:29 -0500 Subject: [PATCH 222/352] Aligns with bash version --- scripts/code.bat | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/scripts/code.bat b/scripts/code.bat index 0eb0eb0b342b8..770d37b7aece2 100644 --- a/scripts/code.bat +++ b/scripts/code.bat @@ -13,9 +13,8 @@ set NAMESHORT=%NAMESHORT: "=% set NAMESHORT=%NAMESHORT:"=%.exe set CODE=".build\electron\%NAMESHORT%" -:: Download Electron if needed -node build\lib\electron.js -if %errorlevel% neq 0 node .\node_modules\gulp\bin\gulp.js electron +:: Get electron +call yarn electron :: Manage built-in extensions if "%1"=="--builtin" goto builtin From 2cd1b8b8e298065e2e07c44b9bf725be978878c5 Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Wed, 13 Nov 2019 14:10:43 -0500 Subject: [PATCH 223/352] Removes calc's --- src/vs/workbench/browser/media/style.css | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/vs/workbench/browser/media/style.css b/src/vs/workbench/browser/media/style.css index 1491381e007b9..e458c9af828e8 100644 --- a/src/vs/workbench/browser/media/style.css +++ b/src/vs/workbench/browser/media/style.css @@ -57,8 +57,7 @@ body.web { } .monaco-workbench.border { - height: calc(100vh - 2px); - width: calc(100vw - 2px); + box-sizing: border-box; border: 1px solid var(--window-border-color); } From d2f01a47397bdb55b8d754d59ab36231bc7a4b8d Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Wed, 13 Nov 2019 18:19:18 -0500 Subject: [PATCH 224/352] Fixes #84267 - no border when maximized/fullscreen --- src/vs/workbench/browser/layout.ts | 23 ++++++++++++++- src/vs/workbench/browser/media/style.css | 2 +- src/vs/workbench/browser/part.ts | 2 +- .../parts/activitybar/activitybarPart.ts | 2 +- .../browser/parts/editor/editorPart.ts | 2 +- .../browser/parts/titlebar/titlebarPart.ts | 14 ++-------- src/vs/workbench/electron-browser/window.ts | 28 +++++++++++++------ .../services/layout/browser/layoutService.ts | 16 +++++++++++ .../workbench/test/workbenchTestServices.ts | 7 +++++ 9 files changed, 72 insertions(+), 24 deletions(-) diff --git a/src/vs/workbench/browser/layout.ts b/src/vs/workbench/browser/layout.ts index 81fd79a40a4f4..70b956eb86214 100644 --- a/src/vs/workbench/browser/layout.ts +++ b/src/vs/workbench/browser/layout.ts @@ -95,6 +95,9 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi private readonly _onCenteredLayoutChange: Emitter = this._register(new Emitter()); readonly onCenteredLayoutChange: Event = this._onCenteredLayoutChange.event; + private readonly _onMaximizeChange: Emitter = this._register(new Emitter()); + readonly onMaximizeChange: Event = this._onMaximizeChange.event; + private readonly _onPanelPositionChange: Emitter = this._register(new Emitter()); readonly onPanelPositionChange: Event = this._onPanelPositionChange.event; @@ -142,6 +145,7 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi protected readonly state = { fullscreen: false, + maximized: false, hasFocus: false, windowBorder: false, @@ -304,6 +308,8 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi // Propagate to grid this.workbenchGrid.setViewVisible(this.titleBarPartView, this.isVisible(Parts.TITLEBAR_PART)); + this.updateWindowBorder(true); + this.layout(); // handle title bar when fullscreen changes } @@ -399,7 +405,7 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi const inactiveBorder = theme.getColor(WINDOW_INACTIVE_BORDER); let windowBorder = false; - if (activeBorder || inactiveBorder) { + if (!this.state.fullscreen && !this.state.maximized && (activeBorder || inactiveBorder)) { windowBorder = true; // If one color is missing, just fallback to the other one @@ -1250,6 +1256,21 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi this._onPanelPositionChange.fire(positionToString(this.state.panel.position)); } + isWindowMaximized() { + return this.state.maximized; + } + + updateWindowMaximizedState(maximized: boolean) { + if (this.state.maximized === maximized) { + return; + } + + this.state.maximized = maximized; + + this.updateWindowBorder(); + this._onMaximizeChange.fire(maximized); + } + private createGridDescriptor(): ISerializedGrid { const workbenchDimensions = this.getClientArea(); const width = this.storageService.getNumber(Storage.GRID_WIDTH, StorageScope.GLOBAL, workbenchDimensions.width); diff --git a/src/vs/workbench/browser/media/style.css b/src/vs/workbench/browser/media/style.css index e458c9af828e8..0f6da876c7b1b 100644 --- a/src/vs/workbench/browser/media/style.css +++ b/src/vs/workbench/browser/media/style.css @@ -56,7 +56,7 @@ body.web { width: 100vw; } -.monaco-workbench.border { +.monaco-workbench.border:not(.fullscreen) { box-sizing: border-box; border: 1px solid var(--window-border-color); } diff --git a/src/vs/workbench/browser/part.ts b/src/vs/workbench/browser/part.ts index d5ee8de28874c..1e07ec2345174 100644 --- a/src/vs/workbench/browser/part.ts +++ b/src/vs/workbench/browser/part.ts @@ -46,7 +46,7 @@ export abstract class Part extends Component implements ISerializableView { private options: IPartOptions, themeService: IThemeService, storageService: IStorageService, - layoutService: IWorkbenchLayoutService + protected readonly layoutService: IWorkbenchLayoutService ) { super(id, themeService, storageService); diff --git a/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts b/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts index 5bc062581736f..b4837c8d6388d 100644 --- a/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts +++ b/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts @@ -83,7 +83,7 @@ export class ActivitybarPart extends Part implements IActivityBarService { constructor( @IViewletService private readonly viewletService: IViewletService, @IInstantiationService private readonly instantiationService: IInstantiationService, - @IWorkbenchLayoutService private readonly layoutService: IWorkbenchLayoutService, + @IWorkbenchLayoutService layoutService: IWorkbenchLayoutService, @IThemeService themeService: IThemeService, @IStorageService private readonly storageService: IStorageService, @IExtensionService private readonly extensionService: IExtensionService, diff --git a/src/vs/workbench/browser/parts/editor/editorPart.ts b/src/vs/workbench/browser/parts/editor/editorPart.ts index 83b1c0cabe385..7cb0562675b10 100644 --- a/src/vs/workbench/browser/parts/editor/editorPart.ts +++ b/src/vs/workbench/browser/parts/editor/editorPart.ts @@ -139,7 +139,7 @@ export class EditorPart extends Part implements IEditorGroupsService, IEditorGro @IThemeService themeService: IThemeService, @IConfigurationService private readonly configurationService: IConfigurationService, @IStorageService storageService: IStorageService, - @IWorkbenchLayoutService private readonly layoutService: IWorkbenchLayoutService + @IWorkbenchLayoutService layoutService: IWorkbenchLayoutService ) { super(Parts.EDITOR_PART, { hasTitle: false }, themeService, storageService, layoutService); diff --git a/src/vs/workbench/browser/parts/titlebar/titlebarPart.ts b/src/vs/workbench/browser/parts/titlebar/titlebarPart.ts index 0e57e5a69082c..ddf68be9e7381 100644 --- a/src/vs/workbench/browser/parts/titlebar/titlebarPart.ts +++ b/src/vs/workbench/browser/parts/titlebar/titlebarPart.ts @@ -45,8 +45,6 @@ import { REMOTE_HOST_SCHEME } from 'vs/platform/remote/common/remoteHosts'; // TODO@sbatten https://github.com/microsoft/vscode/issues/81360 // tslint:disable-next-line: import-patterns layering import { IElectronService } from 'vs/platform/electron/node/electron'; -// tslint:disable-next-line: import-patterns layering -import { IElectronEnvironmentService } from 'vs/workbench/services/electron/electron-browser/electronEnvironmentService'; export class TitlebarPart extends Part implements ITitleService { @@ -107,8 +105,7 @@ export class TitlebarPart extends Part implements ITitleService { @IContextKeyService contextKeyService: IContextKeyService, @IHostService private readonly hostService: IHostService, @IProductService private readonly productService: IProductService, - @optional(IElectronService) private electronService: IElectronService, - @optional(IElectronEnvironmentService) private readonly electronEnvironmentService: IElectronEnvironmentService + @optional(IElectronService) private electronService: IElectronService ) { super(Parts.TITLEBAR_PART, { hasTitle: false }, themeService, storageService, layoutService); @@ -448,13 +445,8 @@ export class TitlebarPart extends Part implements ITitleService { // Resizer this.resizer = append(this.element, $('div.resizer')); - const isMaximized = this.environmentService.configuration.maximized ? true : false; - this.onDidChangeMaximized(isMaximized); - - this._register(Event.any( - Event.map(Event.filter(this.electronService.onWindowMaximize, id => id === this.electronEnvironmentService.windowId), _ => true), - Event.map(Event.filter(this.electronService.onWindowUnmaximize, id => id === this.electronEnvironmentService.windowId), _ => false) - )(e => this.onDidChangeMaximized(e))); + this._register(this.layoutService.onMaximizeChange(maximized => this.onDidChangeMaximized(maximized))); + this.onDidChangeMaximized(this.layoutService.isWindowMaximized()); } // Since the title area is used to drag the window, we do not want to steal focus from the diff --git a/src/vs/workbench/electron-browser/window.ts b/src/vs/workbench/electron-browser/window.ts index 1272f66f0a6c6..46a3496a06574 100644 --- a/src/vs/workbench/electron-browser/window.ts +++ b/src/vs/workbench/electron-browser/window.ts @@ -21,7 +21,7 @@ import * as browser from 'vs/base/browser/browser'; import { ICommandService, CommandsRegistry } from 'vs/platform/commands/common/commands'; import { IResourceInput } from 'vs/platform/editor/common/editor'; import { KeyboardMapperFactory } from 'vs/workbench/services/keybinding/electron-browser/nativeKeymapService'; -import { ipcRenderer as ipc, webFrame, crashReporter, Event } from 'electron'; +import { ipcRenderer as ipc, webFrame, crashReporter, Event as IpcEvent } from 'electron'; import { IWorkspaceEditingService } from 'vs/workbench/services/workspaces/common/workspaceEditing'; import { IMenuService, MenuId, IMenu, MenuItemAction, ICommandAction, SubmenuItemAction, MenuRegistry } from 'vs/platform/actions/common/actions'; import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; @@ -62,6 +62,7 @@ import { IHostService } from 'vs/workbench/services/host/browser/host'; import { IElectronEnvironmentService } from 'vs/workbench/services/electron/electron-browser/electronEnvironmentService'; import { IWorkingCopyService, WorkingCopyCapabilities } from 'vs/workbench/services/workingCopy/common/workingCopyService'; import { AutoSaveMode, IFilesConfigurationService } from 'vs/workbench/services/filesConfiguration/common/filesConfigurationService'; +import { Event } from 'vs/base/common/event'; export class ElectronWindow extends Disposable { @@ -126,7 +127,7 @@ export class ElectronWindow extends Disposable { }); // Support runAction event - ipc.on('vscode:runAction', async (event: Event, request: IRunActionInWindowRequest) => { + ipc.on('vscode:runAction', async (event: IpcEvent, request: IRunActionInWindowRequest) => { const args: unknown[] = request.args || []; // If we run an action from the touchbar, we fill in the currently active resource @@ -157,27 +158,27 @@ export class ElectronWindow extends Disposable { }); // Support runKeybinding event - ipc.on('vscode:runKeybinding', (event: Event, request: IRunKeybindingInWindowRequest) => { + ipc.on('vscode:runKeybinding', (event: IpcEvent, request: IRunKeybindingInWindowRequest) => { if (document.activeElement) { this.keybindingService.dispatchByUserSettingsLabel(request.userSettingsLabel, document.activeElement); } }); // Error reporting from main - ipc.on('vscode:reportError', (event: Event, error: string) => { + ipc.on('vscode:reportError', (event: IpcEvent, error: string) => { if (error) { errors.onUnexpectedError(JSON.parse(error)); } }); // Support openFiles event for existing and new files - ipc.on('vscode:openFiles', (event: Event, request: IOpenFileRequest) => this.onOpenFiles(request)); + ipc.on('vscode:openFiles', (event: IpcEvent, request: IOpenFileRequest) => this.onOpenFiles(request)); // Support addFolders event if we have a workspace opened - ipc.on('vscode:addFolders', (event: Event, request: IAddFoldersRequest) => this.onAddFoldersRequest(request)); + ipc.on('vscode:addFolders', (event: IpcEvent, request: IAddFoldersRequest) => this.onAddFoldersRequest(request)); // Message support - ipc.on('vscode:showInfoMessage', (event: Event, message: string) => { + ipc.on('vscode:showInfoMessage', (event: IpcEvent, message: string) => { this.notificationService.info(message); }); @@ -215,7 +216,7 @@ export class ElectronWindow extends Disposable { }); // keyboard layout changed event - ipc.on('vscode:accessibilitySupportChanged', (event: Event, accessibilitySupportEnabled: boolean) => { + ipc.on('vscode:accessibilitySupportChanged', (event: IpcEvent, accessibilitySupportEnabled: boolean) => { this.accessibilityService.setAccessibilitySupport(accessibilitySupportEnabled ? AccessibilitySupport.Enabled : AccessibilitySupport.Disabled); }); @@ -281,6 +282,17 @@ export class ElectronWindow extends Disposable { } })); } + + this._register(Event.any( + Event.map(Event.filter(this.electronService.onWindowMaximize, id => id === this.electronEnvironmentService.windowId), () => true), + Event.map(Event.filter(this.electronService.onWindowUnmaximize, id => id === this.electronEnvironmentService.windowId), () => false) + )(e => this.onDidChangeMaximized(e))); + + this.onDidChangeMaximized(this.environmentService.configuration.maximized ?? false); + } + + private onDidChangeMaximized(maximized: boolean): void { + this.layoutService.updateWindowMaximizedState(maximized); } private onDidVisibleEditorsChange(): void { diff --git a/src/vs/workbench/services/layout/browser/layoutService.ts b/src/vs/workbench/services/layout/browser/layoutService.ts index 616d872bf579a..94aa3ef9f55ea 100644 --- a/src/vs/workbench/services/layout/browser/layoutService.ts +++ b/src/vs/workbench/services/layout/browser/layoutService.ts @@ -41,6 +41,11 @@ export interface IWorkbenchLayoutService extends ILayoutService { */ readonly onFullscreenChange: Event; + /** + * Emits when the window is maximized or unmaximized. + */ + readonly onMaximizeChange: Event; + /** * Emits when centered layout is enabled or disabled. */ @@ -188,4 +193,15 @@ export interface IWorkbenchLayoutService extends ILayoutService { * Register a part to participate in the layout. */ registerPart(part: Part): void; + + + /** + * Returns whether the window is maximized. + */ + isWindowMaximized(): boolean; + + /** + * Updates the maximized state of the window. + */ + updateWindowMaximizedState(maximized: boolean): void; } diff --git a/src/vs/workbench/test/workbenchTestServices.ts b/src/vs/workbench/test/workbenchTestServices.ts index c150c035c6f84..1e7bd7d147c67 100644 --- a/src/vs/workbench/test/workbenchTestServices.ts +++ b/src/vs/workbench/test/workbenchTestServices.ts @@ -463,6 +463,7 @@ export class TestLayoutService implements IWorkbenchLayoutService { onZenModeChange: Event = Event.None; onCenteredLayoutChange: Event = Event.None; onFullscreenChange: Event = Event.None; + onMaximizeChange: Event = Event.None; onPanelPositionChange: Event = Event.None; onPartVisibilityChange: Event = Event.None; onLayout = Event.None; @@ -572,6 +573,12 @@ export class TestLayoutService implements IWorkbenchLayoutService { public resizePart(_part: Parts, _sizeChange: number): void { } public registerPart(part: Part): void { } + + isWindowMaximized() { + return false; + } + + public updateWindowMaximizedState(maximized: boolean): void { } } let activeViewlet: Viewlet = {} as any; From 9979d4f25269608042e10e2350af01fd1d013af5 Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Wed, 13 Nov 2019 18:31:35 -0500 Subject: [PATCH 225/352] Fixes a tiny dead zone because of the resizer AFAICT, the `-webkit-app-region: no-drag` of the resizer seems to only be honored for the first 4px. Any more and it doesn't eat the mouse event and creates a dead zone --- src/vs/workbench/browser/parts/titlebar/media/titlebarpart.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/browser/parts/titlebar/media/titlebarpart.css b/src/vs/workbench/browser/parts/titlebar/media/titlebarpart.css index 2f312f5581903..265d6518c4019 100644 --- a/src/vs/workbench/browser/parts/titlebar/media/titlebarpart.css +++ b/src/vs/workbench/browser/parts/titlebar/media/titlebarpart.css @@ -68,7 +68,7 @@ position: absolute; top: 0; width: 100%; - height: 20%; + height: 4px; } .monaco-workbench.windows.fullscreen .part.titlebar > .resizer, From 9e3d81afe94be8913d6872a3ccb1304c7d61e94b Mon Sep 17 00:00:00 2001 From: Rob Lourens Date: Wed, 13 Nov 2019 18:49:10 -0600 Subject: [PATCH 226/352] node2@1.41.0 --- build/builtInExtensions.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/builtInExtensions.json b/build/builtInExtensions.json index 29c39c9b5e4a6..8f99cad8880f2 100644 --- a/build/builtInExtensions.json +++ b/build/builtInExtensions.json @@ -16,7 +16,7 @@ }, { "name": "ms-vscode.node-debug2", - "version": "1.39.3", + "version": "1.41.0", "repo": "https://github.com/Microsoft/vscode-node-debug2", "metadata": { "id": "36d19e17-7569-4841-a001-947eb18602b2", From a04563df2c790846986f75c33cae60ab33c39b00 Mon Sep 17 00:00:00 2001 From: Rob Lourens Date: Wed, 13 Nov 2019 19:07:23 -0600 Subject: [PATCH 227/352] Bump node-debug --- build/builtInExtensions.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/builtInExtensions.json b/build/builtInExtensions.json index 8f99cad8880f2..0657b168aca00 100644 --- a/build/builtInExtensions.json +++ b/build/builtInExtensions.json @@ -1,7 +1,7 @@ [ { "name": "ms-vscode.node-debug", - "version": "1.40.1", + "version": "1.41.0", "repo": "https://github.com/Microsoft/vscode-node-debug", "metadata": { "id": "b6ded8fb-a0a0-4c1c-acbd-ab2a3bc995a6", From c9f9081e2fd9846c6f24d5ee782dfa7373ee32c2 Mon Sep 17 00:00:00 2001 From: Miguel Solorio Date: Wed, 13 Nov 2019 17:11:27 -0800 Subject: [PATCH 228/352] Add icon classes to debug tooldbar contributions --- .../ui/codiconLabel/codicon/codicon.css | 3 +- .../ui/codiconLabel/codicon/codicon.ttf | Bin 46836 -> 46932 bytes .../browser/menuEntryActionViewItem.ts | 54 +++++++++++++----- src/vs/platform/actions/common/actions.ts | 3 +- .../debug/browser/debug.contribution.ts | 23 ++++---- .../contrib/debug/browser/debugToolBar.ts | 11 ++++ .../debug/browser/media/debugToolBar.css | 3 + 7 files changed, 69 insertions(+), 28 deletions(-) diff --git a/src/vs/base/browser/ui/codiconLabel/codicon/codicon.css b/src/vs/base/browser/ui/codiconLabel/codicon/codicon.css index 5fe22758599cc..fda705bceb666 100644 --- a/src/vs/base/browser/ui/codiconLabel/codicon/codicon.css +++ b/src/vs/base/browser/ui/codiconLabel/codicon/codicon.css @@ -5,7 +5,7 @@ @font-face { font-family: "codicon"; - src: url("./codicon.ttf?d02baa177e0c5b865597b4e28fca9e07") format("truetype"); + src: url("./codicon.ttf?ffbbbd998c09cc4af5af9e181bb08a70") format("truetype"); } .codicon[class*='codicon-'] { @@ -399,3 +399,4 @@ .codicon-debug-breakpoint-stackframe:before { content: "\eb8b" } .codicon-debug-breakpoint-stackframe-focused:before { content: "\eb8b" } .codicon-debug-breakpoint-unsupported:before { content: "\eb8c" } +.codicon-debug-step-back:before { content: "\f101" } diff --git a/src/vs/base/browser/ui/codiconLabel/codicon/codicon.ttf b/src/vs/base/browser/ui/codiconLabel/codicon/codicon.ttf index 3af3dbb97c51f3979947e67df2d63717f4e4dd77..7e87d7f10387722d05b94db947ddd29351db6cb3 100644 GIT binary patch delta 4143 zcmXxn2Yl4!83*v+dkGOTE@VLlWKReX4#*;8f<{D&5D^EEgcTtPVGofDVK$~32vS?E zrBxZNP)ZOjrIu2)NU2%}0wN+J%KL-}iVG|8_s{cb_1s{% z-u41uS^!L*QCHQ_(_G2{{MG>>hvw9-n0iqAby*)@Cs z7t9m9eVCGK>J~3w)4QvSzwaX8yS;Y)jH(04t($A?kGBLEG21gF2e zHQ@iTi(gp4e?U*ToJaY^pE2oev1Xs^nrVN_%=T&b^r$l4(H~P1vP?Wa!lz?#5miXUUvV#fj_t@Ww_rSiOdRIoe*7Ez@jUjJ-dKl4 zco-ghgQ><3U*IwP4_9&1^x)gN0WZEbuC|I>mU(Z-SloeexD!9a1l)y*n1l-4jmfwN zQ*a+1;7gm1O1``qn2A}KjX9{ngP4a})S({p`Dre|LM+A-Eah{SVL4XdA*{k`G-3^! zuommF0UNOi&3FVY_yr#2t7*k%Y(bkBk7FBtg{SZvJdNMtclbS?!LxV{JFpA8dDwr% zUi=CB@MpB+01o0syoA5t5L4!Fco~1k5&Q%H#4C6eui;-fhSzZ%C-5Jzq?$DR5>MdQcoHK~fFcy51f?iv2KhZx(#wSM zR0EyE4!Y`GyAx}Ie_t=l!d5GuIP46?vxl9jm<6!26pk{^R?H08If^*~TcemQun#Kc z4eVUS41%4fki}RFc%6%h=bbvm1cR+t_>^(JV$Q*`Y8=cySXPRIc?i2uF(Y9YDdr~Z zV#O?lU80z;uuBy(n1yy3?+}w1cDZ6Y!>&*WVst(MVv55)q?qims}$27_F=^WfL*Ov z3b0_&yDjGGke4Ypaa z@?alP%zD@s#cG6|>O4R!OxRY1n~a;4>A|=~v20=66bl&E$sOW{2>ZCg*NoegakU=_ zeAC7HhJ8=5(qT_3);#R{iq#K$O0f^Xo>uG#uxAu|1MCNiT>|#3V!wd>P_c8so>S~0 zupc=o#tYjC?0Ln;0{gLIi-EnM*lb`wQEWS~PRbD*5Ui7m#8w1*NwF!xex}%-V4b`t zHY(W5itUIgW_gF$y99q@IwwQU=&?@PkTY)Vw~7rE_B+K^3j4icQ-yU-o7i4qe^7j9uucjQ zTQ2O6ip>|+$sl4IX8w2aLhQ(Faf-be!hCYDOG8`=jf_5uog3n-*ux=AMF+b%g!%1Y zUx%=89qjOso{GI5(o1>S_96a?0{{}BI0_(vibDYsq&OZRZpA?X306+=NN>gA0SQqY zBal$VfdUCrV68|v&z~1?$Uq_##|@;9;^2YwRUAQ(NX20UiBcR(kZ8pL1&L7{Rgiv) zLkrShaeP5y6`tk!OPu0NgTyONH%NlwoP#7PPCQ7Gauyv)R-A&66vcT6NmZPTkTk^^ z2}xI+mXHkc^1{Ih8K5{qAp;eMDI`;ItU?AU4p_)w#Ze0xqBwLRS<2biWT@gGhIkZ5 zGGv(IaE4cg^A6z%;|Rrx4aruV-H;r`DGte1oac}{#mNrISDf*Xk&4qEQlL2ZA)^#G z07zjse*PzTqeyWrfD|h(2#^xRRRL0}xHLe@6xRpHXvIYWGDdNwfZVFMTtIG9Tr(i$ ziVFwicK&_2o$vlM<5bH4SdePPWeYMxaqWW4ROn)yrHo;mt&9)j9A$bj)+po8 z_@FWYPW{j29WsH8^OOl zv4iJt`trsS<^0D*mMRm)xJ;R7#^uVyFs@LhALB}8`ZGSHOf2InWfB-4R>tWgtCdM& zoXQs<&WmswNux4OBUz(NDr1x477JOcxX(h?DQ>oq^@=+#WP`$!ZD;$A4ZOxvaX9O4 zTXJNZH!-k0us-nVzY_LmxgZ%-y42BA~IrJ#L9?{J{5ho_c_^j zeBWb{rIC$MJ)@eUZbautkBe@J-XG(RDUVqibFg2iw_j<$P5n;vkM2LQ|Em5+W2eM! zitUJ-824=4xp>4^#xIZG8hsl!@_`wbsI{NV7;5vd~@N4%Dul|3%ICTDO?WzN!^r*aPGbmn?;U(P+B z7o9gHZ)M(&ykmJc@>k{W%|A0Tc4Ya;mq*?xm{zc%;K-=KqvnpY z!pBS=)5?*tI65jagEhvl>D;M&;0IP&PEy3Mw1~7}IT6zX0-}n-600jFO&Sm}u)Wz6 hu*9UdZ`(QE<#J`TU)&w(>swtlV_y5!J-)qMz)!Z9cj*8C delta 4060 zcmX}v3w(|D83*v+{|F*-lLV0qxk^IZ4iX`flVBrNMHNk55+WiJf*>w+LQzYN5LGkV ztSB|>Ogb~OPOURlQ|mO1R!fam|4$j3YSwA&_jcIW_e-7-GVfKpiMQCK6 z&Ai0>Cn%w$yt1l#_rr&Lzw3a{uCnWqytJsNgfWbT4|= z|Kda5uz>#nU$~rSdE;wLQe9Vb*d-h5FPP$1^@CeaHQtkt-VmLh$z zoA@&SM{nU{H`tB#Z5bmQoeyLSY>nM)&&gQl(f@CTXHP)^E}BL@=RzGW;ICMQH%(i- zj?eK51bt06e1hxv2hWSc@mx&C2K)>urVSoPfa!`k$j4dy8o$6H6NKlm5G&!v*O+2j z<2E+o-}ooKGd_5Te_<7xjHxSVyVN@pqmYNkFdAd<1jb?<#^Xs$z*CrrNq8F1U@E3z zItnoZGf{+DD8_7*pcHdahH}iqe14A$un3h{%yX7tDXOp>EATA5sK#on!CI`tdOVLG zpaw5sBYw!gW;1HB1zWw?h8M8|KgKTn1V6=Y{2VW15B6do_TvCvC;2h55UHlF2;qSPJ_tAh4(1=U; z5Fg<(KE@TM-lw>R{x|R$ZsH4Ae2H7QgS)tguW%pVpc&ud0a^@<%lMjh#?Q1j{wBZ# z*0t=9PK+_JCeFm01e0jGV>@2LkFXO%kcn(~kb_)iO`E!L?ON(in$~qs__b-rTy}2E zrD=Yhy>(268HyJhcBbNGhb>Y}09fXx18*`GD<%c(Y{m3|WzsvCD6n%BQwFwFF?nF; zD)eP61H8_G83kLem|L*(6tfI=zGA+?vQQk%JXjWogE&}!c-UtZb02nlBL#cD-U*!9K58xv*PAIGr`_e>`|~^ zD0U*InB@avBYW#c1;K#q)T_NflzBguSnv$z#7!&a|=3id_`exx&PL3j3{MXN7grhWN=~A1HQP zSSM?UeHXSxu>&*zAM!wK#!d%#gl!pO6dN?erTAq*S}9aB`Y5(<2y@!OMh;=II@r=7 zZ55k4#8v;@p6AP@Eu; z5XD&n2~}X-NEkm758!-(bX1%)kWPv-2hv$_`ar@J=Mbce;zWW(D9$EGq{42-D8+dN ziB_Ckkgf`QoUgQ-;y8oEC=NDAtm24+#3>FtNW9|MgCrt~P(iI0dWRT)0hh!)Yb;w}F@eUcHIOrjniX$H~RB`x2 zvL500{|@hDD{cf3kK%3s$x+-AAi0YB0%Vxt<^UP4xI;ijC~gyw?Q zy9Q(wf4_|4r*CA;Q(QnGk14JqkkN`u3FL9b^#n3TaZ!PcRa{vh;}otkj#pe`AWteT zG>{1j-W$C0l;V;DnW(t#Kqe_JK9I?ZD-h&q#bpSRuecULo>5$oAX5}qCCF68r3o@k zaeabJcdkDV+@v4{iaQmgP;tA0%uw93ATt#=E=Z9=3*#(h_*PP^jEix$GQNx@%Cuvg zql}+Z|D}9Draj|aW&9b-lnG!gS0<2go-)CV^OfnqSfNY^;{s(u85b%O#<)nCj*OKK zUVqbxcNQztnQ@77{@)@?mFdD*rA!3lGG!temn##+xI&p|#+Ay%Fg~kHEaNI=;uxp$ z4-n^%aGFZBGEP%jtxO{08pRbB@|@x_3t6kU)+whFlB{3#|%07}^-x6jl(nGHgfK>m6Mk(>fM)Z0MBLsixD(&VxE12~Q0#4Zqi= ztjqO?gow0=B@w$Knj_tj1(CZWA4H{kqZURTjrNJoj4qBo)HS#3!mbV7GP`Z+cBY$+ z$%~m0vnu9hEMntgC&V6!%Zl3?cPj2?yl;GR{KWV}@eK(f33&-M2`3V6Cq^ZXPTZP! zyn9^t(xj}Uilp<&G0BsYOOm%IUrg~&Nk|!;QkHT$rKv}CkE=aBJ@@u(==mUZbZSYe zx3X7UuQk11?j6#5a_`f9y7#H*^F|-rH>U5Bz774{{qp;*>UXSPvpdQ?)?MSi+CRAe z^8R-Q3>vU|K;yvRfu#cvr$wZtrHxMyPtQv)NME1+N_yjzN}nD>4rb4IesT=#HTmJy}s%o~)Xzqgm&&qq57g?|6E6 z27B^6`JPhGsT|)Nch0Ju=G?s8mAS`qn}!V-Hep!hup`4h8J;yfe|XCX&xqyq+akJz b*I#n`E;dQ^*Y=Nb)w>Ud`_$*Z*6jNq60LBW diff --git a/src/vs/platform/actions/browser/menuEntryActionViewItem.ts b/src/vs/platform/actions/browser/menuEntryActionViewItem.ts index 17dfd5efde6ab..ac27e5bf8c523 100644 --- a/src/vs/platform/actions/browser/menuEntryActionViewItem.ts +++ b/src/vs/platform/actions/browser/menuEntryActionViewItem.ts @@ -236,28 +236,52 @@ export class MenuEntryActionViewItem extends ActionViewItem { _updateItemClass(item: ICommandAction): void { this._itemClassDispose.value = undefined; - if (item.iconLocation) { - let iconClass: string; - - const iconPathMapKey = item.iconLocation.dark.toString(); - - if (MenuEntryActionViewItem.ICON_PATH_TO_CSS_RULES.has(iconPathMapKey)) { - iconClass = MenuEntryActionViewItem.ICON_PATH_TO_CSS_RULES.get(iconPathMapKey)!; - } else { - iconClass = ids.nextId(); - createCSSRule(`.icon.${iconClass}`, `background-image: ${asCSSUrl(item.iconLocation.light || item.iconLocation.dark)}`); - createCSSRule(`.vs-dark .icon.${iconClass}, .hc-black .icon.${iconClass}`, `background-image: ${asCSSUrl(item.iconLocation.dark)}`); - MenuEntryActionViewItem.ICON_PATH_TO_CSS_RULES.set(iconPathMapKey, iconClass); - } + // icon class + if (item.iconClassName) { + let iconClass = item.iconClassName; if (this.label) { - addClasses(this.label, 'icon', iconClass); + addClasses(this.label, 'codicon', iconClass); this._itemClassDispose.value = toDisposable(() => { if (this.label) { - removeClasses(this.label, 'icon', iconClass); + removeClasses(this.label, 'codicon', iconClass); } }); } + + } + + // icon path + else if (item.iconLocation) { + let iconClass: string; + + if (typeof item.iconLocation?.dark !== 'undefined') { + + const iconPathMapKey = item.iconLocation.dark.toString(); + + if (MenuEntryActionViewItem.ICON_PATH_TO_CSS_RULES.has(iconPathMapKey)) { + iconClass = MenuEntryActionViewItem.ICON_PATH_TO_CSS_RULES.get(iconPathMapKey)!; + } else { + iconClass = ids.nextId(); + createCSSRule(`.icon.${iconClass}`, `background-image: ${asCSSUrl(item.iconLocation.light || item.iconLocation.dark)}`); + createCSSRule(`.vs-dark .icon.${iconClass}, .hc-black .icon.${iconClass}`, `background-image: ${asCSSUrl(item.iconLocation.dark)}`); + MenuEntryActionViewItem.ICON_PATH_TO_CSS_RULES.set(iconPathMapKey, iconClass); + } + + if (this.label) { + + addClasses(this.label, 'icon', iconClass); + this._itemClassDispose.value = toDisposable(() => { + if (this.label) { + removeClasses(this.label, 'icon', iconClass); + } + }); + } + + } + + + } } } diff --git a/src/vs/platform/actions/common/actions.ts b/src/vs/platform/actions/common/actions.ts index a583f7a34f514..a16aca11677d9 100644 --- a/src/vs/platform/actions/common/actions.ts +++ b/src/vs/platform/actions/common/actions.ts @@ -22,7 +22,8 @@ export interface ICommandAction { id: string; title: string | ILocalizedString; category?: string | ILocalizedString; - iconLocation?: { dark: URI; light?: URI; }; + iconClassName?: string; + iconLocation?: { dark?: URI; light?: URI; }; precondition?: ContextKeyExpr; toggled?: ContextKeyExpr; } diff --git a/src/vs/workbench/contrib/debug/browser/debug.contribution.ts b/src/vs/workbench/contrib/debug/browser/debug.contribution.ts index 3c68e97f7115d..ec050e66f7591 100644 --- a/src/vs/workbench/contrib/debug/browser/debug.contribution.ts +++ b/src/vs/workbench/contrib/debug/browser/debug.contribution.ts @@ -278,7 +278,7 @@ Registry.as(WorkbenchExtensions.Workbench).regi // Debug toolbar -const registerDebugToolBarItem = (id: string, title: string, iconLightUri: URI, iconDarkUri: URI, order: number, when?: ContextKeyExpr, precondition?: ContextKeyExpr) => { +const registerDebugToolBarItem = (id: string, title: string, order: number, iconClassName?: string, iconLightUri?: URI, iconDarkUri?: URI, when?: ContextKeyExpr, precondition?: ContextKeyExpr) => { MenuRegistry.appendMenuItem(MenuId.DebugToolBar, { group: 'navigation', when, @@ -286,6 +286,7 @@ const registerDebugToolBarItem = (id: string, title: string, iconLightUri: URI, command: { id, title, + iconClassName, iconLocation: { light: iconLightUri, dark: iconDarkUri @@ -295,16 +296,16 @@ const registerDebugToolBarItem = (id: string, title: string, iconLightUri: URI, }); }; -registerDebugToolBarItem(CONTINUE_ID, CONTINUE_LABEL, URI.parse(registerAndGetAmdImageURL('vs/workbench/contrib/debug/browser/media/continue-light.svg')), URI.parse(registerAndGetAmdImageURL('vs/workbench/contrib/debug/browser/media/continue-dark.svg')), 10, CONTEXT_DEBUG_STATE.isEqualTo('stopped')); -registerDebugToolBarItem(PAUSE_ID, PAUSE_LABEL, URI.parse(registerAndGetAmdImageURL('vs/workbench/contrib/debug/browser/media/pause-light.svg')), URI.parse(registerAndGetAmdImageURL('vs/workbench/contrib/debug/browser/media/pause-dark.svg')), 10, CONTEXT_DEBUG_STATE.notEqualsTo('stopped')); -registerDebugToolBarItem(STOP_ID, STOP_LABEL, URI.parse(registerAndGetAmdImageURL('vs/workbench/contrib/debug/browser/media/stop-light.svg')), URI.parse(registerAndGetAmdImageURL('vs/workbench/contrib/debug/browser/media/stop-dark.svg')), 70, CONTEXT_FOCUSED_SESSION_IS_ATTACH.toNegated()); -registerDebugToolBarItem(DISCONNECT_ID, DISCONNECT_LABEL, URI.parse(registerAndGetAmdImageURL('vs/workbench/contrib/debug/browser/media/disconnect-light.svg')), URI.parse(registerAndGetAmdImageURL('vs/workbench/contrib/debug/browser/media/disconnect-dark.svg')), 70, CONTEXT_FOCUSED_SESSION_IS_ATTACH); -registerDebugToolBarItem(STEP_OVER_ID, STEP_OVER_LABEL, URI.parse(registerAndGetAmdImageURL('vs/workbench/contrib/debug/browser/media/step-over-light.svg')), URI.parse(registerAndGetAmdImageURL('vs/workbench/contrib/debug/browser/media/step-over-dark.svg')), 20, undefined, CONTEXT_DEBUG_STATE.isEqualTo('stopped')); -registerDebugToolBarItem(STEP_INTO_ID, STEP_INTO_LABEL, URI.parse(registerAndGetAmdImageURL('vs/workbench/contrib/debug/browser/media/step-into-light.svg')), URI.parse(registerAndGetAmdImageURL('vs/workbench/contrib/debug/browser/media/step-into-dark.svg')), 30, undefined, CONTEXT_DEBUG_STATE.isEqualTo('stopped')); -registerDebugToolBarItem(STEP_OUT_ID, STEP_OUT_LABEL, URI.parse(registerAndGetAmdImageURL('vs/workbench/contrib/debug/browser/media/step-out-light.svg')), URI.parse(registerAndGetAmdImageURL('vs/workbench/contrib/debug/browser/media/step-out-dark.svg')), 40, undefined, CONTEXT_DEBUG_STATE.isEqualTo('stopped')); -registerDebugToolBarItem(RESTART_SESSION_ID, RESTART_LABEL, URI.parse(registerAndGetAmdImageURL('vs/workbench/contrib/debug/browser/media/restart-light.svg')), URI.parse(registerAndGetAmdImageURL('vs/workbench/contrib/debug/browser/media/restart-dark.svg')), 60); -registerDebugToolBarItem(STEP_BACK_ID, nls.localize('stepBackDebug', "Step Back"), URI.parse(registerAndGetAmdImageURL('vs/workbench/contrib/debug/browser/media/step-back-light.svg')), URI.parse(registerAndGetAmdImageURL('vs/workbench/contrib/debug/browser/media/step-back-dark.svg')), 50, CONTEXT_STEP_BACK_SUPPORTED, CONTEXT_DEBUG_STATE.isEqualTo('stopped')); -registerDebugToolBarItem(REVERSE_CONTINUE_ID, nls.localize('reverseContinue', "Reverse"), URI.parse(registerAndGetAmdImageURL('vs/workbench/contrib/debug/browser/media/reverse-continue-light.svg')), URI.parse(registerAndGetAmdImageURL('vs/workbench/contrib/debug/browser/media/reverse-continue-dark.svg')), 60, CONTEXT_STEP_BACK_SUPPORTED, CONTEXT_DEBUG_STATE.isEqualTo('stopped')); +registerDebugToolBarItem(CONTINUE_ID, CONTINUE_LABEL, 10, 'codicon-debug-continue', undefined, undefined, CONTEXT_DEBUG_STATE.isEqualTo('stopped')); +registerDebugToolBarItem(PAUSE_ID, PAUSE_LABEL, 10, 'codicon-debug-pause', undefined, undefined, CONTEXT_DEBUG_STATE.notEqualsTo('stopped')); +registerDebugToolBarItem(STOP_ID, STOP_LABEL, 70, 'codicon-debug-stop', undefined, undefined, CONTEXT_FOCUSED_SESSION_IS_ATTACH.toNegated()); +registerDebugToolBarItem(DISCONNECT_ID, DISCONNECT_LABEL, 70, 'codicon-debug-disconnect', undefined, undefined, CONTEXT_FOCUSED_SESSION_IS_ATTACH); +registerDebugToolBarItem(STEP_OVER_ID, STEP_OVER_LABEL, 20, 'codicon-debug-step-over', undefined, undefined, undefined, CONTEXT_DEBUG_STATE.isEqualTo('stopped')); +registerDebugToolBarItem(STEP_INTO_ID, STEP_INTO_LABEL, 30, 'codicon-debug-step-into', undefined, undefined, undefined, CONTEXT_DEBUG_STATE.isEqualTo('stopped')); +registerDebugToolBarItem(STEP_OUT_ID, STEP_OUT_LABEL, 40, 'codicon-debug-step-out', undefined, undefined, undefined, CONTEXT_DEBUG_STATE.isEqualTo('stopped')); +registerDebugToolBarItem(RESTART_SESSION_ID, RESTART_LABEL, 60, 'codicon-debug-restart', undefined, undefined); +registerDebugToolBarItem(STEP_BACK_ID, nls.localize('stepBackDebug', "Step Back"), 50, 'codicon-debug-step-back', undefined, undefined, CONTEXT_STEP_BACK_SUPPORTED, CONTEXT_DEBUG_STATE.isEqualTo('stopped')); +registerDebugToolBarItem(REVERSE_CONTINUE_ID, nls.localize('reverseContinue', "Reverse"), 60, 'codicon-debug-continue', undefined, undefined, CONTEXT_STEP_BACK_SUPPORTED, CONTEXT_DEBUG_STATE.isEqualTo('stopped')); // Debug callstack context menu const registerDebugCallstackItem = (id: string, title: string, order: number, when?: ContextKeyExpr, precondition?: ContextKeyExpr, group = 'navigation') => { diff --git a/src/vs/workbench/contrib/debug/browser/debugToolBar.ts b/src/vs/workbench/contrib/debug/browser/debugToolBar.ts index 781ac16a5dea2..1ce4ad3dba49c 100644 --- a/src/vs/workbench/contrib/debug/browser/debugToolBar.ts +++ b/src/vs/workbench/contrib/debug/browser/debugToolBar.ts @@ -102,6 +102,12 @@ export const debugIconContinueForeground = registerColor('debugIcon.continueFore hc: '#75BEFF' }, localize('debugIcon.continueForeground', "Debug toolbar icon for continue.")); +export const debugIconStepBackForeground = registerColor('debugIcon.stepBackForeground', { + dark: '#75BEFF', + light: '#007ACC', + hc: '#75BEFF' +}, localize('debugIcon.stepBackForeground', "Debug toolbar icon for step back.")); + export class DebugToolBar extends Themable implements IWorkbenchContribution { private $el: HTMLElement; @@ -391,4 +397,9 @@ registerThemingParticipant((theme, collector) => { if (debugIconContinueColor) { collector.addRule(`.monaco-workbench .codicon-debug-continue { color: ${debugIconContinueColor} !important; }`); } + + const debugIconStepBackColor = theme.getColor(debugIconStepBackForeground); + if (debugIconStepBackColor) { + collector.addRule(`.monaco-workbench .codicon-debug-step-back { color: ${debugIconStepBackColor} !important; }`); + } }); diff --git a/src/vs/workbench/contrib/debug/browser/media/debugToolBar.css b/src/vs/workbench/contrib/debug/browser/media/debugToolBar.css index a0a76da7ec1d9..4ac6feef4802d 100644 --- a/src/vs/workbench/contrib/debug/browser/media/debugToolBar.css +++ b/src/vs/workbench/contrib/debug/browser/media/debugToolBar.css @@ -43,4 +43,7 @@ background-size: 16px; background-position: center center; background-repeat: no-repeat; + display: flex; + align-items: center; + justify-content: center; } From b6a486e34fe3715f6edec0cdb11138b1672d33bd Mon Sep 17 00:00:00 2001 From: Miguel Solorio Date: Wed, 13 Nov 2019 19:24:56 -0800 Subject: [PATCH 229/352] Fix #84765 --- .../ui/codiconLabel/codicon/codicon.css | 3 ++- .../ui/codiconLabel/codicon/codicon.ttf | Bin 46380 -> 46380 bytes 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/vs/base/browser/ui/codiconLabel/codicon/codicon.css b/src/vs/base/browser/ui/codiconLabel/codicon/codicon.css index 753d70792994e..beb97dd70d544 100644 --- a/src/vs/base/browser/ui/codiconLabel/codicon/codicon.css +++ b/src/vs/base/browser/ui/codiconLabel/codicon/codicon.css @@ -5,7 +5,7 @@ @font-face { font-family: "codicon"; - src: url("./codicon.ttf?3443fb4013ab5a04c23a30f912dd6627") format("truetype"); + src: url("./codicon.ttf?72bd9e6bbf1e48287bcb9a9e4babeb28") format("truetype"); } .codicon[class*='codicon-'] { @@ -385,4 +385,5 @@ .codicon-list-filter:before { content: "\eb83" } .codicon-list-flat:before { content: "\eb84" } .codicon-list-selection:before { content: "\eb85" } +.codicon-selection:before { content: "\eb85" } .codicon-list-tree:before { content: "\eb86" } diff --git a/src/vs/base/browser/ui/codiconLabel/codicon/codicon.ttf b/src/vs/base/browser/ui/codiconLabel/codicon/codicon.ttf index ba3474205da690928d1da0baa9f557ae33a5b1d3..d39e8ad92fd52b2dd582047891bea1d583d4b37d 100644 GIT binary patch delta 48 xcmZ4UifPR&rU`+}B?hV!L#9e!;rS5HZ}XLbo1uUK2yT9=RDsc(Sr|38006nw5WxTd delta 48 xcmZ4UifPR&rU`+}1qHbiL#9gK?n#K}xB1Gz%}~Gq1UEm-^nlTuSr|38007bf5x@Wd From 353510eeece8f2089b94fa7f73f40a80ba0b429f Mon Sep 17 00:00:00 2001 From: Miguel Solorio Date: Wed, 13 Nov 2019 19:55:49 -0800 Subject: [PATCH 230/352] Fix compiler errors --- src/vs/code/electron-main/window.ts | 2 +- src/vs/workbench/test/workbenchTestServices.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/code/electron-main/window.ts b/src/vs/code/electron-main/window.ts index b55f4095e3b82..531dfe2afb807 100644 --- a/src/vs/code/electron-main/window.ts +++ b/src/vs/code/electron-main/window.ts @@ -1096,7 +1096,7 @@ export class CodeWindow extends Disposable implements ICodeWindow { private createTouchBarGroupSegments(items: ISerializableCommandAction[] = []): ITouchBarSegment[] { const segments: ITouchBarSegment[] = items.map(item => { let icon: NativeImage | undefined; - if (item.iconLocation && item.iconLocation.dark.scheme === 'file') { + if (item.iconLocation && typeof item.iconLocation?.dark !== 'undefined' && item.iconLocation.dark.scheme === 'file') { icon = nativeImage.createFromPath(URI.revive(item.iconLocation.dark).fsPath); if (icon.isEmpty()) { icon = undefined; diff --git a/src/vs/workbench/test/workbenchTestServices.ts b/src/vs/workbench/test/workbenchTestServices.ts index b1e238cb5d5f0..89528afc51ad3 100644 --- a/src/vs/workbench/test/workbenchTestServices.ts +++ b/src/vs/workbench/test/workbenchTestServices.ts @@ -1377,7 +1377,7 @@ export class TestElectronService implements IElectronService { async setRepresentedFilename(path: string): Promise { } async setDocumentEdited(edited: boolean): Promise { } async openExternal(url: string): Promise { return false; } - async updateTouchBar(items: { id: string; title: string | { value: string; original: string; }; category?: string | { value: string; original: string; } | undefined; iconLocation?: { dark: UriComponents; light?: { readonly scheme: string; readonly authority: string; readonly path: string; readonly query: string; readonly fragment: string; readonly fsPath: string; with: {}; toString: {}; toJSON: {}; } | undefined; } | undefined; precondition?: { getType: {}; equals: {}; evaluate: {}; serialize: {}; keys: {}; map: {}; negate: {}; } | undefined; toggled?: { getType: {}; equals: {}; evaluate: {}; serialize: {}; keys: {}; map: {}; negate: {}; } | undefined; }[][]): Promise { } + async updateTouchBar(items: { id: string; title: string | { value: string; original: string; }; category?: string | { value: string; original: string; } | undefined; iconLocation?: { dark?: UriComponents; light?: { readonly scheme: string; readonly authority: string; readonly path: string; readonly query: string; readonly fragment: string; readonly fsPath: string; with: {}; toString: {}; toJSON: {}; } | undefined; } | undefined; precondition?: { getType: {}; equals: {}; evaluate: {}; serialize: {}; keys: {}; map: {}; negate: {}; } | undefined; toggled?: { getType: {}; equals: {}; evaluate: {}; serialize: {}; keys: {}; map: {}; negate: {}; } | undefined; }[][]): Promise { } async newWindowTab(): Promise { } async showPreviousWindowTab(): Promise { } async showNextWindowTab(): Promise { } From 9582e83e56d4f9f38562abfd643bc3774370921f Mon Sep 17 00:00:00 2001 From: Miguel Solorio Date: Wed, 13 Nov 2019 20:53:38 -0800 Subject: [PATCH 231/352] Remove unused files --- .../contrib/debug/browser/media/breakpoint-conditional.svg | 3 --- .../contrib/debug/browser/media/breakpoint-data-disabled.svg | 3 --- .../debug/browser/media/breakpoint-data-unverified.svg | 3 --- .../contrib/debug/browser/media/breakpoint-data.svg | 3 --- .../contrib/debug/browser/media/breakpoint-disabled.svg | 3 --- .../debug/browser/media/breakpoint-function-disabled.svg | 3 --- .../debug/browser/media/breakpoint-function-unverified.svg | 3 --- .../contrib/debug/browser/media/breakpoint-function.svg | 3 --- .../contrib/debug/browser/media/breakpoint-hint.svg | 5 ----- .../contrib/debug/browser/media/breakpoint-log-disabled.svg | 3 --- .../debug/browser/media/breakpoint-log-unverified.svg | 3 --- .../workbench/contrib/debug/browser/media/breakpoint-log.svg | 3 --- .../contrib/debug/browser/media/breakpoint-unsupported.svg | 3 --- .../contrib/debug/browser/media/breakpoint-unverified.svg | 3 --- src/vs/workbench/contrib/debug/browser/media/breakpoint.svg | 3 --- .../workbench/contrib/debug/browser/media/continue-dark.svg | 3 --- .../workbench/contrib/debug/browser/media/continue-light.svg | 3 --- .../contrib/debug/browser/media/current-and-breakpoint.svg | 4 ---- .../workbench/contrib/debug/browser/media/current-arrow.svg | 3 --- .../contrib/debug/browser/media/disconnect-dark.svg | 3 --- .../contrib/debug/browser/media/disconnect-light.svg | 3 --- src/vs/workbench/contrib/debug/browser/media/pause-dark.svg | 3 --- src/vs/workbench/contrib/debug/browser/media/pause-light.svg | 3 --- .../workbench/contrib/debug/browser/media/restart-dark.svg | 3 --- .../workbench/contrib/debug/browser/media/restart-light.svg | 3 --- .../contrib/debug/browser/media/reverse-continue-dark.svg | 3 --- .../contrib/debug/browser/media/reverse-continue-light.svg | 3 --- .../debug/browser/media/stackframe-and-breakpoint.svg | 4 ---- .../contrib/debug/browser/media/stackframe-arrow.svg | 3 --- .../workbench/contrib/debug/browser/media/step-back-dark.svg | 3 --- .../contrib/debug/browser/media/step-back-light.svg | 3 --- .../workbench/contrib/debug/browser/media/step-into-dark.svg | 3 --- .../contrib/debug/browser/media/step-into-light.svg | 3 --- .../workbench/contrib/debug/browser/media/step-out-dark.svg | 3 --- .../workbench/contrib/debug/browser/media/step-out-light.svg | 3 --- .../workbench/contrib/debug/browser/media/step-over-dark.svg | 3 --- .../contrib/debug/browser/media/step-over-light.svg | 3 --- src/vs/workbench/contrib/debug/browser/media/stop-dark.svg | 3 --- src/vs/workbench/contrib/debug/browser/media/stop-light.svg | 3 --- 39 files changed, 121 deletions(-) delete mode 100644 src/vs/workbench/contrib/debug/browser/media/breakpoint-conditional.svg delete mode 100644 src/vs/workbench/contrib/debug/browser/media/breakpoint-data-disabled.svg delete mode 100644 src/vs/workbench/contrib/debug/browser/media/breakpoint-data-unverified.svg delete mode 100644 src/vs/workbench/contrib/debug/browser/media/breakpoint-data.svg delete mode 100644 src/vs/workbench/contrib/debug/browser/media/breakpoint-disabled.svg delete mode 100644 src/vs/workbench/contrib/debug/browser/media/breakpoint-function-disabled.svg delete mode 100644 src/vs/workbench/contrib/debug/browser/media/breakpoint-function-unverified.svg delete mode 100644 src/vs/workbench/contrib/debug/browser/media/breakpoint-function.svg delete mode 100644 src/vs/workbench/contrib/debug/browser/media/breakpoint-hint.svg delete mode 100644 src/vs/workbench/contrib/debug/browser/media/breakpoint-log-disabled.svg delete mode 100644 src/vs/workbench/contrib/debug/browser/media/breakpoint-log-unverified.svg delete mode 100644 src/vs/workbench/contrib/debug/browser/media/breakpoint-log.svg delete mode 100644 src/vs/workbench/contrib/debug/browser/media/breakpoint-unsupported.svg delete mode 100644 src/vs/workbench/contrib/debug/browser/media/breakpoint-unverified.svg delete mode 100644 src/vs/workbench/contrib/debug/browser/media/breakpoint.svg delete mode 100644 src/vs/workbench/contrib/debug/browser/media/continue-dark.svg delete mode 100644 src/vs/workbench/contrib/debug/browser/media/continue-light.svg delete mode 100644 src/vs/workbench/contrib/debug/browser/media/current-and-breakpoint.svg delete mode 100644 src/vs/workbench/contrib/debug/browser/media/current-arrow.svg delete mode 100644 src/vs/workbench/contrib/debug/browser/media/disconnect-dark.svg delete mode 100644 src/vs/workbench/contrib/debug/browser/media/disconnect-light.svg delete mode 100644 src/vs/workbench/contrib/debug/browser/media/pause-dark.svg delete mode 100644 src/vs/workbench/contrib/debug/browser/media/pause-light.svg delete mode 100644 src/vs/workbench/contrib/debug/browser/media/restart-dark.svg delete mode 100644 src/vs/workbench/contrib/debug/browser/media/restart-light.svg delete mode 100644 src/vs/workbench/contrib/debug/browser/media/reverse-continue-dark.svg delete mode 100644 src/vs/workbench/contrib/debug/browser/media/reverse-continue-light.svg delete mode 100644 src/vs/workbench/contrib/debug/browser/media/stackframe-and-breakpoint.svg delete mode 100644 src/vs/workbench/contrib/debug/browser/media/stackframe-arrow.svg delete mode 100644 src/vs/workbench/contrib/debug/browser/media/step-back-dark.svg delete mode 100644 src/vs/workbench/contrib/debug/browser/media/step-back-light.svg delete mode 100644 src/vs/workbench/contrib/debug/browser/media/step-into-dark.svg delete mode 100644 src/vs/workbench/contrib/debug/browser/media/step-into-light.svg delete mode 100644 src/vs/workbench/contrib/debug/browser/media/step-out-dark.svg delete mode 100644 src/vs/workbench/contrib/debug/browser/media/step-out-light.svg delete mode 100644 src/vs/workbench/contrib/debug/browser/media/step-over-dark.svg delete mode 100644 src/vs/workbench/contrib/debug/browser/media/step-over-light.svg delete mode 100644 src/vs/workbench/contrib/debug/browser/media/stop-dark.svg delete mode 100644 src/vs/workbench/contrib/debug/browser/media/stop-light.svg diff --git a/src/vs/workbench/contrib/debug/browser/media/breakpoint-conditional.svg b/src/vs/workbench/contrib/debug/browser/media/breakpoint-conditional.svg deleted file mode 100644 index 382507ebcdf4c..0000000000000 --- a/src/vs/workbench/contrib/debug/browser/media/breakpoint-conditional.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/contrib/debug/browser/media/breakpoint-data-disabled.svg b/src/vs/workbench/contrib/debug/browser/media/breakpoint-data-disabled.svg deleted file mode 100644 index a2c8c3417e503..0000000000000 --- a/src/vs/workbench/contrib/debug/browser/media/breakpoint-data-disabled.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/contrib/debug/browser/media/breakpoint-data-unverified.svg b/src/vs/workbench/contrib/debug/browser/media/breakpoint-data-unverified.svg deleted file mode 100644 index 96dda92ee3822..0000000000000 --- a/src/vs/workbench/contrib/debug/browser/media/breakpoint-data-unverified.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/contrib/debug/browser/media/breakpoint-data.svg b/src/vs/workbench/contrib/debug/browser/media/breakpoint-data.svg deleted file mode 100644 index 6752b060aeb62..0000000000000 --- a/src/vs/workbench/contrib/debug/browser/media/breakpoint-data.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/contrib/debug/browser/media/breakpoint-disabled.svg b/src/vs/workbench/contrib/debug/browser/media/breakpoint-disabled.svg deleted file mode 100644 index 84588f8eac598..0000000000000 --- a/src/vs/workbench/contrib/debug/browser/media/breakpoint-disabled.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/contrib/debug/browser/media/breakpoint-function-disabled.svg b/src/vs/workbench/contrib/debug/browser/media/breakpoint-function-disabled.svg deleted file mode 100644 index cd71f6e462e2d..0000000000000 --- a/src/vs/workbench/contrib/debug/browser/media/breakpoint-function-disabled.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/contrib/debug/browser/media/breakpoint-function-unverified.svg b/src/vs/workbench/contrib/debug/browser/media/breakpoint-function-unverified.svg deleted file mode 100644 index 9e2354d67bd9d..0000000000000 --- a/src/vs/workbench/contrib/debug/browser/media/breakpoint-function-unverified.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/contrib/debug/browser/media/breakpoint-function.svg b/src/vs/workbench/contrib/debug/browser/media/breakpoint-function.svg deleted file mode 100644 index f25e57ffde942..0000000000000 --- a/src/vs/workbench/contrib/debug/browser/media/breakpoint-function.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/contrib/debug/browser/media/breakpoint-hint.svg b/src/vs/workbench/contrib/debug/browser/media/breakpoint-hint.svg deleted file mode 100644 index d622c6cf0c4b5..0000000000000 --- a/src/vs/workbench/contrib/debug/browser/media/breakpoint-hint.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/src/vs/workbench/contrib/debug/browser/media/breakpoint-log-disabled.svg b/src/vs/workbench/contrib/debug/browser/media/breakpoint-log-disabled.svg deleted file mode 100644 index ea246058e0f6a..0000000000000 --- a/src/vs/workbench/contrib/debug/browser/media/breakpoint-log-disabled.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/contrib/debug/browser/media/breakpoint-log-unverified.svg b/src/vs/workbench/contrib/debug/browser/media/breakpoint-log-unverified.svg deleted file mode 100644 index ae8ed0ba7b696..0000000000000 --- a/src/vs/workbench/contrib/debug/browser/media/breakpoint-log-unverified.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/contrib/debug/browser/media/breakpoint-log.svg b/src/vs/workbench/contrib/debug/browser/media/breakpoint-log.svg deleted file mode 100644 index fc72afc7e2b3e..0000000000000 --- a/src/vs/workbench/contrib/debug/browser/media/breakpoint-log.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/contrib/debug/browser/media/breakpoint-unsupported.svg b/src/vs/workbench/contrib/debug/browser/media/breakpoint-unsupported.svg deleted file mode 100644 index 624b9f60c80da..0000000000000 --- a/src/vs/workbench/contrib/debug/browser/media/breakpoint-unsupported.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/contrib/debug/browser/media/breakpoint-unverified.svg b/src/vs/workbench/contrib/debug/browser/media/breakpoint-unverified.svg deleted file mode 100644 index 0f39b8b7c8f06..0000000000000 --- a/src/vs/workbench/contrib/debug/browser/media/breakpoint-unverified.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/contrib/debug/browser/media/breakpoint.svg b/src/vs/workbench/contrib/debug/browser/media/breakpoint.svg deleted file mode 100644 index af02a87495033..0000000000000 --- a/src/vs/workbench/contrib/debug/browser/media/breakpoint.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/contrib/debug/browser/media/continue-dark.svg b/src/vs/workbench/contrib/debug/browser/media/continue-dark.svg deleted file mode 100644 index 7c58386cccc63..0000000000000 --- a/src/vs/workbench/contrib/debug/browser/media/continue-dark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/contrib/debug/browser/media/continue-light.svg b/src/vs/workbench/contrib/debug/browser/media/continue-light.svg deleted file mode 100644 index 7c58386cccc63..0000000000000 --- a/src/vs/workbench/contrib/debug/browser/media/continue-light.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/contrib/debug/browser/media/current-and-breakpoint.svg b/src/vs/workbench/contrib/debug/browser/media/current-and-breakpoint.svg deleted file mode 100644 index 17d71fddac9df..0000000000000 --- a/src/vs/workbench/contrib/debug/browser/media/current-and-breakpoint.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/src/vs/workbench/contrib/debug/browser/media/current-arrow.svg b/src/vs/workbench/contrib/debug/browser/media/current-arrow.svg deleted file mode 100644 index 85f288efcd3ee..0000000000000 --- a/src/vs/workbench/contrib/debug/browser/media/current-arrow.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/contrib/debug/browser/media/disconnect-dark.svg b/src/vs/workbench/contrib/debug/browser/media/disconnect-dark.svg deleted file mode 100644 index 71aae0dd887fc..0000000000000 --- a/src/vs/workbench/contrib/debug/browser/media/disconnect-dark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/contrib/debug/browser/media/disconnect-light.svg b/src/vs/workbench/contrib/debug/browser/media/disconnect-light.svg deleted file mode 100644 index 06fc4c31553ed..0000000000000 --- a/src/vs/workbench/contrib/debug/browser/media/disconnect-light.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/contrib/debug/browser/media/pause-dark.svg b/src/vs/workbench/contrib/debug/browser/media/pause-dark.svg deleted file mode 100644 index 9cd9f46613072..0000000000000 --- a/src/vs/workbench/contrib/debug/browser/media/pause-dark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/contrib/debug/browser/media/pause-light.svg b/src/vs/workbench/contrib/debug/browser/media/pause-light.svg deleted file mode 100644 index 01d3cbc290ce6..0000000000000 --- a/src/vs/workbench/contrib/debug/browser/media/pause-light.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/contrib/debug/browser/media/restart-dark.svg b/src/vs/workbench/contrib/debug/browser/media/restart-dark.svg deleted file mode 100644 index fc48916d5a647..0000000000000 --- a/src/vs/workbench/contrib/debug/browser/media/restart-dark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/contrib/debug/browser/media/restart-light.svg b/src/vs/workbench/contrib/debug/browser/media/restart-light.svg deleted file mode 100644 index 4964d5bfaf19e..0000000000000 --- a/src/vs/workbench/contrib/debug/browser/media/restart-light.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/contrib/debug/browser/media/reverse-continue-dark.svg b/src/vs/workbench/contrib/debug/browser/media/reverse-continue-dark.svg deleted file mode 100644 index e0bbfb4202e36..0000000000000 --- a/src/vs/workbench/contrib/debug/browser/media/reverse-continue-dark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/contrib/debug/browser/media/reverse-continue-light.svg b/src/vs/workbench/contrib/debug/browser/media/reverse-continue-light.svg deleted file mode 100644 index e0bbfb4202e36..0000000000000 --- a/src/vs/workbench/contrib/debug/browser/media/reverse-continue-light.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/contrib/debug/browser/media/stackframe-and-breakpoint.svg b/src/vs/workbench/contrib/debug/browser/media/stackframe-and-breakpoint.svg deleted file mode 100644 index 3ce31c822c74b..0000000000000 --- a/src/vs/workbench/contrib/debug/browser/media/stackframe-and-breakpoint.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/src/vs/workbench/contrib/debug/browser/media/stackframe-arrow.svg b/src/vs/workbench/contrib/debug/browser/media/stackframe-arrow.svg deleted file mode 100644 index 38b63a34c5371..0000000000000 --- a/src/vs/workbench/contrib/debug/browser/media/stackframe-arrow.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/contrib/debug/browser/media/step-back-dark.svg b/src/vs/workbench/contrib/debug/browser/media/step-back-dark.svg deleted file mode 100644 index 5a6ada3e113f0..0000000000000 --- a/src/vs/workbench/contrib/debug/browser/media/step-back-dark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/contrib/debug/browser/media/step-back-light.svg b/src/vs/workbench/contrib/debug/browser/media/step-back-light.svg deleted file mode 100644 index b5a994d42525a..0000000000000 --- a/src/vs/workbench/contrib/debug/browser/media/step-back-light.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/contrib/debug/browser/media/step-into-dark.svg b/src/vs/workbench/contrib/debug/browser/media/step-into-dark.svg deleted file mode 100644 index 570ae02aafa4f..0000000000000 --- a/src/vs/workbench/contrib/debug/browser/media/step-into-dark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/contrib/debug/browser/media/step-into-light.svg b/src/vs/workbench/contrib/debug/browser/media/step-into-light.svg deleted file mode 100644 index 55c47062f5c4a..0000000000000 --- a/src/vs/workbench/contrib/debug/browser/media/step-into-light.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/contrib/debug/browser/media/step-out-dark.svg b/src/vs/workbench/contrib/debug/browser/media/step-out-dark.svg deleted file mode 100644 index 33a7a2fdb7281..0000000000000 --- a/src/vs/workbench/contrib/debug/browser/media/step-out-dark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/contrib/debug/browser/media/step-out-light.svg b/src/vs/workbench/contrib/debug/browser/media/step-out-light.svg deleted file mode 100644 index 6ac2139659d46..0000000000000 --- a/src/vs/workbench/contrib/debug/browser/media/step-out-light.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/contrib/debug/browser/media/step-over-dark.svg b/src/vs/workbench/contrib/debug/browser/media/step-over-dark.svg deleted file mode 100644 index 5bf10674eecdd..0000000000000 --- a/src/vs/workbench/contrib/debug/browser/media/step-over-dark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/contrib/debug/browser/media/step-over-light.svg b/src/vs/workbench/contrib/debug/browser/media/step-over-light.svg deleted file mode 100644 index b874a2564b5e5..0000000000000 --- a/src/vs/workbench/contrib/debug/browser/media/step-over-light.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/contrib/debug/browser/media/stop-dark.svg b/src/vs/workbench/contrib/debug/browser/media/stop-dark.svg deleted file mode 100644 index 9a28f77a9f970..0000000000000 --- a/src/vs/workbench/contrib/debug/browser/media/stop-dark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/contrib/debug/browser/media/stop-light.svg b/src/vs/workbench/contrib/debug/browser/media/stop-light.svg deleted file mode 100644 index 9a28f77a9f970..0000000000000 --- a/src/vs/workbench/contrib/debug/browser/media/stop-light.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - From deb6b36378b071e5cb39287dbd73ee4dccd2d494 Mon Sep 17 00:00:00 2001 From: Miguel Solorio Date: Wed, 13 Nov 2019 20:58:51 -0800 Subject: [PATCH 232/352] Add data & unsupported breakpoint color tokens --- .../browser/debugCallStackContribution.ts | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/vs/workbench/contrib/debug/browser/debugCallStackContribution.ts b/src/vs/workbench/contrib/debug/browser/debugCallStackContribution.ts index 6a524f942794d..687eb51cd2d10 100644 --- a/src/vs/workbench/contrib/debug/browser/debugCallStackContribution.ts +++ b/src/vs/workbench/contrib/debug/browser/debugCallStackContribution.ts @@ -234,6 +234,24 @@ registerThemingParticipant((theme, collector) => { `); } + const debugIconBreakpointDataColor = theme.getColor(debugIconBreakpointDataForeground); + if (debugIconBreakpointDataColor) { + collector.addRule(` + .monaco-workbench .codicon-debug-breakpoint-data { + color: ${debugIconBreakpointDataColor} !important; + } + `); + } + + const debugIconBreakpointUnsupportedColor = theme.getColor(debugIconBreakpointUnsupportedForeground); + if (debugIconBreakpointUnsupportedColor) { + collector.addRule(` + .monaco-workbench .codicon-debug-breakpoint-unsupported { + color: ${debugIconBreakpointUnsupportedColor} !important; + } + `); + } + const debugIconBreakpointStackframeColor = theme.getColor(debugIconBreakpointStackframeForeground); if (debugIconBreakpointStackframeColor) { collector.addRule(` @@ -264,5 +282,7 @@ const debugIconBreakpointUnverifiedForeground = registerColor('debugIcon.breakpo const debugIconBreakpointConditionalForeground = registerColor('debugIcon.breakpointConditionalForeground', { dark: debugIconBreakpointForeground, light: debugIconBreakpointForeground, hc: debugIconBreakpointForeground }, localize('debugIcon.breakpointConditionalForeground', 'Icon color for conditional breakpoints.')); const debugIconBreakpointLogForeground = registerColor('debugIcon.breakpointLogForeground', { dark: debugIconBreakpointForeground, light: debugIconBreakpointForeground, hc: debugIconBreakpointForeground }, localize('debugIcon.breakpointLogForeground', 'Icon color for log breakpoints.')); const debugIconBreakpointFunctionForeground = registerColor('debugIcon.breakpointFunctionForeground', { dark: debugIconBreakpointForeground, light: debugIconBreakpointForeground, hc: debugIconBreakpointForeground }, localize('debugIcon.breakpointFunctionForeground', 'Icon color for function breakpoints.')); +const debugIconBreakpointDataForeground = registerColor('debugIcon.breakpointDataForeground', { dark: debugIconBreakpointForeground, light: debugIconBreakpointForeground, hc: debugIconBreakpointForeground }, localize('debugIcon.breakpointDataForeground', 'Icon color for data breakpoints.')); +const debugIconBreakpointUnsupportedForeground = registerColor('debugIcon.breakpointUnsupportedForeground', { dark: debugIconBreakpointForeground, light: debugIconBreakpointForeground, hc: debugIconBreakpointForeground }, localize('debugIcon.breakpointUnsupportedForeground', 'Icon color for unsupported breakpoints.')); const debugIconBreakpointStackframeForeground = registerColor('debugIcon.breakpointStackframeForeground', { dark: '#FFCC00', light: '#FFCC00', hc: '#FFCC00' }, localize('debugIcon.breakpointStackframeForeground', 'Icon color for breakpoints.')); const debugIconBreakpointStackframeFocusedForeground = registerColor('debugIcon.breakpointStackframeFocusedForeground', { dark: '#89D185', light: '#89D185', hc: '#89D185' }, localize('debugIcon.breakpointStackframeFocusedForeground', 'Icon color for breakpoints.')); From a0316e3b3087e1416f8c41acef0b40fca19a30a5 Mon Sep 17 00:00:00 2001 From: Miguel Solorio Date: Wed, 13 Nov 2019 21:18:43 -0800 Subject: [PATCH 233/352] Update breakpoint glyph name in automation test --- test/automation/src/debug.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/automation/src/debug.ts b/test/automation/src/debug.ts index ec6678bb780ab..4739d8a991798 100644 --- a/test/automation/src/debug.ts +++ b/test/automation/src/debug.ts @@ -19,7 +19,7 @@ const STEP_IN = `.debug-toolbar .action-label[title*="Step Into"]`; const STEP_OUT = `.debug-toolbar .action-label[title*="Step Out"]`; const CONTINUE = `.debug-toolbar .action-label[title*="Continue"]`; const GLYPH_AREA = '.margin-view-overlays>:nth-child'; -const BREAKPOINT_GLYPH = '.codicon-circle-filled'; +const BREAKPOINT_GLYPH = '.codicon-debug-breakpoint'; const PAUSE = `.debug-toolbar .action-label[title*="Pause"]`; const DEBUG_STATUS_BAR = `.statusbar.debugging`; const NOT_DEBUG_STATUS_BAR = `.statusbar:not(debugging)`; From e1983faa78e623bbf7ec866d6cd467bf34f07bad Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Wed, 13 Nov 2019 21:27:30 -0800 Subject: [PATCH 234/352] Always show the overload count, even if there are more than 10 Fixes #84682 Also switches the use flexboxes to layout the parameter hints widget instead of absolute positioning --- .../contrib/parameterHints/parameterHints.css | 29 ++++++------------- .../parameterHints/parameterHintsWidget.ts | 18 +++++------- 2 files changed, 16 insertions(+), 31 deletions(-) diff --git a/src/vs/editor/contrib/parameterHints/parameterHints.css b/src/vs/editor/contrib/parameterHints/parameterHints.css index dff7f77f9e463..e77cb3570032b 100644 --- a/src/vs/editor/contrib/parameterHints/parameterHints.css +++ b/src/vs/editor/contrib/parameterHints/parameterHints.css @@ -13,12 +13,12 @@ .monaco-editor .parameter-hints-widget > .wrapper { max-width: 440px; display: flex; - flex-direction: column; + flex-direction: row; } .monaco-editor .parameter-hints-widget.multiple { min-height: 3.3em; - padding: 0 0 0 1.9em; + padding: 0; } .monaco-editor .parameter-hints-widget.visible { @@ -62,20 +62,19 @@ padding: 0 0.4em; } -.monaco-editor .parameter-hints-widget .buttons { - position: absolute; +.monaco-editor .parameter-hints-widget .controls { display: none; - bottom: 0; - left: 0; + flex-direction: column; + align-items: center; + min-width: 22px; + justify-content: flex-end; } -.monaco-editor .parameter-hints-widget.multiple .buttons { - display: block; +.monaco-editor .parameter-hints-widget.multiple .controls { + display: flex; } .monaco-editor .parameter-hints-widget.multiple .button { - position: absolute; - left: 2px; width: 16px; height: 16px; background-repeat: no-repeat; @@ -88,26 +87,16 @@ } .monaco-editor .parameter-hints-widget .button.next { - bottom: 0; background-image: url('arrow-down.svg'); } .monaco-editor .parameter-hints-widget .overloads { - position: absolute; - display: none; text-align: center; - bottom: 14px; - left: 0; - width: 22px; height: 12px; line-height: 12px; opacity: 0.5; } -.monaco-editor .parameter-hints-widget.multiple .overloads { - display: block; -} - .monaco-editor .parameter-hints-widget .signature .parameter.active { font-weight: bold; text-decoration: underline; diff --git a/src/vs/editor/contrib/parameterHints/parameterHintsWidget.ts b/src/vs/editor/contrib/parameterHints/parameterHintsWidget.ts index 2ac6ede62feb9..2120dc7aac833 100644 --- a/src/vs/editor/contrib/parameterHints/parameterHintsWidget.ts +++ b/src/vs/editor/contrib/parameterHints/parameterHintsWidget.ts @@ -22,6 +22,7 @@ import { IOpenerService } from 'vs/platform/opener/common/opener'; import { editorHoverBackground, editorHoverBorder, textCodeBlockBackground, textLinkForeground, editorHoverForeground } from 'vs/platform/theme/common/colorRegistry'; import { HIGH_CONTRAST, registerThemingParticipant } from 'vs/platform/theme/common/themeService'; import { ParameterHintsModel, TriggerContext } from 'vs/editor/contrib/parameterHints/parameterHintsModel'; +import { pad } from 'vs/base/common/strings'; const $ = dom.$; @@ -76,9 +77,10 @@ export class ParameterHintsWidget extends Disposable implements IContentWidget { const wrapper = dom.append(element, $('.wrapper')); wrapper.tabIndex = -1; - const buttons = dom.append(wrapper, $('.buttons')); - const previous = dom.append(buttons, $('.button.previous')); - const next = dom.append(buttons, $('.button.next')); + const controls = dom.append(wrapper, $('.controls')); + const previous = dom.append(controls, $('.button.previous')); + const overloads = dom.append(controls, $('.overloads')); + const next = dom.append(controls, $('.button.next')); const onPreviousClick = stop(domEvent(previous, 'click')); this._register(onPreviousClick(this.previous, this)); @@ -86,8 +88,6 @@ export class ParameterHintsWidget extends Disposable implements IContentWidget { const onNextClick = stop(domEvent(next, 'click')); this._register(onNextClick(this.next, this)); - const overloads = dom.append(wrapper, $('.overloads')); - const body = $('.body'); const scrollbar = new DomScrollableElement(body, {}); this._register(scrollbar); @@ -239,12 +239,8 @@ export class ParameterHintsWidget extends Disposable implements IContentWidget { dom.toggleClass(this.domNodes.signature, 'has-docs', hasDocs); dom.toggleClass(this.domNodes.docs, 'empty', !hasDocs); - let currentOverload = String(hints.activeSignature + 1); - if (hints.signatures.length < 10) { - currentOverload += `/${hints.signatures.length}`; - } - - this.domNodes.overloads.textContent = currentOverload; + this.domNodes.overloads.textContent = + pad(hints.activeSignature + 1, hints.signatures.length.toString().length) + '/' + hints.signatures.length; if (activeParameter) { const labelToAnnounce = this.getParameterLabel(signature, hints.activeParameter); From 9134f9fddd1f6ce751f7651eb17a99a4dd686e1a Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Thu, 14 Nov 2019 07:58:37 +0100 Subject: [PATCH 235/352] some mirco optimizations for CodeLensWidget, #84726 --- .../editor/contrib/codelens/codelensWidget.ts | 67 ++++++++++--------- 1 file changed, 37 insertions(+), 30 deletions(-) diff --git a/src/vs/editor/contrib/codelens/codelensWidget.ts b/src/vs/editor/contrib/codelens/codelensWidget.ts index c048a6f15410c..546cdfd028e14 100644 --- a/src/vs/editor/contrib/codelens/codelensWidget.ts +++ b/src/vs/editor/contrib/codelens/codelensWidget.ts @@ -5,7 +5,6 @@ import 'vs/css!./codelensWidget'; import * as dom from 'vs/base/browser/dom'; -import { coalesce, isFalsyOrEmpty } from 'vs/base/common/arrays'; import { renderCodicons } from 'vs/base/browser/ui/codiconLabel/codiconLabel'; import * as editorBrowser from 'vs/editor/browser/editorBrowser'; import { Range } from 'vs/editor/common/core/range'; @@ -66,7 +65,7 @@ class CodeLensContentWidget implements editorBrowser.IContentWidget { constructor( editor: editorBrowser.ICodeEditor, symbolRange: Range, - data: CodeLensItem[] + lenses: Array ) { this._id = 'codeLensWidget' + (++CodeLensContentWidget._idPool); this._editor = editor; @@ -74,10 +73,9 @@ class CodeLensContentWidget implements editorBrowser.IContentWidget { this.setSymbolRange(symbolRange); this._domNode = document.createElement('span'); - this._domNode.innerHTML = ' '; - dom.addClass(this._domNode, 'codelens-decoration'); + this._domNode.className = 'codelens-decoration'; this.updateHeight(); - this.withCommands(data.map(data => data.symbol), false); + this.withCommands(lenses, false); } updateHeight(): void { @@ -88,39 +86,45 @@ class CodeLensContentWidget implements editorBrowser.IContentWidget { this._domNode.style.lineHeight = `${lineHeight}px`; this._domNode.style.fontSize = `${Math.round(fontInfo.fontSize * 0.9)}px`; this._domNode.style.paddingRight = `${Math.round(fontInfo.fontSize * 0.45)}px`; - this._domNode.innerHTML = ' '; } - withCommands(inSymbols: Array, animate: boolean): void { + withCommands(lenses: Array, animate: boolean): void { this._commands.clear(); - const symbols = coalesce(inSymbols); - if (isFalsyOrEmpty(symbols)) { - this._domNode.innerHTML = 'no commands'; - return; - } - - let html: string[] = []; - for (let i = 0; i < symbols.length; i++) { - const command = symbols[i].command; - if (command) { - const title = renderCodicons(command.title); - let part: string; - if (command.id) { - part = `${title}`; - this._commands.set(String(i), command); + let innerHtml = ''; + let hasSymbol = false; + for (let i = 0; i < lenses.length; i++) { + const lens = lenses[i]; + if (!lens) { + continue; + } + hasSymbol = true; + if (lens.command) { + const title = renderCodicons(lens.command.title); + if (lens.command.id) { + innerHtml += `${title}`; + this._commands.set(String(i), lens.command); } else { - part = `${title}`; + innerHtml += `${title}`; + } + if (i + 1 < lenses.length) { + innerHtml += ' | '; } - html.push(part); } } - const wasEmpty = this._domNode.innerHTML === '' || this._domNode.innerHTML === ' '; - this._domNode.innerHTML = html.join(' | '); - this._editor.layoutContentWidget(this); - if (wasEmpty && animate) { - dom.addClass(this._domNode, 'fadein'); + if (!hasSymbol) { + // symbols but no commands + this._domNode.innerHTML = 'no commands'; + + } else { + // symbols and commands + const wasEmpty = this._domNode.innerHTML === '' || this._domNode.innerHTML === ' '; + this._domNode.innerHTML = innerHtml || ' '; + this._editor.layoutContentWidget(this); + if (wasEmpty && animate) { + dom.addClass(this._domNode, 'fadein'); + } } } @@ -213,8 +217,11 @@ export class CodeLensWidget { this._decorationIds = new Array(this._data.length); let range: Range | undefined; + let lenses: CodeLens[] = []; this._data.forEach((codeLensData, i) => { + lenses.push(codeLensData.symbol); + helper.addDecoration({ range: codeLensData.symbol.range, options: ModelDecorationOptions.EMPTY @@ -229,7 +236,7 @@ export class CodeLensWidget { }); if (range) { - this._contentWidget = new CodeLensContentWidget(editor, range, this._data); + this._contentWidget = new CodeLensContentWidget(editor, range, lenses); this._viewZone = new CodeLensViewZone(range.startLineNumber - 1, updateCallback); this._viewZoneId = viewZoneChangeAccessor.addZone(this._viewZone); From bf9d2637b8c3ebed40c074f4570de63d679d1929 Mon Sep 17 00:00:00 2001 From: Miguel Solorio Date: Wed, 13 Nov 2019 23:04:09 -0800 Subject: [PATCH 236/352] Use optional chaining --- src/vs/code/electron-main/window.ts | 2 +- src/vs/platform/actions/browser/menuEntryActionViewItem.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/code/electron-main/window.ts b/src/vs/code/electron-main/window.ts index 531dfe2afb807..6313aaf033836 100644 --- a/src/vs/code/electron-main/window.ts +++ b/src/vs/code/electron-main/window.ts @@ -1096,7 +1096,7 @@ export class CodeWindow extends Disposable implements ICodeWindow { private createTouchBarGroupSegments(items: ISerializableCommandAction[] = []): ITouchBarSegment[] { const segments: ITouchBarSegment[] = items.map(item => { let icon: NativeImage | undefined; - if (item.iconLocation && typeof item.iconLocation?.dark !== 'undefined' && item.iconLocation.dark.scheme === 'file') { + if (item.iconLocation && item.iconLocation?.dark?.scheme === 'file') { icon = nativeImage.createFromPath(URI.revive(item.iconLocation.dark).fsPath); if (icon.isEmpty()) { icon = undefined; diff --git a/src/vs/platform/actions/browser/menuEntryActionViewItem.ts b/src/vs/platform/actions/browser/menuEntryActionViewItem.ts index ac27e5bf8c523..05efd4bd424ca 100644 --- a/src/vs/platform/actions/browser/menuEntryActionViewItem.ts +++ b/src/vs/platform/actions/browser/menuEntryActionViewItem.ts @@ -255,7 +255,7 @@ export class MenuEntryActionViewItem extends ActionViewItem { else if (item.iconLocation) { let iconClass: string; - if (typeof item.iconLocation?.dark !== 'undefined') { + if (item.iconLocation?.dark?.scheme) { const iconPathMapKey = item.iconLocation.dark.toString(); From 0b72a41d72bdb9b0478e9bde30724082e68252f4 Mon Sep 17 00:00:00 2001 From: Miguel Solorio Date: Wed, 13 Nov 2019 23:04:55 -0800 Subject: [PATCH 237/352] Remove unused import --- src/vs/workbench/contrib/debug/browser/debug.contribution.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/vs/workbench/contrib/debug/browser/debug.contribution.ts b/src/vs/workbench/contrib/debug/browser/debug.contribution.ts index ec050e66f7591..3b28f2ac0c3d4 100644 --- a/src/vs/workbench/contrib/debug/browser/debug.contribution.ts +++ b/src/vs/workbench/contrib/debug/browser/debug.contribution.ts @@ -47,7 +47,6 @@ import { WatchExpressionsView } from 'vs/workbench/contrib/debug/browser/watchEx import { VariablesView } from 'vs/workbench/contrib/debug/browser/variablesView'; import { ClearReplAction, Repl } from 'vs/workbench/contrib/debug/browser/repl'; import { DebugContentProvider } from 'vs/workbench/contrib/debug/common/debugContentProvider'; -import { registerAndGetAmdImageURL } from 'vs/base/common/amd'; import { DebugCallStackContribution } from 'vs/workbench/contrib/debug/browser/debugCallStackContribution'; class OpenDebugViewletAction extends ShowViewletAction { From 929fab18765a7b41bcde7beb723ef4fd2a424e91 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Thu, 14 Nov 2019 08:37:12 +0100 Subject: [PATCH 238/352] dialog - extract confirmSave to file dialog servie --- src/vs/platform/dialogs/common/dialogs.ts | 11 ++++ .../browser/parts/editor/editorActions.ts | 18 ++++-- .../browser/parts/editor/editorGroupView.ts | 10 +-- src/vs/workbench/common/editor.ts | 17 ----- .../common/editor/untitledTextEditorInput.ts | 6 +- .../files/common/editors/fileEditorInput.ts | 6 +- .../browser/testCustomEditors.ts | 7 +-- .../browser/abstractFileDialogService.ts | 48 +++++++++++++- .../electron-browser/fileDialogService.ts | 19 +++++- .../textfile/browser/textFileService.ts | 62 +++++-------------- .../services/textfile/common/textfiles.ts | 10 +-- .../electron-browser/nativeTextFileService.ts | 11 ---- .../textfile/test/textFileService.test.ts | 15 ++--- .../workbench/test/workbenchTestServices.ts | 27 ++++---- 14 files changed, 131 insertions(+), 136 deletions(-) diff --git a/src/vs/platform/dialogs/common/dialogs.ts b/src/vs/platform/dialogs/common/dialogs.ts index 0258fa407dd8e..64f783471bae5 100644 --- a/src/vs/platform/dialogs/common/dialogs.ts +++ b/src/vs/platform/dialogs/common/dialogs.ts @@ -239,12 +239,23 @@ export interface IFileDialogService { */ showSaveDialog(options: ISaveDialogOptions): Promise; + /** + * Shows a confirm dialog for saving 1-N files. + */ + showSaveConfirm(fileNameOrResources: string | URI[]): Promise; + /** * Shows a open file dialog and returns the chosen file URI. */ showOpenDialog(options: IOpenDialogOptions): Promise; } +export const enum ConfirmResult { + SAVE, + DONT_SAVE, + CANCEL +} + const MAX_CONFIRM_FILES = 10; export function getConfirmMessage(start: string, resourcesToConfirm: readonly URI[]): string { const message = [start]; diff --git a/src/vs/workbench/browser/parts/editor/editorActions.ts b/src/vs/workbench/browser/parts/editor/editorActions.ts index 178c61b28b67c..0c2e015645589 100644 --- a/src/vs/workbench/browser/parts/editor/editorActions.ts +++ b/src/vs/workbench/browser/parts/editor/editorActions.ts @@ -6,7 +6,7 @@ import * as nls from 'vs/nls'; import { Action } from 'vs/base/common/actions'; import { mixin } from 'vs/base/common/objects'; -import { IEditorInput, EditorInput, IEditorIdentifier, ConfirmResult, IEditorCommandsContext, CloseDirection } from 'vs/workbench/common/editor'; +import { IEditorInput, EditorInput, IEditorIdentifier, IEditorCommandsContext, CloseDirection } from 'vs/workbench/common/editor'; import { QuickOpenEntryGroup } from 'vs/base/parts/quickopen/browser/quickOpenModel'; import { EditorQuickOpenEntry, EditorQuickOpenEntryGroup, IEditorQuickOpenEntry, QuickOpenAction } from 'vs/workbench/browser/quickopen'; import { IQuickOpenService } from 'vs/platform/quickOpen/common/quickOpen'; @@ -22,6 +22,8 @@ import { IEditorService, SIDE_GROUP } from 'vs/workbench/services/editor/common/ import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { DisposableStore } from 'vs/base/common/lifecycle'; import { IWorkspacesService } from 'vs/platform/workspaces/common/workspaces'; +import { IFileDialogService, ConfirmResult } from 'vs/platform/dialogs/common/dialogs'; +import { IWorkingCopyService } from 'vs/workbench/services/workingCopy/common/workingCopyService'; export class ExecuteCommandAction extends Action { @@ -597,6 +599,8 @@ export abstract class BaseCloseAllAction extends Action { label: string, clazz: string | undefined, private textFileService: ITextFileService, + private workingCopyService: IWorkingCopyService, + private fileDialogService: IFileDialogService, protected editorGroupService: IEditorGroupsService ) { super(id, label, clazz); @@ -619,7 +623,7 @@ export abstract class BaseCloseAllAction extends Action { async run(): Promise { // Just close all if there are no dirty editors - if (!this.textFileService.isDirty()) { + if (!this.workingCopyService.hasDirty) { return this.doCloseAll(); } @@ -636,7 +640,7 @@ export abstract class BaseCloseAllAction extends Action { return undefined; })); - const confirm = await this.textFileService.confirmSave(); + const confirm = await this.fileDialogService.showSaveConfirm(this.workingCopyService.getDirty().map(copy => copy.resource)); if (confirm === ConfirmResult.CANCEL) { return; } @@ -667,9 +671,11 @@ export class CloseAllEditorsAction extends BaseCloseAllAction { id: string, label: string, @ITextFileService textFileService: ITextFileService, + @IWorkingCopyService workingCopyService: IWorkingCopyService, + @IFileDialogService fileDialogService: IFileDialogService, @IEditorGroupsService editorGroupService: IEditorGroupsService ) { - super(id, label, 'codicon-close-all', textFileService, editorGroupService); + super(id, label, 'codicon-close-all', textFileService, workingCopyService, fileDialogService, editorGroupService); } protected doCloseAll(): Promise { @@ -686,9 +692,11 @@ export class CloseAllEditorGroupsAction extends BaseCloseAllAction { id: string, label: string, @ITextFileService textFileService: ITextFileService, + @IWorkingCopyService workingCopyService: IWorkingCopyService, + @IFileDialogService fileDialogService: IFileDialogService, @IEditorGroupsService editorGroupService: IEditorGroupsService ) { - super(id, label, undefined, textFileService, editorGroupService); + super(id, label, undefined, textFileService, workingCopyService, fileDialogService, editorGroupService); } protected async doCloseAll(): Promise { diff --git a/src/vs/workbench/browser/parts/editor/editorGroupView.ts b/src/vs/workbench/browser/parts/editor/editorGroupView.ts index 60c90b3c8428e..281a231ebf3bf 100644 --- a/src/vs/workbench/browser/parts/editor/editorGroupView.ts +++ b/src/vs/workbench/browser/parts/editor/editorGroupView.ts @@ -6,7 +6,7 @@ import 'vs/css!./media/editorgroupview'; import { EditorGroup, IEditorOpenOptions, EditorCloseEvent, ISerializedEditorGroup, isSerializedEditorGroup } from 'vs/workbench/common/editor/editorGroup'; -import { EditorInput, EditorOptions, GroupIdentifier, ConfirmResult, SideBySideEditorInput, CloseDirection, IEditorCloseEvent, EditorGroupActiveEditorDirtyContext, IEditor, EditorGroupEditorsCountContext } from 'vs/workbench/common/editor'; +import { EditorInput, EditorOptions, GroupIdentifier, SideBySideEditorInput, CloseDirection, IEditorCloseEvent, EditorGroupActiveEditorDirtyContext, IEditor, EditorGroupEditorsCountContext, toResource, SideBySideEditor } from 'vs/workbench/common/editor'; import { Event, Emitter, Relay } from 'vs/base/common/event'; import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { addClass, addClasses, Dimension, trackFocus, toggleClass, removeClass, addDisposableListener, EventType, EventHelper, findParentWithClass, clearNode, isAncestor } from 'vs/base/browser/dom'; @@ -50,7 +50,7 @@ import { guessMimeTypes } from 'vs/base/common/mime'; import { extname } from 'vs/base/common/resources'; import { Schemas } from 'vs/base/common/network'; import { EditorActivation, EditorOpenContext } from 'vs/platform/editor/common/editor'; -import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; +import { IDialogService, IFileDialogService, ConfirmResult } from 'vs/platform/dialogs/common/dialogs'; export class EditorGroupView extends Themable implements IEditorGroupView { @@ -131,7 +131,8 @@ export class EditorGroupView extends Themable implements IEditorGroupView { @IUntitledTextEditorService private readonly untitledTextEditorService: IUntitledTextEditorService, @IKeybindingService private readonly keybindingService: IKeybindingService, @IMenuService private readonly menuService: IMenuService, - @IContextMenuService private readonly contextMenuService: IContextMenuService + @IContextMenuService private readonly contextMenuService: IContextMenuService, + @IFileDialogService private readonly fileDialogService: IFileDialogService ) { super(themeService); @@ -1260,7 +1261,8 @@ export class EditorGroupView extends Themable implements IEditorGroupView { // Switch to editor that we want to handle and confirm to save/revert await this.openEditor(editor); - const res = await editor.confirmSave(); + const editorResource = toResource(editor, { supportSideBySide: SideBySideEditor.MASTER }); + const res = await this.fileDialogService.showSaveConfirm(editorResource ? [editorResource] : editor.getName()!); // It could be that the editor saved meanwhile, so we check again // to see if anything needs to happen before closing for good. diff --git a/src/vs/workbench/common/editor.ts b/src/vs/workbench/common/editor.ts index 4ac59c9c71cd5..87782783b9f62 100644 --- a/src/vs/workbench/common/editor.ts +++ b/src/vs/workbench/common/editor.ts @@ -415,13 +415,6 @@ export abstract class EditorInput extends Disposable implements IEditorInput { return false; } - /** - * Subclasses should bring up a proper dialog for the user if the editor is dirty and return the result. - */ - confirmSave(): Promise { - return Promise.resolve(ConfirmResult.DONT_SAVE); - } - /** * Saves the editor if it is dirty. Subclasses return a promise with a boolean indicating the success of the operation. */ @@ -476,12 +469,6 @@ export abstract class EditorInput extends Disposable implements IEditorInput { } } -export const enum ConfirmResult { - SAVE, - DONT_SAVE, - CANCEL -} - export const enum EncodingMode { /** @@ -573,10 +560,6 @@ export class SideBySideEditorInput extends EditorInput { return this.master.isDirty(); } - confirmSave(): Promise { - return this.master.confirmSave(); - } - save(): Promise { return this.master.save(); } diff --git a/src/vs/workbench/common/editor/untitledTextEditorInput.ts b/src/vs/workbench/common/editor/untitledTextEditorInput.ts index 466216f984050..28ecc5b4b2322 100644 --- a/src/vs/workbench/common/editor/untitledTextEditorInput.ts +++ b/src/vs/workbench/common/editor/untitledTextEditorInput.ts @@ -8,7 +8,7 @@ import { suggestFilename } from 'vs/base/common/mime'; import { createMemoizer } from 'vs/base/common/decorators'; import { PLAINTEXT_MODE_ID } from 'vs/editor/common/modes/modesRegistry'; import { basenameOrAuthority, dirname } from 'vs/base/common/resources'; -import { EditorInput, IEncodingSupport, EncodingMode, ConfirmResult, Verbosity, IModeSupport } from 'vs/workbench/common/editor'; +import { EditorInput, IEncodingSupport, EncodingMode, Verbosity, IModeSupport } from 'vs/workbench/common/editor'; import { UntitledTextEditorModel } from 'vs/workbench/common/editor/untitledTextEditorModel'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { Event, Emitter } from 'vs/base/common/event'; @@ -148,10 +148,6 @@ export class UntitledTextEditorInput extends EditorInput implements IEncodingSup return false; } - confirmSave(): Promise { - return this.textFileService.confirmSave([this.resource]); - } - save(): Promise { return this.textFileService.save(this.resource); } diff --git a/src/vs/workbench/contrib/files/common/editors/fileEditorInput.ts b/src/vs/workbench/contrib/files/common/editors/fileEditorInput.ts index 2695c40d587c9..104bebe8fb3b3 100644 --- a/src/vs/workbench/contrib/files/common/editors/fileEditorInput.ts +++ b/src/vs/workbench/contrib/files/common/editors/fileEditorInput.ts @@ -7,7 +7,7 @@ import { localize } from 'vs/nls'; import { createMemoizer } from 'vs/base/common/decorators'; import { dirname } from 'vs/base/common/resources'; import { URI } from 'vs/base/common/uri'; -import { EncodingMode, ConfirmResult, EditorInput, IFileEditorInput, ITextEditorModel, Verbosity, IRevertOptions } from 'vs/workbench/common/editor'; +import { EncodingMode, EditorInput, IFileEditorInput, ITextEditorModel, Verbosity, IRevertOptions } from 'vs/workbench/common/editor'; import { TextFileEditorModel } from 'vs/workbench/services/textfile/common/textFileEditorModel'; import { BinaryEditorModel } from 'vs/workbench/common/editor/binaryEditorModel'; import { FileOperationError, FileOperationResult, IFileService } from 'vs/platform/files/common/files'; @@ -243,10 +243,6 @@ export class FileEditorInput extends EditorInput implements IFileEditorInput { return model.isDirty(); } - confirmSave(): Promise { - return this.textFileService.confirmSave([this.resource]); - } - save(): Promise { return this.textFileService.save(this.resource); } diff --git a/src/vs/workbench/contrib/testCustomEditors/browser/testCustomEditors.ts b/src/vs/workbench/contrib/testCustomEditors/browser/testCustomEditors.ts index 62711b74fc8b2..1a43978f69281 100644 --- a/src/vs/workbench/contrib/testCustomEditors/browser/testCustomEditors.ts +++ b/src/vs/workbench/contrib/testCustomEditors/browser/testCustomEditors.ts @@ -6,7 +6,7 @@ import * as nls from 'vs/nls'; import { Action } from 'vs/base/common/actions'; import { BaseEditor } from 'vs/workbench/browser/parts/editor/baseEditor'; -import { IEditorInputFactory, EditorInput, IEditorInputFactoryRegistry, Extensions as EditorInputExtensions, EditorModel, ConfirmResult, IRevertOptions, EditorOptions } from 'vs/workbench/common/editor'; +import { IEditorInputFactory, EditorInput, IEditorInputFactoryRegistry, Extensions as EditorInputExtensions, EditorModel, IRevertOptions, EditorOptions } from 'vs/workbench/common/editor'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IEditorModel } from 'vs/platform/editor/common/editor'; import { Dimension, addDisposableListener, EventType } from 'vs/base/browser/dom'; @@ -160,11 +160,6 @@ class TestCustomEditorInput extends EditorInput implements IWorkingCopy { return this.dirty; } - confirmSave(): Promise { - // TODO - return Promise.resolve(ConfirmResult.DONT_SAVE); - } - save(): Promise { this.setDirty(false); diff --git a/src/vs/workbench/services/dialogs/browser/abstractFileDialogService.ts b/src/vs/workbench/services/dialogs/browser/abstractFileDialogService.ts index f8d717d76a5cd..cead0c626ba5b 100644 --- a/src/vs/workbench/services/dialogs/browser/abstractFileDialogService.ts +++ b/src/vs/workbench/services/dialogs/browser/abstractFileDialogService.ts @@ -5,7 +5,7 @@ import * as nls from 'vs/nls'; import { IWindowOpenable } from 'vs/platform/windows/common/windows'; -import { IPickAndOpenOptions, ISaveDialogOptions, IOpenDialogOptions, FileFilter } from 'vs/platform/dialogs/common/dialogs'; +import { IPickAndOpenOptions, ISaveDialogOptions, IOpenDialogOptions, FileFilter, IFileDialogService, IDialogService, ConfirmResult, getConfirmMessage } from 'vs/platform/dialogs/common/dialogs'; import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; import { IHistoryService } from 'vs/workbench/services/history/common/history'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; @@ -20,8 +20,9 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur import { IFileService } from 'vs/platform/files/common/files'; import { IOpenerService } from 'vs/platform/opener/common/opener'; import { IHostService } from 'vs/workbench/services/host/browser/host'; +import Severity from 'vs/base/common/severity'; -export abstract class AbstractFileDialogService { +export abstract class AbstractFileDialogService implements IFileDialogService { _serviceBrand: undefined; @@ -34,6 +35,7 @@ export abstract class AbstractFileDialogService { @IConfigurationService protected readonly configurationService: IConfigurationService, @IFileService protected readonly fileService: IFileService, @IOpenerService protected readonly openerService: IOpenerService, + @IDialogService private readonly dialogService: IDialogService ) { } defaultFilePath(schemeFilter = this.getSchemeFilterForWindow()): URI | undefined { @@ -78,6 +80,40 @@ export abstract class AbstractFileDialogService { return this.defaultFilePath(schemeFilter); } + async showSaveConfirm(fileNameOrResources: string | URI[]): Promise { + if (this.environmentService.isExtensionDevelopment) { + return ConfirmResult.DONT_SAVE; // no veto when we are in extension dev mode because we cannot assume we run interactive (e.g. tests) + } + + if (Array.isArray(fileNameOrResources) && fileNameOrResources.length === 0) { + return ConfirmResult.DONT_SAVE; + } + + let message: string; + if (typeof fileNameOrResources === 'string' || fileNameOrResources.length === 1) { + message = nls.localize('saveChangesMessage', "Do you want to save the changes you made to {0}?", typeof fileNameOrResources === 'string' ? fileNameOrResources : resources.basename(fileNameOrResources[0])); + } else { + message = getConfirmMessage(nls.localize('saveChangesMessages', "Do you want to save the changes to the following {0} files?", fileNameOrResources.length), fileNameOrResources); + } + + const buttons: string[] = [ + Array.isArray(fileNameOrResources) && fileNameOrResources.length > 1 ? nls.localize({ key: 'saveAll', comment: ['&& denotes a mnemonic'] }, "&&Save All") : nls.localize({ key: 'save', comment: ['&& denotes a mnemonic'] }, "&&Save"), + nls.localize({ key: 'dontSave', comment: ['&& denotes a mnemonic'] }, "Do&&n't Save"), + nls.localize('cancel', "Cancel") + ]; + + const { choice } = await this.dialogService.show(Severity.Warning, message, buttons, { + cancelId: 2, + detail: nls.localize('saveChangesDetail', "Your changes will be lost if you don't save them.") + }); + + switch (choice) { + case 0: return ConfirmResult.SAVE; + case 1: return ConfirmResult.DONT_SAVE; + default: return ConfirmResult.CANCEL; + } + } + protected abstract addFileSchemaIfNeeded(schema: string): string[]; protected async pickFileFolderAndOpenSimplified(schema: string, options: IPickAndOpenOptions, preferNewWindow: boolean): Promise { @@ -179,4 +215,12 @@ export abstract class AbstractFileDialogService { protected getFileSystemSchema(options: { availableFileSystems?: readonly string[], defaultUri?: URI }): string { return options.availableFileSystems && options.availableFileSystems[0] || this.getSchemeFilterForWindow(); } + + abstract pickFileFolderAndOpen(options: IPickAndOpenOptions): Promise; + abstract pickFileAndOpen(options: IPickAndOpenOptions): Promise; + abstract pickFolderAndOpen(options: IPickAndOpenOptions): Promise; + abstract pickWorkspaceAndOpen(options: IPickAndOpenOptions): Promise; + abstract pickFileToSave(options: ISaveDialogOptions): Promise; + abstract showSaveDialog(options: ISaveDialogOptions): Promise; + abstract showOpenDialog(options: IOpenDialogOptions): Promise; } diff --git a/src/vs/workbench/services/dialogs/electron-browser/fileDialogService.ts b/src/vs/workbench/services/dialogs/electron-browser/fileDialogService.ts index a4873580a8da5..f4452c6dc6fae 100644 --- a/src/vs/workbench/services/dialogs/electron-browser/fileDialogService.ts +++ b/src/vs/workbench/services/dialogs/electron-browser/fileDialogService.ts @@ -6,7 +6,7 @@ import { SaveDialogOptions, OpenDialogOptions } from 'electron'; import { INativeOpenDialogOptions } from 'vs/platform/dialogs/node/dialogs'; import { IHostService } from 'vs/workbench/services/host/browser/host'; -import { IPickAndOpenOptions, ISaveDialogOptions, IOpenDialogOptions, IFileDialogService } from 'vs/platform/dialogs/common/dialogs'; +import { IPickAndOpenOptions, ISaveDialogOptions, IOpenDialogOptions, IFileDialogService, IDialogService, ConfirmResult } from 'vs/platform/dialogs/common/dialogs'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; import { IHistoryService } from 'vs/workbench/services/history/common/history'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; @@ -33,8 +33,11 @@ export class FileDialogService extends AbstractFileDialogService implements IFil @IConfigurationService configurationService: IConfigurationService, @IFileService fileService: IFileService, @IOpenerService openerService: IOpenerService, - @IElectronService private readonly electronService: IElectronService - ) { super(hostService, contextService, historyService, environmentService, instantiationService, configurationService, fileService, openerService); } + @IElectronService private readonly electronService: IElectronService, + @IDialogService dialogService: IDialogService + ) { + super(hostService, contextService, historyService, environmentService, instantiationService, configurationService, fileService, openerService, dialogService); + } private toNativeOpenDialogOptions(options: IPickAndOpenOptions): INativeOpenDialogOptions { return { @@ -180,6 +183,16 @@ export class FileDialogService extends AbstractFileDialogService implements IFil // Don't allow untitled schema through. return schema === Schemas.untitled ? [Schemas.file] : (schema !== Schemas.file ? [schema, Schemas.file] : [schema]); } + + async showSaveConfirm(fileNameOrResources: string | URI[]): Promise { + if (this.environmentService.isExtensionDevelopment) { + if (!this.environmentService.args['extension-development-confirm-save']) { + return ConfirmResult.DONT_SAVE; // no veto when we are in extension dev mode because we cannot assume we run interactive (e.g. tests) + } + } + + return super.showSaveConfirm(fileNameOrResources); + } } registerSingleton(IFileDialogService, FileDialogService, true); diff --git a/src/vs/workbench/services/textfile/browser/textFileService.ts b/src/vs/workbench/services/textfile/browser/textFileService.ts index f7409aa72ca81..7961fcdb09db9 100644 --- a/src/vs/workbench/services/textfile/browser/textFileService.ts +++ b/src/vs/workbench/services/textfile/browser/textFileService.ts @@ -9,7 +9,7 @@ import { Emitter, AsyncEmitter } from 'vs/base/common/event'; import * as platform from 'vs/base/common/platform'; import { IBackupFileService } from 'vs/workbench/services/backup/common/backup'; import { IResult, ITextFileOperationResult, ITextFileService, ITextFileStreamContent, SaveReason, ITextFileEditorModelManager, ITextFileEditorModel, ModelState, ISaveOptions, ITextFileContent, IResourceEncodings, IReadTextFileOptions, IWriteTextFileOptions, toBufferOrReadable, TextFileOperationError, TextFileOperationResult, FileOperationWillRunEvent, FileOperationDidRunEvent } from 'vs/workbench/services/textfile/common/textfiles'; -import { ConfirmResult, IRevertOptions } from 'vs/workbench/common/editor'; +import { IRevertOptions } from 'vs/workbench/common/editor'; import { ILifecycleService, ShutdownReason, LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle'; import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; import { IFileService, FileOperationError, FileOperationResult, HotExitConfiguration, IFileStatWithMetadata, ICreateFileOptions, FileOperation } from 'vs/platform/files/common/files'; @@ -24,9 +24,9 @@ import { Schemas } from 'vs/base/common/network'; import { IHistoryService } from 'vs/workbench/services/history/common/history'; import { createTextBufferFactoryFromSnapshot, createTextBufferFactoryFromStream } from 'vs/editor/common/model/textModel'; import { IModelService } from 'vs/editor/common/services/modelService'; -import { INotificationService, Severity } from 'vs/platform/notification/common/notification'; +import { INotificationService } from 'vs/platform/notification/common/notification'; import { isEqualOrParent, isEqual, joinPath, dirname, extname, basename, toLocalResource } from 'vs/base/common/resources'; -import { getConfirmMessage, IDialogService, IFileDialogService, ISaveDialogOptions, IConfirmation } from 'vs/platform/dialogs/common/dialogs'; +import { IDialogService, IFileDialogService, ISaveDialogOptions, IConfirmation, ConfirmResult } from 'vs/platform/dialogs/common/dialogs'; import { IModeService } from 'vs/editor/common/services/modeService'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { coalesce } from 'vs/base/common/arrays'; @@ -232,7 +232,7 @@ export abstract class AbstractTextFileService extends Disposable implements ITex } private async confirmBeforeShutdown(): Promise { - const confirm = await this.confirmSave(); + const confirm = await this.fileDialogService.showSaveConfirm(this.getDirty()); // Save if (confirm === ConfirmResult.SAVE) { @@ -496,49 +496,6 @@ export abstract class AbstractTextFileService extends Disposable implements ITex return result.results.length === 1 && !!result.results[0].success; } - async confirmSave(resources?: URI[]): Promise { - if (this.environmentService.isExtensionDevelopment) { - return ConfirmResult.DONT_SAVE; // no veto when we are in extension dev mode because we cannot assume we run interactive (e.g. tests) - } - - const resourcesToConfirm = this.getDirty(resources); - if (resourcesToConfirm.length === 0) { - return ConfirmResult.DONT_SAVE; - } - - const message = resourcesToConfirm.length === 1 - ? nls.localize('saveChangesMessage', "Do you want to save the changes you made to {0}?", basename(resourcesToConfirm[0])) - : getConfirmMessage(nls.localize('saveChangesMessages', "Do you want to save the changes to the following {0} files?", resourcesToConfirm.length), resourcesToConfirm); - - const buttons: string[] = [ - resourcesToConfirm.length > 1 ? nls.localize({ key: 'saveAll', comment: ['&& denotes a mnemonic'] }, "&&Save All") : nls.localize({ key: 'save', comment: ['&& denotes a mnemonic'] }, "&&Save"), - nls.localize({ key: 'dontSave', comment: ['&& denotes a mnemonic'] }, "Do&&n't Save"), - nls.localize('cancel', "Cancel") - ]; - - const { choice } = await this.dialogService.show(Severity.Warning, message, buttons, { - cancelId: 2, - detail: nls.localize('saveChangesDetail', "Your changes will be lost if you don't save them.") - }); - - switch (choice) { - case 0: return ConfirmResult.SAVE; - case 1: return ConfirmResult.DONT_SAVE; - default: return ConfirmResult.CANCEL; - } - } - - async confirmOverwrite(resource: URI): Promise { - const confirm: IConfirmation = { - message: nls.localize('confirmOverwrite', "'{0}' already exists. Do you want to replace it?", basename(resource)), - detail: nls.localize('irreversible', "A file or folder with the same name already exists in the folder {0}. Replacing it will overwrite its current contents.", basename(dirname(resource))), - primaryButton: nls.localize({ key: 'replaceButtonLabel', comment: ['&& denotes a mnemonic'] }, "&&Replace"), - type: 'warning' - }; - - return (await this.dialogService.confirm(confirm)).confirmed; - } - saveAll(includeUntitled?: boolean, options?: ISaveOptions): Promise; saveAll(resources: URI[], options?: ISaveOptions): Promise; saveAll(arg1?: boolean | URI[], options?: ISaveOptions): Promise { @@ -849,6 +806,17 @@ export abstract class AbstractTextFileService extends Disposable implements ITex } } + private async confirmOverwrite(resource: URI): Promise { + const confirm: IConfirmation = { + message: nls.localize('confirmOverwrite', "'{0}' already exists. Do you want to replace it?", basename(resource)), + detail: nls.localize('irreversible', "A file or folder with the same name already exists in the folder {0}. Replacing it will overwrite its current contents.", basename(dirname(resource))), + primaryButton: nls.localize({ key: 'replaceButtonLabel', comment: ['&& denotes a mnemonic'] }, "&&Replace"), + type: 'warning' + }; + + return (await this.dialogService.confirm(confirm)).confirmed; + } + private suggestFileName(untitledResource: URI): URI { const untitledFileName = this.untitledTextEditorService.suggestFileName(untitledResource); const remoteAuthority = this.environmentService.configuration.remoteAuthority; diff --git a/src/vs/workbench/services/textfile/common/textfiles.ts b/src/vs/workbench/services/textfile/common/textfiles.ts index bfc329ca941fe..d07dc93f41ee7 100644 --- a/src/vs/workbench/services/textfile/common/textfiles.ts +++ b/src/vs/workbench/services/textfile/common/textfiles.ts @@ -6,7 +6,7 @@ import { URI } from 'vs/base/common/uri'; import { Event, IWaitUntil } from 'vs/base/common/event'; import { IDisposable } from 'vs/base/common/lifecycle'; -import { IEncodingSupport, ConfirmResult, IRevertOptions, IModeSupport } from 'vs/workbench/common/editor'; +import { IEncodingSupport, IRevertOptions, IModeSupport } from 'vs/workbench/common/editor'; import { IBaseStatWithMetadata, IFileStatWithMetadata, IReadFileOptions, IWriteFileOptions, FileOperationError, FileOperationResult, FileOperation } from 'vs/platform/files/common/files'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { ITextEditorModel } from 'vs/editor/common/services/resolverService'; @@ -129,14 +129,6 @@ export interface ITextFileService extends IDisposable { * Move a file. If the file is dirty, its contents will be preserved and restored. */ move(source: URI, target: URI, overwrite?: boolean): Promise; - - /** - * Brings up the confirm dialog to either save, don't save or cancel. - * - * @param resources the resources of the files to ask for confirmation or null if - * confirming for all dirty resources. - */ - confirmSave(resources?: URI[]): Promise; } export class FileOperationWillRunEvent implements IWaitUntil { diff --git a/src/vs/workbench/services/textfile/electron-browser/nativeTextFileService.ts b/src/vs/workbench/services/textfile/electron-browser/nativeTextFileService.ts index 7a37e7ca8abc1..e105588731ade 100644 --- a/src/vs/workbench/services/textfile/electron-browser/nativeTextFileService.ts +++ b/src/vs/workbench/services/textfile/electron-browser/nativeTextFileService.ts @@ -39,7 +39,6 @@ import { IBackupFileService } from 'vs/workbench/services/backup/common/backup'; import { IHistoryService } from 'vs/workbench/services/history/common/history'; import { IDialogService, IFileDialogService } from 'vs/platform/dialogs/common/dialogs'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; -import { ConfirmResult } from 'vs/workbench/common/editor'; import { assign } from 'vs/base/common/objects'; import { IFilesConfigurationService } from 'vs/workbench/services/filesConfiguration/common/filesConfigurationService'; @@ -315,16 +314,6 @@ export class NativeTextFileService extends AbstractTextFileService { protected getWindowCount(): Promise { return this.electronService.getWindowCount(); } - - async confirmSave(resources?: URI[]): Promise { - if (this.environmentService.isExtensionDevelopment) { - if (!this.environmentService.args['extension-development-confirm-save']) { - return ConfirmResult.DONT_SAVE; // no veto when we are in extension dev mode because we cannot assume we run interactive (e.g. tests) - } - } - - return super.confirmSave(resources); - } } export interface IEncodingOverride { diff --git a/src/vs/workbench/services/textfile/test/textFileService.test.ts b/src/vs/workbench/services/textfile/test/textFileService.test.ts index 152212b71a2bc..db7e2bd8033ff 100644 --- a/src/vs/workbench/services/textfile/test/textFileService.test.ts +++ b/src/vs/workbench/services/textfile/test/textFileService.test.ts @@ -7,12 +7,11 @@ import * as sinon from 'sinon'; import * as platform from 'vs/base/common/platform'; import { URI } from 'vs/base/common/uri'; import { ILifecycleService, BeforeShutdownEvent, ShutdownReason } from 'vs/platform/lifecycle/common/lifecycle'; -import { workbenchInstantiationService, TestLifecycleService, TestTextFileService, TestContextService, TestFileService, TestElectronService, TestFilesConfigurationService } from 'vs/workbench/test/workbenchTestServices'; +import { workbenchInstantiationService, TestLifecycleService, TestTextFileService, TestContextService, TestFileService, TestElectronService, TestFilesConfigurationService, TestFileDialogService } from 'vs/workbench/test/workbenchTestServices'; import { toResource } from 'vs/base/test/common/utils'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { TextFileEditorModel } from 'vs/workbench/services/textfile/common/textFileEditorModel'; import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; -import { ConfirmResult } from 'vs/workbench/common/editor'; import { IUntitledTextEditorService } from 'vs/workbench/services/untitled/common/untitledTextEditorService'; import { HotExitConfiguration, IFileService } from 'vs/platform/files/common/files'; import { TextFileEditorModelManager } from 'vs/workbench/services/textfile/common/textFileEditorModelManager'; @@ -22,6 +21,7 @@ import { ModelServiceImpl } from 'vs/editor/common/services/modelServiceImpl'; import { Schemas } from 'vs/base/common/network'; import { IElectronService } from 'vs/platform/electron/node/electron'; import { IFilesConfigurationService } from 'vs/workbench/services/filesConfiguration/common/filesConfigurationService'; +import { IFileDialogService, ConfirmResult } from 'vs/platform/dialogs/common/dialogs'; class ServiceAccessor { constructor( @@ -32,7 +32,8 @@ class ServiceAccessor { @IWorkspaceContextService public contextService: TestContextService, @IModelService public modelService: ModelServiceImpl, @IFileService public fileService: TestFileService, - @IElectronService public electronService: TestElectronService + @IElectronService public electronService: TestElectronService, + @IFileDialogService public fileDialogService: TestFileDialogService ) { } } @@ -87,7 +88,7 @@ suite('Files - TextFileService', () => { (accessor.textFileService.models).add(model.resource, model); const service = accessor.textFileService; - service.setConfirmResult(ConfirmResult.CANCEL); + accessor.fileDialogService.setConfirmResult(ConfirmResult.CANCEL); await model.load(); model.textEditorModel!.setValue('foo'); @@ -103,7 +104,7 @@ suite('Files - TextFileService', () => { (accessor.textFileService.models).add(model.resource, model); const service = accessor.textFileService; - service.setConfirmResult(ConfirmResult.DONT_SAVE); + accessor.fileDialogService.setConfirmResult(ConfirmResult.DONT_SAVE); accessor.filesConfigurationService.onFilesConfigurationChange({ files: { hotExit: 'off' } }); await model.load(); @@ -129,7 +130,7 @@ suite('Files - TextFileService', () => { (accessor.textFileService.models).add(model.resource, model); const service = accessor.textFileService; - service.setConfirmResult(ConfirmResult.SAVE); + accessor.fileDialogService.setConfirmResult(ConfirmResult.SAVE); accessor.filesConfigurationService.onFilesConfigurationChange({ files: { hotExit: 'off' } }); await model.load(); @@ -429,7 +430,7 @@ suite('Files - TextFileService', () => { accessor.electronService.windowCount = Promise.resolve(2); } // Set cancel to force a veto if hot exit does not trigger - service.setConfirmResult(ConfirmResult.CANCEL); + accessor.fileDialogService.setConfirmResult(ConfirmResult.CANCEL); await model.load(); model.textEditorModel!.setValue('foo'); diff --git a/src/vs/workbench/test/workbenchTestServices.ts b/src/vs/workbench/test/workbenchTestServices.ts index 1e7bd7d147c67..1e87e03eeaa09 100644 --- a/src/vs/workbench/test/workbenchTestServices.ts +++ b/src/vs/workbench/test/workbenchTestServices.ts @@ -11,7 +11,7 @@ import * as resources from 'vs/base/common/resources'; import { URI, UriComponents } from 'vs/base/common/uri'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { NullTelemetryService } from 'vs/platform/telemetry/common/telemetryUtils'; -import { ConfirmResult, IEditorInputWithOptions, CloseDirection, IEditorIdentifier, IUntitledTextResourceInput, IResourceDiffInput, IResourceSideBySideInput, IEditorInput, IEditor, IEditorCloseEvent, IEditorPartOptions } from 'vs/workbench/common/editor'; +import { IEditorInputWithOptions, CloseDirection, IEditorIdentifier, IUntitledTextResourceInput, IResourceDiffInput, IResourceSideBySideInput, IEditorInput, IEditor, IEditorCloseEvent, IEditorPartOptions } from 'vs/workbench/common/editor'; import { IEditorOpeningEvent, EditorServiceImpl, IEditorGroupView } from 'vs/workbench/browser/parts/editor/editor'; import { Event, Emitter } from 'vs/base/common/event'; import Severity from 'vs/base/common/severity'; @@ -49,7 +49,7 @@ import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { MockContextKeyService, MockKeybindingService } from 'vs/platform/keybinding/test/common/mockKeybindingService'; import { ITextBufferFactory, DefaultEndOfLine, EndOfLinePreference, IModelDecorationOptions, ITextModel, ITextSnapshot } from 'vs/editor/common/model'; import { Range } from 'vs/editor/common/core/range'; -import { IConfirmation, IConfirmationResult, IDialogService, IDialogOptions, IPickAndOpenOptions, ISaveDialogOptions, IOpenDialogOptions, IFileDialogService, IShowResult } from 'vs/platform/dialogs/common/dialogs'; +import { IConfirmation, IConfirmationResult, IDialogService, IDialogOptions, IPickAndOpenOptions, ISaveDialogOptions, IOpenDialogOptions, IFileDialogService, IShowResult, ConfirmResult } from 'vs/platform/dialogs/common/dialogs'; import { INotificationService } from 'vs/platform/notification/common/notification'; import { TestNotificationService } from 'vs/platform/notification/test/common/testNotificationService'; import { IExtensionService, NullExtensionService } from 'vs/workbench/services/extensions/common/extensions'; @@ -192,7 +192,6 @@ export class TestTextFileService extends NativeTextFileService { public cleanupBackupsBeforeShutdownCalled!: boolean; private promptPath!: URI; - private confirmResult!: ConfirmResult; private resolveTextContentError!: FileOperationError | null; constructor( @@ -241,10 +240,6 @@ export class TestTextFileService extends NativeTextFileService { this.promptPath = path; } - public setConfirmResult(result: ConfirmResult): void { - this.confirmResult = result; - } - public setResolveTextContentErrorOnce(error: FileOperationError): void { this.resolveTextContentError = error; } @@ -275,14 +270,6 @@ export class TestTextFileService extends NativeTextFileService { return Promise.resolve(this.promptPath); } - public confirmSave(_resources?: URI[]): Promise { - return Promise.resolve(this.confirmResult); - } - - public confirmOverwrite(_resource: URI): Promise { - return Promise.resolve(true); - } - protected cleanupBackupsBeforeShutdown(): Promise { this.cleanupBackupsBeforeShutdownCalled = true; return Promise.resolve(); @@ -303,6 +290,8 @@ export function workbenchInstantiationService(): IInstantiationService { instantiationService.stub(IUntitledTextEditorService, instantiationService.createInstance(UntitledTextEditorService)); instantiationService.stub(IStorageService, new TestStorageService()); instantiationService.stub(IWorkbenchLayoutService, new TestLayoutService()); + instantiationService.stub(IDialogService, new TestDialogService()); + instantiationService.stub(IFileDialogService, new TestFileDialogService()); instantiationService.stub(IElectronService, new TestElectronService()); instantiationService.stub(IModeService, instantiationService.createInstance(ModeServiceImpl)); instantiationService.stub(IHistoryService, new TestHistoryService()); @@ -420,6 +409,8 @@ export class TestFileDialogService implements IFileDialogService { public _serviceBrand: undefined; + private confirmResult!: ConfirmResult; + public defaultFilePath(_schemeFilter?: string): URI | undefined { return undefined; } @@ -450,6 +441,12 @@ export class TestFileDialogService implements IFileDialogService { public showOpenDialog(_options: IOpenDialogOptions): Promise { return Promise.resolve(undefined); } + public setConfirmResult(result: ConfirmResult): void { + this.confirmResult = result; + } + public showSaveConfirm(resources: string | URI[]): Promise { + return Promise.resolve(this.confirmResult); + } } export class TestLayoutService implements IWorkbenchLayoutService { From a73d87acae94380e5b8553587663e904c0893fa7 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Thu, 14 Nov 2019 08:54:29 +0100 Subject: [PATCH 239/352] editor - getName() is required --- src/vs/workbench/browser/labels.ts | 2 +- .../browser/parts/editor/binaryEditor.ts | 2 +- .../browser/parts/editor/editorGroupView.ts | 2 +- .../browser/parts/editor/editorPicker.ts | 5 ++-- .../parts/editor/noTabsTitleControl.ts | 2 +- .../browser/parts/editor/textDiffEditor.ts | 4 ++-- .../browser/parts/editor/titleControl.ts | 2 +- .../parts/quickopen/quickOpenController.ts | 6 ++--- src/vs/workbench/common/editor.ts | 8 +++---- .../common/editor/binaryEditorModel.ts | 6 ++--- .../common/editor/dataUriEditorInput.ts | 24 ++++++++++++------- .../common/editor/diffEditorInput.ts | 8 ++++++- .../common/editor/untitledTextEditorInput.ts | 4 +--- .../files/browser/editors/binaryFileEditor.ts | 2 +- .../files/browser/views/openEditorsView.ts | 6 ++--- .../webview/browser/webviewEditorInput.ts | 2 +- .../services/editor/browser/editorService.ts | 2 +- .../services/history/browser/history.ts | 4 ++-- .../common/preferencesEditorInput.ts | 2 +- .../common/editor/dataUriEditorInput.test.ts | 2 +- .../test/common/editor/editorInput.test.ts | 4 ++-- 21 files changed, 54 insertions(+), 45 deletions(-) diff --git a/src/vs/workbench/browser/labels.ts b/src/vs/workbench/browser/labels.ts index fa66a47103461..d6c63962f8eb0 100644 --- a/src/vs/workbench/browser/labels.ts +++ b/src/vs/workbench/browser/labels.ts @@ -367,7 +367,7 @@ class ResourceLabelWidget extends IconLabel { setEditor(editor: IEditorInput, options?: IResourceLabelOptions): void { this.setResource({ resource: toResource(editor, { supportSideBySide: SideBySideEditor.MASTER }), - name: withNullAsUndefined(editor.getName()), + name: editor.getName(), description: editor.getDescription(options ? options.descriptionVerbosity : undefined) }, options); } diff --git a/src/vs/workbench/browser/parts/editor/binaryEditor.ts b/src/vs/workbench/browser/parts/editor/binaryEditor.ts index d196daa8517ec..017b60833b68f 100644 --- a/src/vs/workbench/browser/parts/editor/binaryEditor.ts +++ b/src/vs/workbench/browser/parts/editor/binaryEditor.ts @@ -56,7 +56,7 @@ export abstract class BaseBinaryResourceEditor extends BaseEditor { this.callbacks = callbacks; } - getTitle() { + getTitle(): string { return this.input ? this.input.getName() : nls.localize('binaryEditor', "Binary Viewer"); } diff --git a/src/vs/workbench/browser/parts/editor/editorGroupView.ts b/src/vs/workbench/browser/parts/editor/editorGroupView.ts index 281a231ebf3bf..9237e6b3ab994 100644 --- a/src/vs/workbench/browser/parts/editor/editorGroupView.ts +++ b/src/vs/workbench/browser/parts/editor/editorGroupView.ts @@ -1262,7 +1262,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView { await this.openEditor(editor); const editorResource = toResource(editor, { supportSideBySide: SideBySideEditor.MASTER }); - const res = await this.fileDialogService.showSaveConfirm(editorResource ? [editorResource] : editor.getName()!); + const res = await this.fileDialogService.showSaveConfirm(editorResource ? [editorResource] : editor.getName()); // It could be that the editor saved meanwhile, so we check again // to see if anything needs to happen before closing for good. diff --git a/src/vs/workbench/browser/parts/editor/editorPicker.ts b/src/vs/workbench/browser/parts/editor/editorPicker.ts index 1c8e7996d068e..bcb59d73090e4 100644 --- a/src/vs/workbench/browser/parts/editor/editorPicker.ts +++ b/src/vs/workbench/browser/parts/editor/editorPicker.ts @@ -18,7 +18,6 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti import { toResource, SideBySideEditor, IEditorInput } from 'vs/workbench/common/editor'; import { compareItemsByScore, scoreItem, ScorerCache, prepareQuery } from 'vs/base/parts/quickopen/common/quickOpenScorer'; import { CancellationToken } from 'vs/base/common/cancellation'; -import { withNullAsUndefined } from 'vs/base/common/types'; export class EditorPickerEntry extends QuickOpenEntryGroup { @@ -38,8 +37,8 @@ export class EditorPickerEntry extends QuickOpenEntryGroup { }; } - getLabel() { - return withNullAsUndefined(this.editor.getName()); + getLabel(): string { + return this.editor.getName(); } getIcon(): string { diff --git a/src/vs/workbench/browser/parts/editor/noTabsTitleControl.ts b/src/vs/workbench/browser/parts/editor/noTabsTitleControl.ts index 1f2612e42ff46..645159a33995c 100644 --- a/src/vs/workbench/browser/parts/editor/noTabsTitleControl.ts +++ b/src/vs/workbench/browser/parts/editor/noTabsTitleControl.ts @@ -248,7 +248,7 @@ export class NoTabsTitleControl extends TitleControl { // Editor Label const resource = toResource(editor, { supportSideBySide: SideBySideEditor.MASTER }); - const name = editor.getName() || ''; + const name = editor.getName(); const { labelFormat } = this.accessor.partOptions; let description: string; diff --git a/src/vs/workbench/browser/parts/editor/textDiffEditor.ts b/src/vs/workbench/browser/parts/editor/textDiffEditor.ts index 889d9c678adcb..ecbc295c0daf4 100644 --- a/src/vs/workbench/browser/parts/editor/textDiffEditor.ts +++ b/src/vs/workbench/browser/parts/editor/textDiffEditor.ts @@ -65,7 +65,7 @@ export class TextDiffEditor extends BaseTextEditor implements ITextDiffEditor { return new EditorMemento(this.getId(), key, Object.create(null), limit, editorGroupService); // do not persist in storage as diff editors are never persisted } - getTitle(): string | undefined { + getTitle(): string { if (this.input) { return this.input.getName(); } @@ -219,7 +219,7 @@ export class TextDiffEditor extends BaseTextEditor implements ITextDiffEditor { protected getAriaLabel(): string { let ariaLabel: string; - const inputName = this.input && this.input.getName(); + const inputName = this.input?.getName(); if (this.isReadOnly()) { ariaLabel = inputName ? nls.localize('readonlyEditorWithInputAriaLabel', "{0}. Readonly text compare editor.", inputName) : nls.localize('readonlyEditorAriaLabel', "Readonly text compare editor."); } else { diff --git a/src/vs/workbench/browser/parts/editor/titleControl.ts b/src/vs/workbench/browser/parts/editor/titleControl.ts index f5bfe3e7adbfe..1077097eddeab 100644 --- a/src/vs/workbench/browser/parts/editor/titleControl.ts +++ b/src/vs/workbench/browser/parts/editor/titleControl.ts @@ -287,7 +287,7 @@ export abstract class TitleControl extends Themable { label = localize('draggedEditorGroup', "{0} (+{1})", label, this.group.count - 1); } - applyDragImage(e, withUndefinedAsNull(label), 'monaco-editor-group-drag-image'); + applyDragImage(e, label, 'monaco-editor-group-drag-image'); } })); diff --git a/src/vs/workbench/browser/parts/quickopen/quickOpenController.ts b/src/vs/workbench/browser/parts/quickopen/quickOpenController.ts index 6f7e2254a6ae3..c56d69a480c77 100644 --- a/src/vs/workbench/browser/parts/quickopen/quickOpenController.ts +++ b/src/vs/workbench/browser/parts/quickopen/quickOpenController.ts @@ -724,7 +724,7 @@ export class EditorHistoryEntryGroup extends QuickOpenEntryGroup { export class EditorHistoryEntry extends EditorQuickOpenEntry { private input: IEditorInput | IResourceInput; private resource: URI | undefined; - private label: string | undefined; + private label: string; private description?: string; private dirty: boolean; @@ -745,7 +745,7 @@ export class EditorHistoryEntry extends EditorQuickOpenEntry { if (input instanceof EditorInput) { this.resource = resourceForEditorHistory(input, fileService); - this.label = types.withNullAsUndefined(input.getName()); + this.label = input.getName(); this.description = input.getDescription(); this.dirty = input.isDirty(); } else { @@ -765,7 +765,7 @@ export class EditorHistoryEntry extends EditorQuickOpenEntry { return this.dirty ? 'dirty' : ''; } - getLabel(): string | undefined { + getLabel(): string { return this.label; } diff --git a/src/vs/workbench/common/editor.ts b/src/vs/workbench/common/editor.ts index 87782783b9f62..e2dcb62669cf0 100644 --- a/src/vs/workbench/common/editor.ts +++ b/src/vs/workbench/common/editor.ts @@ -294,7 +294,7 @@ export interface IEditorInput extends IDisposable { /** * Returns the display name of this input. */ - getName(): string | undefined; + getName(): string; /** * Returns the display description of this input. @@ -360,8 +360,8 @@ export abstract class EditorInput extends Disposable implements IEditorInput { * Returns the name of this input that can be shown to the user. Examples include showing the name of the input * above the editor area when the input is shown. */ - getName(): string | undefined { - return undefined; + getName(): string { + return `Editor ${this.getTypeId()}`; } /** @@ -376,7 +376,7 @@ export abstract class EditorInput extends Disposable implements IEditorInput { * Returns the title of this input that can be shown to the user. Examples include showing the title of * the input above the editor area as hover over the input label. */ - getTitle(verbosity?: Verbosity): string | undefined { + getTitle(verbosity?: Verbosity): string { return this.getName(); } diff --git a/src/vs/workbench/common/editor/binaryEditorModel.ts b/src/vs/workbench/common/editor/binaryEditorModel.ts index a911af30a8c2a..a211169a6b7df 100644 --- a/src/vs/workbench/common/editor/binaryEditorModel.ts +++ b/src/vs/workbench/common/editor/binaryEditorModel.ts @@ -7,7 +7,7 @@ import { EditorModel } from 'vs/workbench/common/editor'; import { URI } from 'vs/base/common/uri'; import { IFileService } from 'vs/platform/files/common/files'; import { Schemas } from 'vs/base/common/network'; -import { DataUri, basename } from 'vs/base/common/resources'; +import { DataUri } from 'vs/base/common/resources'; import { MIME_BINARY } from 'vs/base/common/mime'; /** @@ -20,7 +20,7 @@ export class BinaryEditorModel extends EditorModel { constructor( public readonly resource: URI, - private readonly name: string | undefined, + private readonly name: string, @IFileService private readonly fileService: IFileService ) { super(); @@ -46,7 +46,7 @@ export class BinaryEditorModel extends EditorModel { * The name of the binary resource. */ getName(): string { - return this.name || basename(this.resource); + return this.name; } /** diff --git a/src/vs/workbench/common/editor/dataUriEditorInput.ts b/src/vs/workbench/common/editor/dataUriEditorInput.ts index d13f9e9881e5f..94911e9c9dbd6 100644 --- a/src/vs/workbench/common/editor/dataUriEditorInput.ts +++ b/src/vs/workbench/common/editor/dataUriEditorInput.ts @@ -7,7 +7,7 @@ import { EditorInput } from 'vs/workbench/common/editor'; import { URI } from 'vs/base/common/uri'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { BinaryEditorModel } from 'vs/workbench/common/editor/binaryEditorModel'; -import { DataUri } from 'vs/base/common/resources'; +import { DataUri, basename } from 'vs/base/common/resources'; /** * An editor input to present data URIs in a binary editor. Data URIs have the form of: @@ -17,25 +17,31 @@ export class DataUriEditorInput extends EditorInput { static readonly ID: string = 'workbench.editors.dataUriEditorInput'; + private readonly name: string; + private readonly description: string | undefined; + constructor( - private readonly name: string | undefined, - private readonly description: string | undefined, + name: string | undefined, + description: string | undefined, private readonly resource: URI, @IInstantiationService private readonly instantiationService: IInstantiationService ) { super(); - if (!this.name || !this.description) { + if (!name || !description) { const metadata = DataUri.parseMetaData(this.resource); - if (!this.name) { - this.name = metadata.get(DataUri.META_DATA_LABEL); + if (!name) { + name = metadata.get(DataUri.META_DATA_LABEL) || basename(resource); } - if (!this.description) { - this.description = metadata.get(DataUri.META_DATA_DESCRIPTION); + if (!description) { + description = metadata.get(DataUri.META_DATA_DESCRIPTION); } } + + this.name = name; + this.description = description; } getResource(): URI { @@ -46,7 +52,7 @@ export class DataUriEditorInput extends EditorInput { return DataUriEditorInput.ID; } - getName(): string | undefined { + getName(): string { return this.name; } diff --git a/src/vs/workbench/common/editor/diffEditorInput.ts b/src/vs/workbench/common/editor/diffEditorInput.ts index bd2b9376854cb..3b30153f526e2 100644 --- a/src/vs/workbench/common/editor/diffEditorInput.ts +++ b/src/vs/workbench/common/editor/diffEditorInput.ts @@ -18,7 +18,13 @@ export class DiffEditorInput extends SideBySideEditorInput { private cachedModel: DiffEditorModel | null = null; - constructor(name: string, description: string | undefined, original: EditorInput, modified: EditorInput, private readonly forceOpenAsBinary?: boolean) { + constructor( + name: string, + description: string | undefined, + original: EditorInput, + modified: EditorInput, + private readonly forceOpenAsBinary?: boolean + ) { super(name, description, original, modified); } diff --git a/src/vs/workbench/common/editor/untitledTextEditorInput.ts b/src/vs/workbench/common/editor/untitledTextEditorInput.ts index 28ecc5b4b2322..3e2998c3e2948 100644 --- a/src/vs/workbench/common/editor/untitledTextEditorInput.ts +++ b/src/vs/workbench/common/editor/untitledTextEditorInput.ts @@ -109,7 +109,7 @@ export class UntitledTextEditorInput extends EditorInput implements IEncodingSup return this.labelService.getUriLabel(this.resource); } - getTitle(verbosity: Verbosity): string | undefined { + getTitle(verbosity: Verbosity): string { if (!this.hasAssociatedFilePath) { return this.getName(); } @@ -122,8 +122,6 @@ export class UntitledTextEditorInput extends EditorInput implements IEncodingSup case Verbosity.LONG: return this.longTitle; } - - return undefined; } isDirty(): boolean { diff --git a/src/vs/workbench/contrib/files/browser/editors/binaryFileEditor.ts b/src/vs/workbench/contrib/files/browser/editors/binaryFileEditor.ts index e3229c3f61327..618920a6e2882 100644 --- a/src/vs/workbench/contrib/files/browser/editors/binaryFileEditor.ts +++ b/src/vs/workbench/contrib/files/browser/editors/binaryFileEditor.ts @@ -51,7 +51,7 @@ export class BinaryFileEditor extends BaseBinaryResourceEditor { } } - getTitle(): string | undefined { + getTitle(): string { return this.input ? this.input.getName() : nls.localize('binaryFileEditor', "Binary File Viewer"); } } diff --git a/src/vs/workbench/contrib/files/browser/views/openEditorsView.ts b/src/vs/workbench/contrib/files/browser/views/openEditorsView.ts index 2304fbb4d742d..8b93f82c51a1f 100644 --- a/src/vs/workbench/contrib/files/browser/views/openEditorsView.ts +++ b/src/vs/workbench/contrib/files/browser/views/openEditorsView.ts @@ -39,7 +39,7 @@ import { IDragAndDropData, DataTransfers } from 'vs/base/browser/dnd'; import { memoize } from 'vs/base/common/decorators'; import { ElementsDragAndDropData, DesktopDragAndDropData } from 'vs/base/browser/ui/list/listView'; import { URI } from 'vs/base/common/uri'; -import { withNullAsUndefined, withUndefinedAsNull } from 'vs/base/common/types'; +import { withUndefinedAsNull } from 'vs/base/common/types'; import { isWeb } from 'vs/base/common/platform'; import { IWorkingCopyService } from 'vs/workbench/services/workingCopy/common/workingCopyService'; @@ -619,13 +619,13 @@ class OpenEditorsDragAndDrop implements IListDragAndDrop 1) { return String(elements.length); } const element = elements[0]; - return element instanceof OpenEditor ? withNullAsUndefined(element.editor.getName()) : element.label; + return element instanceof OpenEditor ? element.editor.getName() : element.label; } onDragStart(data: IDragAndDropData, originalEvent: DragEvent): void { diff --git a/src/vs/workbench/contrib/webview/browser/webviewEditorInput.ts b/src/vs/workbench/contrib/webview/browser/webviewEditorInput.ts index 1a6bee73161b1..4577a20a046b6 100644 --- a/src/vs/workbench/contrib/webview/browser/webviewEditorInput.ts +++ b/src/vs/workbench/contrib/webview/browser/webviewEditorInput.ts @@ -101,7 +101,7 @@ export class WebviewInput extends EditorInput { return this._name; } - public getTitle(_verbosity?: Verbosity) { + public getTitle(_verbosity?: Verbosity): string { return this.getName(); } diff --git a/src/vs/workbench/services/editor/browser/editorService.ts b/src/vs/workbench/services/editor/browser/editorService.ts index fcdb63ab519b9..7f48cf25e5732 100644 --- a/src/vs/workbench/services/editor/browser/editorService.ts +++ b/src/vs/workbench/services/editor/browser/editorService.ts @@ -623,7 +623,7 @@ export class EditorService extends Disposable implements EditorServiceImpl { // Data URI else if (resource.scheme === Schemas.data) { - input = instantiationService.createInstance(DataUriEditorInput, label, description, resource); + input = instantiationService.createInstance(DataUriEditorInput, label || basename(resource), description, resource); } // Resource diff --git a/src/vs/workbench/services/history/browser/history.ts b/src/vs/workbench/services/history/browser/history.ts index 2851a78df2b3e..429b7460fa6f5 100644 --- a/src/vs/workbench/services/history/browser/history.ts +++ b/src/vs/workbench/services/history/browser/history.ts @@ -484,8 +484,8 @@ export class HistoryService extends Disposable implements IHistoryService { private handleEditorEventInHistory(editor?: IBaseEditor): void { const input = editor?.input; - // Ensure we have at least a name to show and not configured to exclude input - if (!input || !input.getName() || !this.include(input)) { + // Ensure we have not configured to exclude input + if (!input || !this.include(input)) { return; } diff --git a/src/vs/workbench/services/preferences/common/preferencesEditorInput.ts b/src/vs/workbench/services/preferences/common/preferencesEditorInput.ts index edcb4902f766f..0b4e5a69d7932 100644 --- a/src/vs/workbench/services/preferences/common/preferencesEditorInput.ts +++ b/src/vs/workbench/services/preferences/common/preferencesEditorInput.ts @@ -21,7 +21,7 @@ export class PreferencesEditorInput extends SideBySideEditorInput { return PreferencesEditorInput.ID; } - getTitle(verbosity: Verbosity): string | undefined { + getTitle(verbosity: Verbosity): string { return this.master.getTitle(verbosity); } } diff --git a/src/vs/workbench/test/common/editor/dataUriEditorInput.test.ts b/src/vs/workbench/test/common/editor/dataUriEditorInput.test.ts index ade72e9f942d1..44d111a1f8143 100644 --- a/src/vs/workbench/test/common/editor/dataUriEditorInput.test.ts +++ b/src/vs/workbench/test/common/editor/dataUriEditorInput.test.ts @@ -31,4 +31,4 @@ suite('DataUriEditorInput', () => { assert.equal(model.getMime(), 'image/png'); }); }); -}); \ No newline at end of file +}); diff --git a/src/vs/workbench/test/common/editor/editorInput.test.ts b/src/vs/workbench/test/common/editor/editorInput.test.ts index 5208ba30b5ab3..3adc2957bf5b5 100644 --- a/src/vs/workbench/test/common/editor/editorInput.test.ts +++ b/src/vs/workbench/test/common/editor/editorInput.test.ts @@ -22,7 +22,7 @@ suite('Workbench editor input', () => { assert(input.matches(input)); assert(!input.matches(otherInput)); assert(!input.matches(null)); - assert(!input.getName()); + assert(input.getName()); input.onDispose(() => { assert(true); @@ -84,4 +84,4 @@ suite('Workbench editor input', () => { otherInput.dispose(); assert.equal(counter, 2); }); -}); \ No newline at end of file +}); From 175b78de96b1b36d25d249b706d0c95d9691ba7f Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Thu, 14 Nov 2019 09:01:41 +0100 Subject: [PATCH 240/352] debt - remove sudo-prompt typings --- package.json | 2 +- src/typings/sudo-prompt.d.ts | 9 --------- .../textfile/electron-browser/nativeTextFileService.ts | 3 ++- yarn.lock | 8 ++++---- 4 files changed, 7 insertions(+), 15 deletions(-) delete mode 100644 src/typings/sudo-prompt.d.ts diff --git a/package.json b/package.json index 28c243771debd..2dce29d332d29 100644 --- a/package.json +++ b/package.json @@ -45,7 +45,7 @@ "onigasm-umd": "^2.2.4", "semver-umd": "^5.5.3", "spdlog": "^0.11.1", - "sudo-prompt": "9.0.0", + "sudo-prompt": "9.1.0", "v8-inspect-profiler": "^0.0.20", "vscode-minimist": "^1.2.1", "vscode-nsfw": "1.2.8", diff --git a/src/typings/sudo-prompt.d.ts b/src/typings/sudo-prompt.d.ts deleted file mode 100644 index 85f9783d0a669..0000000000000 --- a/src/typings/sudo-prompt.d.ts +++ /dev/null @@ -1,9 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -declare module 'sudo-prompt' { - - export function exec(cmd: string, options: { name?: string, icns?: string }, callback: (error: string, stdout: string, stderr: string) => void): void; -} \ No newline at end of file diff --git a/src/vs/workbench/services/textfile/electron-browser/nativeTextFileService.ts b/src/vs/workbench/services/textfile/electron-browser/nativeTextFileService.ts index e105588731ade..7caae05d5ecf6 100644 --- a/src/vs/workbench/services/textfile/electron-browser/nativeTextFileService.ts +++ b/src/vs/workbench/services/textfile/electron-browser/nativeTextFileService.ts @@ -286,7 +286,8 @@ export class NativeTextFileService extends AbstractTextFileService { private async sudoPromptCopy(source: string, target: string, options?: IWriteTextFileOptions): Promise { // load sudo-prompt module lazy - const sudoPrompt = await import('sudo-prompt'); + // @ts-ignore TODO@ben wait for update of sudo-prompt + const sudoPrompt: { exec(cmd: string, options: { name?: string, icns?: string }, callback: (error: string, stdout: string, stderr: string) => void): void } = await import('sudo-prompt'); return new Promise((resolve, reject) => { const promptOptions = { diff --git a/yarn.lock b/yarn.lock index 8bd5a9e0fb38f..1d949d454a4e5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8150,10 +8150,10 @@ strip-json-comments@^2.0.1, strip-json-comments@~2.0.1: resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo= -sudo-prompt@9.0.0: - version "9.0.0" - resolved "https://registry.yarnpkg.com/sudo-prompt/-/sudo-prompt-9.0.0.tgz#eebedeee9fcd6f661324e6bb46335e3288e8dc8a" - integrity sha512-kUn5fiOk0nhY2oKD9onIkcNCE4Zt85WTsvOfSmqCplmlEvXCcPOmp1npH5YWuf8Bmyy9wLWkIxx+D+8cThBORQ== +sudo-prompt@9.1.0: + version "9.1.0" + resolved "https://registry.yarnpkg.com/sudo-prompt/-/sudo-prompt-9.1.0.tgz#9618823e748ce19e2d9e481feaf3ada7d52df52f" + integrity sha512-bJigY3ELFd2ZA7gfyQ4wMZIp1EICPFQcMe3RgSz5OQTzrPPaeryhgaxbInO/G62vpiqJs37qlGdb9TaqHeF2yA== supports-color@1.2.0: version "1.2.0" From 4e8ef4cf4deaefa8d9f4383e937cb10ea6958a92 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Thu, 14 Nov 2019 00:17:21 -0800 Subject: [PATCH 241/352] Remove gating for inMemoryResourcePrefix Some users are setting weird errors related to untitled TS files. In some of these cases (such as https://github.com/microsoft/TypeScript/issues/35091) we see a untitled file being sent to the tsserver without the `inMemoryResourcePrefix`. I can't figure out how to get into this state but am removing the gating that *could* perhaps cause use not to set `inMemoryResourcePrefix`. This gating targets TS 2.7 or older, which telemetry shows very, very few users are still enabling in their workspaces --- .../src/typescriptServiceClient.ts | 22 ++++++++----------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/extensions/typescript-language-features/src/typescriptServiceClient.ts b/extensions/typescript-language-features/src/typescriptServiceClient.ts index 51bf7d9568dc9..e376922dbaf94 100644 --- a/extensions/typescript-language-features/src/typescriptServiceClient.ts +++ b/extensions/typescript-language-features/src/typescriptServiceClient.ts @@ -82,7 +82,8 @@ namespace ServerState { export default class TypeScriptServiceClient extends Disposable implements ITypeScriptServiceClient { private static readonly WALK_THROUGH_SNIPPET_SCHEME_COLON = `${fileSchemes.walkThroughSnippet}:`; - private pathSeparator: string; + private readonly pathSeparator: string; + private readonly inMemoryResourcePrefix = '^'; private _onReady?: { promise: Promise; resolve: () => void; reject: () => void; }; private _configuration: TypeScriptServiceConfiguration; @@ -591,23 +592,18 @@ export default class TypeScriptServiceClient extends Disposable implements IType return this.toPath(document.uri) || undefined; } - private get inMemoryResourcePrefix(): string { - return this.apiVersion.gte(API.v270) ? '^' : ''; - } - public toResource(filepath: string): vscode.Uri { if (filepath.startsWith(TypeScriptServiceClient.WALK_THROUGH_SNIPPET_SCHEME_COLON) || (filepath.startsWith(fileSchemes.untitled + ':')) ) { let resource = vscode.Uri.parse(filepath); - if (this.inMemoryResourcePrefix) { - const dirName = path.dirname(resource.path); - const fileName = path.basename(resource.path); - if (fileName.startsWith(this.inMemoryResourcePrefix)) { - resource = resource.with({ - path: path.posix.join(dirName, fileName.slice(this.inMemoryResourcePrefix.length)) - }); - } + const dirName = path.dirname(resource.path); + const fileName = path.basename(resource.path); + if (fileName.startsWith(this.inMemoryResourcePrefix)) { + resource = resource.with({ + path: path.posix.join(dirName, fileName.slice(this.inMemoryResourcePrefix.length)) + }); } + return this.bufferSyncSupport.toVsCodeResource(resource); } From e24fefe0a89205ce519efd8bd4ee53bde4bfe90c Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Thu, 14 Nov 2019 09:34:30 +0100 Subject: [PATCH 242/352] add URI.from(url)-overload --- src/vs/base/common/uri.ts | 9 ++++++++- src/vs/monaco.d.ts | 2 +- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/vs/base/common/uri.ts b/src/vs/base/common/uri.ts index f6a8959a04c9c..29cd09a479ef0 100644 --- a/src/vs/base/common/uri.ts +++ b/src/vs/base/common/uri.ts @@ -323,7 +323,14 @@ 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 } | URL): URI { + + if (components instanceof URL) { + const value = <_URI>_URI.parse(components.href); + value._formatted = components.href; + return value; + } + return new _URI( components.scheme, components.authority, diff --git a/src/vs/monaco.d.ts b/src/vs/monaco.d.ts index 2fa74f0ac351d..ff535f4bfbcf3 100644 --- a/src/vs/monaco.d.ts +++ b/src/vs/monaco.d.ts @@ -160,7 +160,7 @@ declare namespace monaco { path?: string; query?: string; fragment?: string; - }): Uri; + } | URL): Uri; /** * Creates a string representation for this Uri. It's guaranteed that calling * `Uri.parse` with the result of this function creates an Uri which is equal From 9106843dc2f3a6d419c19c191e16a1da80299700 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Thu, 14 Nov 2019 10:08:03 +0100 Subject: [PATCH 243/352] IOpener must accept URI and URL --- .../editor/browser/services/openerService.ts | 174 ++++++++++-------- .../browser/services/openerService.test.ts | 26 +-- src/vs/platform/opener/common/opener.ts | 3 +- .../url/electron-browser/urlService.ts | 11 +- 4 files changed, 124 insertions(+), 90 deletions(-) diff --git a/src/vs/editor/browser/services/openerService.ts b/src/vs/editor/browser/services/openerService.ts index 48175adfb4272..ff7c67ebbbb35 100644 --- a/src/vs/editor/browser/services/openerService.ts +++ b/src/vs/editor/browser/services/openerService.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import * as dom from 'vs/base/browser/dom'; -import { Disposable, IDisposable } from 'vs/base/common/lifecycle'; +import { IDisposable } from 'vs/base/common/lifecycle'; import { LinkedList } from 'vs/base/common/linkedList'; import { parse } from 'vs/base/common/marshalling'; import { Schemas } from 'vs/base/common/network'; @@ -16,46 +16,123 @@ import { CommandsRegistry, ICommandService } from 'vs/platform/commands/common/c import { IOpener, IOpenerService, IValidator, IExternalUriResolver, OpenOptions, ResolveExternalUriOptions, IResolvedExternalUri, IExternalOpener } from 'vs/platform/opener/common/opener'; import { EditorOpenContext } from 'vs/platform/editor/common/editor'; -export class OpenerService extends Disposable implements IOpenerService { +function hasScheme(target: URI | URL, scheme: string) { + if (URI.isUri(target)) { + return equalsIgnoreCase(target.scheme, scheme); + } else { + return equalsIgnoreCase(target.protocol, scheme + ':'); + } +} + +export class OpenerService implements IOpenerService { _serviceBrand: undefined; private readonly _openers = new LinkedList(); private readonly _validators = new LinkedList(); private readonly _resolvers = new LinkedList(); + private _externalOpener: IExternalOpener; + private _openerAsExternal: IOpener; + private _openerAsCommand: IOpener; + private _openerAsEditor: IOpener; constructor( - @ICodeEditorService private readonly _editorService: ICodeEditorService, - @ICommandService private readonly _commandService: ICommandService, + @ICodeEditorService editorService: ICodeEditorService, + @ICommandService commandService: ICommandService, ) { - super(); - // Default external opener is going through window.open() this._externalOpener = { openExternal: href => { dom.windowOpenNoOpener(href); - return Promise.resolve(true); } }; + + // Default opener: maito, http(s), command, and catch-all-editors + this._openerAsExternal = { + open: async (target: URI | URL, options?: OpenOptions) => { + if (options?.openExternal || hasScheme(target, Schemas.mailto) || hasScheme(target, Schemas.http) || hasScheme(target, Schemas.https)) { + // open externally + await this._doOpenExternal(target, options); + return true; + } + return false; + } + }; + + this._openerAsCommand = { + open: async (target) => { + if (!hasScheme(target, Schemas.command)) { + return false; + } + // run command or bail out if command isn't known + if (!URI.isUri(target)) { + target = URI.from(target); + } + if (!CommandsRegistry.getCommand(target.path)) { + throw new Error(`command '${target.path}' NOT known`); + } + // execute as command + let args: any = []; + try { + args = parse(target.query); + if (!Array.isArray(args)) { + args = [args]; + } + } catch (e) { + // ignore error + } + await commandService.executeCommand(target.path, ...args); + return true; + } + }; + + this._openerAsEditor = { + open: async (target, options: OpenOptions) => { + if (!URI.isUri(target)) { + target = URI.from(target); + } + let selection: { startLineNumber: number; startColumn: number; } | undefined = undefined; + const match = /^L?(\d+)(?:,(\d+))?/.exec(target.fragment); + if (match) { + // support file:///some/file.js#73,84 + // support file:///some/file.js#L73 + selection = { + startLineNumber: parseInt(match[1]), + startColumn: match[2] ? parseInt(match[2]) : 1 + }; + // remove fragment + target = target.with({ fragment: '' }); + } + + if (target.scheme === Schemas.file) { + target = resources.normalizePath(target); // workaround for non-normalized paths (https://github.com/Microsoft/vscode/issues/12954) + } + + await editorService.openCodeEditor( + { resource: target, options: { selection, context: options?.fromUserGesture ? EditorOpenContext.USER : EditorOpenContext.API } }, + editorService.getFocusedCodeEditor(), + options?.openToSide + ); + + return true; + } + }; } registerOpener(opener: IOpener): IDisposable { const remove = this._openers.push(opener); - return { dispose: remove }; } registerValidator(validator: IValidator): IDisposable { const remove = this._validators.push(validator); - return { dispose: remove }; } registerExternalUriResolver(resolver: IExternalUriResolver): IDisposable { const remove = this._resolvers.push(resolver); - return { dispose: remove }; } @@ -86,7 +163,12 @@ export class OpenerService extends Disposable implements IOpenerService { } // use default openers - return this._doOpen(resource, options); + for (const opener of [this._openerAsExternal, this._openerAsCommand, this._openerAsEditor]) { + if (await opener.open(resource, options)) { + break; + } + } + return true; } async resolveExternalUri(resource: URI, options?: ResolveExternalUriOptions): Promise { @@ -100,68 +182,16 @@ export class OpenerService extends Disposable implements IOpenerService { return { resolved: resource, dispose: () => { } }; } - private async _doOpen(resource: URI, options: OpenOptions | undefined): Promise { - const { scheme, path, query, fragment } = resource; - - if (options?.openExternal || equalsIgnoreCase(scheme, Schemas.mailto) || equalsIgnoreCase(scheme, Schemas.http) || equalsIgnoreCase(scheme, Schemas.https)) { - // open externally - return this._doOpenExternal(resource, options); - } - - if (equalsIgnoreCase(scheme, Schemas.command)) { - // run command or bail out if command isn't known - if (!CommandsRegistry.getCommand(path)) { - throw new Error(`command '${path}' NOT known`); - } - // execute as command - let args: any = []; - try { - args = parse(query); - if (!Array.isArray(args)) { - args = [args]; - } - } catch (e) { - // ignore error - } - - await this._commandService.executeCommand(path, ...args); - - return true; - } - - // finally open in editor - let selection: { startLineNumber: number; startColumn: number; } | undefined = undefined; - const match = /^L?(\d+)(?:,(\d+))?/.exec(fragment); - if (match) { - // support file:///some/file.js#73,84 - // support file:///some/file.js#L73 - selection = { - startLineNumber: parseInt(match[1]), - startColumn: match[2] ? parseInt(match[2]) : 1 - }; - // remove fragment - resource = resource.with({ fragment: '' }); - } - - if (resource.scheme === Schemas.file) { - resource = resources.normalizePath(resource); // workaround for non-normalized paths (https://github.com/Microsoft/vscode/issues/12954) + private async _doOpenExternal(resource: URI | URL, options: OpenOptions | undefined): Promise { + if (URI.isUri(resource)) { + const { resolved } = await this.resolveExternalUri(resource, options); + // TODO@Jo neither encodeURI nor toString(true) should be needed + // once we go with URL and not URI + return this._externalOpener.openExternal(encodeURI(resolved.toString(true))); + } else { + //todo@joh what about resolveExternalUri? + return this._externalOpener.openExternal(resource.href); } - - await this._editorService.openCodeEditor( - { resource, options: { selection, context: options?.fromUserGesture ? EditorOpenContext.USER : EditorOpenContext.API } }, - this._editorService.getFocusedCodeEditor(), - options?.openToSide - ); - - return true; - } - - private async _doOpenExternal(resource: URI, options: OpenOptions | undefined): Promise { - const { resolved } = await this.resolveExternalUri(resource, options); - - // TODO@Jo neither encodeURI nor toString(true) should be needed - // once we go with URL and not URI - return this._externalOpener.openExternal(encodeURI(resolved.toString(true))); } dispose() { diff --git a/src/vs/editor/test/browser/services/openerService.test.ts b/src/vs/editor/test/browser/services/openerService.test.ts index 6f03b911e3793..4081b6fc5f8ac 100644 --- a/src/vs/editor/test/browser/services/openerService.test.ts +++ b/src/vs/editor/test/browser/services/openerService.test.ts @@ -28,27 +28,27 @@ suite('OpenerService', function () { lastCommand = undefined; }); - test('delegate to editorService, scheme:///fff', function () { + test('delegate to editorService, scheme:///fff', async function () { const openerService = new OpenerService(editorService, NullCommandService); - openerService.open(URI.parse('another:///somepath')); + await openerService.open(URI.parse('another:///somepath')); assert.equal(editorService.lastInput!.options!.selection, undefined); }); - test('delegate to editorService, scheme:///fff#L123', function () { + test('delegate to editorService, scheme:///fff#L123', async function () { const openerService = new OpenerService(editorService, NullCommandService); - openerService.open(URI.parse('file:///somepath#L23')); + await openerService.open(URI.parse('file:///somepath#L23')); assert.equal(editorService.lastInput!.options!.selection!.startLineNumber, 23); assert.equal(editorService.lastInput!.options!.selection!.startColumn, 1); assert.equal(editorService.lastInput!.options!.selection!.endLineNumber, undefined); assert.equal(editorService.lastInput!.options!.selection!.endColumn, undefined); assert.equal(editorService.lastInput!.resource.fragment, ''); - openerService.open(URI.parse('another:///somepath#L23')); + await openerService.open(URI.parse('another:///somepath#L23')); assert.equal(editorService.lastInput!.options!.selection!.startLineNumber, 23); assert.equal(editorService.lastInput!.options!.selection!.startColumn, 1); - openerService.open(URI.parse('another:///somepath#L23,45')); + await openerService.open(URI.parse('another:///somepath#L23,45')); assert.equal(editorService.lastInput!.options!.selection!.startLineNumber, 23); assert.equal(editorService.lastInput!.options!.selection!.startColumn, 45); assert.equal(editorService.lastInput!.options!.selection!.endLineNumber, undefined); @@ -56,17 +56,17 @@ suite('OpenerService', function () { assert.equal(editorService.lastInput!.resource.fragment, ''); }); - test('delegate to editorService, scheme:///fff#123,123', function () { + test('delegate to editorService, scheme:///fff#123,123', async function () { const openerService = new OpenerService(editorService, NullCommandService); - openerService.open(URI.parse('file:///somepath#23')); + await openerService.open(URI.parse('file:///somepath#23')); assert.equal(editorService.lastInput!.options!.selection!.startLineNumber, 23); assert.equal(editorService.lastInput!.options!.selection!.startColumn, 1); assert.equal(editorService.lastInput!.options!.selection!.endLineNumber, undefined); assert.equal(editorService.lastInput!.options!.selection!.endColumn, undefined); assert.equal(editorService.lastInput!.resource.fragment, ''); - openerService.open(URI.parse('file:///somepath#23,45')); + await openerService.open(URI.parse('file:///somepath#23,45')); assert.equal(editorService.lastInput!.options!.selection!.startLineNumber, 23); assert.equal(editorService.lastInput!.options!.selection!.startColumn, 45); assert.equal(editorService.lastInput!.options!.selection!.endLineNumber, undefined); @@ -74,22 +74,22 @@ suite('OpenerService', function () { assert.equal(editorService.lastInput!.resource.fragment, ''); }); - test('delegate to commandsService, command:someid', function () { + test('delegate to commandsService, command:someid', async function () { const openerService = new OpenerService(editorService, commandService); const id = `aCommand${Math.random()}`; CommandsRegistry.registerCommand(id, function () { }); - openerService.open(URI.parse('command:' + id)); + await openerService.open(URI.parse('command:' + id)); assert.equal(lastCommand!.id, id); assert.equal(lastCommand!.args.length, 0); - openerService.open(URI.parse('command:' + id).with({ query: '123' })); + await openerService.open(URI.parse('command:' + id).with({ query: '123' })); assert.equal(lastCommand!.id, id); assert.equal(lastCommand!.args.length, 1); assert.equal(lastCommand!.args[0], '123'); - openerService.open(URI.parse('command:' + id).with({ query: JSON.stringify([12, true]) })); + await openerService.open(URI.parse('command:' + id).with({ query: JSON.stringify([12, true]) })); assert.equal(lastCommand!.id, id); assert.equal(lastCommand!.args.length, 2); assert.equal(lastCommand!.args[0], 12); diff --git a/src/vs/platform/opener/common/opener.ts b/src/vs/platform/opener/common/opener.ts index 3b60521677a04..8b9ce48f621c0 100644 --- a/src/vs/platform/opener/common/opener.ts +++ b/src/vs/platform/opener/common/opener.ts @@ -35,8 +35,7 @@ export interface IResolvedExternalUri extends IDisposable { } export interface IOpener { - open(resource: URI, options?: OpenInternalOptions): Promise; - open(resource: URI, options?: OpenExternalOptions): Promise; + open(resource: URI | URL, options?: OpenInternalOptions | OpenExternalOptions): Promise; } export interface IExternalOpener { diff --git a/src/vs/workbench/services/url/electron-browser/urlService.ts b/src/vs/workbench/services/url/electron-browser/urlService.ts index 73fa15e1f8ec9..c46c1948c4512 100644 --- a/src/vs/workbench/services/url/electron-browser/urlService.ts +++ b/src/vs/workbench/services/url/electron-browser/urlService.ts @@ -8,7 +8,7 @@ import { URI, UriComponents } from 'vs/base/common/uri'; import { IMainProcessService } from 'vs/platform/ipc/electron-browser/mainProcessService'; import { URLHandlerChannel } from 'vs/platform/url/common/urlIpc'; import { URLService } from 'vs/platform/url/node/urlService'; -import { IOpenerService } from 'vs/platform/opener/common/opener'; +import { IOpenerService, IOpener } from 'vs/platform/opener/common/opener'; import product from 'vs/platform/product/common/product'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { IElectronEnvironmentService } from 'vs/workbench/services/electron/electron-browser/electronEnvironmentService'; @@ -20,7 +20,7 @@ export interface IRelayOpenURLOptions extends IOpenURLOptions { openExternal?: boolean; } -export class RelayURLService extends URLService implements IURLHandler { +export class RelayURLService extends URLService implements IURLHandler, IOpener { private urlService: IURLService; @@ -51,7 +51,12 @@ export class RelayURLService extends URLService implements IURLHandler { return uri.with({ query }); } - async open(resource: URI, options?: IRelayOpenURLOptions): Promise { + async open(resource: URI | URL, options?: IRelayOpenURLOptions): Promise { + + if (resource instanceof URL) { + resource = URI.from(resource); + } + if (resource.scheme !== product.urlProtocol) { return false; } From eccf417b72fc0a632ec2cbd7855a681cdb8c81fa Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Thu, 14 Nov 2019 10:10:40 +0100 Subject: [PATCH 244/352] outline nav - only bind keys on mac --- src/vs/workbench/contrib/outline/browser/outlineNavigation.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/contrib/outline/browser/outlineNavigation.ts b/src/vs/workbench/contrib/outline/browser/outlineNavigation.ts index 8362d0f7ad7b9..7d22b68aa6999 100644 --- a/src/vs/workbench/contrib/outline/browser/outlineNavigation.ts +++ b/src/vs/workbench/contrib/outline/browser/outlineNavigation.ts @@ -164,7 +164,7 @@ registerEditorAction(class extends EditorAction { kbOpts: { weight: KeybindingWeight.EditorContrib, kbExpr: EditorContextKeys.focus, - primary: KeyMod.Shift | KeyMod.Alt | KeyCode.DownArrow, + primary: undefined, mac: { primary: KeyMod.WinCtrl | KeyMod.Shift | KeyCode.DownArrow, }, @@ -188,7 +188,7 @@ registerEditorAction(class extends EditorAction { kbOpts: { weight: KeybindingWeight.EditorContrib, kbExpr: EditorContextKeys.focus, - primary: KeyMod.Shift | KeyMod.Alt | KeyCode.UpArrow, + primary: undefined, mac: { primary: KeyMod.WinCtrl | KeyMod.Shift | KeyCode.UpArrow, }, From 95b521d3890736fd966e39ef5141ad34c20628d3 Mon Sep 17 00:00:00 2001 From: Christof Marti Date: Thu, 14 Nov 2019 10:20:21 +0100 Subject: [PATCH 245/352] Update commands.yml --- .github/commands.yml | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/.github/commands.yml b/.github/commands.yml index c649e6c4d8915..ea0895b3dd2f6 100644 --- a/.github/commands.yml +++ b/.github/commands.yml @@ -118,10 +118,10 @@ }, { type: 'label', - name: '*needs more info', + name: '~needs more info', action: 'updateLabels', addLabel: 'needs more info', - removeLabel: '*needs more info', + removeLabel: '~needs more info', comment: "Thanks for creating this issue! We figured it's missing some basic information or in some other way doesn't follow our [issue reporting](https://aka.ms/vscodeissuereporting) guidelines. Please take the time to review these and update the issue.\n\nHappy Coding!" }, { @@ -131,12 +131,5 @@ action: 'updateLabels', addLabel: 'a11ymas' }, - { - type: 'label', - name: '*needs more info', - action: 'updateLabels', - addLabel: 'needs more info', - removeLabel: '*needs more info' - }, ] } From 3816ecfe24d7835c319d89f2b9aeb9e5836a9f2c Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Thu, 14 Nov 2019 10:29:58 +0100 Subject: [PATCH 246/352] IOpenerService#open accepts URI and URL --- src/vs/editor/browser/services/openerService.ts | 9 ++++++--- src/vs/platform/opener/common/opener.ts | 3 +-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/vs/editor/browser/services/openerService.ts b/src/vs/editor/browser/services/openerService.ts index ff7c67ebbbb35..dab6794e8ca02 100644 --- a/src/vs/editor/browser/services/openerService.ts +++ b/src/vs/editor/browser/services/openerService.ts @@ -140,13 +140,16 @@ export class OpenerService implements IOpenerService { this._externalOpener = externalOpener; } - async open(resource: URI, options?: OpenOptions): Promise { + async open(target: URI | URL, options?: OpenOptions): Promise { + + const resource = URI.isUri(target) ? target : URI.from(target); // no scheme ?!? if (!resource.scheme) { return Promise.resolve(false); } + //todo@joh adopt validator // check with contributed validators for (const validator of this._validators.toArray()) { if (!(await validator.shouldOpen(resource))) { @@ -156,7 +159,7 @@ export class OpenerService implements IOpenerService { // check with contributed openers for (const opener of this._openers.toArray()) { - const handled = await opener.open(resource, options); + const handled = await opener.open(target, options); if (handled) { return true; } @@ -164,7 +167,7 @@ export class OpenerService implements IOpenerService { // use default openers for (const opener of [this._openerAsExternal, this._openerAsCommand, this._openerAsEditor]) { - if (await opener.open(resource, options)) { + if (await opener.open(target, options)) { break; } } diff --git a/src/vs/platform/opener/common/opener.ts b/src/vs/platform/opener/common/opener.ts index 8b9ce48f621c0..a0caf1463e29b 100644 --- a/src/vs/platform/opener/common/opener.ts +++ b/src/vs/platform/opener/common/opener.ts @@ -82,8 +82,7 @@ export interface IOpenerService { * @param resource A resource * @return A promise that resolves when the opening is done. */ - open(resource: URI, options?: OpenInternalOptions): Promise; - open(resource: URI, options?: OpenExternalOptions): Promise; + open(resource: URI | URL, options?: OpenInternalOptions | OpenExternalOptions): Promise; /** * Resolve a resource to its external form. From 6245d67152fd77ac7560f62a58a58cdeaf4a9047 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Thu, 14 Nov 2019 10:31:53 +0100 Subject: [PATCH 247/352] fix typo --- src/vs/platform/files/common/fileService.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/platform/files/common/fileService.ts b/src/vs/platform/files/common/fileService.ts index d3a70db859d29..d914b9c5810d8 100644 --- a/src/vs/platform/files/common/fileService.ts +++ b/src/vs/platform/files/common/fileService.ts @@ -362,7 +362,7 @@ export class FileService extends Disposable implements IFileService { // mtime and etag, we bail out to prevent dirty writing. // // First, we check for a mtime that is in the future before we do more checks. The assumption is - // that only the mtime is an indicator for a file that has changd on disk. + // that only the mtime is an indicator for a file that has changed on disk. // // Second, if the mtime has advanced, we compare the size of the file on disk with our previous // one using the etag() function. Relying only on the mtime check has prooven to produce false From d891b0d3493a3180cfdf2ea53f46b41445151bb4 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Thu, 14 Nov 2019 10:52:36 +0100 Subject: [PATCH 248/352] editor link detector uses URL --- src/vs/editor/contrib/links/getLinks.ts | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/src/vs/editor/contrib/links/getLinks.ts b/src/vs/editor/contrib/links/getLinks.ts index df34eed560087..e7a66f482345d 100644 --- a/src/vs/editor/contrib/links/getLinks.ts +++ b/src/vs/editor/contrib/links/getLinks.ts @@ -14,6 +14,18 @@ import { CommandsRegistry } from 'vs/platform/commands/common/commands'; import { isDisposable, Disposable } from 'vs/base/common/lifecycle'; import { coalesce } from 'vs/base/common/arrays'; +// in IE11 there is URL but a constructor +// https://developer.mozilla.org/en-US/docs/Web/API/URL/URL#Browser_compatibility +const canUseUrl = (function () { + try { + // tslint:disable-next-line: no-unused-expression + new URL('some://thing'); + return true; + } catch { + return false; + } +})(); + export class Link implements ILink { private _link: ILink; @@ -44,13 +56,15 @@ export class Link implements ILink { return this._link.tooltip; } - resolve(token: CancellationToken): Promise { + async resolve(token: CancellationToken): Promise { if (this._link.url) { try { - if (typeof this._link.url === 'string') { - return Promise.resolve(URI.parse(this._link.url)); + if (URI.isUri(this._link.url)) { + return this._link.url; + } else if (!canUseUrl) { + return URI.parse(this._link.url); } else { - return Promise.resolve(this._link.url); + return new URL(this._link.url); } } catch (e) { return Promise.reject(new Error('invalid')); From 1603d3e6e52c5e6d93d274e3b322097df1afb1c1 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Thu, 14 Nov 2019 11:03:05 +0100 Subject: [PATCH 249/352] validator must support URI and URL, also extract utils for re-use --- src/vs/base/common/resources.ts | 22 ++++++++++++++++ .../editor/browser/services/openerService.ts | 26 ++++--------------- src/vs/editor/contrib/links/getLinks.ts | 15 ++--------- src/vs/platform/opener/common/opener.ts | 2 +- .../url/common/trustedDomainsValidator.ts | 13 ++++++---- 5 files changed, 38 insertions(+), 40 deletions(-) diff --git a/src/vs/base/common/resources.ts b/src/vs/base/common/resources.ts index bea40bbdc628c..6a9dcd13095f8 100644 --- a/src/vs/base/common/resources.ts +++ b/src/vs/base/common/resources.ts @@ -361,3 +361,25 @@ export function toLocalResource(resource: URI, authority: string | undefined): U return resource.with({ scheme: Schemas.file }); } + +export function matchesScheme(target: URI | URL, scheme: string) { + if (URI.isUri(target)) { + return equalsIgnoreCase(target.scheme, scheme); + } else { + return equalsIgnoreCase(target.protocol, scheme + ':'); + } +} + +/** + * `true` when urls can be constructed via `new URL("string")`, should only be `false` in IE: + * https://developer.mozilla.org/en-US/docs/Web/API/URL/URL#Browser_compatibility + */ +export const hasURLCtor = (function () { + try { + // tslint:disable-next-line: no-unused-expression + new URL('some://thing'); + return true; + } catch { + return false; + } +})(); diff --git a/src/vs/editor/browser/services/openerService.ts b/src/vs/editor/browser/services/openerService.ts index dab6794e8ca02..be0bcb1dcf840 100644 --- a/src/vs/editor/browser/services/openerService.ts +++ b/src/vs/editor/browser/services/openerService.ts @@ -8,21 +8,13 @@ import { IDisposable } from 'vs/base/common/lifecycle'; import { LinkedList } from 'vs/base/common/linkedList'; import { parse } from 'vs/base/common/marshalling'; import { Schemas } from 'vs/base/common/network'; -import * as resources from 'vs/base/common/resources'; -import { equalsIgnoreCase } from 'vs/base/common/strings'; +import { matchesScheme, normalizePath } from 'vs/base/common/resources'; import { URI } from 'vs/base/common/uri'; import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService'; import { CommandsRegistry, ICommandService } from 'vs/platform/commands/common/commands'; import { IOpener, IOpenerService, IValidator, IExternalUriResolver, OpenOptions, ResolveExternalUriOptions, IResolvedExternalUri, IExternalOpener } from 'vs/platform/opener/common/opener'; import { EditorOpenContext } from 'vs/platform/editor/common/editor'; -function hasScheme(target: URI | URL, scheme: string) { - if (URI.isUri(target)) { - return equalsIgnoreCase(target.scheme, scheme); - } else { - return equalsIgnoreCase(target.protocol, scheme + ':'); - } -} export class OpenerService implements IOpenerService { @@ -52,7 +44,7 @@ export class OpenerService implements IOpenerService { // Default opener: maito, http(s), command, and catch-all-editors this._openerAsExternal = { open: async (target: URI | URL, options?: OpenOptions) => { - if (options?.openExternal || hasScheme(target, Schemas.mailto) || hasScheme(target, Schemas.http) || hasScheme(target, Schemas.https)) { + if (options?.openExternal || matchesScheme(target, Schemas.mailto) || matchesScheme(target, Schemas.http) || matchesScheme(target, Schemas.https)) { // open externally await this._doOpenExternal(target, options); return true; @@ -63,7 +55,7 @@ export class OpenerService implements IOpenerService { this._openerAsCommand = { open: async (target) => { - if (!hasScheme(target, Schemas.command)) { + if (!matchesScheme(target, Schemas.command)) { return false; } // run command or bail out if command isn't known @@ -107,7 +99,7 @@ export class OpenerService implements IOpenerService { } if (target.scheme === Schemas.file) { - target = resources.normalizePath(target); // workaround for non-normalized paths (https://github.com/Microsoft/vscode/issues/12954) + target = normalizePath(target); // workaround for non-normalized paths (https://github.com/Microsoft/vscode/issues/12954) } await editorService.openCodeEditor( @@ -142,17 +134,9 @@ export class OpenerService implements IOpenerService { async open(target: URI | URL, options?: OpenOptions): Promise { - const resource = URI.isUri(target) ? target : URI.from(target); - - // no scheme ?!? - if (!resource.scheme) { - return Promise.resolve(false); - } - - //todo@joh adopt validator // check with contributed validators for (const validator of this._validators.toArray()) { - if (!(await validator.shouldOpen(resource))) { + if (!(await validator.shouldOpen(target))) { return false; } } diff --git a/src/vs/editor/contrib/links/getLinks.ts b/src/vs/editor/contrib/links/getLinks.ts index e7a66f482345d..081d8b4adde3c 100644 --- a/src/vs/editor/contrib/links/getLinks.ts +++ b/src/vs/editor/contrib/links/getLinks.ts @@ -13,18 +13,7 @@ import { IModelService } from 'vs/editor/common/services/modelService'; import { CommandsRegistry } from 'vs/platform/commands/common/commands'; import { isDisposable, Disposable } from 'vs/base/common/lifecycle'; import { coalesce } from 'vs/base/common/arrays'; - -// in IE11 there is URL but a constructor -// https://developer.mozilla.org/en-US/docs/Web/API/URL/URL#Browser_compatibility -const canUseUrl = (function () { - try { - // tslint:disable-next-line: no-unused-expression - new URL('some://thing'); - return true; - } catch { - return false; - } -})(); +import { hasURLCtor } from 'vs/base/common/resources'; export class Link implements ILink { @@ -61,7 +50,7 @@ export class Link implements ILink { try { if (URI.isUri(this._link.url)) { return this._link.url; - } else if (!canUseUrl) { + } else if (!hasURLCtor) { return URI.parse(this._link.url); } else { return new URL(this._link.url); diff --git a/src/vs/platform/opener/common/opener.ts b/src/vs/platform/opener/common/opener.ts index a0caf1463e29b..5cdaebc93ce28 100644 --- a/src/vs/platform/opener/common/opener.ts +++ b/src/vs/platform/opener/common/opener.ts @@ -43,7 +43,7 @@ export interface IExternalOpener { } export interface IValidator { - shouldOpen(resource: URI): Promise; + shouldOpen(resource: URI | URL): Promise; } export interface IExternalUriResolver { diff --git a/src/vs/workbench/contrib/url/common/trustedDomainsValidator.ts b/src/vs/workbench/contrib/url/common/trustedDomainsValidator.ts index f930d68bccfde..aabcd4405b23e 100644 --- a/src/vs/workbench/contrib/url/common/trustedDomainsValidator.ts +++ b/src/vs/workbench/contrib/url/common/trustedDomainsValidator.ts @@ -5,7 +5,6 @@ import { Schemas } from 'vs/base/common/network'; import Severity from 'vs/base/common/severity'; -import { equalsIgnoreCase } from 'vs/base/common/strings'; import { URI } from 'vs/base/common/uri'; import { localize } from 'vs/nls'; import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; @@ -20,6 +19,7 @@ import { } from 'vs/workbench/contrib/url/common/trustedDomains'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService'; +import { matchesScheme } from 'vs/base/common/resources'; export class OpenerValidatorContributions implements IWorkbenchContribution { constructor( @@ -34,13 +34,16 @@ export class OpenerValidatorContributions implements IWorkbenchContribution { this._openerService.registerValidator({ shouldOpen: r => this.validateLink(r) }); } - async validateLink(resource: URI): Promise { - const { scheme, authority, path, query, fragment } = resource; - - if (!equalsIgnoreCase(scheme, Schemas.http) && !equalsIgnoreCase(scheme, Schemas.https)) { + async validateLink(resource: URI | URL): Promise { + if (!matchesScheme(resource, Schemas.http) && !matchesScheme(resource, Schemas.https)) { return true; } + if (!URI.isUri(resource)) { + resource = URI.from(resource); + } + const { scheme, authority, path, query, fragment } = resource; + const domainToOpen = `${scheme}://${authority}`; const { defaultTrustedDomains, trustedDomains } = readTrustedDomains(this._storageService, this._productService); const allTrustedDomains = [...defaultTrustedDomains, ...trustedDomains]; From 92f6d2210e0c9cd21c897a4413aabbb2a56b6f5f Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Thu, 14 Nov 2019 11:09:10 +0100 Subject: [PATCH 250/352] editors - log errors when restoring editors --- .../browser/parts/editor/editorGroupView.ts | 106 ++++++++++-------- 1 file changed, 59 insertions(+), 47 deletions(-) diff --git a/src/vs/workbench/browser/parts/editor/editorGroupView.ts b/src/vs/workbench/browser/parts/editor/editorGroupView.ts index 9237e6b3ab994..01eab7e685699 100644 --- a/src/vs/workbench/browser/parts/editor/editorGroupView.ts +++ b/src/vs/workbench/browser/parts/editor/editorGroupView.ts @@ -51,6 +51,7 @@ import { extname } from 'vs/base/common/resources'; import { Schemas } from 'vs/base/common/network'; import { EditorActivation, EditorOpenContext } from 'vs/platform/editor/common/editor'; import { IDialogService, IFileDialogService, ConfirmResult } from 'vs/platform/dialogs/common/dialogs'; +import { ILogService } from 'vs/platform/log/common/log'; export class EditorGroupView extends Themable implements IEditorGroupView { @@ -132,7 +133,8 @@ export class EditorGroupView extends Themable implements IEditorGroupView { @IKeybindingService private readonly keybindingService: IKeybindingService, @IMenuService private readonly menuService: IMenuService, @IContextMenuService private readonly contextMenuService: IContextMenuService, - @IFileDialogService private readonly fileDialogService: IFileDialogService + @IFileDialogService private readonly fileDialogService: IFileDialogService, + @ILogService private readonly logService: ILogService ) { super(themeService); @@ -921,64 +923,74 @@ export class EditorGroupView extends Themable implements IEditorGroupView { private async doHandleOpenEditorError(error: Error, editor: EditorInput, options?: EditorOptions): Promise { - // Report error only if this was not us restoring previous error state or - // we are told to ignore errors that occur from opening an editor - if (this.isRestored && !isPromiseCanceledError(error) && (!options || !options.ignoreError)) { + // Report error only if we are not told to ignore errors that occur from opening an editor + if (!isPromiseCanceledError(error) && (!options || !options.ignoreError)) { - // Extract possible error actions from the error - let errorActions: ReadonlyArray | undefined = undefined; - if (isErrorWithActions(error)) { - errorActions = (error as IErrorWithActions).actions; - } + // Since it is more likely that errors fail to open when restoring them e.g. + // because files got deleted or moved meanwhile, we do not show any notifications + // if we are still restoring editors. + if (this.isRestored) { - // If the context is USER, we try to show a modal dialog instead of a background notification - if (options?.context === EditorOpenContext.USER) { - const buttons: string[] = []; - if (Array.isArray(errorActions) && errorActions.length > 0) { - errorActions.forEach(action => buttons.push(action.label)); - } else { - buttons.push(localize('ok', 'OK')); + // Extract possible error actions from the error + let errorActions: ReadonlyArray | undefined = undefined; + if (isErrorWithActions(error)) { + errorActions = (error as IErrorWithActions).actions; } - let cancelId: number | undefined = undefined; - if (buttons.length === 1) { - buttons.push(localize('cancel', "Cancel")); - cancelId = 1; - } + // If the context is USER, we try to show a modal dialog instead of a background notification + if (options?.context === EditorOpenContext.USER) { + const buttons: string[] = []; + if (Array.isArray(errorActions) && errorActions.length > 0) { + errorActions.forEach(action => buttons.push(action.label)); + } else { + buttons.push(localize('ok', 'OK')); + } - const result = await this.dialogService.show( - Severity.Error, - localize('editorOpenErrorDialog', "Unable to open '{0}'", editor.getName()), - buttons, - { - detail: toErrorMessage(error), - cancelId + let cancelId: number | undefined = undefined; + if (buttons.length === 1) { + buttons.push(localize('cancel', "Cancel")); + cancelId = 1; } - ); - // Make sure to run any error action if present - if (result.choice !== cancelId && Array.isArray(errorActions)) { - const errorAction = errorActions[result.choice]; - if (errorAction) { - errorAction.run(); + const result = await this.dialogService.show( + Severity.Error, + localize('editorOpenErrorDialog', "Unable to open '{0}'", editor.getName()), + buttons, + { + detail: toErrorMessage(error), + cancelId + } + ); + + // Make sure to run any error action if present + if (result.choice !== cancelId && Array.isArray(errorActions)) { + const errorAction = errorActions[result.choice]; + if (errorAction) { + errorAction.run(); + } } } - } - // Otherwise, show a background notification. - else { - const actions: INotificationActions = { primary: [] }; - if (Array.isArray(errorActions)) { - actions.primary = errorActions; - } + // Otherwise, show a background notification. + else { + const actions: INotificationActions = { primary: [] }; + if (Array.isArray(errorActions)) { + actions.primary = errorActions; + } + + const handle = this.notificationService.notify({ + severity: Severity.Error, + message: localize('editorOpenError', "Unable to open '{0}': {1}.", editor.getName(), toErrorMessage(error)), + actions + }); - const handle = this.notificationService.notify({ - severity: Severity.Error, - message: localize('editorOpenError', "Unable to open '{0}': {1}.", editor.getName(), toErrorMessage(error)), - actions - }); + Event.once(handle.onDidClose)(() => actions.primary && dispose(actions.primary)); + } + } - Event.once(handle.onDidClose)(() => actions.primary && dispose(actions.primary)); + // Restoring: just log errors to console + else { + this.logService.error(error); } } From 1876ce6361634423d0d5534b12dad1270c1373ff Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Thu, 14 Nov 2019 11:20:51 +0100 Subject: [PATCH 251/352] update docs on fs provider for mtime (#84802) * update docs on fs provider for mtime * size is also needed --- src/vs/vscode.d.ts | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/vs/vscode.d.ts b/src/vs/vscode.d.ts index e5cc977472552..9d00a3150b1b3 100644 --- a/src/vs/vscode.d.ts +++ b/src/vs/vscode.d.ts @@ -5743,10 +5743,18 @@ declare module 'vscode' { ctime: number; /** * The modification timestamp in milliseconds elapsed since January 1, 1970 00:00:00 UTC. + * + * *Note:* If the file changed, it is important to provide an updated `mtime` that advanced + * from the previous value. Otherwise there may be optimizations in place that will not show + * the updated file contents in an editor for example. */ mtime: number; /** * The size in bytes. + * + * *Note:* If the file changed, it is important to provide an updated `size`. Otherwise there + * may be optimizations in place that will not show the updated file contents in an editor for + * example. */ size: number; } @@ -5860,6 +5868,11 @@ declare module 'vscode' { * An event to signal that a resource has been created, changed, or deleted. This * event should fire for resources that are being [watched](#FileSystemProvider.watch) * by clients of this provider. + * + * *Note:* It is important that the metadata of the file that changed provides an + * updated `mtime` that advanced from the previous value in the [stat](#FileStat) and a + * correct `size` value. Otherwise there may be optimizations in place that will not show + * the change in an editor for example. */ readonly onDidChangeFile: Event; From 673a942d4a28f50980f2552005f2386e60a488a5 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Thu, 14 Nov 2019 11:44:12 +0100 Subject: [PATCH 252/352] uri - don't fail with invalid percentage encoded parts --- src/vs/base/common/uri.ts | 31 +++++++++++++++++++++++++---- src/vs/base/test/common/uri.test.ts | 4 ++++ 2 files changed, 31 insertions(+), 4 deletions(-) diff --git a/src/vs/base/common/uri.ts b/src/vs/base/common/uri.ts index f6a8959a04c9c..19f89eec62678 100644 --- a/src/vs/base/common/uri.ts +++ b/src/vs/base/common/uri.ts @@ -267,10 +267,10 @@ export class URI implements UriComponents { } return new _URI( match[2] || _empty, - decodeURIComponent(match[4] || _empty), - decodeURIComponent(match[5] || _empty), - decodeURIComponent(match[7] || _empty), - decodeURIComponent(match[9] || _empty), + percentDecode(match[4] || _empty), + percentDecode(match[5] || _empty), + percentDecode(match[7] || _empty), + percentDecode(match[9] || _empty), _strict ); } @@ -648,3 +648,26 @@ function _asFormatted(uri: URI, skipEncoding: boolean): string { } return res; } + +// --- decode + +function decodeURIComponentGraceful(str: string): string { + try { + return decodeURIComponent(str); + } catch { + if (str.length > 3) { + return str.substr(0, 3) + decodeURIComponentGraceful(str.substr(3)); + } else { + return str; + } + } +} + +const _rEncodedAsHex = /(%[0-9A-Za-z][0-9A-Za-z])+/g; + +function percentDecode(str: string): string { + if (!str.match(_rEncodedAsHex)) { + return str; + } + return str.replace(_rEncodedAsHex, (match) => decodeURIComponentGraceful(match)); +} diff --git a/src/vs/base/test/common/uri.test.ts b/src/vs/base/test/common/uri.test.ts index 3255575ae5717..6b35d6afc9c03 100644 --- a/src/vs/base/test/common/uri.test.ts +++ b/src/vs/base/test/common/uri.test.ts @@ -439,6 +439,10 @@ suite('URI', () => { assert.equal(uri.path, uri2.path); }); + test('Unable to open \'%A0.txt\': URI malformed #76506', function () { + assert.equal(URI.parse('file://some/%.txt'), 'file://some/%25.txt'); + assert.equal(URI.parse('file://some/%A0.txt'), 'file://some/%25A0.txt'); + }); test('Links in markdown are broken if url contains encoded parameters #79474', function () { this.skip(); From 7b39c4a28dba0e2118653271b417165a44c929a2 Mon Sep 17 00:00:00 2001 From: Martin Aeschlimann Date: Thu, 14 Nov 2019 11:53:36 +0100 Subject: [PATCH 253/352] macOS: File > Open no longer adds files to recently opened. Fixes #84421 --- src/vs/platform/windows/electron-main/windowsMainService.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/vs/platform/windows/electron-main/windowsMainService.ts b/src/vs/platform/windows/electron-main/windowsMainService.ts index d0b62c048bd8a..fdf7f2e890b6f 100644 --- a/src/vs/platform/windows/electron-main/windowsMainService.ts +++ b/src/vs/platform/windows/electron-main/windowsMainService.ts @@ -496,7 +496,8 @@ export class WindowsMainService extends Disposable implements IWindowsMainServic // Remember in recent document list (unless this opens for extension development) // Also do not add paths when files are opened for diffing, only if opened individually - if (!usedWindows.some(window => window.isExtensionDevelopmentHost) && !(fileInputs?.filesToDiff) && !openConfig.noRecentEntry) { + const isDiff = fileInputs && fileInputs.filesToDiff.length > 0; + if (!usedWindows.some(window => window.isExtensionDevelopmentHost) && !isDiff && !openConfig.noRecentEntry) { const recents: IRecent[] = []; for (let pathToOpen of pathsToOpen) { if (pathToOpen.workspace) { From 65159d001a60c01985666dbdde7b14ba24262399 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Thu, 14 Nov 2019 11:55:52 +0100 Subject: [PATCH 254/352] terminal link handler using URL, #74604 --- .../workbench/contrib/terminal/browser/terminalLinkHandler.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/terminalLinkHandler.ts b/src/vs/workbench/contrib/terminal/browser/terminalLinkHandler.ts index 544cabcde0d58..2699cf8ab8abf 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalLinkHandler.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalLinkHandler.ts @@ -266,8 +266,8 @@ export class TerminalLinkHandler { } private _handleHypertextLink(url: string): void { - const uri = URI.parse(url); - this._openerService.open(uri, { allowTunneling: !!(this._processManager && this._processManager.remoteAuthority) }); + const urlObj = new URL(url); + this._openerService.open(urlObj, { allowTunneling: !!(this._processManager && this._processManager.remoteAuthority) }); } private _isLinkActivationModifierDown(event: MouseEvent): boolean { From 71ea9ad65172947e955745c514af153f86f8523e Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 14 Nov 2019 11:57:04 +0100 Subject: [PATCH 255/352] lcd - put title part on own layer --- .../browser/parts/titlebar/media/titlebarpart.css | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/vs/workbench/browser/parts/titlebar/media/titlebarpart.css b/src/vs/workbench/browser/parts/titlebar/media/titlebarpart.css index 265d6518c4019..c0789900ba25b 100644 --- a/src/vs/workbench/browser/parts/titlebar/media/titlebarpart.css +++ b/src/vs/workbench/browser/parts/titlebar/media/titlebarpart.css @@ -19,6 +19,13 @@ display: flex; } +.monaco-workbench.windows .part.titlebar, +.monaco-workbench.linux .part.titlebar, +.monaco-workbench.web .part.titlebar { + /* put on own layer due to https://github.com/microsoft/vscode/issues/84806 */ + transform: translate3d(0px, 0px, 0px); +} + .monaco-workbench .part.titlebar > .titlebar-drag-region { top: 0; left: 0; From 5fab28fdab5d0f11c492946e4f6b39b31a250ef1 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Thu, 14 Nov 2019 11:32:29 +0100 Subject: [PATCH 256/352] Introduce signing in status --- src/vs/platform/auth/common/auth.ts | 3 +- .../auth/electron-browser/authTokenService.ts | 2 ++ .../userDataSync/browser/userDataSync.ts | 29 ++++++++++++++++--- 3 files changed, 29 insertions(+), 5 deletions(-) diff --git a/src/vs/platform/auth/common/auth.ts b/src/vs/platform/auth/common/auth.ts index 1f4e643c62e0b..d2e026fedd318 100644 --- a/src/vs/platform/auth/common/auth.ts +++ b/src/vs/platform/auth/common/auth.ts @@ -9,7 +9,8 @@ import { URI } from 'vs/base/common/uri'; export const enum AuthTokenStatus { Inactive = 'Inactive', - Active = 'Active' + Active = 'Active', + SigningIn = 'SigningIn' } export const IAuthTokenService = createDecorator('IAuthTokenService'); diff --git a/src/vs/platform/auth/electron-browser/authTokenService.ts b/src/vs/platform/auth/electron-browser/authTokenService.ts index 00a35957be51b..95e606b68def4 100644 --- a/src/vs/platform/auth/electron-browser/authTokenService.ts +++ b/src/vs/platform/auth/electron-browser/authTokenService.ts @@ -71,6 +71,7 @@ export class AuthTokenService extends Disposable implements IAuthTokenService { } public async login(callbackUri: URI): Promise { + this.setStatus(AuthTokenStatus.SigningIn); const nonce = generateUuid(); const port = (callbackUri.authority.match(/:([0-9]*)$/) || [])[1] || (callbackUri.scheme === 'https' || callbackUri.scheme === 'http' ? 443 : 80); const state = `${callbackUri.scheme},${port},${encodeURIComponent(nonce)},${encodeURIComponent(callbackUri.query)}`; @@ -88,6 +89,7 @@ export class AuthTokenService extends Disposable implements IAuthTokenService { const timeoutPromise = new Promise((resolve: (value: IToken) => void, reject) => { const wait = setTimeout(() => { + this.setStatus(AuthTokenStatus.Inactive); clearTimeout(wait); reject('Login timed out.'); }, 1000 * 60 * 5); diff --git a/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts b/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts index 7d72356a6f02b..88e65232e1d70 100644 --- a/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts +++ b/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts @@ -26,6 +26,7 @@ import { isEqual } from 'vs/base/common/resources'; import { IEditorInput } from 'vs/workbench/common/editor'; import { IAuthTokenService, AuthTokenStatus } from 'vs/platform/auth/common/auth'; import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; +import { FalseContext } from 'vs/platform/contextkey/common/contextkeys'; const CONTEXT_AUTH_TOKEN_STATE = new RawContextKey('authTokenStatus', AuthTokenStatus.Inactive); const SYNC_PUSH_LIGHT_ICON_URI = URI.parse(registerAndGetAmdImageURL(`vs/workbench/contrib/userDataSync/browser/media/check-light.svg`)); @@ -128,6 +129,9 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo if (this.userDataSyncService.status !== SyncStatus.Uninitialized && this.configurationService.getValue(UserDataSyncWorkbenchContribution.ENABLEMENT_SETTING) && this.authTokenService.status === AuthTokenStatus.Inactive) { badge = new NumberBadge(1, () => localize('sign in', "Sync: Sign in...")); + } else if (this.authTokenService.status === AuthTokenStatus.SigningIn) { + badge = new ProgressBadge(() => localize('signing in', "Signin in...")); + clazz = 'progress-badge'; } else if (this.userDataSyncService.status === SyncStatus.HasConflicts) { badge = new NumberBadge(1, () => localize('resolve conflicts', "Resolve Conflicts")); } else if (this.userDataSyncService.status === SyncStatus.Syncing) { @@ -151,7 +155,12 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo if (!result.confirmed) { return; } - await this.signIn(); + try { + await this.signIn(); + } catch (e) { + this.notificationService.error(e); + return; + } } await this.configurationService.updateValue(UserDataSyncWorkbenchContribution.ENABLEMENT_SETTING, true); } @@ -225,13 +234,13 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo id: 'workbench.userData.actions.syncStart', title: localize('start sync', "Sync: Turn On") }, - when: ContextKeyExpr.and(CONTEXT_SYNC_STATE.notEqualsTo(SyncStatus.Uninitialized), ContextKeyExpr.not(`config.${UserDataSyncWorkbenchContribution.ENABLEMENT_SETTING}`)), + when: ContextKeyExpr.and(CONTEXT_SYNC_STATE.notEqualsTo(SyncStatus.Uninitialized), ContextKeyExpr.not(`config.${UserDataSyncWorkbenchContribution.ENABLEMENT_SETTING}`), CONTEXT_AUTH_TOKEN_STATE.notEqualsTo(AuthTokenStatus.SigningIn)), }; CommandsRegistry.registerCommand(startSyncMenuItem.command.id, () => this.turnOn()); MenuRegistry.appendMenuItem(MenuId.GlobalActivity, startSyncMenuItem); MenuRegistry.appendMenuItem(MenuId.CommandPalette, startSyncMenuItem); - const signInCommandId = 'workbench.userData.actions.login'; + const signInCommandId = 'workbench.userData.actions.signin'; const signInWhenContext = ContextKeyExpr.and(CONTEXT_SYNC_STATE.notEqualsTo(SyncStatus.Uninitialized), ContextKeyExpr.has(`config.${UserDataSyncWorkbenchContribution.ENABLEMENT_SETTING}`), CONTEXT_AUTH_TOKEN_STATE.isEqualTo(AuthTokenStatus.Inactive)); CommandsRegistry.registerCommand(signInCommandId, () => this.signIn()); MenuRegistry.appendMenuItem(MenuId.GlobalActivity, { @@ -250,6 +259,18 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo when: signInWhenContext, }); + const signingInCommandId = 'workbench.userData.actions.signingin'; + CommandsRegistry.registerCommand(signInCommandId, () => null); + MenuRegistry.appendMenuItem(MenuId.GlobalActivity, { + group: '5_sync', + command: { + id: signingInCommandId, + title: localize('signinig in', "Sync: Signing in..."), + precondition: FalseContext + }, + when: CONTEXT_AUTH_TOKEN_STATE.isEqualTo(AuthTokenStatus.SigningIn) + }); + const stopSycCommand = { id: 'workbench.userData.actions.stopSync', title: localize('stop sync', "Sync: Turn Off") @@ -310,7 +331,7 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo const signOutMenuItem: IMenuItem = { group: '5_sync', command: { - id: 'workbench.userData.actions.logout', + id: 'workbench.userData.actions.signout', title: localize('sign out', "Sign Out") }, when: ContextKeyExpr.and(CONTEXT_AUTH_TOKEN_STATE.isEqualTo(AuthTokenStatus.Active)), From 914721a7809dd45b5c9203c08d192d2f6c13b6f2 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Thu, 14 Nov 2019 11:38:14 +0100 Subject: [PATCH 257/352] move error handling --- .../contrib/userDataSync/browser/userDataSync.ts | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts b/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts index 88e65232e1d70..9a8b2425616c6 100644 --- a/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts +++ b/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts @@ -155,12 +155,7 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo if (!result.confirmed) { return; } - try { - await this.signIn(); - } catch (e) { - this.notificationService.error(e); - return; - } + await this.signIn(); } await this.configurationService.updateValue(UserDataSyncWorkbenchContribution.ENABLEMENT_SETTING, true); } @@ -170,7 +165,12 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo } private async signIn(): Promise { - return this.authTokenService.login(); + try { + await this.authTokenService.login(); + } catch (e) { + this.notificationService.error(e); + throw e; + } } private async signOut(): Promise { From 0fd9727b1221418d9519ca61f9920911f8ec19de Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Thu, 14 Nov 2019 12:42:51 +0100 Subject: [PATCH 258/352] Configure sync options while turning on --- .../userDataSync/browser/userDataSync.ts | 49 ++++++++++++++++++- 1 file changed, 48 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts b/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts index 9a8b2425616c6..5e631d1627384 100644 --- a/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts +++ b/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts @@ -6,7 +6,7 @@ import { IWorkbenchContribution } from 'vs/workbench/common/contributions'; import { IUserDataSyncService, SyncStatus, SyncSource, CONTEXT_SYNC_STATE } from 'vs/platform/userDataSync/common/userDataSync'; import { localize } from 'vs/nls'; -import { Disposable, MutableDisposable, toDisposable } from 'vs/base/common/lifecycle'; +import { Disposable, MutableDisposable, toDisposable, DisposableStore } from 'vs/base/common/lifecycle'; import { CommandsRegistry } from 'vs/platform/commands/common/commands'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { MenuRegistry, MenuId, IMenuItem } from 'vs/platform/actions/common/actions'; @@ -27,6 +27,8 @@ import { IEditorInput } from 'vs/workbench/common/editor'; import { IAuthTokenService, AuthTokenStatus } from 'vs/platform/auth/common/auth'; import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; import { FalseContext } from 'vs/platform/contextkey/common/contextkeys'; +import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; +import { IQuickInputService } from 'vs/platform/quickinput/common/quickInput'; const CONTEXT_AUTH_TOKEN_STATE = new RawContextKey('authTokenStatus', AuthTokenStatus.Inactive); const SYNC_PUSH_LIGHT_ICON_URI = URI.parse(registerAndGetAmdImageURL(`vs/workbench/contrib/userDataSync/browser/media/check-light.svg`)); @@ -54,6 +56,8 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo @IHistoryService private readonly historyService: IHistoryService, @IWorkbenchEnvironmentService private readonly workbenchEnvironmentService: IWorkbenchEnvironmentService, @IDialogService private readonly dialogService: IDialogService, + @IStorageService private readonly storageService: IStorageService, + @IQuickInputService private readonly quickInputService: IQuickInputService, ) { super(); this.syncStatusContext = CONTEXT_SYNC_STATE.bindTo(contextKeyService); @@ -157,7 +161,50 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo } await this.signIn(); } + await this.configureSyncOptions(); await this.configurationService.updateValue(UserDataSyncWorkbenchContribution.ENABLEMENT_SETTING, true); + this.notificationService.info(localize('Sync Started', "Sync Started.")); + } + + private async configureSyncOptions(): Promise { + if (this.storageService.getBoolean('userDataSync.configureOptions.donotAsk', StorageScope.GLOBAL, false)) { + return; + } + return new Promise((c, e) => { + const disposables: DisposableStore = new DisposableStore(); + const quickPick = this.quickInputService.createQuickPick(); + disposables.add(quickPick); + quickPick.placeholder = localize('select configurations to sync', "Choose what to sync"); + quickPick.canSelectMany = true; + const items = [{ + id: 'configurationSync.enableSettings', + label: localize('user settings', "User Settings") + }, { + id: 'configurationSync.enableExtensions', + label: localize('extensions', "Extensions") + }]; + quickPick.items = items; + quickPick.selectedItems = items.filter(item => this.configurationService.getValue(item.id)); + quickPick.customButton = true; + quickPick.customLabel = localize('do not ask', "Don't Ask Again"); + disposables.add(quickPick.onDidCustom(() => { + this.storageService.store('userDataSync.configureOptions.donotAsk', true, StorageScope.GLOBAL); + quickPick.hide(); + })); + disposables.add(quickPick.onDidAccept(() => quickPick.hide())); + disposables.add(quickPick.onDidHide(() => { + for (const item of items) { + const wasEnabled = this.configurationService.getValue(item.id); + const isEnabled = !!quickPick.selectedItems.filter(selected => selected.id === item.id)[0]; + if (wasEnabled !== isEnabled) { + this.configurationService.updateValue(item.id!, isEnabled); + } + } + disposables.dispose(); + c(); + })); + quickPick.show(); + }); } private async turnOff(): Promise { From c8377edb83908b50a874ac2730f8aa82311fd457 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Thu, 14 Nov 2019 12:44:01 +0100 Subject: [PATCH 259/352] enable custom button in multiselect --- src/vs/workbench/browser/parts/quickinput/quickInput.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/browser/parts/quickinput/quickInput.ts b/src/vs/workbench/browser/parts/quickinput/quickInput.ts index 36f7c6eb674b6..ec2738527698e 100644 --- a/src/vs/workbench/browser/parts/quickinput/quickInput.ts +++ b/src/vs/workbench/browser/parts/quickinput/quickInput.ts @@ -702,7 +702,7 @@ class QuickPick extends QuickInput implements IQuickPi if (!this.visible) { return; } - this.ui.setVisibilities(this.canSelectMany ? { title: !!this.title || !!this.step, checkAll: true, inputBox: true, visibleCount: true, count: true, ok: true, list: true, message: !!this.validationMessage } : { title: !!this.title || !!this.step, inputBox: true, visibleCount: true, list: true, message: !!this.validationMessage, customButton: this.customButton, ok: this.ok }); + this.ui.setVisibilities(this.canSelectMany ? { title: !!this.title || !!this.step, checkAll: true, inputBox: true, visibleCount: true, count: true, ok: true, list: true, message: !!this.validationMessage, customButton: this.customButton } : { title: !!this.title || !!this.step, inputBox: true, visibleCount: true, list: true, message: !!this.validationMessage, customButton: this.customButton, ok: this.ok }); super.update(); if (this.ui.inputBox.value !== this.value) { this.ui.inputBox.value = this.value; From 687e276dc236266d47deca999720cb52ff30d235 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Thu, 14 Nov 2019 14:07:18 +0100 Subject: [PATCH 260/352] update references viewlet --- build/builtInExtensions.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/builtInExtensions.json b/build/builtInExtensions.json index 0657b168aca00..7365025c3439c 100644 --- a/build/builtInExtensions.json +++ b/build/builtInExtensions.json @@ -31,7 +31,7 @@ }, { "name": "ms-vscode.references-view", - "version": "0.0.36", + "version": "0.0.37", "repo": "https://github.com/Microsoft/vscode-reference-view", "metadata": { "id": "dc489f46-520d-4556-ae85-1f9eab3c412d", From 46a5e6285355acd95a82f5c5138433fbad39af55 Mon Sep 17 00:00:00 2001 From: Christof Marti Date: Thu, 14 Nov 2019 14:29:46 +0100 Subject: [PATCH 261/352] Adapt height (fixes #84734) --- src/vs/workbench/browser/parts/quickinput/quickInput.ts | 4 +++- src/vs/workbench/browser/parts/quickinput/quickInputList.ts | 3 ++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/browser/parts/quickinput/quickInput.ts b/src/vs/workbench/browser/parts/quickinput/quickInput.ts index 36f7c6eb674b6..bdf955e61a93f 100644 --- a/src/vs/workbench/browser/parts/quickinput/quickInput.ts +++ b/src/vs/workbench/browser/parts/quickinput/quickInput.ts @@ -895,6 +895,7 @@ export class QuickInputService extends Component implements IQuickInputService { private idPrefix = 'quickInput_'; // Constant since there is still only one. private ui: QuickInputUI | undefined; + private dimension?: dom.Dimension; private comboboxAccessibility = false; private enabled = true; private inQuickOpenWidgets: Record = {}; @@ -1498,6 +1499,7 @@ export class QuickInputService extends Component implements IQuickInputService { } layout(dimension: dom.Dimension): void { + this.dimension = dimension; this.updateLayout(); } @@ -1512,7 +1514,7 @@ export class QuickInputService extends Component implements IQuickInputService { style.marginLeft = '-' + (width / 2) + 'px'; this.ui.inputBox.layout(); - this.ui.list.layout(); + this.ui.list.layout(this.dimension && this.dimension.height * 0.6); } } diff --git a/src/vs/workbench/browser/parts/quickinput/quickInputList.ts b/src/vs/workbench/browser/parts/quickinput/quickInputList.ts index 1e62ba48a8aa1..9129e303b84d9 100644 --- a/src/vs/workbench/browser/parts/quickinput/quickInputList.ts +++ b/src/vs/workbench/browser/parts/quickinput/quickInputList.ts @@ -468,7 +468,8 @@ export class QuickInputList { this.list.domFocus(); } - layout(): void { + layout(maxHeight?: number): void { + this.list.getHTMLElement().style.maxHeight = maxHeight ? `calc(${Math.floor(maxHeight / 44) * 44}px)` : ''; this.list.layout(); } From dccaf037f35ed2d73fa97e48e8e053887d0366b1 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Thu, 14 Nov 2019 14:31:03 +0100 Subject: [PATCH 262/352] lcd rendering - put parts on their own GPU layer --- .../parts/activitybar/media/activitybarpart.css | 15 +++++++++++++++ .../browser/parts/panel/media/panelpart.css | 15 +++++++++++++++ .../parts/statusbar/media/statusbarpart.css | 15 +++++++++++++++ .../browser/parts/titlebar/media/titlebarpart.css | 12 +++++++++++- 4 files changed, 56 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/browser/parts/activitybar/media/activitybarpart.css b/src/vs/workbench/browser/parts/activitybar/media/activitybarpart.css index 7b900b9d42bd8..66231d1ab2e2a 100644 --- a/src/vs/workbench/browser/parts/activitybar/media/activitybarpart.css +++ b/src/vs/workbench/browser/parts/activitybar/media/activitybarpart.css @@ -7,6 +7,21 @@ width: 48px; } +.monaco-workbench.windows .part.activitybar, +.monaco-workbench.linux .part.activitybar, +.monaco-workbench.web .part.activitybar { + /* + * Explicitly put the part onto its own layer to help Chrome to + * render the content with LCD-anti-aliasing. By partioning the + * workbench into multiple layers, we can ensure that a bad + * behaving part is not making another part fallback to greyscale + * rendering. + * + * macOS: does not render LCD-anti-aliased. + */ + transform: translate3d(0px, 0px, 0px); +} + .monaco-workbench .activitybar > .content { height: 100%; display: flex; diff --git a/src/vs/workbench/browser/parts/panel/media/panelpart.css b/src/vs/workbench/browser/parts/panel/media/panelpart.css index 64af1d2101147..82e2097540f6f 100644 --- a/src/vs/workbench/browser/parts/panel/media/panelpart.css +++ b/src/vs/workbench/browser/parts/panel/media/panelpart.css @@ -12,6 +12,21 @@ z-index: initial; } +.monaco-workbench.windows .part.panel, +.monaco-workbench.linux .part.panel, +.monaco-workbench.web .part.panel { + /* + * Explicitly put the part onto its own layer to help Chrome to + * render the content with LCD-anti-aliasing. By partioning the + * workbench into multiple layers, we can ensure that a bad + * behaving part is not making another part fallback to greyscale + * rendering. + * + * macOS: does not render LCD-anti-aliased. + */ + transform: translate3d(0px, 0px, 0px); +} + .monaco-workbench .part.panel .title { height: 35px; display: flex; diff --git a/src/vs/workbench/browser/parts/statusbar/media/statusbarpart.css b/src/vs/workbench/browser/parts/statusbar/media/statusbarpart.css index b859f25c71fb6..458d024626b85 100644 --- a/src/vs/workbench/browser/parts/statusbar/media/statusbarpart.css +++ b/src/vs/workbench/browser/parts/statusbar/media/statusbarpart.css @@ -13,6 +13,21 @@ overflow: visible; } +.monaco-workbench.windows .part.statusbar, +.monaco-workbench.linux .part.statusbar, +.monaco-workbench.web .part.statusbar { + /* + * Explicitly put the part onto its own layer to help Chrome to + * render the content with LCD-anti-aliasing. By partioning the + * workbench into multiple layers, we can ensure that a bad + * behaving part is not making another part fallback to greyscale + * rendering. + * + * macOS: does not render LCD-anti-aliased. + */ + transform: translate3d(0px, 0px, 0px); +} + .monaco-workbench .part.statusbar.status-border-top::after { content: ''; position: absolute; diff --git a/src/vs/workbench/browser/parts/titlebar/media/titlebarpart.css b/src/vs/workbench/browser/parts/titlebar/media/titlebarpart.css index c0789900ba25b..cdfba0ded3201 100644 --- a/src/vs/workbench/browser/parts/titlebar/media/titlebarpart.css +++ b/src/vs/workbench/browser/parts/titlebar/media/titlebarpart.css @@ -22,7 +22,17 @@ .monaco-workbench.windows .part.titlebar, .monaco-workbench.linux .part.titlebar, .monaco-workbench.web .part.titlebar { - /* put on own layer due to https://github.com/microsoft/vscode/issues/84806 */ + /* + * Explicitly put the part onto its own layer to help Chrome to + * render the content with LCD-anti-aliasing. By partioning the + * workbench into multiple layers, we can ensure that a bad + * behaving part is not making another part fallback to greyscale + * rendering. + * + * macOS: does not render LCD-anti-aliased. + * + * Related: https://github.com/microsoft/vscode/issues/84806 + */ transform: translate3d(0px, 0px, 0px); } From 9e128e432243e05fd9468aa2a83bedbd6032a395 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Thu, 14 Nov 2019 14:58:42 +0100 Subject: [PATCH 263/352] lcd rendering for title (fix #84806) --- src/vs/base/common/color.ts | 17 +++++++++++++++++ .../parts/titlebar/media/titlebarpart.css | 2 -- .../browser/parts/titlebar/titlebarPart.ts | 10 ++++++++-- 3 files changed, 25 insertions(+), 4 deletions(-) diff --git a/src/vs/base/common/color.ts b/src/vs/base/common/color.ts index 8068e76aadd38..58397cfbcaee5 100644 --- a/src/vs/base/common/color.ts +++ b/src/vs/base/common/color.ts @@ -399,6 +399,23 @@ export class Color { return new Color(new RGBA(r, g, b, a)); } + makeOpaque(opaqueBackground: Color): Color { + if (this.isOpaque() || opaqueBackground.rgba.a !== 1) { + // only allow to blend onto a non-opaque color onto a opaque color + return this; + } + + const { r, g, b, a } = this.rgba; + + // https://stackoverflow.com/questions/12228548/finding-equivalent-color-with-opacity + return new Color(new RGBA( + opaqueBackground.rgba.r - a * (opaqueBackground.rgba.r - r), + opaqueBackground.rgba.g - a * (opaqueBackground.rgba.g - g), + opaqueBackground.rgba.b - a * (opaqueBackground.rgba.b - b), + 1 + )); + } + flatten(...backgrounds: Color[]): Color { const background = backgrounds.reduceRight((accumulator, color) => { return Color._flatten(color, accumulator); diff --git a/src/vs/workbench/browser/parts/titlebar/media/titlebarpart.css b/src/vs/workbench/browser/parts/titlebar/media/titlebarpart.css index cdfba0ded3201..f67701b108156 100644 --- a/src/vs/workbench/browser/parts/titlebar/media/titlebarpart.css +++ b/src/vs/workbench/browser/parts/titlebar/media/titlebarpart.css @@ -30,8 +30,6 @@ * rendering. * * macOS: does not render LCD-anti-aliased. - * - * Related: https://github.com/microsoft/vscode/issues/84806 */ transform: translate3d(0px, 0px, 0px); } diff --git a/src/vs/workbench/browser/parts/titlebar/titlebarPart.ts b/src/vs/workbench/browser/parts/titlebar/titlebarPart.ts index ddf68be9e7381..0bbd42aae2088 100644 --- a/src/vs/workbench/browser/parts/titlebar/titlebarPart.ts +++ b/src/vs/workbench/browser/parts/titlebar/titlebarPart.ts @@ -20,7 +20,7 @@ import { EditorInput, toResource, Verbosity, SideBySideEditor } from 'vs/workben import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; import { IWorkspaceContextService, WorkbenchState, IWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; import { IThemeService, registerThemingParticipant, ITheme, ICssStyleCollector } from 'vs/platform/theme/common/themeService'; -import { TITLE_BAR_ACTIVE_BACKGROUND, TITLE_BAR_ACTIVE_FOREGROUND, TITLE_BAR_INACTIVE_FOREGROUND, TITLE_BAR_INACTIVE_BACKGROUND, TITLE_BAR_BORDER } from 'vs/workbench/common/theme'; +import { TITLE_BAR_ACTIVE_BACKGROUND, TITLE_BAR_ACTIVE_FOREGROUND, TITLE_BAR_INACTIVE_FOREGROUND, TITLE_BAR_INACTIVE_BACKGROUND, TITLE_BAR_BORDER, WORKBENCH_BACKGROUND } from 'vs/workbench/common/theme'; import { isMacintosh, isWindows, isLinux, isWeb } from 'vs/base/common/platform'; import { URI } from 'vs/base/common/uri'; import { Color } from 'vs/base/common/color'; @@ -502,7 +502,13 @@ export class TitlebarPart extends Part implements ITitleService { removeClass(this.element, 'inactive'); } - const titleBackground = this.getColor(this.isInactive ? TITLE_BAR_INACTIVE_BACKGROUND : TITLE_BAR_ACTIVE_BACKGROUND) || ''; + const titleBackground = this.getColor(this.isInactive ? TITLE_BAR_INACTIVE_BACKGROUND : TITLE_BAR_ACTIVE_BACKGROUND, (color, theme) => { + // LCD Rendering Support: the title bar part is a defining its own GPU layer. + // To benefit from LCD font rendering, we must ensure that we always set an + // opaque background color. As such, we compute an opaque color given we know + // the background color is the workbench background. + return color.isOpaque() ? color : color.makeOpaque(WORKBENCH_BACKGROUND(theme)); + }) || ''; this.element.style.backgroundColor = titleBackground; if (titleBackground && Color.fromHex(titleBackground).isLighter()) { addClass(this.element, 'light'); From 481485b354b6a32eac31101daaf8cd1cc81787da Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Thu, 14 Nov 2019 15:05:10 +0100 Subject: [PATCH 264/352] use string instead of URL, help with IE11 and with unwanted URL magic --- src/vs/base/common/resources.ts | 22 ------------------- .../editor/browser/services/openerService.ts | 20 ++++++++--------- src/vs/editor/contrib/links/getLinks.ts | 15 ++----------- .../browser/services/openerService.test.ts | 15 +++++++++++++ src/vs/platform/opener/common/opener.ts | 15 ++++++++++--- .../terminal/browser/terminalLinkHandler.ts | 3 +-- .../url/common/trustedDomainsValidator.ts | 10 ++++----- .../url/electron-browser/urlService.ts | 13 +++++------ 8 files changed, 51 insertions(+), 62 deletions(-) diff --git a/src/vs/base/common/resources.ts b/src/vs/base/common/resources.ts index 6a9dcd13095f8..bea40bbdc628c 100644 --- a/src/vs/base/common/resources.ts +++ b/src/vs/base/common/resources.ts @@ -361,25 +361,3 @@ export function toLocalResource(resource: URI, authority: string | undefined): U return resource.with({ scheme: Schemas.file }); } - -export function matchesScheme(target: URI | URL, scheme: string) { - if (URI.isUri(target)) { - return equalsIgnoreCase(target.scheme, scheme); - } else { - return equalsIgnoreCase(target.protocol, scheme + ':'); - } -} - -/** - * `true` when urls can be constructed via `new URL("string")`, should only be `false` in IE: - * https://developer.mozilla.org/en-US/docs/Web/API/URL/URL#Browser_compatibility - */ -export const hasURLCtor = (function () { - try { - // tslint:disable-next-line: no-unused-expression - new URL('some://thing'); - return true; - } catch { - return false; - } -})(); diff --git a/src/vs/editor/browser/services/openerService.ts b/src/vs/editor/browser/services/openerService.ts index be0bcb1dcf840..7e1d50546aa5f 100644 --- a/src/vs/editor/browser/services/openerService.ts +++ b/src/vs/editor/browser/services/openerService.ts @@ -8,11 +8,11 @@ import { IDisposable } from 'vs/base/common/lifecycle'; import { LinkedList } from 'vs/base/common/linkedList'; import { parse } from 'vs/base/common/marshalling'; import { Schemas } from 'vs/base/common/network'; -import { matchesScheme, normalizePath } from 'vs/base/common/resources'; +import { normalizePath } from 'vs/base/common/resources'; import { URI } from 'vs/base/common/uri'; import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService'; import { CommandsRegistry, ICommandService } from 'vs/platform/commands/common/commands'; -import { IOpener, IOpenerService, IValidator, IExternalUriResolver, OpenOptions, ResolveExternalUriOptions, IResolvedExternalUri, IExternalOpener } from 'vs/platform/opener/common/opener'; +import { IOpener, IOpenerService, IValidator, IExternalUriResolver, OpenOptions, ResolveExternalUriOptions, IResolvedExternalUri, IExternalOpener, matchesScheme } from 'vs/platform/opener/common/opener'; import { EditorOpenContext } from 'vs/platform/editor/common/editor'; @@ -43,7 +43,7 @@ export class OpenerService implements IOpenerService { // Default opener: maito, http(s), command, and catch-all-editors this._openerAsExternal = { - open: async (target: URI | URL, options?: OpenOptions) => { + open: async (target: URI | string, options?: OpenOptions) => { if (options?.openExternal || matchesScheme(target, Schemas.mailto) || matchesScheme(target, Schemas.http) || matchesScheme(target, Schemas.https)) { // open externally await this._doOpenExternal(target, options); @@ -59,8 +59,8 @@ export class OpenerService implements IOpenerService { return false; } // run command or bail out if command isn't known - if (!URI.isUri(target)) { - target = URI.from(target); + if (typeof target === 'string') { + target = URI.parse(target); } if (!CommandsRegistry.getCommand(target.path)) { throw new Error(`command '${target.path}' NOT known`); @@ -82,8 +82,8 @@ export class OpenerService implements IOpenerService { this._openerAsEditor = { open: async (target, options: OpenOptions) => { - if (!URI.isUri(target)) { - target = URI.from(target); + if (typeof target === 'string') { + target = URI.parse(target); } let selection: { startLineNumber: number; startColumn: number; } | undefined = undefined; const match = /^L?(\d+)(?:,(\d+))?/.exec(target.fragment); @@ -132,7 +132,7 @@ export class OpenerService implements IOpenerService { this._externalOpener = externalOpener; } - async open(target: URI | URL, options?: OpenOptions): Promise { + async open(target: URI | string, options?: OpenOptions): Promise { // check with contributed validators for (const validator of this._validators.toArray()) { @@ -169,7 +169,7 @@ export class OpenerService implements IOpenerService { return { resolved: resource, dispose: () => { } }; } - private async _doOpenExternal(resource: URI | URL, options: OpenOptions | undefined): Promise { + private async _doOpenExternal(resource: URI | string, options: OpenOptions | undefined): Promise { if (URI.isUri(resource)) { const { resolved } = await this.resolveExternalUri(resource, options); // TODO@Jo neither encodeURI nor toString(true) should be needed @@ -177,7 +177,7 @@ export class OpenerService implements IOpenerService { return this._externalOpener.openExternal(encodeURI(resolved.toString(true))); } else { //todo@joh what about resolveExternalUri? - return this._externalOpener.openExternal(resource.href); + return this._externalOpener.openExternal(resource); } } diff --git a/src/vs/editor/contrib/links/getLinks.ts b/src/vs/editor/contrib/links/getLinks.ts index 081d8b4adde3c..a85e7f8c94297 100644 --- a/src/vs/editor/contrib/links/getLinks.ts +++ b/src/vs/editor/contrib/links/getLinks.ts @@ -13,7 +13,6 @@ import { IModelService } from 'vs/editor/common/services/modelService'; import { CommandsRegistry } from 'vs/platform/commands/common/commands'; import { isDisposable, Disposable } from 'vs/base/common/lifecycle'; import { coalesce } from 'vs/base/common/arrays'; -import { hasURLCtor } from 'vs/base/common/resources'; export class Link implements ILink { @@ -45,19 +44,9 @@ export class Link implements ILink { return this._link.tooltip; } - async resolve(token: CancellationToken): Promise { + async resolve(token: CancellationToken): Promise { if (this._link.url) { - try { - if (URI.isUri(this._link.url)) { - return this._link.url; - } else if (!hasURLCtor) { - return URI.parse(this._link.url); - } else { - return new URL(this._link.url); - } - } catch (e) { - return Promise.reject(new Error('invalid')); - } + return this._link.url; } if (typeof this._provider.resolveLink === 'function') { diff --git a/src/vs/editor/test/browser/services/openerService.test.ts b/src/vs/editor/test/browser/services/openerService.test.ts index 4081b6fc5f8ac..697dc99402dfa 100644 --- a/src/vs/editor/test/browser/services/openerService.test.ts +++ b/src/vs/editor/test/browser/services/openerService.test.ts @@ -8,6 +8,7 @@ import { URI } from 'vs/base/common/uri'; import { OpenerService } from 'vs/editor/browser/services/openerService'; import { TestCodeEditorService } from 'vs/editor/test/browser/editorTestServices'; import { CommandsRegistry, ICommandService, NullCommandService } from 'vs/platform/commands/common/commands'; +import { matchesScheme } from 'vs/platform/opener/common/opener'; suite('OpenerService', function () { const editorService = new TestCodeEditorService(); @@ -199,4 +200,18 @@ suite('OpenerService', function () { assert.equal(v1, 2); assert.equal(v2, 0); }); + + test('matchesScheme', function () { + assert.ok(matchesScheme('https://microsoft.com', 'https')); + assert.ok(matchesScheme('http://microsoft.com', 'http')); + assert.ok(matchesScheme('hTTPs://microsoft.com', 'https')); + assert.ok(matchesScheme('httP://microsoft.com', 'http')); + assert.ok(matchesScheme(URI.parse('https://microsoft.com'), 'https')); + assert.ok(matchesScheme(URI.parse('http://microsoft.com'), 'http')); + assert.ok(matchesScheme(URI.parse('hTTPs://microsoft.com'), 'https')); + assert.ok(matchesScheme(URI.parse('httP://microsoft.com'), 'http')); + assert.ok(!matchesScheme(URI.parse('https://microsoft.com'), 'http')); + assert.ok(!matchesScheme(URI.parse('htt://microsoft.com'), 'http')); + assert.ok(!matchesScheme(URI.parse('z://microsoft.com'), 'http')); + }); }); diff --git a/src/vs/platform/opener/common/opener.ts b/src/vs/platform/opener/common/opener.ts index 5cdaebc93ce28..8f7921d15816a 100644 --- a/src/vs/platform/opener/common/opener.ts +++ b/src/vs/platform/opener/common/opener.ts @@ -6,6 +6,7 @@ import { URI } from 'vs/base/common/uri'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { IDisposable, Disposable } from 'vs/base/common/lifecycle'; +import { equalsIgnoreCase, startsWithIgnoreCase } from 'vs/base/common/strings'; export const IOpenerService = createDecorator('openerService'); @@ -35,7 +36,7 @@ export interface IResolvedExternalUri extends IDisposable { } export interface IOpener { - open(resource: URI | URL, options?: OpenInternalOptions | OpenExternalOptions): Promise; + open(resource: URI | string, options?: OpenInternalOptions | OpenExternalOptions): Promise; } export interface IExternalOpener { @@ -43,7 +44,7 @@ export interface IExternalOpener { } export interface IValidator { - shouldOpen(resource: URI | URL): Promise; + shouldOpen(resource: URI | string): Promise; } export interface IExternalUriResolver { @@ -82,7 +83,7 @@ export interface IOpenerService { * @param resource A resource * @return A promise that resolves when the opening is done. */ - open(resource: URI | URL, options?: OpenInternalOptions | OpenExternalOptions): Promise; + open(resource: URI | string, options?: OpenInternalOptions | OpenExternalOptions): Promise; /** * Resolve a resource to its external form. @@ -99,3 +100,11 @@ export const NullOpenerService: IOpenerService = Object.freeze({ async open() { return false; }, async resolveExternalUri(uri: URI) { return { resolved: uri, dispose() { } }; }, }); + +export function matchesScheme(target: URI | string, scheme: string) { + if (URI.isUri(target)) { + return equalsIgnoreCase(target.scheme, scheme); + } else { + return startsWithIgnoreCase(target, scheme + ':'); + } +} diff --git a/src/vs/workbench/contrib/terminal/browser/terminalLinkHandler.ts b/src/vs/workbench/contrib/terminal/browser/terminalLinkHandler.ts index 2699cf8ab8abf..6cb08ae0b26b1 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalLinkHandler.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalLinkHandler.ts @@ -266,8 +266,7 @@ export class TerminalLinkHandler { } private _handleHypertextLink(url: string): void { - const urlObj = new URL(url); - this._openerService.open(urlObj, { allowTunneling: !!(this._processManager && this._processManager.remoteAuthority) }); + this._openerService.open(url, { allowTunneling: !!(this._processManager && this._processManager.remoteAuthority) }); } private _isLinkActivationModifierDown(event: MouseEvent): boolean { diff --git a/src/vs/workbench/contrib/url/common/trustedDomainsValidator.ts b/src/vs/workbench/contrib/url/common/trustedDomainsValidator.ts index aabcd4405b23e..d8b03dc04d074 100644 --- a/src/vs/workbench/contrib/url/common/trustedDomainsValidator.ts +++ b/src/vs/workbench/contrib/url/common/trustedDomainsValidator.ts @@ -8,7 +8,7 @@ import Severity from 'vs/base/common/severity'; import { URI } from 'vs/base/common/uri'; import { localize } from 'vs/nls'; import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; -import { IOpenerService } from 'vs/platform/opener/common/opener'; +import { IOpenerService, matchesScheme } from 'vs/platform/opener/common/opener'; import { IProductService } from 'vs/platform/product/common/productService'; import { IQuickInputService } from 'vs/platform/quickinput/common/quickInput'; import { IStorageService } from 'vs/platform/storage/common/storage'; @@ -19,7 +19,7 @@ import { } from 'vs/workbench/contrib/url/common/trustedDomains'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService'; -import { matchesScheme } from 'vs/base/common/resources'; + export class OpenerValidatorContributions implements IWorkbenchContribution { constructor( @@ -34,13 +34,13 @@ export class OpenerValidatorContributions implements IWorkbenchContribution { this._openerService.registerValidator({ shouldOpen: r => this.validateLink(r) }); } - async validateLink(resource: URI | URL): Promise { + async validateLink(resource: URI | string): Promise { if (!matchesScheme(resource, Schemas.http) && !matchesScheme(resource, Schemas.https)) { return true; } - if (!URI.isUri(resource)) { - resource = URI.from(resource); + if (typeof resource === 'string') { + resource = URI.parse(resource); } const { scheme, authority, path, query, fragment } = resource; diff --git a/src/vs/workbench/services/url/electron-browser/urlService.ts b/src/vs/workbench/services/url/electron-browser/urlService.ts index c46c1948c4512..c1485a6ec59ca 100644 --- a/src/vs/workbench/services/url/electron-browser/urlService.ts +++ b/src/vs/workbench/services/url/electron-browser/urlService.ts @@ -8,7 +8,7 @@ import { URI, UriComponents } from 'vs/base/common/uri'; import { IMainProcessService } from 'vs/platform/ipc/electron-browser/mainProcessService'; import { URLHandlerChannel } from 'vs/platform/url/common/urlIpc'; import { URLService } from 'vs/platform/url/node/urlService'; -import { IOpenerService, IOpener } from 'vs/platform/opener/common/opener'; +import { IOpenerService, IOpener, matchesScheme } from 'vs/platform/opener/common/opener'; import product from 'vs/platform/product/common/product'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { IElectronEnvironmentService } from 'vs/workbench/services/electron/electron-browser/electronEnvironmentService'; @@ -51,16 +51,15 @@ export class RelayURLService extends URLService implements IURLHandler, IOpener return uri.with({ query }); } - async open(resource: URI | URL, options?: IRelayOpenURLOptions): Promise { + async open(resource: URI | string, options?: IRelayOpenURLOptions): Promise { - if (resource instanceof URL) { - resource = URI.from(resource); - } - - if (resource.scheme !== product.urlProtocol) { + if (!matchesScheme(resource, product.urlProtocol)) { return false; } + if (typeof resource === 'string') { + resource = URI.parse(resource); + } return await this.urlService.open(resource, options); } From c861fe99c18aac7a9289a5b411d8124b81ef1163 Mon Sep 17 00:00:00 2001 From: Andre Weinand Date: Thu, 14 Nov 2019 11:47:45 +0100 Subject: [PATCH 265/352] tweak proposed debug uri API --- src/vs/vscode.proposed.d.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/vscode.proposed.d.ts b/src/vs/vscode.proposed.d.ts index d139918f061ed..51728ea8fb42a 100644 --- a/src/vs/vscode.proposed.d.ts +++ b/src/vs/vscode.proposed.d.ts @@ -524,7 +524,7 @@ declare module 'vscode' { //#region André: debug /** - * A DebugSource is an opaque stand-in type for the type [Source](https://microsoft.github.io/debug-adapter-protocol/specification#Types_Source) defined in the Debug Adapter Protocol. + * A DebugSource is an opaque stand-in type for the [Source](https://microsoft.github.io/debug-adapter-protocol/specification#Types_Source) type defined in the Debug Adapter Protocol. */ export interface DebugSource { // opaque contents @@ -541,7 +541,7 @@ declare module 'vscode' { * @param session An optional debug session that will be used to locate the Debug Adapter Protocol. * @return A uri that can be used to load the contents of the source. */ - function asDebugSourceUri(source: DebugSource, session?: DebugSession): Uri; + export function asDebugSourceUri(source: DebugSource, session?: DebugSession): Uri; } // deprecated From 953cd2e6a21c9750456023928ba4ccea224f549a Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Thu, 14 Nov 2019 15:47:32 +0100 Subject: [PATCH 266/352] use string in markdown rendering - in most cases --- src/vs/base/browser/markdownRenderer.ts | 10 +++++----- src/vs/editor/contrib/hover/modesContentHover.ts | 2 +- src/vs/editor/contrib/hover/modesGlyphHover.ts | 2 +- src/vs/editor/contrib/markdown/markdownRenderer.ts | 13 ++----------- 4 files changed, 9 insertions(+), 18 deletions(-) diff --git a/src/vs/base/browser/markdownRenderer.ts b/src/vs/base/browser/markdownRenderer.ts index 57144d67ea618..971addf8f00bd 100644 --- a/src/vs/base/browser/markdownRenderer.ts +++ b/src/vs/base/browser/markdownRenderer.ts @@ -50,19 +50,19 @@ export function renderMarkdown(markdown: IMarkdownString, options: MarkdownRende const _href = function (href: string, isDomUri: boolean): string { const data = markdown.uris && markdown.uris[href]; if (!data) { - return href; + return href; // no uri exists } let uri = URI.revive(data); + if (URI.parse(href).toString() === uri.toString()) { + return href; // no tranformation performed + } if (isDomUri) { uri = DOM.asDomUri(uri); } if (uri.query) { uri = uri.with({ query: _uriMassage(uri.query) }); } - if (data) { - href = uri.toString(true); - } - return href; + return uri.toString(); }; // signal to code-block render that the diff --git a/src/vs/editor/contrib/hover/modesContentHover.ts b/src/vs/editor/contrib/hover/modesContentHover.ts index f37254d776f34..ca710263b2407 100644 --- a/src/vs/editor/contrib/hover/modesContentHover.ts +++ b/src/vs/editor/contrib/hover/modesContentHover.ts @@ -207,7 +207,7 @@ export class ModesContentHoverWidget extends ContentHoverWidget { private readonly _themeService: IThemeService, private readonly _keybindingService: IKeybindingService, private readonly _modeService: IModeService, - private readonly _openerService: IOpenerService | null = NullOpenerService, + private readonly _openerService: IOpenerService = NullOpenerService, ) { super(ModesContentHoverWidget.ID, editor); diff --git a/src/vs/editor/contrib/hover/modesGlyphHover.ts b/src/vs/editor/contrib/hover/modesGlyphHover.ts index 85dece77b64b2..32c6cf146563c 100644 --- a/src/vs/editor/contrib/hover/modesGlyphHover.ts +++ b/src/vs/editor/contrib/hover/modesGlyphHover.ts @@ -97,7 +97,7 @@ export class ModesGlyphHoverWidget extends GlyphHoverWidget { constructor( editor: ICodeEditor, modeService: IModeService, - openerService: IOpenerService | null = NullOpenerService, + openerService: IOpenerService = NullOpenerService, ) { super(ModesGlyphHoverWidget.ID, editor); diff --git a/src/vs/editor/contrib/markdown/markdownRenderer.ts b/src/vs/editor/contrib/markdown/markdownRenderer.ts index eb17228cfa8ba..b4bfe8ddd9e49 100644 --- a/src/vs/editor/contrib/markdown/markdownRenderer.ts +++ b/src/vs/editor/contrib/markdown/markdownRenderer.ts @@ -7,7 +7,6 @@ import { IMarkdownString } from 'vs/base/common/htmlContent'; import { renderMarkdown, MarkdownRenderOptions } from 'vs/base/browser/markdownRenderer'; import { IOpenerService, NullOpenerService } from 'vs/platform/opener/common/opener'; import { IModeService } from 'vs/editor/common/services/modeService'; -import { URI } from 'vs/base/common/uri'; import { onUnexpectedError } from 'vs/base/common/errors'; import { tokenizeToString } from 'vs/editor/common/modes/textToHtmlTokenizer'; import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; @@ -29,7 +28,7 @@ export class MarkdownRenderer extends Disposable { constructor( private readonly _editor: ICodeEditor, @IModeService private readonly _modeService: IModeService, - @optional(IOpenerService) private readonly _openerService: IOpenerService | null = NullOpenerService, + @optional(IOpenerService) private readonly _openerService: IOpenerService = NullOpenerService, ) { super(); } @@ -64,15 +63,7 @@ export class MarkdownRenderer extends Disposable { codeBlockRenderCallback: () => this._onDidRenderCodeBlock.fire(), actionHandler: { callback: (content) => { - let uri: URI | undefined; - try { - uri = URI.parse(content); - } catch { - // ignore - } - if (uri && this._openerService) { - this._openerService.open(uri, { fromUserGesture: true }).catch(onUnexpectedError); - } + this._openerService.open(content, { fromUserGesture: true }).catch(onUnexpectedError); }, disposeables } From 6d66ce848ea93ed5cbf301689b863dce595c5977 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Thu, 14 Nov 2019 15:50:10 +0100 Subject: [PATCH 267/352] Fix #83336 --- src/vs/base/browser/ui/highlightedlabel/highlightedLabel.ts | 6 +++++- .../workbench/contrib/markers/browser/markersTreeViewer.ts | 1 + 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/vs/base/browser/ui/highlightedlabel/highlightedLabel.ts b/src/vs/base/browser/ui/highlightedlabel/highlightedLabel.ts index 701d3a6a7858c..8980c3e5b0d10 100644 --- a/src/vs/base/browser/ui/highlightedlabel/highlightedLabel.ts +++ b/src/vs/base/browser/ui/highlightedlabel/highlightedLabel.ts @@ -84,7 +84,11 @@ export class HighlightedLabel { } this.domNode.innerHTML = htmlContent; - this.domNode.title = this.title; + if (this.title) { + this.domNode.title = this.title; + } else { + this.domNode.removeAttribute('title'); + } this.didEverRender = true; } diff --git a/src/vs/workbench/contrib/markers/browser/markersTreeViewer.ts b/src/vs/workbench/contrib/markers/browser/markersTreeViewer.ts index 2201cbe11d0cb..d8f7409222556 100644 --- a/src/vs/workbench/contrib/markers/browser/markersTreeViewer.ts +++ b/src/vs/workbench/contrib/markers/browser/markersTreeViewer.ts @@ -314,6 +314,7 @@ class MarkerWidget extends Disposable { const lineMatches = filterData && filterData.lineMatches || []; let lastLineElement: HTMLElement | undefined = undefined; + this.messageAndDetailsContainer.title = element.marker.message; for (let index = 0; index < (multiline ? lines.length : 1); index++) { lastLineElement = dom.append(this.messageAndDetailsContainer, dom.$('.marker-message-line')); const messageElement = dom.append(lastLineElement, dom.$('.marker-message')); From 705973999095bc2c67e9d03cf0341409135915fc Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Thu, 14 Nov 2019 15:52:12 +0100 Subject: [PATCH 268/352] simpler markdown link handling --- .../contrib/comments/browser/commentsTreeViewer.ts | 8 +------- .../contrib/preferences/browser/settingsTree.ts | 11 +---------- 2 files changed, 2 insertions(+), 17 deletions(-) diff --git a/src/vs/workbench/contrib/comments/browser/commentsTreeViewer.ts b/src/vs/workbench/contrib/comments/browser/commentsTreeViewer.ts index 299a7271b2bd3..c499a52051e73 100644 --- a/src/vs/workbench/contrib/comments/browser/commentsTreeViewer.ts +++ b/src/vs/workbench/contrib/comments/browser/commentsTreeViewer.ts @@ -8,7 +8,6 @@ import * as nls from 'vs/nls'; import { renderMarkdown } from 'vs/base/browser/markdownRenderer'; import { onUnexpectedError } from 'vs/base/common/errors'; import { IDisposable, DisposableStore } from 'vs/base/common/lifecycle'; -import { URI } from 'vs/base/common/uri'; import { IOpenerService } from 'vs/platform/opener/common/opener'; import { IResourceLabel, ResourceLabels } from 'vs/workbench/browser/labels'; import { CommentNode, CommentsModel, ResourceWithCommentThreads } from 'vs/workbench/contrib/comments/common/commentModel'; @@ -127,12 +126,7 @@ export class CommentNodeRenderer implements IListRenderer inline: true, actionHandler: { callback: (content) => { - try { - const uri = URI.parse(content); - this.openerService.open(uri).catch(onUnexpectedError); - } catch (err) { - // ignore - } + this.openerService.open(content).catch(onUnexpectedError); }, disposeables: disposables } diff --git a/src/vs/workbench/contrib/preferences/browser/settingsTree.ts b/src/vs/workbench/contrib/preferences/browser/settingsTree.ts index 329d660bca6e1..d026d0da5267b 100644 --- a/src/vs/workbench/contrib/preferences/browser/settingsTree.ts +++ b/src/vs/workbench/contrib/preferences/browser/settingsTree.ts @@ -28,7 +28,6 @@ import { KeyCode } from 'vs/base/common/keyCodes'; import { dispose, IDisposable, Disposable, DisposableStore } from 'vs/base/common/lifecycle'; import { ISpliceable } from 'vs/base/common/sequence'; import { escapeRegExpCharacters, startsWith } from 'vs/base/common/strings'; -import { URI } from 'vs/base/common/uri'; import { localize } from 'vs/nls'; import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService'; import { ICommandService } from 'vs/platform/commands/common/commands'; @@ -485,15 +484,7 @@ export abstract class AbstractSettingRenderer extends Disposable implements ITre }; this._onDidClickSettingLink.fire(e); } else { - let uri: URI | undefined; - try { - uri = URI.parse(content); - } catch (err) { - // ignore - } - if (uri) { - this._openerService.open(uri).catch(onUnexpectedError); - } + this._openerService.open(content).catch(onUnexpectedError); } }, disposeables From c1997dcd4bc2ee23c39349218ee1828dd99bb9d1 Mon Sep 17 00:00:00 2001 From: Martin Aeschlimann Date: Thu, 14 Nov 2019 16:41:07 +0100 Subject: [PATCH 269/352] add type bindings to minimist (for #83421) --- package.json | 2 +- remote/package.json | 2 +- remote/yarn.lock | 8 +-- src/typings/vscode-minimist.d.ts | 92 -------------------------------- yarn.lock | 8 +-- 5 files changed, 10 insertions(+), 102 deletions(-) delete mode 100644 src/typings/vscode-minimist.d.ts diff --git a/package.json b/package.json index 2dce29d332d29..66caa48db65cc 100644 --- a/package.json +++ b/package.json @@ -47,7 +47,7 @@ "spdlog": "^0.11.1", "sudo-prompt": "9.1.0", "v8-inspect-profiler": "^0.0.20", - "vscode-minimist": "^1.2.1", + "vscode-minimist": "^1.2.2", "vscode-nsfw": "1.2.8", "vscode-proxy-agent": "^0.5.2", "vscode-ripgrep": "^1.5.7", diff --git a/remote/package.json b/remote/package.json index 446f54ff57ed0..7b87df3defd4d 100644 --- a/remote/package.json +++ b/remote/package.json @@ -15,7 +15,7 @@ "onigasm-umd": "^2.2.4", "semver-umd": "^5.5.3", "spdlog": "^0.11.1", - "vscode-minimist": "^1.2.1", + "vscode-minimist": "^1.2.2", "vscode-nsfw": "1.2.8", "vscode-proxy-agent": "^0.5.2", "vscode-ripgrep": "^1.5.7", diff --git a/remote/yarn.lock b/remote/yarn.lock index 99fb10b59c3a8..8f2882c971463 100644 --- a/remote/yarn.lock +++ b/remote/yarn.lock @@ -369,10 +369,10 @@ universalify@^0.1.0: resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== -vscode-minimist@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/vscode-minimist/-/vscode-minimist-1.2.1.tgz#e63d3f4a9bf3680dcb8f9304eed612323fd6926a" - integrity sha512-cmB72+qDoiCFJ1UKnGUBdGYfXzdpJ3bQM/D/+XhkVk5v7uZgLbYiCz5JcwVyk7NC7hSi5VGtQ4wihzmi12NeXw== +vscode-minimist@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/vscode-minimist/-/vscode-minimist-1.2.2.tgz#65403f44f0c6010d259b2271d36eb5c6f4ad8aab" + integrity sha512-DXMNG2QgrXn1jOP12LzjVfvxVkzxv/0Qa27JrMBj/XP2esj+fJ/wP2T4YUH5derj73Lc96dC8F25WyfDUbTpxQ== vscode-nsfw@1.2.8: version "1.2.8" diff --git a/src/typings/vscode-minimist.d.ts b/src/typings/vscode-minimist.d.ts deleted file mode 100644 index 17558a1a7383a..0000000000000 --- a/src/typings/vscode-minimist.d.ts +++ /dev/null @@ -1,92 +0,0 @@ -// Type definitions for minimist 1.2.0 -// Project: https://github.com/substack/minimist -// Definitions by: Bart van der Schoor , Necroskillz , kamranayub -// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped - -/** - * Return an argument object populated with the array arguments from args - * - * @param args An optional argument array (typically `process.argv.slice(2)`) - * @param opts An optional options object to customize the parsing - */ -declare function minimist(args?: string[], opts?: minimist.Opts): minimist.ParsedArgs; - -/** - * Return an argument object populated with the array arguments from args. Strongly-typed - * to be the intersect of type T with minimist.ParsedArgs. - * - * @type T The type that will be intersected with minimist.ParsedArgs to represent the argument object - * @param args An optional argument array (typically `process.argv.slice(2)`) - * @param opts An optional options object to customize the parsing - */ -declare function minimist(args?: string[], opts?: minimist.Opts): T & minimist.ParsedArgs; - -/** - * Return an argument object populated with the array arguments from args. Strongly-typed - * to be the the type T which should extend minimist.ParsedArgs - * - * @type T The type that extends minimist.ParsedArgs and represents the argument object - * @param args An optional argument array (typically `process.argv.slice(2)`) - * @param opts An optional options object to customize the parsing - */ -declare function minimist(args?: string[], opts?: minimist.Opts): T; - -declare namespace minimist { - export interface Opts { - /** - * A string or array of strings argument names to always treat as strings - */ - string?: string | string[]; - - /** - * A boolean, string or array of strings to always treat as booleans. If true will treat - * all double hyphenated arguments without equals signs as boolean (e.g. affects `--foo`, not `-f` or `--foo=bar`) - */ - boolean?: boolean | string | string[]; - - /** - * An object mapping string names to strings or arrays of string argument names to use as aliases - */ - alias?: { [key: string]: string | string[] }; - - /** - * An object mapping string argument names to default values - */ - default?: { [key: string]: any }; - - /** - * When true, populate argv._ with everything after the first non-option - */ - stopEarly?: boolean; - - /** - * A function which is invoked with a command line parameter not defined in the opts - * configuration object. If the function returns false, the unknown option is not added to argv - */ - unknown?: (arg: string) => boolean; - - /** - * When true, populate argv._ with everything before the -- and argv['--'] with everything after the --. - * Note that with -- set, parsing for arguments still stops after the `--`. - */ - '--'?: boolean; - } - - export interface ParsedArgs { - [arg: string]: any; - - /** - * If opts['--'] is true, populated with everything after the -- - */ - '--'?: string[]; - - /** - * Contains all the arguments that didn't have an option associated with them - */ - _: string[]; - } -} - -declare module "vscode-minimist" { - export = minimist; -} diff --git a/yarn.lock b/yarn.lock index 1d949d454a4e5..78889420ad566 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9017,10 +9017,10 @@ vscode-debugprotocol@1.37.0: resolved "https://registry.yarnpkg.com/vscode-debugprotocol/-/vscode-debugprotocol-1.37.0.tgz#e8c4694a078d18ea1a639553a7a241b35c1e6f6d" integrity sha512-ppZLEBbFRVNsK0YpfgFi/x2CDyihx0F+UpdKmgeJcvi05UgSXYdO0n9sDVYwoGvvYQPvlpDQeWuY0nloOC4mPA== -vscode-minimist@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/vscode-minimist/-/vscode-minimist-1.2.1.tgz#e63d3f4a9bf3680dcb8f9304eed612323fd6926a" - integrity sha512-cmB72+qDoiCFJ1UKnGUBdGYfXzdpJ3bQM/D/+XhkVk5v7uZgLbYiCz5JcwVyk7NC7hSi5VGtQ4wihzmi12NeXw== +vscode-minimist@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/vscode-minimist/-/vscode-minimist-1.2.2.tgz#65403f44f0c6010d259b2271d36eb5c6f4ad8aab" + integrity sha512-DXMNG2QgrXn1jOP12LzjVfvxVkzxv/0Qa27JrMBj/XP2esj+fJ/wP2T4YUH5derj73Lc96dC8F25WyfDUbTpxQ== vscode-nls-dev@^3.3.1: version "3.3.1" From 67ac71161cc2295441b70d3d772af77e9b0bdfaa Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Thu, 14 Nov 2019 16:42:35 +0100 Subject: [PATCH 270/352] openExternal uses resolver for URI and string --- src/vs/editor/browser/services/openerService.ts | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/src/vs/editor/browser/services/openerService.ts b/src/vs/editor/browser/services/openerService.ts index 7e1d50546aa5f..b92275c5cf0f7 100644 --- a/src/vs/editor/browser/services/openerService.ts +++ b/src/vs/editor/browser/services/openerService.ts @@ -170,14 +170,17 @@ export class OpenerService implements IOpenerService { } private async _doOpenExternal(resource: URI | string, options: OpenOptions | undefined): Promise { - if (URI.isUri(resource)) { - const { resolved } = await this.resolveExternalUri(resource, options); - // TODO@Jo neither encodeURI nor toString(true) should be needed - // once we go with URL and not URI - return this._externalOpener.openExternal(encodeURI(resolved.toString(true))); - } else { - //todo@joh what about resolveExternalUri? + + //todo@joh IExternalUriResolver should support `uri: URI | string` + const uri = typeof resource === 'string' ? URI.parse(resource) : resource; + const { resolved } = await this.resolveExternalUri(uri, options); + + if (typeof resource === 'string' && uri.toString() === resolved.toString()) { + // open the url-string AS IS return this._externalOpener.openExternal(resource); + } else { + // open URI using the toString(noEncode)+encodeURI-trick + return this._externalOpener.openExternal(encodeURI(resolved.toString(true))); } } From bfea1b4f6159c25a75c3e49b3fdb13710aa3d67d Mon Sep 17 00:00:00 2001 From: Miguel Solorio Date: Thu, 14 Nov 2019 07:58:21 -0800 Subject: [PATCH 271/352] Update codicons --- .../ui/codiconLabel/codicon/codicon.css | 3 ++- .../ui/codiconLabel/codicon/codicon.ttf | Bin 46932 -> 46932 bytes 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/vs/base/browser/ui/codiconLabel/codicon/codicon.css b/src/vs/base/browser/ui/codiconLabel/codicon/codicon.css index fda705bceb666..ef963fea47371 100644 --- a/src/vs/base/browser/ui/codiconLabel/codicon/codicon.css +++ b/src/vs/base/browser/ui/codiconLabel/codicon/codicon.css @@ -5,7 +5,7 @@ @font-face { font-family: "codicon"; - src: url("./codicon.ttf?ffbbbd998c09cc4af5af9e181bb08a70") format("truetype"); + src: url("./codicon.ttf?b035097bd976825411d2c57142be0530") format("truetype"); } .codicon[class*='codicon-'] { @@ -390,6 +390,7 @@ .codicon-list-filter:before { content: "\eb83" } .codicon-list-flat:before { content: "\eb84" } .codicon-list-selection:before { content: "\eb85" } +.codicon-selection:before { content: "\eb85" } .codicon-list-tree:before { content: "\eb86" } .codicon-debug-breakpoint-function-unverified:before { content: "\eb87" } .codicon-debug-breakpoint-function:before { content: "\eb88" } diff --git a/src/vs/base/browser/ui/codiconLabel/codicon/codicon.ttf b/src/vs/base/browser/ui/codiconLabel/codicon/codicon.ttf index 7e87d7f10387722d05b94db947ddd29351db6cb3..e2d73d87e70f684d27a21420951c6be81593157b 100644 GIT binary patch delta 48 xcmccej_JxfrU`+}r4vghhD?=~Q5K2kxB1Gz%}~Gq1UElxo`KPuSr`Mh0RX&_5h?%x delta 48 xcmccej_JxfrU`+}#V0>c44En|zeysV-{va=H$wpf5ZwIa#tox4voHp10|4Aa5h?%x From a95ec814013b2f45a0ac76549f9169b53a3a497b Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Thu, 14 Nov 2019 17:03:15 +0100 Subject: [PATCH 272/352] lcd rendering - also promote sidebar to own layer --- .../parts/sidebar/media/sidebarpart.css | 23 +++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/src/vs/workbench/browser/parts/sidebar/media/sidebarpart.css b/src/vs/workbench/browser/parts/sidebar/media/sidebarpart.css index eb324691b3455..6d699628cb663 100644 --- a/src/vs/workbench/browser/parts/sidebar/media/sidebarpart.css +++ b/src/vs/workbench/browser/parts/sidebar/media/sidebarpart.css @@ -3,16 +3,31 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -.monaco-workbench .sidebar > .content { +.monaco-workbench.windows .part.sidebar, +.monaco-workbench.linux .part.sidebar, +.monaco-workbench.web .part.sidebar { + /* + * Explicitly put the part onto its own layer to help Chrome to + * render the content with LCD-anti-aliasing. By partioning the + * workbench into multiple layers, we can ensure that a bad + * behaving part is not making another part fallback to greyscale + * rendering. + * + * macOS: does not render LCD-anti-aliased. + */ + transform: translate3d(0px, 0px, 0px); +} + +.monaco-workbench .part.sidebar > .content { overflow: hidden; } -.monaco-workbench.nosidebar > .sidebar { +.monaco-workbench.nosidebar > .part.sidebar { display: none !important; visibility: hidden !important; } -.monaco-workbench .sidebar > .title > .title-label h2 { +.monaco-workbench .part.sidebar > .title > .title-label h2 { text-transform: uppercase; } @@ -54,4 +69,4 @@ background-repeat: no-repeat; width: 16px; height: 16px; -} \ No newline at end of file +} From baea605e2df6ba6dddcd6160b632bfbe2e9e2d33 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Thu, 14 Nov 2019 17:25:27 +0100 Subject: [PATCH 273/352] peek - fix rendering glitches with meta title --- src/vs/editor/contrib/peekView/media/peekViewWidget.css | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/vs/editor/contrib/peekView/media/peekViewWidget.css b/src/vs/editor/contrib/peekView/media/peekViewWidget.css index 889d1148298be..d0e9bc3c5525f 100644 --- a/src/vs/editor/contrib/peekView/media/peekViewWidget.css +++ b/src/vs/editor/contrib/peekView/media/peekViewWidget.css @@ -21,7 +21,11 @@ margin-left: 0.5em; } -.monaco-editor .peekview-widget .head .peekview-title .meta::before { +.monaco-editor .peekview-widget .head .peekview-title .meta { + white-space: nowrap; +} + +.monaco-editor .peekview-widget .head .peekview-title .meta:not(:empty)::before { content: '-'; padding: 0 0.3em; } From 71107e37e8bb494f9223ed6490b24cf2fba6bff8 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Thu, 14 Nov 2019 17:25:07 +0100 Subject: [PATCH 274/352] title - seems to be broken when put on separate layer --- .../browser/parts/titlebar/media/titlebarpart.css | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/src/vs/workbench/browser/parts/titlebar/media/titlebarpart.css b/src/vs/workbench/browser/parts/titlebar/media/titlebarpart.css index f67701b108156..265d6518c4019 100644 --- a/src/vs/workbench/browser/parts/titlebar/media/titlebarpart.css +++ b/src/vs/workbench/browser/parts/titlebar/media/titlebarpart.css @@ -19,21 +19,6 @@ display: flex; } -.monaco-workbench.windows .part.titlebar, -.monaco-workbench.linux .part.titlebar, -.monaco-workbench.web .part.titlebar { - /* - * Explicitly put the part onto its own layer to help Chrome to - * render the content with LCD-anti-aliasing. By partioning the - * workbench into multiple layers, we can ensure that a bad - * behaving part is not making another part fallback to greyscale - * rendering. - * - * macOS: does not render LCD-anti-aliased. - */ - transform: translate3d(0px, 0px, 0px); -} - .monaco-workbench .part.titlebar > .titlebar-drag-region { top: 0; left: 0; From 042c660f7cd9b86ef897299b10cdeff9bf7c6e6d Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Thu, 14 Nov 2019 17:42:55 +0100 Subject: [PATCH 275/352] :up: sudo-prompt@9.1.1 --- package.json | 2 +- .../textfile/electron-browser/nativeTextFileService.ts | 3 +-- yarn.lock | 8 ++++---- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/package.json b/package.json index 66caa48db65cc..ec7cd7ba956a5 100644 --- a/package.json +++ b/package.json @@ -45,7 +45,7 @@ "onigasm-umd": "^2.2.4", "semver-umd": "^5.5.3", "spdlog": "^0.11.1", - "sudo-prompt": "9.1.0", + "sudo-prompt": "9.1.1", "v8-inspect-profiler": "^0.0.20", "vscode-minimist": "^1.2.2", "vscode-nsfw": "1.2.8", diff --git a/src/vs/workbench/services/textfile/electron-browser/nativeTextFileService.ts b/src/vs/workbench/services/textfile/electron-browser/nativeTextFileService.ts index 7caae05d5ecf6..e105588731ade 100644 --- a/src/vs/workbench/services/textfile/electron-browser/nativeTextFileService.ts +++ b/src/vs/workbench/services/textfile/electron-browser/nativeTextFileService.ts @@ -286,8 +286,7 @@ export class NativeTextFileService extends AbstractTextFileService { private async sudoPromptCopy(source: string, target: string, options?: IWriteTextFileOptions): Promise { // load sudo-prompt module lazy - // @ts-ignore TODO@ben wait for update of sudo-prompt - const sudoPrompt: { exec(cmd: string, options: { name?: string, icns?: string }, callback: (error: string, stdout: string, stderr: string) => void): void } = await import('sudo-prompt'); + const sudoPrompt = await import('sudo-prompt'); return new Promise((resolve, reject) => { const promptOptions = { diff --git a/yarn.lock b/yarn.lock index 78889420ad566..e9078a4f13f8a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8150,10 +8150,10 @@ strip-json-comments@^2.0.1, strip-json-comments@~2.0.1: resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo= -sudo-prompt@9.1.0: - version "9.1.0" - resolved "https://registry.yarnpkg.com/sudo-prompt/-/sudo-prompt-9.1.0.tgz#9618823e748ce19e2d9e481feaf3ada7d52df52f" - integrity sha512-bJigY3ELFd2ZA7gfyQ4wMZIp1EICPFQcMe3RgSz5OQTzrPPaeryhgaxbInO/G62vpiqJs37qlGdb9TaqHeF2yA== +sudo-prompt@9.1.1: + version "9.1.1" + resolved "https://registry.yarnpkg.com/sudo-prompt/-/sudo-prompt-9.1.1.tgz#73853d729770392caec029e2470db9c221754db0" + integrity sha512-es33J1g2HjMpyAhz8lOR+ICmXXAqTuKbuXuUWLhOLew20oN9oUCgCJx615U/v7aioZg7IX5lIh9x34vwneu4pA== supports-color@1.2.0: version "1.2.0" From 9c9b8a9043f4f8eabf9143bbf029743493dd48d3 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Thu, 14 Nov 2019 17:52:11 +0100 Subject: [PATCH 276/352] drop all view zones via setModel(null) to make closing peek fast, workaround for #84726 --- src/vs/editor/contrib/gotoSymbol/peek/referencesWidget.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/vs/editor/contrib/gotoSymbol/peek/referencesWidget.ts b/src/vs/editor/contrib/gotoSymbol/peek/referencesWidget.ts index 82f86384de484..9d7b3fa0b199c 100644 --- a/src/vs/editor/contrib/gotoSymbol/peek/referencesWidget.ts +++ b/src/vs/editor/contrib/gotoSymbol/peek/referencesWidget.ts @@ -227,6 +227,7 @@ export class ReferenceWidget extends peekView.PeekViewWidget { this.setModel(undefined); this._callOnDispose.dispose(); this._disposeOnNewModel.dispose(); + this._preview.setModel(null); // drop all view-zones, workaround for https://github.com/microsoft/vscode/issues/84726 dispose(this._preview); dispose(this._previewNotAvailableMessage); dispose(this._tree); From 485fdf8beac1c3acf87d3cbe1db147ae875541da Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Thu, 14 Nov 2019 17:56:41 +0100 Subject: [PATCH 277/352] :lipstick: when disposing all lenses, #84726 --- src/vs/editor/contrib/codelens/codelensController.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/vs/editor/contrib/codelens/codelensController.ts b/src/vs/editor/contrib/codelens/codelensController.ts index e61b9acafb18e..b50d4508fe3b0 100644 --- a/src/vs/editor/contrib/codelens/codelensController.ts +++ b/src/vs/editor/contrib/codelens/codelensController.ts @@ -222,8 +222,10 @@ export class CodeLensContribution implements editorCommon.IEditorContribution { } private _disposeAllLenses(decChangeAccessor: IModelDecorationsChangeAccessor | undefined, viewZoneChangeAccessor: editorBrowser.IViewZoneChangeAccessor | undefined): void { - let helper = new CodeLensHelper(); - this._lenses.forEach((lens) => lens.dispose(helper, viewZoneChangeAccessor)); + const helper = new CodeLensHelper(); + for (const lens of this._lenses) { + lens.dispose(helper, viewZoneChangeAccessor); + } if (decChangeAccessor) { helper.commit(decChangeAccessor); } From d5bc3ab7ee3f7f2a974bf4e76793b0a0560db623 Mon Sep 17 00:00:00 2001 From: isidor Date: Thu, 14 Nov 2019 18:19:56 +0100 Subject: [PATCH 278/352] Remove gray attributes in launch.json since they are confusing fixes #80026 --- .../configuration-editing/src/extension.ts | 57 ------------------- 1 file changed, 57 deletions(-) diff --git a/extensions/configuration-editing/src/extension.ts b/extensions/configuration-editing/src/extension.ts index 72e2fcf627f94..644e9bb11922f 100644 --- a/extensions/configuration-editing/src/extension.ts +++ b/extensions/configuration-editing/src/extension.ts @@ -4,23 +4,11 @@ *--------------------------------------------------------------------------------------------*/ import { getLocation, parse, visit } from 'jsonc-parser'; -import * as path from 'path'; import * as vscode from 'vscode'; import * as nls from 'vscode-nls'; import { SettingsDocument } from './settingsDocumentHelper'; const localize = nls.loadMessageBundle(); -const fadedDecoration = vscode.window.createTextEditorDecorationType({ - light: { - color: '#757575' - }, - dark: { - color: '#878787' - } -}); - -let pendingLaunchJsonDecoration: NodeJS.Timer; - export function activate(context: vscode.ExtensionContext): void { //settings.json suggestions context.subscriptions.push(registerSettingsCompletions()); @@ -33,18 +21,6 @@ export function activate(context: vscode.ExtensionContext): void { // task.json variable suggestions context.subscriptions.push(registerVariableCompletions('**/tasks.json')); - - // launch.json decorations - context.subscriptions.push(vscode.window.onDidChangeActiveTextEditor(editor => updateLaunchJsonDecorations(editor), null, context.subscriptions)); - context.subscriptions.push(vscode.workspace.onDidChangeTextDocument(event => { - if (vscode.window.activeTextEditor && event.document === vscode.window.activeTextEditor.document) { - if (pendingLaunchJsonDecoration) { - clearTimeout(pendingLaunchJsonDecoration); - } - pendingLaunchJsonDecoration = setTimeout(() => updateLaunchJsonDecorations(vscode.window.activeTextEditor), 1000); - } - }, null, context.subscriptions)); - updateLaunchJsonDecorations(vscode.window.activeTextEditor); } function registerSettingsCompletions(): vscode.Disposable { @@ -153,39 +129,6 @@ function provideInstalledExtensionProposals(extensionsContent: IExtensionsConten return undefined; } -function updateLaunchJsonDecorations(editor: vscode.TextEditor | undefined): void { - if (!editor || path.basename(editor.document.fileName) !== 'launch.json') { - return; - } - - const ranges: vscode.Range[] = []; - let addPropertyAndValue = false; - let depthInArray = 0; - visit(editor.document.getText(), { - onObjectProperty: (property, offset, length) => { - // Decorate attributes which are unlikely to be edited by the user. - // Only decorate "configurations" if it is not inside an array (compounds have a configurations property which should not be decorated). - addPropertyAndValue = property === 'version' || property === 'type' || property === 'request' || property === 'compounds' || (property === 'configurations' && depthInArray === 0); - if (addPropertyAndValue) { - ranges.push(new vscode.Range(editor.document.positionAt(offset), editor.document.positionAt(offset + length))); - } - }, - onLiteralValue: (_value, offset, length) => { - if (addPropertyAndValue) { - ranges.push(new vscode.Range(editor.document.positionAt(offset), editor.document.positionAt(offset + length))); - } - }, - onArrayBegin: (_offset: number, _length: number) => { - depthInArray++; - }, - onArrayEnd: (_offset: number, _length: number) => { - depthInArray--; - } - }); - - editor.setDecorations(fadedDecoration, ranges); -} - vscode.languages.registerDocumentSymbolProvider({ pattern: '**/launch.json', language: 'jsonc' }, { provideDocumentSymbols(document: vscode.TextDocument, _token: vscode.CancellationToken): vscode.ProviderResult { const result: vscode.SymbolInformation[] = []; From 0616326888e22a6e928a172f9d73a2cb7ffea56d Mon Sep 17 00:00:00 2001 From: isidor Date: Thu, 14 Nov 2019 18:36:41 +0100 Subject: [PATCH 279/352] fixes #83736 --- .../files/browser/views/explorerViewer.ts | 19 +++++++++++-------- .../textfile/browser/textFileService.ts | 2 +- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/src/vs/workbench/contrib/files/browser/views/explorerViewer.ts b/src/vs/workbench/contrib/files/browser/views/explorerViewer.ts index 1186a19c258ee..f88860ab91b78 100644 --- a/src/vs/workbench/contrib/files/browser/views/explorerViewer.ts +++ b/src/vs/workbench/contrib/files/browser/views/explorerViewer.ts @@ -456,11 +456,13 @@ export class FileSorter implements ITreeSorter { } } -const fileOverwriteConfirm: IConfirmation = { - message: localize('confirmOverwrite', "A file or folder with the same name already exists in the destination folder. Do you want to replace it?"), - detail: localize('irreversible', "This action is irreversible!"), - primaryButton: localize({ key: 'replaceButtonLabel', comment: ['&& denotes a mnemonic'] }, "&&Replace"), - type: 'warning' +const fileOverwriteConfirm = (name: string) => { + return { + message: localize('confirmOverwrite', "A file or folder with the name '{0}' already exists in the destination folder. Do you want to replace it?", name), + detail: localize('irreversible', "This action is irreversible!"), + primaryButton: localize({ key: 'replaceButtonLabel', comment: ['&& denotes a mnemonic'] }, "&&Replace"), + type: 'warning' + }; }; export class FileDragAndDrop implements ITreeDragAndDrop { @@ -643,7 +645,7 @@ export class FileDragAndDrop implements ITreeDragAndDrop { const name = file.name; if (typeof name === 'string' && event.target?.result instanceof ArrayBuffer) { if (target.getChild(name)) { - const { confirmed } = await this.dialogService.confirm(fileOverwriteConfirm); + const { confirmed } = await this.dialogService.confirm(fileOverwriteConfirm(name)); if (!confirmed) { return; } @@ -717,9 +719,10 @@ export class FileDragAndDrop implements ITreeDragAndDrop { }); } - const resourceExists = resources.some(resource => targetNames.has(!hasToIgnoreCase(resource) ? basename(resource) : basename(resource).toLowerCase())); + const filtered = resources.filter(resource => targetNames.has(!hasToIgnoreCase(resource) ? basename(resource) : basename(resource).toLowerCase())); + const resourceExists = filtered.length >= 1; if (resourceExists) { - const confirmationResult = await this.dialogService.confirm(fileOverwriteConfirm); + const confirmationResult = await this.dialogService.confirm(fileOverwriteConfirm(basename(filtered[0]))); if (!confirmationResult.confirmed) { return; } diff --git a/src/vs/workbench/services/textfile/browser/textFileService.ts b/src/vs/workbench/services/textfile/browser/textFileService.ts index 7961fcdb09db9..fe4ddff014d88 100644 --- a/src/vs/workbench/services/textfile/browser/textFileService.ts +++ b/src/vs/workbench/services/textfile/browser/textFileService.ts @@ -809,7 +809,7 @@ export abstract class AbstractTextFileService extends Disposable implements ITex private async confirmOverwrite(resource: URI): Promise { const confirm: IConfirmation = { message: nls.localize('confirmOverwrite', "'{0}' already exists. Do you want to replace it?", basename(resource)), - detail: nls.localize('irreversible', "A file or folder with the same name already exists in the folder {0}. Replacing it will overwrite its current contents.", basename(dirname(resource))), + detail: nls.localize('irreversible', "A file or folder with the name '{0}' already exists in the folder '{1}'. Replacing it will overwrite its current contents.", basename(resource), basename(dirname(resource))), primaryButton: nls.localize({ key: 'replaceButtonLabel', comment: ['&& denotes a mnemonic'] }, "&&Replace"), type: 'warning' }; From 74e3cf237753ecb3d60b9eae890cd06061bf2ca3 Mon Sep 17 00:00:00 2001 From: Jackson Kearl Date: Thu, 14 Nov 2019 10:28:23 -0800 Subject: [PATCH 280/352] Flip triggeredOnType logic --- src/vs/workbench/contrib/search/browser/patternInputWidget.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/contrib/search/browser/patternInputWidget.ts b/src/vs/workbench/contrib/search/browser/patternInputWidget.ts index 014d39c99bdd9..01ae7e23081de 100644 --- a/src/vs/workbench/contrib/search/browser/patternInputWidget.ts +++ b/src/vs/workbench/contrib/search/browser/patternInputWidget.ts @@ -152,7 +152,7 @@ export class PatternInputWidget extends Widget { this._register(this.inputBox.onDidChange(() => { if (this.searchConfig.searchOnType) { this._onCancel.fire(); - this.searchOnTypeDelayer.trigger(() => this._onSubmit.fire(false), this.searchConfig.searchOnTypeDebouncePeriod); + this.searchOnTypeDelayer.trigger(() => this._onSubmit.fire(true), this.searchConfig.searchOnTypeDebouncePeriod); } })); @@ -170,7 +170,7 @@ export class PatternInputWidget extends Widget { private onInputKeyUp(keyboardEvent: IKeyboardEvent) { switch (keyboardEvent.keyCode) { case KeyCode.Enter: - this._onSubmit.fire(true); + this._onSubmit.fire(false); return; case KeyCode.Escape: this._onCancel.fire(); From e5e3589293fc74feed0a62a94f8a902784dd2da4 Mon Sep 17 00:00:00 2001 From: Jackson Kearl Date: Thu, 14 Nov 2019 10:32:43 -0800 Subject: [PATCH 281/352] Remove double search on glob enter --- src/vs/workbench/contrib/search/browser/patternInputWidget.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/search/browser/patternInputWidget.ts b/src/vs/workbench/contrib/search/browser/patternInputWidget.ts index 01ae7e23081de..0d41239f52702 100644 --- a/src/vs/workbench/contrib/search/browser/patternInputWidget.ts +++ b/src/vs/workbench/contrib/search/browser/patternInputWidget.ts @@ -170,7 +170,7 @@ export class PatternInputWidget extends Widget { private onInputKeyUp(keyboardEvent: IKeyboardEvent) { switch (keyboardEvent.keyCode) { case KeyCode.Enter: - this._onSubmit.fire(false); + this.searchOnTypeDelayer.trigger(() => this._onSubmit.fire(false), 0); return; case KeyCode.Escape: this._onCancel.fire(); From 8a22996a43318fff1b960c5dfbe79fa1bd18bb19 Mon Sep 17 00:00:00 2001 From: Peng Lyu Date: Wed, 13 Nov 2019 20:13:18 -0800 Subject: [PATCH 282/352] Fix #83715. Handle touch to scroll in interactive playground. --- .../welcome/walkThrough/browser/walkThroughPart.ts | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/vs/workbench/contrib/welcome/walkThrough/browser/walkThroughPart.ts b/src/vs/workbench/contrib/welcome/walkThrough/browser/walkThroughPart.ts index d550a53a3c4df..149c916f53dd0 100644 --- a/src/vs/workbench/contrib/welcome/walkThrough/browser/walkThroughPart.ts +++ b/src/vs/workbench/contrib/welcome/walkThrough/browser/walkThroughPart.ts @@ -5,6 +5,7 @@ import 'vs/css!./walkThroughPart'; import { DomScrollableElement } from 'vs/base/browser/ui/scrollbar/scrollableElement'; +import { EventType as TouchEventType, GestureEvent, Gesture } from 'vs/base/browser/touch'; import { ScrollbarVisibility } from 'vs/base/common/scrollable'; import * as strings from 'vs/base/common/strings'; import { URI } from 'vs/base/common/uri'; @@ -37,6 +38,7 @@ import { INotificationService } from 'vs/platform/notification/common/notificati import { Dimension, size } from 'vs/base/browser/dom'; import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService'; import { CancellationToken } from 'vs/base/common/cancellation'; +import { domEvent } from 'vs/base/browser/event'; export const WALK_THROUGH_FOCUS = new RawContextKey('interactivePlaygroundFocus', false); @@ -112,6 +114,14 @@ export class WalkThroughPart extends BaseEditor { } } + private onTouchChange(event: GestureEvent) { + event.preventDefault(); + event.stopPropagation(); + + const scrollPosition = this.scrollbar.getScrollPosition(); + this.scrollbar.setScrollPosition({ scrollTop: scrollPosition.scrollTop - event.translationY }); + } + private addEventListener(element: E, type: K, listener: (this: E, ev: HTMLElementEventMap[K]) => any, useCapture?: boolean): IDisposable; private addEventListener(element: E, type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): IDisposable; private addEventListener(element: E, type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): IDisposable { @@ -396,6 +406,8 @@ export class WalkThroughPart extends BaseEditor { this.scrollbar.scanDomNode(); this.loadTextEditorViewState(input); this.updatedScrollPosition(); + this.contentDisposables.push(Gesture.addTarget(innerContent)); + this.contentDisposables.push(domEvent(innerContent, TouchEventType.Change)(this.onTouchChange, this, this.disposables)); }); } From 50767577edbdc05abac1000b43b9a8bdbaad9cbc Mon Sep 17 00:00:00 2001 From: Peng Lyu Date: Wed, 13 Nov 2019 20:27:40 -0800 Subject: [PATCH 283/352] Fix #83721. Handle pointer events in Color Picker. --- .../contrib/colorPicker/colorPickerWidget.ts | 23 +++++++++++++------ 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/src/vs/editor/contrib/colorPicker/colorPickerWidget.ts b/src/vs/editor/contrib/colorPicker/colorPickerWidget.ts index 4a74a4a5e0d12..106c2a357e28a 100644 --- a/src/vs/editor/contrib/colorPicker/colorPickerWidget.ts +++ b/src/vs/editor/contrib/colorPicker/colorPickerWidget.ts @@ -6,7 +6,7 @@ import 'vs/css!./colorPicker'; import { onDidChangeZoomLevel } from 'vs/base/browser/browser'; import * as dom from 'vs/base/browser/dom'; -import { GlobalMouseMoveMonitor, IStandardMouseMoveEventData, standardMouseMoveMerger } from 'vs/base/browser/globalMouseMoveMonitor'; +import { GlobalMouseMoveMonitor, IStandardMouseMoveEventData, standardMouseMoveMerger, GlobalPointerMoveMonitor } from 'vs/base/browser/globalMouseMoveMonitor'; import { Widget } from 'vs/base/browser/ui/widget'; import { Color, HSVA, RGBA } from 'vs/base/common/color'; import { Emitter, Event } from 'vs/base/common/event'; @@ -14,6 +14,7 @@ import { Disposable } from 'vs/base/common/lifecycle'; import { ColorPickerModel } from 'vs/editor/contrib/colorPicker/colorPickerModel'; import { editorHoverBackground } from 'vs/platform/theme/common/colorRegistry'; import { IThemeService, registerThemingParticipant } from 'vs/platform/theme/common/themeService'; +import { BrowserFeatures } from 'vs/base/browser/canIUse'; const $ = dom.$; @@ -150,13 +151,17 @@ class SaturationBox extends Disposable { this.layout(); - this._register(dom.addDisposableListener(this.domNode, dom.EventType.MOUSE_DOWN, e => this.onMouseDown(e))); + this._register(dom.addDisposableListener(this.domNode, BrowserFeatures.pointerEvents ? dom.EventType.POINTER_DOWN : dom.EventType.MOUSE_DOWN, e => this.onMouseDown(e))); this._register(this.model.onDidChangeColor(this.onDidChangeColor, this)); this.monitor = null; } private onMouseDown(e: MouseEvent): void { - this.monitor = this._register(new GlobalMouseMoveMonitor()); + this.monitor = this._register( + BrowserFeatures.pointerEvents + ? new GlobalPointerMoveMonitor() + : new GlobalMouseMoveMonitor() + ); const origin = dom.getDomNodePagePosition(this.domNode); if (e.target !== this.selection) { @@ -165,7 +170,7 @@ class SaturationBox extends Disposable { this.monitor.startMonitoring(standardMouseMoveMerger, event => this.onDidChangePosition(event.posx - origin.left, event.posy - origin.top), () => null); - const mouseUpListener = dom.addDisposableListener(document, dom.EventType.MOUSE_UP, () => { + const mouseUpListener = dom.addDisposableListener(document, BrowserFeatures.pointerEvents ? dom.EventType.POINTER_UP : dom.EventType.MOUSE_UP, () => { this._onColorFlushed.fire(); mouseUpListener.dispose(); if (this.monitor) { @@ -250,7 +255,7 @@ abstract class Strip extends Disposable { this.slider = dom.append(this.domNode, $('.slider')); this.slider.style.top = `0px`; - this._register(dom.addDisposableListener(this.domNode, dom.EventType.MOUSE_DOWN, e => this.onMouseDown(e))); + this._register(dom.addDisposableListener(this.domNode, BrowserFeatures.pointerEvents ? dom.EventType.POINTER_DOWN : dom.EventType.MOUSE_DOWN, e => this.onMouseDown(e))); this.layout(); } @@ -262,7 +267,11 @@ abstract class Strip extends Disposable { } private onMouseDown(e: MouseEvent): void { - const monitor = this._register(new GlobalMouseMoveMonitor()); + const monitor = this._register( + BrowserFeatures.pointerEvents + ? new GlobalPointerMoveMonitor() + : new GlobalMouseMoveMonitor() + ); const origin = dom.getDomNodePagePosition(this.domNode); dom.addClass(this.domNode, 'grabbing'); @@ -272,7 +281,7 @@ abstract class Strip extends Disposable { monitor.startMonitoring(standardMouseMoveMerger, event => this.onDidChangeTop(event.posy - origin.top), () => null); - const mouseUpListener = dom.addDisposableListener(document, dom.EventType.MOUSE_UP, () => { + const mouseUpListener = dom.addDisposableListener(document, BrowserFeatures.pointerEvents ? dom.EventType.POINTER_UP : dom.EventType.MOUSE_UP, () => { this._onColorFlushed.fire(); mouseUpListener.dispose(); monitor.stopMonitoring(true); From be772cc38f01cf408ace03a758e32b4993a724aa Mon Sep 17 00:00:00 2001 From: Peng Lyu Date: Thu, 14 Nov 2019 10:28:47 -0800 Subject: [PATCH 284/352] Fix #83719. PointerEvent handler for iOS. --- src/vs/base/browser/canIUse.ts | 3 +- src/vs/base/browser/dom.ts | 17 +++++ src/vs/base/browser/globalMouseMoveMonitor.ts | 37 ++++++++-- .../editor/browser/controller/mouseHandler.ts | 9 ++- .../browser/controller/pointerHandler.ts | 67 ++++++++++++++++++- src/vs/editor/browser/editorDom.ts | 50 +++++++++++++- 6 files changed, 168 insertions(+), 15 deletions(-) diff --git a/src/vs/base/browser/canIUse.ts b/src/vs/base/browser/canIUse.ts index 061d1bfc74fb3..989b11c370f50 100644 --- a/src/vs/base/browser/canIUse.ts +++ b/src/vs/base/browser/canIUse.ts @@ -55,5 +55,6 @@ export const BrowserFeatures = { return KeyboardSupport.None; })(), - touch: 'ontouchstart' in window || navigator.maxTouchPoints > 0 || window.navigator.msMaxTouchPoints > 0 + touch: 'ontouchstart' in window || navigator.maxTouchPoints > 0 || window.navigator.msMaxTouchPoints > 0, + pointerEvents: browser.isSafari && ('ontouchstart' in window || navigator.maxTouchPoints > 0 || window.navigator.msMaxTouchPoints > 0) }; diff --git a/src/vs/base/browser/dom.ts b/src/vs/base/browser/dom.ts index db901ed9e5e09..cbdf3775398e9 100644 --- a/src/vs/base/browser/dom.ts +++ b/src/vs/base/browser/dom.ts @@ -281,6 +281,21 @@ export function addDisposableNonBubblingMouseOutListener(node: Element, handler: }); } +export function addDisposableNonBubblingPointerOutListener(node: Element, handler: (event: MouseEvent) => void): IDisposable { + return addDisposableListener(node, 'pointerout', (e: MouseEvent) => { + // Mouse out bubbles, so this is an attempt to ignore faux mouse outs coming from children elements + let toElement: Node | null = (e.relatedTarget || e.target); + while (toElement && toElement !== node) { + toElement = toElement.parentNode; + } + if (toElement === node) { + return; + } + + handler(e); + }); +} + interface IRequestAnimationFrame { (callback: (time: number) => void): number; } @@ -852,6 +867,8 @@ export const EventType = { MOUSE_OUT: 'mouseout', MOUSE_ENTER: 'mouseenter', MOUSE_LEAVE: 'mouseleave', + POINTER_UP: 'pointerup', + POINTER_DOWN: 'pointerdown', CONTEXT_MENU: 'contextmenu', WHEEL: 'wheel', // Keyboard diff --git a/src/vs/base/browser/globalMouseMoveMonitor.ts b/src/vs/base/browser/globalMouseMoveMonitor.ts index 109f6f722604e..c15a4a4d60fbf 100644 --- a/src/vs/base/browser/globalMouseMoveMonitor.ts +++ b/src/vs/base/browser/globalMouseMoveMonitor.ts @@ -38,10 +38,10 @@ export function standardMouseMoveMerger(lastEvent: IStandardMouseMoveEventData, export class GlobalMouseMoveMonitor implements IDisposable { - private readonly hooks = new DisposableStore(); - private mouseMoveEventMerger: IEventMerger | null = null; - private mouseMoveCallback: IMouseMoveCallback | null = null; - private onStopCallback: IOnStopCallback | null = null; + protected readonly hooks = new DisposableStore(); + protected mouseMoveEventMerger: IEventMerger | null = null; + protected mouseMoveCallback: IMouseMoveCallback | null = null; + protected onStopCallback: IOnStopCallback | null = null; public dispose(): void { this.stopMonitoring(false); @@ -116,3 +116,32 @@ export class GlobalMouseMoveMonitor implements IDisposable { } } } + +export class GlobalPointerMoveMonitor extends GlobalMouseMoveMonitor { + public startMonitoring( + mouseMoveEventMerger: IEventMerger, + mouseMoveCallback: IMouseMoveCallback, + onStopCallback: IOnStopCallback + ): void { + if (this.isMonitoring()) { + // I am already hooked + return; + } + this.mouseMoveEventMerger = mouseMoveEventMerger; + this.mouseMoveCallback = mouseMoveCallback; + this.onStopCallback = onStopCallback; + + let windowChain = IframeUtils.getSameOriginWindowChain(); + for (const element of windowChain) { + this.hooks.add(dom.addDisposableThrottledListener(element.window.document, 'pointermove', + (data: R) => { + this.mouseMoveCallback!(data); + }, + (lastEvent: R, currentEvent) => this.mouseMoveEventMerger!(lastEvent, currentEvent as MouseEvent) + )); + this.hooks.add(dom.addDisposableListener(element.window.document, 'pointerup', (e: MouseEvent) => this.stopMonitoring(true))); + } + + // Currently we didn't test pointer events in iframe yet. + } +} diff --git a/src/vs/editor/browser/controller/mouseHandler.ts b/src/vs/editor/browser/controller/mouseHandler.ts index d1a1984102862..8c8bb7434624e 100644 --- a/src/vs/editor/browser/controller/mouseHandler.ts +++ b/src/vs/editor/browser/controller/mouseHandler.ts @@ -26,7 +26,7 @@ import { EditorOption } from 'vs/editor/common/config/editorOptions'; /** * Merges mouse events when mouse move events are throttled */ -function createMouseMoveEventMerger(mouseTargetFactory: MouseTargetFactory | null) { +export function createMouseMoveEventMerger(mouseTargetFactory: MouseTargetFactory | null) { return function (lastEvent: EditorMouseEvent, currentEvent: EditorMouseEvent): EditorMouseEvent { let targetIsWidget = false; if (mouseTargetFactory) { @@ -71,8 +71,7 @@ export class MouseHandler extends ViewEventHandler { protected viewHelper: IPointerHandlerHelper; protected mouseTargetFactory: MouseTargetFactory; private readonly _asyncFocus: RunOnceScheduler; - - private readonly _mouseDownOperation: MouseDownOperation; + protected readonly _mouseDownOperation: MouseDownOperation; private lastMouseLeaveTime: number; constructor(context: ViewContext, viewController: ViewController, viewHelper: IPointerHandlerHelper) { @@ -179,7 +178,7 @@ export class MouseHandler extends ViewEventHandler { }); } - private _onMouseMove(e: EditorMouseEvent): void { + public _onMouseMove(e: EditorMouseEvent): void { if (this._mouseDownOperation.isActive()) { // In selection/drag operation return; @@ -196,7 +195,7 @@ export class MouseHandler extends ViewEventHandler { }); } - private _onMouseLeave(e: EditorMouseEvent): void { + public _onMouseLeave(e: EditorMouseEvent): void { this.lastMouseLeaveTime = (new Date()).getTime(); this.viewController.emitMouseLeave({ event: e, diff --git a/src/vs/editor/browser/controller/pointerHandler.ts b/src/vs/editor/browser/controller/pointerHandler.ts index 51988d09968cd..f5891def720a1 100644 --- a/src/vs/editor/browser/controller/pointerHandler.ts +++ b/src/vs/editor/browser/controller/pointerHandler.ts @@ -6,11 +6,12 @@ import * as dom from 'vs/base/browser/dom'; import { EventType, Gesture, GestureEvent } from 'vs/base/browser/touch'; import { IDisposable, Disposable } from 'vs/base/common/lifecycle'; -import { IPointerHandlerHelper, MouseHandler } from 'vs/editor/browser/controller/mouseHandler'; +import { IPointerHandlerHelper, MouseHandler, createMouseMoveEventMerger } from 'vs/editor/browser/controller/mouseHandler'; import { IMouseTarget } from 'vs/editor/browser/editorBrowser'; -import { EditorMouseEvent } from 'vs/editor/browser/editorDom'; +import { EditorMouseEvent, EditorPointerEventFactory } from 'vs/editor/browser/editorDom'; import { ViewController } from 'vs/editor/browser/view/viewController'; import { ViewContext } from 'vs/editor/common/view/viewContext'; +import { isSafari } from 'vs/base/browser/browser'; interface IThrottledGestureEvent { translationX: number; @@ -185,6 +186,66 @@ class StandardPointerHandler extends MouseHandler implements IDisposable { } } +/** + * Currently only tested on iOS 13/ iPadOS. + */ +export class PointerEventHandler extends MouseHandler { + private _lastPointerType: string; + constructor(context: ViewContext, viewController: ViewController, viewHelper: IPointerHandlerHelper) { + super(context, viewController, viewHelper); + + this._register(Gesture.addTarget(this.viewHelper.linesContentDomNode)); + this._register(dom.addDisposableListener(this.viewHelper.linesContentDomNode, EventType.Tap, (e) => this.onTap(e))); + this._register(dom.addDisposableListener(this.viewHelper.linesContentDomNode, EventType.Change, (e) => this.onChange(e))); + + this._lastPointerType = 'mouse'; + + this.viewHelper.linesContentDomNode.addEventListener('pointerdown', (e: any) => { + const pointerType = e.pointerType; + if (pointerType === 'mouse') { + this._lastPointerType = 'mouse'; + return; + } else if (pointerType === 'touch') { + this._lastPointerType = 'touch'; + } else { + this._lastPointerType = 'pen'; + } + }); + + // PonterEvents + const pointerEvents = new EditorPointerEventFactory(this.viewHelper.viewDomNode); + + this._register(pointerEvents.onPointerMoveThrottled(this.viewHelper.viewDomNode, + (e) => this._onMouseMove(e), + createMouseMoveEventMerger(this.mouseTargetFactory), MouseHandler.MOUSE_MOVE_MINIMUM_TIME)); + this._register(pointerEvents.onPointerUp(this.viewHelper.viewDomNode, (e) => this._onMouseUp(e))); + this._register(pointerEvents.onPointerLeave(this.viewHelper.viewDomNode, (e) => this._onMouseLeave(e))); + this._register(pointerEvents.onPointerDown(this.viewHelper.viewDomNode, (e) => this._onMouseDown(e))); + } + + private onTap(event: GestureEvent): void { + event.preventDefault(); + this.viewHelper.focusTextArea(); + const target = this._createMouseTarget(new EditorMouseEvent(event, this.viewHelper.viewDomNode), false); + + if (target.position) { + this.viewController.moveTo(target.position); + } + } + + private onChange(e: GestureEvent): void { + if (this._lastPointerType === 'touch') { + this._context.viewLayout.deltaScrollNow(-e.translationX, -e.translationY); + } + } + + public _onMouseDown(e: EditorMouseEvent): void { + if (this._lastPointerType !== 'touch') { + super._onMouseDown(e); + } + } +} + class TouchHandler extends MouseHandler { constructor(context: ViewContext, viewController: ViewController, viewHelper: IPointerHandlerHelper) { @@ -221,6 +282,8 @@ export class PointerHandler extends Disposable { super(); if (window.navigator.msPointerEnabled) { this.handler = this._register(new MsPointerHandler(context, viewController, viewHelper)); + } else if (((window).PointerEvent && isSafari)) { + this.handler = this._register(new PointerEventHandler(context, viewController, viewHelper)); } else if ((window).TouchEvent) { this.handler = this._register(new TouchHandler(context, viewController, viewHelper)); } else if (window.navigator.pointerEnabled || (window).PointerEvent) { diff --git a/src/vs/editor/browser/editorDom.ts b/src/vs/editor/browser/editorDom.ts index 92357091f0861..0e9ec4b2f52a7 100644 --- a/src/vs/editor/browser/editorDom.ts +++ b/src/vs/editor/browser/editorDom.ts @@ -4,9 +4,11 @@ *--------------------------------------------------------------------------------------------*/ import * as dom from 'vs/base/browser/dom'; -import { GlobalMouseMoveMonitor } from 'vs/base/browser/globalMouseMoveMonitor'; +import { GlobalMouseMoveMonitor, GlobalPointerMoveMonitor } from 'vs/base/browser/globalMouseMoveMonitor'; import { StandardMouseEvent } from 'vs/base/browser/mouseEvent'; import { Disposable, IDisposable } from 'vs/base/common/lifecycle'; +import { BrowserFeatures } from 'vs/base/browser/canIUse'; +import { isSafari } from 'vs/base/browser/browser'; /** * Coordinates relative to the whole document (e.g. mouse event's pageX and pageY) @@ -131,16 +133,58 @@ export class EditorMouseEventFactory { } } +export class EditorPointerEventFactory { + + private readonly _editorViewDomNode: HTMLElement; + + constructor(editorViewDomNode: HTMLElement) { + this._editorViewDomNode = editorViewDomNode; + } + + private _create(e: MouseEvent): EditorMouseEvent { + return new EditorMouseEvent(e, this._editorViewDomNode); + } + + public onPointerUp(target: HTMLElement, callback: (e: EditorMouseEvent) => void): IDisposable { + return dom.addDisposableListener(target, 'pointerup', (e: MouseEvent) => { + callback(this._create(e)); + }); + } + + public onPointerDown(target: HTMLElement, callback: (e: EditorMouseEvent) => void): IDisposable { + return dom.addDisposableListener(target, 'pointerdown', (e: MouseEvent) => { + callback(this._create(e)); + }); + } + + public onPointerLeave(target: HTMLElement, callback: (e: EditorMouseEvent) => void): IDisposable { + return dom.addDisposableNonBubblingPointerOutListener(target, (e: MouseEvent) => { + callback(this._create(e)); + }); + } + + public onPointerMoveThrottled(target: HTMLElement, callback: (e: EditorMouseEvent) => void, merger: EditorMouseEventMerger, minimumTimeMs: number): IDisposable { + const myMerger: dom.IEventMerger = (lastEvent: EditorMouseEvent, currentEvent: MouseEvent): EditorMouseEvent => { + return merger(lastEvent, this._create(currentEvent)); + }; + return dom.addDisposableThrottledListener(target, 'pointermove', callback, myMerger, minimumTimeMs); + } +} + export class GlobalEditorMouseMoveMonitor extends Disposable { private readonly _editorViewDomNode: HTMLElement; - private readonly _globalMouseMoveMonitor: GlobalMouseMoveMonitor; + protected readonly _globalMouseMoveMonitor: GlobalMouseMoveMonitor; private _keydownListener: IDisposable | null; constructor(editorViewDomNode: HTMLElement) { super(); this._editorViewDomNode = editorViewDomNode; - this._globalMouseMoveMonitor = this._register(new GlobalMouseMoveMonitor()); + this._globalMouseMoveMonitor = this._register( + BrowserFeatures.pointerEvents + ? new GlobalPointerMoveMonitor() + : new GlobalMouseMoveMonitor() + ); this._keydownListener = null; } From 3180eafa4ed3cf481dcb6ed4c411a22f057b8ee0 Mon Sep 17 00:00:00 2001 From: Peng Lyu Date: Thu, 14 Nov 2019 10:31:06 -0800 Subject: [PATCH 285/352] Fix #83719. Trigger Context Menu in Editor with touch. --- src/vs/editor/browser/controller/pointerHandler.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/vs/editor/browser/controller/pointerHandler.ts b/src/vs/editor/browser/controller/pointerHandler.ts index f5891def720a1..4c7ad07a75939 100644 --- a/src/vs/editor/browser/controller/pointerHandler.ts +++ b/src/vs/editor/browser/controller/pointerHandler.ts @@ -197,6 +197,7 @@ export class PointerEventHandler extends MouseHandler { this._register(Gesture.addTarget(this.viewHelper.linesContentDomNode)); this._register(dom.addDisposableListener(this.viewHelper.linesContentDomNode, EventType.Tap, (e) => this.onTap(e))); this._register(dom.addDisposableListener(this.viewHelper.linesContentDomNode, EventType.Change, (e) => this.onChange(e))); + this._register(dom.addDisposableListener(this.viewHelper.linesContentDomNode, EventType.Contextmenu, (e: MouseEvent) => this._onContextMenu(new EditorMouseEvent(e, this.viewHelper.viewDomNode), false))); this._lastPointerType = 'mouse'; From 8400359843cb24b3f05063132392798e21057e0a Mon Sep 17 00:00:00 2001 From: Peng Lyu Date: Thu, 14 Nov 2019 10:47:37 -0800 Subject: [PATCH 286/352] Do not hide context menu when relayout happens on iPadOS. Co-authored-by: penlv@microsoft.com Co-authored-by: sbatten@microsoft.com --- src/vs/base/browser/ui/contextview/contextview.ts | 3 ++- src/vs/workbench/browser/parts/titlebar/menubarControl.ts | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/vs/base/browser/ui/contextview/contextview.ts b/src/vs/base/browser/ui/contextview/contextview.ts index 098e8b03182f2..54c9954259bf3 100644 --- a/src/vs/base/browser/ui/contextview/contextview.ts +++ b/src/vs/base/browser/ui/contextview/contextview.ts @@ -7,6 +7,7 @@ import 'vs/css!./contextview'; import * as DOM from 'vs/base/browser/dom'; import { IDisposable, toDisposable, Disposable, DisposableStore } from 'vs/base/common/lifecycle'; import { Range } from 'vs/base/common/range'; +import { BrowserFeatures } from 'vs/base/browser/canIUse'; export interface IAnchor { x: number; @@ -178,7 +179,7 @@ export class ContextView extends Disposable { return; } - if (this.delegate!.canRelayout === false) { + if (this.delegate!.canRelayout === false && !BrowserFeatures.pointerEvents) { this.hide(); return; } diff --git a/src/vs/workbench/browser/parts/titlebar/menubarControl.ts b/src/vs/workbench/browser/parts/titlebar/menubarControl.ts index dac036e01dcb5..0c3d435f0aa78 100644 --- a/src/vs/workbench/browser/parts/titlebar/menubarControl.ts +++ b/src/vs/workbench/browser/parts/titlebar/menubarControl.ts @@ -42,6 +42,7 @@ import { IElectronService } from 'vs/platform/electron/node/electron'; import { optional } from 'vs/platform/instantiation/common/instantiation'; // tslint:disable-next-line: import-patterns layering TODO@sbatten import { IElectronEnvironmentService } from 'vs/workbench/services/electron/electron-browser/electronEnvironmentService'; +import { BrowserFeatures } from 'vs/base/browser/canIUse'; export abstract class MenubarControl extends Disposable { @@ -673,7 +674,7 @@ export class CustomMenubarControl extends MenubarControl { } this._register(DOM.addDisposableListener(window, DOM.EventType.RESIZE, () => { - if (this.menubar) { + if (this.menubar && !BrowserFeatures.pointerEvents) { this.menubar.blur(); } })); From 38d848caad12ce1f71fbdb6b050b5a95e086d0ed Mon Sep 17 00:00:00 2001 From: Peng Lyu Date: Thu, 14 Nov 2019 10:49:09 -0800 Subject: [PATCH 287/352] remove unsed issafari --- src/vs/editor/browser/editorDom.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/vs/editor/browser/editorDom.ts b/src/vs/editor/browser/editorDom.ts index 0e9ec4b2f52a7..f27c6b45e5723 100644 --- a/src/vs/editor/browser/editorDom.ts +++ b/src/vs/editor/browser/editorDom.ts @@ -8,7 +8,6 @@ import { GlobalMouseMoveMonitor, GlobalPointerMoveMonitor } from 'vs/base/browse import { StandardMouseEvent } from 'vs/base/browser/mouseEvent'; import { Disposable, IDisposable } from 'vs/base/common/lifecycle'; import { BrowserFeatures } from 'vs/base/browser/canIUse'; -import { isSafari } from 'vs/base/browser/browser'; /** * Coordinates relative to the whole document (e.g. mouse event's pageX and pageY) From 537fcc46d724913ba8109e63ef932ead859a41b2 Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Thu, 14 Nov 2019 10:50:46 -0800 Subject: [PATCH 288/352] Update css LS --- extensions/css-language-features/server/package.json | 2 +- extensions/css-language-features/server/yarn.lock | 8 ++++---- extensions/html-language-features/server/package.json | 2 +- extensions/html-language-features/server/yarn.lock | 8 ++++---- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/extensions/css-language-features/server/package.json b/extensions/css-language-features/server/package.json index 6d4265225396c..ed0eb4d49267a 100644 --- a/extensions/css-language-features/server/package.json +++ b/extensions/css-language-features/server/package.json @@ -9,7 +9,7 @@ }, "main": "./out/cssServerMain", "dependencies": { - "vscode-css-languageservice": "^4.0.3-next.19", + "vscode-css-languageservice": "^4.0.3-next.20", "vscode-languageserver": "^6.0.0-next.3" }, "devDependencies": { diff --git a/extensions/css-language-features/server/yarn.lock b/extensions/css-language-features/server/yarn.lock index b52fde99a0079..eade4e075036f 100644 --- a/extensions/css-language-features/server/yarn.lock +++ b/extensions/css-language-features/server/yarn.lock @@ -781,10 +781,10 @@ supports-color@^5.3.0: dependencies: has-flag "^3.0.0" -vscode-css-languageservice@^4.0.3-next.19: - version "4.0.3-next.19" - resolved "https://registry.yarnpkg.com/vscode-css-languageservice/-/vscode-css-languageservice-4.0.3-next.19.tgz#b7dc58fb8d1968877724e163b6ef20b26c0b5ff6" - integrity sha512-wWSo2MZvd8aEI9lf/Asy0MP0Ao6xAzhBeEWxGcF+Ms/zcV4lDRkyFCNzwDt0OgWRzsBNaEBXfjeWLq9rNXkREA== +vscode-css-languageservice@^4.0.3-next.20: + version "4.0.3-next.20" + resolved "https://registry.yarnpkg.com/vscode-css-languageservice/-/vscode-css-languageservice-4.0.3-next.20.tgz#d0c4933c33e356617ccfaeb6b7144be196b8b3d9" + integrity sha512-9j32ppmJauPg9XYieAS6alCGazTaeEi8nhSAb11le5qfFNWep4Ngz7dNc/UMlt6hB7BESRyk2B8MM/KTlnsNBw== dependencies: vscode-languageserver-textdocument "^1.0.0-next.4" vscode-languageserver-types "^3.15.0-next.6" diff --git a/extensions/html-language-features/server/package.json b/extensions/html-language-features/server/package.json index dc078cfcb7108..6ce9bce33208a 100644 --- a/extensions/html-language-features/server/package.json +++ b/extensions/html-language-features/server/package.json @@ -9,7 +9,7 @@ }, "main": "./out/htmlServerMain", "dependencies": { - "vscode-css-languageservice": "^4.0.3-next.19", + "vscode-css-languageservice": "^4.0.3-next.20", "vscode-html-languageservice": "^3.0.4-next.8", "vscode-languageserver": "^6.0.0-next.3", "vscode-nls": "^4.1.1", diff --git a/extensions/html-language-features/server/yarn.lock b/extensions/html-language-features/server/yarn.lock index f96dfc5df6203..4f9260128b26d 100644 --- a/extensions/html-language-features/server/yarn.lock +++ b/extensions/html-language-features/server/yarn.lock @@ -611,10 +611,10 @@ supports-color@^5.3.0: dependencies: has-flag "^3.0.0" -vscode-css-languageservice@^4.0.3-next.19: - version "4.0.3-next.19" - resolved "https://registry.yarnpkg.com/vscode-css-languageservice/-/vscode-css-languageservice-4.0.3-next.19.tgz#b7dc58fb8d1968877724e163b6ef20b26c0b5ff6" - integrity sha512-wWSo2MZvd8aEI9lf/Asy0MP0Ao6xAzhBeEWxGcF+Ms/zcV4lDRkyFCNzwDt0OgWRzsBNaEBXfjeWLq9rNXkREA== +vscode-css-languageservice@^4.0.3-next.20: + version "4.0.3-next.20" + resolved "https://registry.yarnpkg.com/vscode-css-languageservice/-/vscode-css-languageservice-4.0.3-next.20.tgz#d0c4933c33e356617ccfaeb6b7144be196b8b3d9" + integrity sha512-9j32ppmJauPg9XYieAS6alCGazTaeEi8nhSAb11le5qfFNWep4Ngz7dNc/UMlt6hB7BESRyk2B8MM/KTlnsNBw== dependencies: vscode-languageserver-textdocument "^1.0.0-next.4" vscode-languageserver-types "^3.15.0-next.6" From 88c2100793b73cebda2d7753ac4bf52060671653 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Thu, 14 Nov 2019 00:46:01 -0800 Subject: [PATCH 289/352] Make sure we always reset bufferSyncSupport when the TS server is started Splits `reset` from `reinitialize` and makes sure we always `resset` buffer sync support when the service starts --- .../src/features/bufferSyncSupport.ts | 3 +++ .../src/typeScriptServiceClientHost.ts | 2 -- .../src/typescriptServiceClient.ts | 4 ++++ 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/extensions/typescript-language-features/src/features/bufferSyncSupport.ts b/extensions/typescript-language-features/src/features/bufferSyncSupport.ts index 28e201352061e..3cb7f24d80ad9 100644 --- a/extensions/typescript-language-features/src/features/bufferSyncSupport.ts +++ b/extensions/typescript-language-features/src/features/bufferSyncSupport.ts @@ -401,7 +401,10 @@ export default class BufferSyncSupport extends Disposable { this.pendingGetErr?.cancel(); this.pendingDiagnostics.clear(); this.synchronizer.reset(); + } + public reinitialize(): void { + this.reset(); for (const buffer of this.syncedBuffers.allBuffers) { buffer.open(); } diff --git a/extensions/typescript-language-features/src/typeScriptServiceClientHost.ts b/extensions/typescript-language-features/src/typeScriptServiceClientHost.ts index c0c1d6edc172d..6eeb2ed78ab6d 100644 --- a/extensions/typescript-language-features/src/typeScriptServiceClientHost.ts +++ b/extensions/typescript-language-features/src/typeScriptServiceClientHost.ts @@ -182,8 +182,6 @@ export default class TypeScriptServiceClientHost extends Disposable { private populateService(): void { this.fileConfigurationManager.reset(); - this.client.bufferSyncSupport.reset(); - this.client.bufferSyncSupport.requestAllDiagnostics(); // See https://github.com/Microsoft/TypeScript/issues/5530 vscode.workspace.saveAll(false).then(() => { diff --git a/extensions/typescript-language-features/src/typescriptServiceClient.ts b/extensions/typescript-language-features/src/typescriptServiceClient.ts index e376922dbaf94..5d8ea7f14209e 100644 --- a/extensions/typescript-language-features/src/typescriptServiceClient.ts +++ b/extensions/typescript-language-features/src/typescriptServiceClient.ts @@ -465,6 +465,8 @@ export default class TypeScriptServiceClient extends Disposable implements IType } private serviceStarted(resendModels: boolean): void { + this.bufferSyncSupport.reset(); + const configureOptions: Proto.ConfigureRequestArguments = { hostInfo: 'vscode', preferences: { @@ -476,6 +478,8 @@ export default class TypeScriptServiceClient extends Disposable implements IType this.setCompilerOptionsForInferredProjects(this._configuration); if (resendModels) { this._onResendModelsRequested.fire(); + this.bufferSyncSupport.reinitialize(); + this.bufferSyncSupport.requestAllDiagnostics(); } // Reconfigure any plugins From 90aec68c507840481201e594ac801c7f33cc1c47 Mon Sep 17 00:00:00 2001 From: SteVen Batten Date: Thu, 14 Nov 2019 11:59:34 -0800 Subject: [PATCH 290/352] fixes #84806 --- .../parts/titlebar/media/titlebarpart.css | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/vs/workbench/browser/parts/titlebar/media/titlebarpart.css b/src/vs/workbench/browser/parts/titlebar/media/titlebarpart.css index 265d6518c4019..4492478746c24 100644 --- a/src/vs/workbench/browser/parts/titlebar/media/titlebarpart.css +++ b/src/vs/workbench/browser/parts/titlebar/media/titlebarpart.css @@ -19,6 +19,23 @@ display: flex; } +.monaco-workbench.windows .part.titlebar, +.monaco-workbench.linux .part.titlebar, +.monaco-workbench.web .part.titlebar { + /* + * Explicitly put the part onto its own layer to help Chrome to + * render the content with LCD-anti-aliasing. By partioning the + * workbench into multiple layers, we can ensure that a bad + * behaving part is not making another part fallback to greyscale + * rendering. + * + * macOS: does not render LCD-anti-aliased. + */ + transform: translate3d(0px, 0px, 0px); + position: relative; + z-index: 1; +} + .monaco-workbench .part.titlebar > .titlebar-drag-region { top: 0; left: 0; @@ -103,6 +120,7 @@ height: 100%; width: 138px; margin-left: auto; + transform: translate3d(0px, 0px, 0px); } .monaco-workbench.fullscreen .part.titlebar > .window-controls-container { From 402acff09fce85c1a082f6c89d026fd2e4217ac9 Mon Sep 17 00:00:00 2001 From: SteVen Batten Date: Thu, 14 Nov 2019 12:44:16 -0800 Subject: [PATCH 291/352] fixes #84859 --- src/vs/workbench/contrib/search/browser/searchPanel.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/search/browser/searchPanel.ts b/src/vs/workbench/contrib/search/browser/searchPanel.ts index 0c0def101626c..0c50a100a55ae 100644 --- a/src/vs/workbench/contrib/search/browser/searchPanel.ts +++ b/src/vs/workbench/contrib/search/browser/searchPanel.ts @@ -25,7 +25,7 @@ export class SearchPanel extends Panel { @IInstantiationService instantiationService: IInstantiationService, ) { super(PANEL_ID, telemetryService, themeService, storageService); - this.searchView = this._register(instantiationService.createInstance(SearchView, { id: PANEL_ID, title: localize('search', "Search") })); + this.searchView = this._register(instantiationService.createInstance(SearchView, { id: PANEL_ID, title: localize('search', "Search"), actionRunner: this.getActionRunner() })); this._register(this.searchView.onDidChangeTitleArea(() => this.updateTitleArea())); this._register(this.onDidChangeVisibility(visible => this.searchView.setVisible(visible))); } From 524441ffc2841d9d84651e4c8144b907cb8ce1bd Mon Sep 17 00:00:00 2001 From: Connor Peet Date: Thu, 14 Nov 2019 12:58:23 -0800 Subject: [PATCH 292/352] debug: add pwa prefix as an extension host debugger --- src/vs/workbench/contrib/debug/common/debugUtils.ts | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/debug/common/debugUtils.ts b/src/vs/workbench/contrib/debug/common/debugUtils.ts index ca30e45a3ac40..38aebf4b0835d 100644 --- a/src/vs/workbench/contrib/debug/common/debugUtils.ts +++ b/src/vs/workbench/contrib/debug/common/debugUtils.ts @@ -28,7 +28,15 @@ export function isSessionAttach(session: IDebugSession): boolean { } export function isExtensionHostDebugging(config: IConfig) { - return config.type && equalsIgnoreCase(config.type === 'vslsShare' ? (config).adapterProxy.configuration.type : config.type, 'extensionhost'); + if (!config.type) { + return false; + } + + const type = config.type === 'vslsShare' + ? (config).adapterProxy.configuration.type + : config.type; + + return equalsIgnoreCase(type, 'extensionhost') || equalsIgnoreCase(type, 'pwa-extensionhost'); } // only a debugger contributions with a label, program, or runtime attribute is considered a "defining" or "main" debugger contribution From 230baa73721a5813950e7c4509443d407512f8d4 Mon Sep 17 00:00:00 2001 From: SteVen Batten <6561887+sbatten@users.noreply.github.com> Date: Thu, 14 Nov 2019 14:59:31 -0800 Subject: [PATCH 293/352] Fix/84231 (#84872) * account for padding on macOS fixes #84231 * move to native context menu service and account for zoom --- .../contextmenu/electron-browser/contextmenuService.ts | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/services/contextmenu/electron-browser/contextmenuService.ts b/src/vs/workbench/services/contextmenu/electron-browser/contextmenuService.ts index cea0688e45f49..e607464f9028e 100644 --- a/src/vs/workbench/services/contextmenu/electron-browser/contextmenuService.ts +++ b/src/vs/workbench/services/contextmenu/electron-browser/contextmenuService.ts @@ -91,18 +91,25 @@ class NativeContextMenuService extends Disposable implements IContextMenuService const anchor = delegate.getAnchor(); let x: number, y: number; + let zoom = webFrame.getZoomFactor(); if (dom.isHTMLElement(anchor)) { let elementPosition = dom.getDomNodePagePosition(anchor); x = elementPosition.left; y = elementPosition.top + elementPosition.height; + + // Shift macOS menus by a few pixels below elements + // to account for extra padding on top of native menu + // https://github.com/microsoft/vscode/issues/84231 + if (isMacintosh) { + y += 4 / zoom; + } } else { const pos: { x: number; y: number; } = anchor; x = pos.x + 1; /* prevent first item from being selected automatically under mouse */ y = pos.y; } - let zoom = webFrame.getZoomFactor(); x *= zoom; y *= zoom; From de94cbe1b02a92ec347d30c0ab0d2d816943d775 Mon Sep 17 00:00:00 2001 From: Miguel Solorio Date: Thu, 14 Nov 2019 15:00:44 -0800 Subject: [PATCH 294/352] Reduce bottom margin on activity bar items --- .../browser/parts/activitybar/media/activityaction.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/browser/parts/activitybar/media/activityaction.css b/src/vs/workbench/browser/parts/activitybar/media/activityaction.css index c4e9ea9430c64..28c43d3ab7a7a 100644 --- a/src/vs/workbench/browser/parts/activitybar/media/activityaction.css +++ b/src/vs/workbench/browser/parts/activitybar/media/activityaction.css @@ -6,7 +6,7 @@ .monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-item { display: block; position: relative; - margin-bottom: 8px; + margin-bottom: 4px; } .monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-label { From 738d85a51e56b9d373632511b633d6884bef4d1d Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Thu, 14 Nov 2019 11:46:13 -0800 Subject: [PATCH 295/352] Don't return js/ts fix all for empty edits --- .../typescript-language-features/src/features/fixAll.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/extensions/typescript-language-features/src/features/fixAll.ts b/extensions/typescript-language-features/src/features/fixAll.ts index d9461442e51df..c65dbf472a6db 100644 --- a/extensions/typescript-language-features/src/features/fixAll.ts +++ b/extensions/typescript-language-features/src/features/fixAll.ts @@ -82,6 +82,10 @@ class TypeScriptAutoFixProvider implements vscode.CodeActionProvider { return undefined; } const { edit, fixedDiagnostics } = autoFixResponse; + if (!edit.size) { + return undefined; + } + const codeAction = new vscode.CodeAction( localize('autoFix.label', 'Auto fix'), TypeScriptAutoFixProvider.kind); @@ -105,11 +109,11 @@ class TypeScriptAutoFixProvider implements vscode.CodeActionProvider { }; const response = await this.client.execute('getCodeFixes', args, token); if (response.type !== 'response' || !response.body || response.body.length > 1) { - return undefined; + continue; } const fix = response.body[0]; - if (new Set(['fixClassIncorrectlyImplementsInterface', 'spelling']).has(fix.fixName)) { + if (['fixClassIncorrectlyImplementsInterface', 'spelling'].includes(fix.fixName)) { typeConverters.WorkspaceEdit.withFileCodeEdits(edit, this.client, fix.changes); fixedDiagnostics.push(diagnostic); } From 40b8c9d073ec19274f6376f77b879f4fcf39ab43 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Thu, 14 Nov 2019 15:35:08 -0800 Subject: [PATCH 296/352] Allow _ in markdown word definitions --- extensions/markdown-language-features/src/extension.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/extensions/markdown-language-features/src/extension.ts b/extensions/markdown-language-features/src/extension.ts index 7180f0a69c84a..80595ff26f733 100644 --- a/extensions/markdown-language-features/src/extension.ts +++ b/extensions/markdown-language-features/src/extension.ts @@ -54,9 +54,11 @@ function registerMarkdownLanguageFeatures( { language: 'markdown', scheme: 'untitled' } ]; + const charPattern = '(\\p{Alphabetic}|\\p{Number}|\\p{Nonspacing_Mark})'; + return vscode.Disposable.from( vscode.languages.setLanguageConfiguration('markdown', { - wordPattern: new RegExp('(\\p{Alphabetic}|\\p{Number}|\\p{Nonspacing_Mark})+', 'ug'), + wordPattern: new RegExp(`${charPattern}((${charPattern}|[_])?${charPattern})*`, 'ug'), }), vscode.languages.registerDocumentSymbolProvider(selector, symbolProvider), vscode.languages.registerDocumentLinkProvider(selector, new LinkProvider()), From 01a1603d5139ad433968c51d20948987ab8b76f5 Mon Sep 17 00:00:00 2001 From: Peng Lyu Date: Thu, 14 Nov 2019 16:30:42 -0800 Subject: [PATCH 297/352] Global mouse move handler should understand pointer move. --- src/vs/base/browser/globalMouseMoveMonitor.ts | 36 +++---------------- src/vs/editor/browser/editorDom.ts | 9 ++--- .../contrib/colorPicker/colorPickerWidget.ts | 14 ++------ 3 files changed, 10 insertions(+), 49 deletions(-) diff --git a/src/vs/base/browser/globalMouseMoveMonitor.ts b/src/vs/base/browser/globalMouseMoveMonitor.ts index c15a4a4d60fbf..b24a3db0e504e 100644 --- a/src/vs/base/browser/globalMouseMoveMonitor.ts +++ b/src/vs/base/browser/globalMouseMoveMonitor.ts @@ -7,6 +7,7 @@ import * as dom from 'vs/base/browser/dom'; import { IframeUtils } from 'vs/base/browser/iframe'; import { StandardMouseEvent } from 'vs/base/browser/mouseEvent'; import { IDisposable, DisposableStore } from 'vs/base/common/lifecycle'; +import { BrowserFeatures } from 'vs/base/browser/canIUse'; export interface IStandardMouseMoveEventData { leftButton: boolean; @@ -84,12 +85,14 @@ export class GlobalMouseMoveMonitor implements IDisposable { this.onStopCallback = onStopCallback; let windowChain = IframeUtils.getSameOriginWindowChain(); + const mouseMove = BrowserFeatures.pointerEvents ? 'pointermove' : 'mousemove'; + const mouseUp = BrowserFeatures.pointerEvents ? 'pointerup' : 'mouseup'; for (const element of windowChain) { - this.hooks.add(dom.addDisposableThrottledListener(element.window.document, 'mousemove', + this.hooks.add(dom.addDisposableThrottledListener(element.window.document, mouseMove, (data: R) => this.mouseMoveCallback!(data), (lastEvent: R, currentEvent) => this.mouseMoveEventMerger!(lastEvent, currentEvent as MouseEvent) )); - this.hooks.add(dom.addDisposableListener(element.window.document, 'mouseup', (e: MouseEvent) => this.stopMonitoring(true))); + this.hooks.add(dom.addDisposableListener(element.window.document, mouseUp, (e: MouseEvent) => this.stopMonitoring(true))); } if (IframeUtils.hasDifferentOriginAncestor()) { @@ -116,32 +119,3 @@ export class GlobalMouseMoveMonitor implements IDisposable { } } } - -export class GlobalPointerMoveMonitor extends GlobalMouseMoveMonitor { - public startMonitoring( - mouseMoveEventMerger: IEventMerger, - mouseMoveCallback: IMouseMoveCallback, - onStopCallback: IOnStopCallback - ): void { - if (this.isMonitoring()) { - // I am already hooked - return; - } - this.mouseMoveEventMerger = mouseMoveEventMerger; - this.mouseMoveCallback = mouseMoveCallback; - this.onStopCallback = onStopCallback; - - let windowChain = IframeUtils.getSameOriginWindowChain(); - for (const element of windowChain) { - this.hooks.add(dom.addDisposableThrottledListener(element.window.document, 'pointermove', - (data: R) => { - this.mouseMoveCallback!(data); - }, - (lastEvent: R, currentEvent) => this.mouseMoveEventMerger!(lastEvent, currentEvent as MouseEvent) - )); - this.hooks.add(dom.addDisposableListener(element.window.document, 'pointerup', (e: MouseEvent) => this.stopMonitoring(true))); - } - - // Currently we didn't test pointer events in iframe yet. - } -} diff --git a/src/vs/editor/browser/editorDom.ts b/src/vs/editor/browser/editorDom.ts index f27c6b45e5723..60df7e8f1b893 100644 --- a/src/vs/editor/browser/editorDom.ts +++ b/src/vs/editor/browser/editorDom.ts @@ -4,10 +4,9 @@ *--------------------------------------------------------------------------------------------*/ import * as dom from 'vs/base/browser/dom'; -import { GlobalMouseMoveMonitor, GlobalPointerMoveMonitor } from 'vs/base/browser/globalMouseMoveMonitor'; +import { GlobalMouseMoveMonitor } from 'vs/base/browser/globalMouseMoveMonitor'; import { StandardMouseEvent } from 'vs/base/browser/mouseEvent'; import { Disposable, IDisposable } from 'vs/base/common/lifecycle'; -import { BrowserFeatures } from 'vs/base/browser/canIUse'; /** * Coordinates relative to the whole document (e.g. mouse event's pageX and pageY) @@ -179,11 +178,7 @@ export class GlobalEditorMouseMoveMonitor extends Disposable { constructor(editorViewDomNode: HTMLElement) { super(); this._editorViewDomNode = editorViewDomNode; - this._globalMouseMoveMonitor = this._register( - BrowserFeatures.pointerEvents - ? new GlobalPointerMoveMonitor() - : new GlobalMouseMoveMonitor() - ); + this._globalMouseMoveMonitor = this._register(new GlobalMouseMoveMonitor()); this._keydownListener = null; } diff --git a/src/vs/editor/contrib/colorPicker/colorPickerWidget.ts b/src/vs/editor/contrib/colorPicker/colorPickerWidget.ts index 106c2a357e28a..0c3f47322b8a8 100644 --- a/src/vs/editor/contrib/colorPicker/colorPickerWidget.ts +++ b/src/vs/editor/contrib/colorPicker/colorPickerWidget.ts @@ -6,7 +6,7 @@ import 'vs/css!./colorPicker'; import { onDidChangeZoomLevel } from 'vs/base/browser/browser'; import * as dom from 'vs/base/browser/dom'; -import { GlobalMouseMoveMonitor, IStandardMouseMoveEventData, standardMouseMoveMerger, GlobalPointerMoveMonitor } from 'vs/base/browser/globalMouseMoveMonitor'; +import { GlobalMouseMoveMonitor, IStandardMouseMoveEventData, standardMouseMoveMerger } from 'vs/base/browser/globalMouseMoveMonitor'; import { Widget } from 'vs/base/browser/ui/widget'; import { Color, HSVA, RGBA } from 'vs/base/common/color'; import { Emitter, Event } from 'vs/base/common/event'; @@ -157,11 +157,7 @@ class SaturationBox extends Disposable { } private onMouseDown(e: MouseEvent): void { - this.monitor = this._register( - BrowserFeatures.pointerEvents - ? new GlobalPointerMoveMonitor() - : new GlobalMouseMoveMonitor() - ); + this.monitor = this._register(new GlobalMouseMoveMonitor()); const origin = dom.getDomNodePagePosition(this.domNode); if (e.target !== this.selection) { @@ -267,11 +263,7 @@ abstract class Strip extends Disposable { } private onMouseDown(e: MouseEvent): void { - const monitor = this._register( - BrowserFeatures.pointerEvents - ? new GlobalPointerMoveMonitor() - : new GlobalMouseMoveMonitor() - ); + const monitor = this._register(new GlobalMouseMoveMonitor()); const origin = dom.getDomNodePagePosition(this.domNode); dom.addClass(this.domNode, 'grabbing'); From 36a8322ae8c969640b7853ce50b8d580cc35c2f1 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Thu, 14 Nov 2019 16:49:25 -0800 Subject: [PATCH 298/352] Convert SyncActionDescriptor to use a `create` function (#84878) For #81574 See #84669 for details of the problem around strict function types. This change converts `SyncActionDescriptor` to use a static `create` function. This allows us to make the `create` function generic so that it can take the correct types for strictFunctionTypes --- src/vs/platform/actions/common/actions.ts | 10 +- .../api/browser/viewsExtensionPoint.ts | 2 +- .../browser/actions/developerActions.ts | 6 +- .../workbench/browser/actions/helpActions.ts | 18 +- .../browser/actions/layoutActions.ts | 24 +-- .../browser/actions/navigationActions.ts | 8 +- .../browser/actions/windowActions.ts | 12 +- .../browser/actions/workspaceActions.ts | 10 +- .../parts/activitybar/activitybarActions.ts | 4 +- .../parts/editor/editor.contribution.ts | 154 +++++++++--------- .../browser/parts/panel/panelActions.ts | 16 +- .../parts/quickinput/quickInputActions.ts | 2 +- .../parts/quickopen/quickOpenActions.ts | 12 +- .../browser/parts/sidebar/sidebarPart.ts | 2 +- .../contrib/cli/node/cli.contribution.ts | 4 +- .../codeEditor/browser/inspectKeybindings.ts | 2 +- .../codeEditor/browser/toggleMinimap.ts | 2 +- .../browser/toggleMultiCursorModifier.ts | 4 +- .../browser/toggleRenderControlCharacter.ts | 2 +- .../browser/toggleRenderWhitespace.ts | 2 +- .../debug/browser/debug.contribution.ts | 24 +-- .../browser/extensions.contribution.ts | 46 +++--- .../extensions.contribution.ts | 4 +- .../files/browser/fileActions.contribution.ts | 26 +-- .../files/browser/files.contribution.ts | 2 +- .../fileActions.contribution.ts | 2 +- .../electron-browser/issue.contribution.ts | 6 +- .../browser/localizations.contribution.ts | 2 +- .../contrib/logs/common/logs.contribution.ts | 4 +- .../electron-browser/logs.contribution.ts | 2 +- .../markers/browser/markers.contribution.ts | 4 +- .../output/browser/output.contribution.ts | 8 +- .../browser/keyboardLayoutPicker.ts | 2 +- .../browser/preferences.contribution.ts | 18 +- .../browser/quickopen.contribution.ts | 12 +- .../contrib/remote/browser/remote.ts | 2 +- .../contrib/scm/browser/scm.contribution.ts | 2 +- .../search/browser/search.contribution.ts | 18 +- .../tasks/browser/task.contribution.ts | 2 +- .../terminal/browser/terminal.contribution.ts | 124 +++++++------- .../electron-browser/terminalRemote.ts | 2 +- .../browser/testCustomEditors.ts | 2 +- .../themes/browser/themes.contribution.ts | 6 +- .../update/browser/update.contribution.ts | 4 +- .../contrib/url/common/url.contribution.ts | 2 +- .../webview/browser/webview.contribution.ts | 2 +- .../electron-browser/webview.contribution.ts | 2 +- .../welcome/overlay/browser/welcomeOverlay.ts | 4 +- .../page/browser/welcomePage.contribution.ts | 2 +- .../browser/walkThrough.contribution.ts | 2 +- .../electron-browser/desktop.contribution.ts | 20 +-- .../extensions/browser/extensionUrlHandler.ts | 2 +- .../common/extensionHostProcessManager.ts | 2 +- .../common/keybindingsEditorModel.test.ts | 2 +- 54 files changed, 333 insertions(+), 327 deletions(-) diff --git a/src/vs/platform/actions/common/actions.ts b/src/vs/platform/actions/common/actions.ts index a583f7a34f514..2cea44d858941 100644 --- a/src/vs/platform/actions/common/actions.ts +++ b/src/vs/platform/actions/common/actions.ts @@ -5,7 +5,7 @@ import { Action } from 'vs/base/common/actions'; import { SyncDescriptor0, createSyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; -import { IConstructorSignature2, createDecorator } from 'vs/platform/instantiation/common/instantiation'; +import { IConstructorSignature2, createDecorator, BrandedService } from 'vs/platform/instantiation/common/instantiation'; import { IKeybindings, KeybindingsRegistry } from 'vs/platform/keybinding/common/keybindingsRegistry'; import { ContextKeyExpr, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { ICommandService, ICommandHandler, CommandsRegistry } from 'vs/platform/commands/common/commands'; @@ -295,7 +295,13 @@ export class SyncActionDescriptor { private readonly _keybindingContext: ContextKeyExpr | undefined; private readonly _keybindingWeight: number | undefined; - constructor(ctor: IConstructorSignature2, + public static create(ctor: { new(id: string, label: string, ...services: Services): Action }, + id: string, label: string | undefined, keybindings?: IKeybindings, keybindingContext?: ContextKeyExpr, keybindingWeight?: number + ): SyncActionDescriptor { + return new SyncActionDescriptor(ctor as IConstructorSignature2, id, label, keybindings, keybindingContext, keybindingWeight); + } + + private constructor(ctor: IConstructorSignature2, id: string, label: string | undefined, keybindings?: IKeybindings, keybindingContext?: ContextKeyExpr, keybindingWeight?: number ) { this._id = id; diff --git a/src/vs/workbench/api/browser/viewsExtensionPoint.ts b/src/vs/workbench/api/browser/viewsExtensionPoint.ts index 0f1fe0a1eee0b..efbc23c293f29 100644 --- a/src/vs/workbench/api/browser/viewsExtensionPoint.ts +++ b/src/vs/workbench/api/browser/viewsExtensionPoint.ts @@ -359,7 +359,7 @@ class ViewsExtensionHandler implements IWorkbenchContribution { } const registry = Registry.as(ActionExtensions.WorkbenchActions); registry.registerWorkbenchAction( - new SyncActionDescriptor(OpenCustomViewletAction, id, localize('showViewlet', "Show {0}", title)), + SyncActionDescriptor.create(OpenCustomViewletAction, id, localize('showViewlet', "Show {0}", title)), `View: Show ${title}`, localize('view', "View") ); diff --git a/src/vs/workbench/browser/actions/developerActions.ts b/src/vs/workbench/browser/actions/developerActions.ts index abf8bdb9d1239..cf9666dc65db0 100644 --- a/src/vs/workbench/browser/actions/developerActions.ts +++ b/src/vs/workbench/browser/actions/developerActions.ts @@ -214,9 +214,9 @@ class LogStorageAction extends Action { const developerCategory = nls.localize('developer', "Developer"); const registry = Registry.as(Extensions.WorkbenchActions); -registry.registerWorkbenchAction(new SyncActionDescriptor(InspectContextKeysAction, InspectContextKeysAction.ID, InspectContextKeysAction.LABEL), 'Developer: Inspect Context Keys', developerCategory); -registry.registerWorkbenchAction(new SyncActionDescriptor(ToggleScreencastModeAction, ToggleScreencastModeAction.ID, ToggleScreencastModeAction.LABEL), 'Developer: Toggle Screencast Mode', developerCategory); -registry.registerWorkbenchAction(new SyncActionDescriptor(LogStorageAction, LogStorageAction.ID, LogStorageAction.LABEL), 'Developer: Log Storage Database Contents', developerCategory); +registry.registerWorkbenchAction(SyncActionDescriptor.create(InspectContextKeysAction, InspectContextKeysAction.ID, InspectContextKeysAction.LABEL), 'Developer: Inspect Context Keys', developerCategory); +registry.registerWorkbenchAction(SyncActionDescriptor.create(ToggleScreencastModeAction, ToggleScreencastModeAction.ID, ToggleScreencastModeAction.LABEL), 'Developer: Toggle Screencast Mode', developerCategory); +registry.registerWorkbenchAction(SyncActionDescriptor.create(LogStorageAction, LogStorageAction.ID, LogStorageAction.LABEL), 'Developer: Log Storage Database Contents', developerCategory); // Screencast Mode const configurationRegistry = Registry.as(ConfigurationExtensions.Configuration); diff --git a/src/vs/workbench/browser/actions/helpActions.ts b/src/vs/workbench/browser/actions/helpActions.ts index e16e460cff048..2ecc5026fc851 100644 --- a/src/vs/workbench/browser/actions/helpActions.ts +++ b/src/vs/workbench/browser/actions/helpActions.ts @@ -248,39 +248,39 @@ const registry = Registry.as(Extensions.WorkbenchActio const helpCategory = nls.localize('help', "Help"); if (KeybindingsReferenceAction.AVAILABLE) { - registry.registerWorkbenchAction(new SyncActionDescriptor(KeybindingsReferenceAction, KeybindingsReferenceAction.ID, KeybindingsReferenceAction.LABEL, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.KEY_R) }), 'Help: Keyboard Shortcuts Reference', helpCategory); + registry.registerWorkbenchAction(SyncActionDescriptor.create(KeybindingsReferenceAction, KeybindingsReferenceAction.ID, KeybindingsReferenceAction.LABEL, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.KEY_R) }), 'Help: Keyboard Shortcuts Reference', helpCategory); } if (OpenDocumentationUrlAction.AVAILABLE) { - registry.registerWorkbenchAction(new SyncActionDescriptor(OpenDocumentationUrlAction, OpenDocumentationUrlAction.ID, OpenDocumentationUrlAction.LABEL), 'Help: Documentation', helpCategory); + registry.registerWorkbenchAction(SyncActionDescriptor.create(OpenDocumentationUrlAction, OpenDocumentationUrlAction.ID, OpenDocumentationUrlAction.LABEL), 'Help: Documentation', helpCategory); } if (OpenIntroductoryVideosUrlAction.AVAILABLE) { - registry.registerWorkbenchAction(new SyncActionDescriptor(OpenIntroductoryVideosUrlAction, OpenIntroductoryVideosUrlAction.ID, OpenIntroductoryVideosUrlAction.LABEL), 'Help: Introductory Videos', helpCategory); + registry.registerWorkbenchAction(SyncActionDescriptor.create(OpenIntroductoryVideosUrlAction, OpenIntroductoryVideosUrlAction.ID, OpenIntroductoryVideosUrlAction.LABEL), 'Help: Introductory Videos', helpCategory); } if (OpenTipsAndTricksUrlAction.AVAILABLE) { - registry.registerWorkbenchAction(new SyncActionDescriptor(OpenTipsAndTricksUrlAction, OpenTipsAndTricksUrlAction.ID, OpenTipsAndTricksUrlAction.LABEL), 'Help: Tips and Tricks', helpCategory); + registry.registerWorkbenchAction(SyncActionDescriptor.create(OpenTipsAndTricksUrlAction, OpenTipsAndTricksUrlAction.ID, OpenTipsAndTricksUrlAction.LABEL), 'Help: Tips and Tricks', helpCategory); } if (OpenNewsletterSignupUrlAction.AVAILABLE) { - registry.registerWorkbenchAction(new SyncActionDescriptor(OpenNewsletterSignupUrlAction, OpenNewsletterSignupUrlAction.ID, OpenNewsletterSignupUrlAction.LABEL), 'Help: Tips and Tricks', helpCategory); + registry.registerWorkbenchAction(SyncActionDescriptor.create(OpenNewsletterSignupUrlAction, OpenNewsletterSignupUrlAction.ID, OpenNewsletterSignupUrlAction.LABEL), 'Help: Tips and Tricks', helpCategory); } if (OpenTwitterUrlAction.AVAILABLE) { - registry.registerWorkbenchAction(new SyncActionDescriptor(OpenTwitterUrlAction, OpenTwitterUrlAction.ID, OpenTwitterUrlAction.LABEL), 'Help: Join Us on Twitter', helpCategory); + registry.registerWorkbenchAction(SyncActionDescriptor.create(OpenTwitterUrlAction, OpenTwitterUrlAction.ID, OpenTwitterUrlAction.LABEL), 'Help: Join Us on Twitter', helpCategory); } if (OpenRequestFeatureUrlAction.AVAILABLE) { - registry.registerWorkbenchAction(new SyncActionDescriptor(OpenRequestFeatureUrlAction, OpenRequestFeatureUrlAction.ID, OpenRequestFeatureUrlAction.LABEL), 'Help: Search Feature Requests', helpCategory); + registry.registerWorkbenchAction(SyncActionDescriptor.create(OpenRequestFeatureUrlAction, OpenRequestFeatureUrlAction.ID, OpenRequestFeatureUrlAction.LABEL), 'Help: Search Feature Requests', helpCategory); } if (OpenLicenseUrlAction.AVAILABLE) { - registry.registerWorkbenchAction(new SyncActionDescriptor(OpenLicenseUrlAction, OpenLicenseUrlAction.ID, OpenLicenseUrlAction.LABEL), 'Help: View License', helpCategory); + registry.registerWorkbenchAction(SyncActionDescriptor.create(OpenLicenseUrlAction, OpenLicenseUrlAction.ID, OpenLicenseUrlAction.LABEL), 'Help: View License', helpCategory); } if (OpenPrivacyStatementUrlAction.AVAILABE) { - registry.registerWorkbenchAction(new SyncActionDescriptor(OpenPrivacyStatementUrlAction, OpenPrivacyStatementUrlAction.ID, OpenPrivacyStatementUrlAction.LABEL), 'Help: Privacy Statement', helpCategory); + registry.registerWorkbenchAction(SyncActionDescriptor.create(OpenPrivacyStatementUrlAction, OpenPrivacyStatementUrlAction.ID, OpenPrivacyStatementUrlAction.LABEL), 'Help: Privacy Statement', helpCategory); } // --- Menu Registration diff --git a/src/vs/workbench/browser/actions/layoutActions.ts b/src/vs/workbench/browser/actions/layoutActions.ts index 944c253c1b23f..65a1a71dd5b2d 100644 --- a/src/vs/workbench/browser/actions/layoutActions.ts +++ b/src/vs/workbench/browser/actions/layoutActions.ts @@ -56,7 +56,7 @@ export class ToggleActivityBarVisibilityAction extends Action { } } -registry.registerWorkbenchAction(new SyncActionDescriptor(ToggleActivityBarVisibilityAction, ToggleActivityBarVisibilityAction.ID, ToggleActivityBarVisibilityAction.LABEL), 'View: Toggle Activity Bar Visibility', viewCategory); +registry.registerWorkbenchAction(SyncActionDescriptor.create(ToggleActivityBarVisibilityAction, ToggleActivityBarVisibilityAction.ID, ToggleActivityBarVisibilityAction.LABEL), 'View: Toggle Activity Bar Visibility', viewCategory); MenuRegistry.appendMenuItem(MenuId.MenubarAppearanceMenu, { group: '2_workbench_layout', @@ -91,7 +91,7 @@ class ToggleCenteredLayout extends Action { } } -registry.registerWorkbenchAction(new SyncActionDescriptor(ToggleCenteredLayout, ToggleCenteredLayout.ID, ToggleCenteredLayout.LABEL), 'View: Toggle Centered Layout', viewCategory); +registry.registerWorkbenchAction(SyncActionDescriptor.create(ToggleCenteredLayout, ToggleCenteredLayout.ID, ToggleCenteredLayout.LABEL), 'View: Toggle Centered Layout', viewCategory); MenuRegistry.appendMenuItem(MenuId.MenubarAppearanceMenu, { group: '1_toggle_view', @@ -143,7 +143,7 @@ export class ToggleEditorLayoutAction extends Action { } const group = viewCategory; -registry.registerWorkbenchAction(new SyncActionDescriptor(ToggleEditorLayoutAction, ToggleEditorLayoutAction.ID, ToggleEditorLayoutAction.LABEL, { primary: KeyMod.Shift | KeyMod.Alt | KeyCode.KEY_0, mac: { primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.KEY_0 } }), 'View: Toggle Vertical/Horizontal Editor Layout', group); +registry.registerWorkbenchAction(SyncActionDescriptor.create(ToggleEditorLayoutAction, ToggleEditorLayoutAction.ID, ToggleEditorLayoutAction.LABEL, { primary: KeyMod.Shift | KeyMod.Alt | KeyCode.KEY_0, mac: { primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.KEY_0 } }), 'View: Toggle Vertical/Horizontal Editor Layout', group); MenuRegistry.appendMenuItem(MenuId.MenubarLayoutMenu, { group: 'z_flip', @@ -186,7 +186,7 @@ export class ToggleSidebarPositionAction extends Action { } } -registry.registerWorkbenchAction(new SyncActionDescriptor(ToggleSidebarPositionAction, ToggleSidebarPositionAction.ID, ToggleSidebarPositionAction.LABEL), 'View: Toggle Side Bar Position', viewCategory); +registry.registerWorkbenchAction(SyncActionDescriptor.create(ToggleSidebarPositionAction, ToggleSidebarPositionAction.ID, ToggleSidebarPositionAction.LABEL), 'View: Toggle Side Bar Position', viewCategory); MenuRegistry.appendMenuItem(MenuId.MenubarAppearanceMenu, { group: '3_workbench_layout_move', @@ -231,7 +231,7 @@ export class ToggleEditorVisibilityAction extends Action { } } -registry.registerWorkbenchAction(new SyncActionDescriptor(ToggleEditorVisibilityAction, ToggleEditorVisibilityAction.ID, ToggleEditorVisibilityAction.LABEL), 'View: Toggle Editor Area Visibility', viewCategory); +registry.registerWorkbenchAction(SyncActionDescriptor.create(ToggleEditorVisibilityAction, ToggleEditorVisibilityAction.ID, ToggleEditorVisibilityAction.LABEL), 'View: Toggle Editor Area Visibility', viewCategory); MenuRegistry.appendMenuItem(MenuId.MenubarAppearanceMenu, { group: '2_workbench_layout', @@ -266,7 +266,7 @@ export class ToggleSidebarVisibilityAction extends Action { } } -registry.registerWorkbenchAction(new SyncActionDescriptor(ToggleSidebarVisibilityAction, ToggleSidebarVisibilityAction.ID, ToggleSidebarVisibilityAction.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.KEY_B }), 'View: Toggle Side Bar Visibility', viewCategory); +registry.registerWorkbenchAction(SyncActionDescriptor.create(ToggleSidebarVisibilityAction, ToggleSidebarVisibilityAction.ID, ToggleSidebarVisibilityAction.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.KEY_B }), 'View: Toggle Side Bar Visibility', viewCategory); MenuRegistry.appendMenuItem(MenuId.MenubarViewMenu, { group: '2_appearance', @@ -313,7 +313,7 @@ export class ToggleStatusbarVisibilityAction extends Action { } } -registry.registerWorkbenchAction(new SyncActionDescriptor(ToggleStatusbarVisibilityAction, ToggleStatusbarVisibilityAction.ID, ToggleStatusbarVisibilityAction.LABEL), 'View: Toggle Status Bar Visibility', viewCategory); +registry.registerWorkbenchAction(SyncActionDescriptor.create(ToggleStatusbarVisibilityAction, ToggleStatusbarVisibilityAction.ID, ToggleStatusbarVisibilityAction.LABEL), 'View: Toggle Status Bar Visibility', viewCategory); MenuRegistry.appendMenuItem(MenuId.MenubarAppearanceMenu, { group: '2_workbench_layout', @@ -350,7 +350,7 @@ class ToggleTabsVisibilityAction extends Action { } } -registry.registerWorkbenchAction(new SyncActionDescriptor(ToggleTabsVisibilityAction, ToggleTabsVisibilityAction.ID, ToggleTabsVisibilityAction.LABEL, { +registry.registerWorkbenchAction(SyncActionDescriptor.create(ToggleTabsVisibilityAction, ToggleTabsVisibilityAction.ID, ToggleTabsVisibilityAction.LABEL, { primary: undefined, mac: { primary: KeyMod.CtrlCmd | KeyMod.WinCtrl | KeyCode.KEY_W, }, linux: { primary: KeyMod.CtrlCmd | KeyMod.WinCtrl | KeyCode.KEY_W, } @@ -379,7 +379,7 @@ class ToggleZenMode extends Action { } } -registry.registerWorkbenchAction(new SyncActionDescriptor(ToggleZenMode, ToggleZenMode.ID, ToggleZenMode.LABEL, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyCode.KEY_Z) }), 'View: Toggle Zen Mode', viewCategory); +registry.registerWorkbenchAction(SyncActionDescriptor.create(ToggleZenMode, ToggleZenMode.ID, ToggleZenMode.LABEL, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyCode.KEY_Z) }), 'View: Toggle Zen Mode', viewCategory); MenuRegistry.appendMenuItem(MenuId.MenubarAppearanceMenu, { group: '1_toggle_view', @@ -442,7 +442,7 @@ export class ToggleMenuBarAction extends Action { } if (isWindows || isLinux || isWeb) { - registry.registerWorkbenchAction(new SyncActionDescriptor(ToggleMenuBarAction, ToggleMenuBarAction.ID, ToggleMenuBarAction.LABEL), 'View: Toggle Menu Bar', viewCategory); + registry.registerWorkbenchAction(SyncActionDescriptor.create(ToggleMenuBarAction, ToggleMenuBarAction.ID, ToggleMenuBarAction.LABEL), 'View: Toggle Menu Bar', viewCategory); } MenuRegistry.appendMenuItem(MenuId.MenubarAppearanceMenu, { @@ -529,5 +529,5 @@ export class DecreaseViewSizeAction extends BaseResizeViewAction { } } -registry.registerWorkbenchAction(new SyncActionDescriptor(IncreaseViewSizeAction, IncreaseViewSizeAction.ID, IncreaseViewSizeAction.LABEL, undefined), 'View: Increase Current View Size', viewCategory); -registry.registerWorkbenchAction(new SyncActionDescriptor(DecreaseViewSizeAction, DecreaseViewSizeAction.ID, DecreaseViewSizeAction.LABEL, undefined), 'View: Decrease Current View Size', viewCategory); +registry.registerWorkbenchAction(SyncActionDescriptor.create(IncreaseViewSizeAction, IncreaseViewSizeAction.ID, IncreaseViewSizeAction.LABEL, undefined), 'View: Increase Current View Size', viewCategory); +registry.registerWorkbenchAction(SyncActionDescriptor.create(DecreaseViewSizeAction, DecreaseViewSizeAction.ID, DecreaseViewSizeAction.LABEL, undefined), 'View: Decrease Current View Size', viewCategory); diff --git a/src/vs/workbench/browser/actions/navigationActions.ts b/src/vs/workbench/browser/actions/navigationActions.ts index fae9742c7bf95..538edac8a28ed 100644 --- a/src/vs/workbench/browser/actions/navigationActions.ts +++ b/src/vs/workbench/browser/actions/navigationActions.ts @@ -280,7 +280,7 @@ class NavigateDownAction extends BaseNavigationAction { const registry = Registry.as(Extensions.WorkbenchActions); const viewCategory = nls.localize('view', "View"); -registry.registerWorkbenchAction(new SyncActionDescriptor(NavigateUpAction, NavigateUpAction.ID, NavigateUpAction.LABEL, undefined), 'View: Navigate to the View Above', viewCategory); -registry.registerWorkbenchAction(new SyncActionDescriptor(NavigateDownAction, NavigateDownAction.ID, NavigateDownAction.LABEL, undefined), 'View: Navigate to the View Below', viewCategory); -registry.registerWorkbenchAction(new SyncActionDescriptor(NavigateLeftAction, NavigateLeftAction.ID, NavigateLeftAction.LABEL, undefined), 'View: Navigate to the View on the Left', viewCategory); -registry.registerWorkbenchAction(new SyncActionDescriptor(NavigateRightAction, NavigateRightAction.ID, NavigateRightAction.LABEL, undefined), 'View: Navigate to the View on the Right', viewCategory); +registry.registerWorkbenchAction(SyncActionDescriptor.create(NavigateUpAction, NavigateUpAction.ID, NavigateUpAction.LABEL, undefined), 'View: Navigate to the View Above', viewCategory); +registry.registerWorkbenchAction(SyncActionDescriptor.create(NavigateDownAction, NavigateDownAction.ID, NavigateDownAction.LABEL, undefined), 'View: Navigate to the View Below', viewCategory); +registry.registerWorkbenchAction(SyncActionDescriptor.create(NavigateLeftAction, NavigateLeftAction.ID, NavigateLeftAction.LABEL, undefined), 'View: Navigate to the View on the Left', viewCategory); +registry.registerWorkbenchAction(SyncActionDescriptor.create(NavigateRightAction, NavigateRightAction.ID, NavigateRightAction.LABEL, undefined), 'View: Navigate to the View on the Right', viewCategory); diff --git a/src/vs/workbench/browser/actions/windowActions.ts b/src/vs/workbench/browser/actions/windowActions.ts index c445910548383..e59fdc54f7532 100644 --- a/src/vs/workbench/browser/actions/windowActions.ts +++ b/src/vs/workbench/browser/actions/windowActions.ts @@ -269,18 +269,18 @@ const registry = Registry.as(Extensions.WorkbenchActio // --- Actions Registration const fileCategory = nls.localize('file', "File"); -registry.registerWorkbenchAction(new SyncActionDescriptor(NewWindowAction, NewWindowAction.ID, NewWindowAction.LABEL, { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_N }), 'New Window'); -registry.registerWorkbenchAction(new SyncActionDescriptor(QuickOpenRecentAction, QuickOpenRecentAction.ID, QuickOpenRecentAction.LABEL), 'File: Quick Open Recent...', fileCategory); -registry.registerWorkbenchAction(new SyncActionDescriptor(OpenRecentAction, OpenRecentAction.ID, OpenRecentAction.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.KEY_R, mac: { primary: KeyMod.WinCtrl | KeyCode.KEY_R } }), 'File: Open Recent...', fileCategory); +registry.registerWorkbenchAction(SyncActionDescriptor.create(NewWindowAction, NewWindowAction.ID, NewWindowAction.LABEL, { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_N }), 'New Window'); +registry.registerWorkbenchAction(SyncActionDescriptor.create(QuickOpenRecentAction, QuickOpenRecentAction.ID, QuickOpenRecentAction.LABEL), 'File: Quick Open Recent...', fileCategory); +registry.registerWorkbenchAction(SyncActionDescriptor.create(OpenRecentAction, OpenRecentAction.ID, OpenRecentAction.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.KEY_R, mac: { primary: KeyMod.WinCtrl | KeyCode.KEY_R } }), 'File: Open Recent...', fileCategory); const viewCategory = nls.localize('view', "View"); -registry.registerWorkbenchAction(new SyncActionDescriptor(ToggleFullScreenAction, ToggleFullScreenAction.ID, ToggleFullScreenAction.LABEL, { primary: KeyCode.F11, mac: { primary: KeyMod.CtrlCmd | KeyMod.WinCtrl | KeyCode.KEY_F } }), 'View: Toggle Full Screen', viewCategory); +registry.registerWorkbenchAction(SyncActionDescriptor.create(ToggleFullScreenAction, ToggleFullScreenAction.ID, ToggleFullScreenAction.LABEL, { primary: KeyCode.F11, mac: { primary: KeyMod.CtrlCmd | KeyMod.WinCtrl | KeyCode.KEY_F } }), 'View: Toggle Full Screen', viewCategory); const developerCategory = nls.localize('developer', "Developer"); -registry.registerWorkbenchAction(new SyncActionDescriptor(ReloadWindowAction, ReloadWindowAction.ID, ReloadWindowAction.LABEL), 'Developer: Reload Window', developerCategory); +registry.registerWorkbenchAction(SyncActionDescriptor.create(ReloadWindowAction, ReloadWindowAction.ID, ReloadWindowAction.LABEL), 'Developer: Reload Window', developerCategory); const helpCategory = nls.localize('help', "Help"); -registry.registerWorkbenchAction(new SyncActionDescriptor(ShowAboutDialogAction, ShowAboutDialogAction.ID, ShowAboutDialogAction.LABEL), `Help: About`, helpCategory); +registry.registerWorkbenchAction(SyncActionDescriptor.create(ShowAboutDialogAction, ShowAboutDialogAction.ID, ShowAboutDialogAction.LABEL), `Help: About`, helpCategory); // --- Commands/Keybindings Registration diff --git a/src/vs/workbench/browser/actions/workspaceActions.ts b/src/vs/workbench/browser/actions/workspaceActions.ts index 0834621124a3e..b129dc792f8c8 100644 --- a/src/vs/workbench/browser/actions/workspaceActions.ts +++ b/src/vs/workbench/browser/actions/workspaceActions.ts @@ -259,11 +259,11 @@ export class DuplicateWorkspaceInNewWindowAction extends Action { const registry = Registry.as(Extensions.WorkbenchActions); const workspacesCategory = nls.localize('workspaces', "Workspaces"); -registry.registerWorkbenchAction(new SyncActionDescriptor(AddRootFolderAction, AddRootFolderAction.ID, AddRootFolderAction.LABEL), 'Workspaces: Add Folder to Workspace...', workspacesCategory); -registry.registerWorkbenchAction(new SyncActionDescriptor(GlobalRemoveRootFolderAction, GlobalRemoveRootFolderAction.ID, GlobalRemoveRootFolderAction.LABEL), 'Workspaces: Remove Folder from Workspace...', workspacesCategory); -registry.registerWorkbenchAction(new SyncActionDescriptor(CloseWorkspaceAction, CloseWorkspaceAction.ID, CloseWorkspaceAction.LABEL, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyCode.KEY_F) }), 'Workspaces: Close Workspace', workspacesCategory); -registry.registerWorkbenchAction(new SyncActionDescriptor(SaveWorkspaceAsAction, SaveWorkspaceAsAction.ID, SaveWorkspaceAsAction.LABEL), 'Workspaces: Save Workspace As...', workspacesCategory); -registry.registerWorkbenchAction(new SyncActionDescriptor(DuplicateWorkspaceInNewWindowAction, DuplicateWorkspaceInNewWindowAction.ID, DuplicateWorkspaceInNewWindowAction.LABEL), 'Workspaces: Duplicate Workspace in New Window', workspacesCategory); +registry.registerWorkbenchAction(SyncActionDescriptor.create(AddRootFolderAction, AddRootFolderAction.ID, AddRootFolderAction.LABEL), 'Workspaces: Add Folder to Workspace...', workspacesCategory); +registry.registerWorkbenchAction(SyncActionDescriptor.create(GlobalRemoveRootFolderAction, GlobalRemoveRootFolderAction.ID, GlobalRemoveRootFolderAction.LABEL), 'Workspaces: Remove Folder from Workspace...', workspacesCategory); +registry.registerWorkbenchAction(SyncActionDescriptor.create(CloseWorkspaceAction, CloseWorkspaceAction.ID, CloseWorkspaceAction.LABEL, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyCode.KEY_F) }), 'Workspaces: Close Workspace', workspacesCategory); +registry.registerWorkbenchAction(SyncActionDescriptor.create(SaveWorkspaceAsAction, SaveWorkspaceAsAction.ID, SaveWorkspaceAsAction.LABEL), 'Workspaces: Save Workspace As...', workspacesCategory); +registry.registerWorkbenchAction(SyncActionDescriptor.create(DuplicateWorkspaceInNewWindowAction, DuplicateWorkspaceInNewWindowAction.ID, DuplicateWorkspaceInNewWindowAction.LABEL), 'Workspaces: Duplicate Workspace in New Window', workspacesCategory); // --- Menu Registration diff --git a/src/vs/workbench/browser/parts/activitybar/activitybarActions.ts b/src/vs/workbench/browser/parts/activitybar/activitybarActions.ts index bd8425e05552b..15acfe38cd99b 100644 --- a/src/vs/workbench/browser/parts/activitybar/activitybarActions.ts +++ b/src/vs/workbench/browser/parts/activitybar/activitybarActions.ts @@ -267,8 +267,8 @@ export class NextSideBarViewAction extends SwitchSideBarViewAction { } const registry = Registry.as(ActionExtensions.WorkbenchActions); -registry.registerWorkbenchAction(new SyncActionDescriptor(PreviousSideBarViewAction, PreviousSideBarViewAction.ID, PreviousSideBarViewAction.LABEL), 'View: Previous Side Bar View', nls.localize('view', "View")); -registry.registerWorkbenchAction(new SyncActionDescriptor(NextSideBarViewAction, NextSideBarViewAction.ID, NextSideBarViewAction.LABEL), 'View: Next Side Bar View', nls.localize('view', "View")); +registry.registerWorkbenchAction(SyncActionDescriptor.create(PreviousSideBarViewAction, PreviousSideBarViewAction.ID, PreviousSideBarViewAction.LABEL), 'View: Previous Side Bar View', nls.localize('view', "View")); +registry.registerWorkbenchAction(SyncActionDescriptor.create(NextSideBarViewAction, NextSideBarViewAction.ID, NextSideBarViewAction.LABEL), 'View: Next Side Bar View', nls.localize('view', "View")); registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => { diff --git a/src/vs/workbench/browser/parts/editor/editor.contribution.ts b/src/vs/workbench/browser/parts/editor/editor.contribution.ts index fe4d6da6b5881..2e25ce67d18cc 100644 --- a/src/vs/workbench/browser/parts/editor/editor.contribution.ts +++ b/src/vs/workbench/browser/parts/editor/editor.contribution.ts @@ -226,11 +226,11 @@ Registry.as(WorkbenchExtensions.Workbench).regi // Register Status Actions const registry = Registry.as(ActionExtensions.WorkbenchActions); -registry.registerWorkbenchAction(new SyncActionDescriptor(ChangeModeAction, ChangeModeAction.ID, ChangeModeAction.LABEL, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyCode.KEY_M) }), 'Change Language Mode'); -registry.registerWorkbenchAction(new SyncActionDescriptor(ChangeEOLAction, ChangeEOLAction.ID, ChangeEOLAction.LABEL), 'Change End of Line Sequence'); +registry.registerWorkbenchAction(SyncActionDescriptor.create(ChangeModeAction, ChangeModeAction.ID, ChangeModeAction.LABEL, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyCode.KEY_M) }), 'Change Language Mode'); +registry.registerWorkbenchAction(SyncActionDescriptor.create(ChangeEOLAction, ChangeEOLAction.ID, ChangeEOLAction.LABEL), 'Change End of Line Sequence'); if (Object.keys(SUPPORTED_ENCODINGS).length > 1) { - registry.registerWorkbenchAction(new SyncActionDescriptor(ChangeEncodingAction, ChangeEncodingAction.ID, ChangeEncodingAction.LABEL), 'Change File Encoding'); + registry.registerWorkbenchAction(SyncActionDescriptor.create(ChangeEncodingAction, ChangeEncodingAction.ID, ChangeEncodingAction.LABEL), 'Change File Encoding'); } export class QuickOpenActionContributor extends ActionBarContributor { @@ -312,84 +312,84 @@ Registry.as(QuickOpenExtensions.Quickopen).registerQuickOpen // Register Editor Actions const category = nls.localize('view', "View"); -registry.registerWorkbenchAction(new SyncActionDescriptor(OpenNextEditorInGroup, OpenNextEditorInGroup.ID, OpenNextEditorInGroup.LABEL), 'View: Open Next Editor in Group', category); -registry.registerWorkbenchAction(new SyncActionDescriptor(OpenPreviousEditorInGroup, OpenPreviousEditorInGroup.ID, OpenPreviousEditorInGroup.LABEL), 'View: Open Previous Editor in Group', category); -registry.registerWorkbenchAction(new SyncActionDescriptor(OpenLastEditorInGroup, OpenLastEditorInGroup.ID, OpenLastEditorInGroup.LABEL, { primary: KeyMod.Alt | KeyCode.KEY_0, secondary: [KeyMod.CtrlCmd | KeyCode.KEY_9], mac: { primary: KeyMod.WinCtrl | KeyCode.KEY_0, secondary: [KeyMod.CtrlCmd | KeyCode.KEY_9] } }), 'View: Open Last Editor in Group', category); -registry.registerWorkbenchAction(new SyncActionDescriptor(OpenFirstEditorInGroup, OpenFirstEditorInGroup.ID, OpenFirstEditorInGroup.LABEL), 'View: Open First Editor in Group', category); -registry.registerWorkbenchAction(new SyncActionDescriptor(OpenNextRecentlyUsedEditorAction, OpenNextRecentlyUsedEditorAction.ID, OpenNextRecentlyUsedEditorAction.LABEL), 'View: Open Next Recently Used Editor', category); -registry.registerWorkbenchAction(new SyncActionDescriptor(OpenPreviousRecentlyUsedEditorAction, OpenPreviousRecentlyUsedEditorAction.ID, OpenPreviousRecentlyUsedEditorAction.LABEL), 'View: Open Previous Recently Used Editor', category); -registry.registerWorkbenchAction(new SyncActionDescriptor(ShowAllEditorsAction, ShowAllEditorsAction.ID, ShowAllEditorsAction.LABEL, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.KEY_P), mac: { primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.Tab } }), 'View: Show All Editors', category); -registry.registerWorkbenchAction(new SyncActionDescriptor(ShowEditorsInActiveGroupAction, ShowEditorsInActiveGroupAction.ID, ShowEditorsInActiveGroupAction.LABEL), 'View: Show Editors in Active Group', category); -registry.registerWorkbenchAction(new SyncActionDescriptor(OpenNextEditor, OpenNextEditor.ID, OpenNextEditor.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.PageDown, mac: { primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.RightArrow, secondary: [KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.US_CLOSE_SQUARE_BRACKET] } }), 'View: Open Next Editor', category); -registry.registerWorkbenchAction(new SyncActionDescriptor(OpenPreviousEditor, OpenPreviousEditor.ID, OpenPreviousEditor.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.PageUp, mac: { primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.LeftArrow, secondary: [KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.US_OPEN_SQUARE_BRACKET] } }), 'View: Open Previous Editor', category); -registry.registerWorkbenchAction(new SyncActionDescriptor(ReopenClosedEditorAction, ReopenClosedEditorAction.ID, ReopenClosedEditorAction.LABEL, { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_T }), 'View: Reopen Closed Editor', category); -registry.registerWorkbenchAction(new SyncActionDescriptor(ClearRecentFilesAction, ClearRecentFilesAction.ID, ClearRecentFilesAction.LABEL), 'File: Clear Recently Opened', nls.localize('file', "File")); -registry.registerWorkbenchAction(new SyncActionDescriptor(CloseAllEditorsAction, CloseAllEditorsAction.ID, CloseAllEditorsAction.LABEL, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.KEY_W) }), 'View: Close All Editors', category); -registry.registerWorkbenchAction(new SyncActionDescriptor(CloseAllEditorGroupsAction, CloseAllEditorGroupsAction.ID, CloseAllEditorGroupsAction.LABEL, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_W) }), 'View: Close All Editor Groups', category); -registry.registerWorkbenchAction(new SyncActionDescriptor(CloseLeftEditorsInGroupAction, CloseLeftEditorsInGroupAction.ID, CloseLeftEditorsInGroupAction.LABEL), 'View: Close Editors to the Left in Group', category); -registry.registerWorkbenchAction(new SyncActionDescriptor(CloseEditorsInOtherGroupsAction, CloseEditorsInOtherGroupsAction.ID, CloseEditorsInOtherGroupsAction.LABEL), 'View: Close Editors in Other Groups', category); -registry.registerWorkbenchAction(new SyncActionDescriptor(CloseEditorInAllGroupsAction, CloseEditorInAllGroupsAction.ID, CloseEditorInAllGroupsAction.LABEL), 'View: Close Editor in All Groups', category); -registry.registerWorkbenchAction(new SyncActionDescriptor(SplitEditorAction, SplitEditorAction.ID, SplitEditorAction.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.US_BACKSLASH }), 'View: Split Editor', category); -registry.registerWorkbenchAction(new SyncActionDescriptor(SplitEditorOrthogonalAction, SplitEditorOrthogonalAction.ID, SplitEditorOrthogonalAction.LABEL, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.US_BACKSLASH) }), 'View: Split Editor Orthogonal', category); -registry.registerWorkbenchAction(new SyncActionDescriptor(SplitEditorLeftAction, SplitEditorLeftAction.ID, SplitEditorLeftAction.LABEL), 'View: Split Editor Left', category); -registry.registerWorkbenchAction(new SyncActionDescriptor(SplitEditorRightAction, SplitEditorRightAction.ID, SplitEditorRightAction.LABEL), 'View: Split Editor Right', category); -registry.registerWorkbenchAction(new SyncActionDescriptor(SplitEditorUpAction, SplitEditorUpAction.ID, SplitEditorUpAction.LABEL), 'Split Editor Up', category); -registry.registerWorkbenchAction(new SyncActionDescriptor(SplitEditorDownAction, SplitEditorDownAction.ID, SplitEditorDownAction.LABEL), 'View: Split Editor Down', category); -registry.registerWorkbenchAction(new SyncActionDescriptor(JoinTwoGroupsAction, JoinTwoGroupsAction.ID, JoinTwoGroupsAction.LABEL), 'View: Join Editor Group with Next Group', category); -registry.registerWorkbenchAction(new SyncActionDescriptor(JoinAllGroupsAction, JoinAllGroupsAction.ID, JoinAllGroupsAction.LABEL), 'View: Join All Editor Groups', category); -registry.registerWorkbenchAction(new SyncActionDescriptor(NavigateBetweenGroupsAction, NavigateBetweenGroupsAction.ID, NavigateBetweenGroupsAction.LABEL), 'View: Navigate Between Editor Groups', category); -registry.registerWorkbenchAction(new SyncActionDescriptor(ResetGroupSizesAction, ResetGroupSizesAction.ID, ResetGroupSizesAction.LABEL), 'View: Reset Editor Group Sizes', category); -registry.registerWorkbenchAction(new SyncActionDescriptor(ToggleGroupSizesAction, ToggleGroupSizesAction.ID, ToggleGroupSizesAction.LABEL), 'View: Toggle Editor Group Sizes', category); -registry.registerWorkbenchAction(new SyncActionDescriptor(MaximizeGroupAction, MaximizeGroupAction.ID, MaximizeGroupAction.LABEL), 'View: Maximize Editor Group and Hide Side Bar', category); -registry.registerWorkbenchAction(new SyncActionDescriptor(MinimizeOtherGroupsAction, MinimizeOtherGroupsAction.ID, MinimizeOtherGroupsAction.LABEL), 'View: Maximize Editor Group', category); -registry.registerWorkbenchAction(new SyncActionDescriptor(MoveEditorLeftInGroupAction, MoveEditorLeftInGroupAction.ID, MoveEditorLeftInGroupAction.LABEL, { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.PageUp, mac: { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.LeftArrow) } }), 'View: Move Editor Left', category); -registry.registerWorkbenchAction(new SyncActionDescriptor(MoveEditorRightInGroupAction, MoveEditorRightInGroupAction.ID, MoveEditorRightInGroupAction.LABEL, { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.PageDown, mac: { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.RightArrow) } }), 'View: Move Editor Right', category); -registry.registerWorkbenchAction(new SyncActionDescriptor(MoveGroupLeftAction, MoveGroupLeftAction.ID, MoveGroupLeftAction.LABEL, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyCode.LeftArrow) }), 'View: Move Editor Group Left', category); -registry.registerWorkbenchAction(new SyncActionDescriptor(MoveGroupRightAction, MoveGroupRightAction.ID, MoveGroupRightAction.LABEL, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyCode.RightArrow) }), 'View: Move Editor Group Right', category); -registry.registerWorkbenchAction(new SyncActionDescriptor(MoveGroupUpAction, MoveGroupUpAction.ID, MoveGroupUpAction.LABEL, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyCode.UpArrow) }), 'View: Move Editor Group Up', category); -registry.registerWorkbenchAction(new SyncActionDescriptor(MoveGroupDownAction, MoveGroupDownAction.ID, MoveGroupDownAction.LABEL, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyCode.DownArrow) }), 'View: Move Editor Group Down', category); -registry.registerWorkbenchAction(new SyncActionDescriptor(MoveEditorToPreviousGroupAction, MoveEditorToPreviousGroupAction.ID, MoveEditorToPreviousGroupAction.LABEL, { primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.LeftArrow, mac: { primary: KeyMod.CtrlCmd | KeyMod.WinCtrl | KeyCode.LeftArrow } }), 'View: Move Editor into Previous Group', category); -registry.registerWorkbenchAction(new SyncActionDescriptor(MoveEditorToNextGroupAction, MoveEditorToNextGroupAction.ID, MoveEditorToNextGroupAction.LABEL, { primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.RightArrow, mac: { primary: KeyMod.CtrlCmd | KeyMod.WinCtrl | KeyCode.RightArrow } }), 'View: Move Editor into Next Group', category); -registry.registerWorkbenchAction(new SyncActionDescriptor(MoveEditorToFirstGroupAction, MoveEditorToFirstGroupAction.ID, MoveEditorToFirstGroupAction.LABEL, { primary: KeyMod.Shift | KeyMod.Alt | KeyCode.KEY_1, mac: { primary: KeyMod.CtrlCmd | KeyMod.WinCtrl | KeyCode.KEY_1 } }), 'View: Move Editor into First Group', category); -registry.registerWorkbenchAction(new SyncActionDescriptor(MoveEditorToLastGroupAction, MoveEditorToLastGroupAction.ID, MoveEditorToLastGroupAction.LABEL, { primary: KeyMod.Shift | KeyMod.Alt | KeyCode.KEY_9, mac: { primary: KeyMod.CtrlCmd | KeyMod.WinCtrl | KeyCode.KEY_9 } }), 'View: Move Editor into Last Group', category); -registry.registerWorkbenchAction(new SyncActionDescriptor(MoveEditorToLeftGroupAction, MoveEditorToLeftGroupAction.ID, MoveEditorToLeftGroupAction.LABEL), 'View: Move Editor into Left Group', category); -registry.registerWorkbenchAction(new SyncActionDescriptor(MoveEditorToRightGroupAction, MoveEditorToRightGroupAction.ID, MoveEditorToRightGroupAction.LABEL), 'View: Move Editor into Right Group', category); -registry.registerWorkbenchAction(new SyncActionDescriptor(MoveEditorToAboveGroupAction, MoveEditorToAboveGroupAction.ID, MoveEditorToAboveGroupAction.LABEL), 'View: Move Editor into Above Group', category); -registry.registerWorkbenchAction(new SyncActionDescriptor(MoveEditorToBelowGroupAction, MoveEditorToBelowGroupAction.ID, MoveEditorToBelowGroupAction.LABEL), 'View: Move Editor into Below Group', category); -registry.registerWorkbenchAction(new SyncActionDescriptor(FocusActiveGroupAction, FocusActiveGroupAction.ID, FocusActiveGroupAction.LABEL), 'View: Focus Active Editor Group', category); -registry.registerWorkbenchAction(new SyncActionDescriptor(FocusFirstGroupAction, FocusFirstGroupAction.ID, FocusFirstGroupAction.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.KEY_1 }), 'View: Focus First Editor Group', category); -registry.registerWorkbenchAction(new SyncActionDescriptor(FocusLastGroupAction, FocusLastGroupAction.ID, FocusLastGroupAction.LABEL), 'View: Focus Last Editor Group', category); -registry.registerWorkbenchAction(new SyncActionDescriptor(FocusPreviousGroup, FocusPreviousGroup.ID, FocusPreviousGroup.LABEL), 'View: Focus Previous Editor Group', category); -registry.registerWorkbenchAction(new SyncActionDescriptor(FocusNextGroup, FocusNextGroup.ID, FocusNextGroup.LABEL), 'View: Focus Next Editor Group', category); -registry.registerWorkbenchAction(new SyncActionDescriptor(FocusLeftGroup, FocusLeftGroup.ID, FocusLeftGroup.LABEL, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.LeftArrow) }), 'View: Focus Left Editor Group', category); -registry.registerWorkbenchAction(new SyncActionDescriptor(FocusRightGroup, FocusRightGroup.ID, FocusRightGroup.LABEL, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.RightArrow) }), 'View: Focus Right Editor Group', category); -registry.registerWorkbenchAction(new SyncActionDescriptor(FocusAboveGroup, FocusAboveGroup.ID, FocusAboveGroup.LABEL, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.UpArrow) }), 'View: Focus Above Editor Group', category); -registry.registerWorkbenchAction(new SyncActionDescriptor(FocusBelowGroup, FocusBelowGroup.ID, FocusBelowGroup.LABEL, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.DownArrow) }), 'View: Focus Below Editor Group', category); -registry.registerWorkbenchAction(new SyncActionDescriptor(NewEditorGroupLeftAction, NewEditorGroupLeftAction.ID, NewEditorGroupLeftAction.LABEL), 'View: New Editor Group to the Left', category); -registry.registerWorkbenchAction(new SyncActionDescriptor(NewEditorGroupRightAction, NewEditorGroupRightAction.ID, NewEditorGroupRightAction.LABEL), 'View: New Editor Group to the Right', category); -registry.registerWorkbenchAction(new SyncActionDescriptor(NewEditorGroupAboveAction, NewEditorGroupAboveAction.ID, NewEditorGroupAboveAction.LABEL), 'View: New Editor Group Above', category); -registry.registerWorkbenchAction(new SyncActionDescriptor(NewEditorGroupBelowAction, NewEditorGroupBelowAction.ID, NewEditorGroupBelowAction.LABEL), 'View: New Editor Group Below', category); -registry.registerWorkbenchAction(new SyncActionDescriptor(NavigateForwardAction, NavigateForwardAction.ID, NavigateForwardAction.LABEL, { primary: 0, win: { primary: KeyMod.Alt | KeyCode.RightArrow }, mac: { primary: KeyMod.WinCtrl | KeyMod.Shift | KeyCode.US_MINUS }, linux: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.US_MINUS } }), 'Go Forward'); -registry.registerWorkbenchAction(new SyncActionDescriptor(NavigateBackwardsAction, NavigateBackwardsAction.ID, NavigateBackwardsAction.LABEL, { primary: 0, win: { primary: KeyMod.Alt | KeyCode.LeftArrow }, mac: { primary: KeyMod.WinCtrl | KeyCode.US_MINUS }, linux: { primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.US_MINUS } }), 'Go Back'); -registry.registerWorkbenchAction(new SyncActionDescriptor(NavigateToLastEditLocationAction, NavigateToLastEditLocationAction.ID, NavigateToLastEditLocationAction.LABEL, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.KEY_Q) }), 'Go to Last Edit Location'); -registry.registerWorkbenchAction(new SyncActionDescriptor(NavigateLastAction, NavigateLastAction.ID, NavigateLastAction.LABEL), 'Go Last'); -registry.registerWorkbenchAction(new SyncActionDescriptor(OpenPreviousEditorFromHistoryAction, OpenPreviousEditorFromHistoryAction.ID, OpenPreviousEditorFromHistoryAction.LABEL), 'Open Previous Editor from History'); -registry.registerWorkbenchAction(new SyncActionDescriptor(ClearEditorHistoryAction, ClearEditorHistoryAction.ID, ClearEditorHistoryAction.LABEL), 'Clear Editor History'); -registry.registerWorkbenchAction(new SyncActionDescriptor(RevertAndCloseEditorAction, RevertAndCloseEditorAction.ID, RevertAndCloseEditorAction.LABEL), 'View: Revert and Close Editor', category); -registry.registerWorkbenchAction(new SyncActionDescriptor(EditorLayoutSingleAction, EditorLayoutSingleAction.ID, EditorLayoutSingleAction.LABEL), 'View: Single Column Editor Layout', category); -registry.registerWorkbenchAction(new SyncActionDescriptor(EditorLayoutTwoColumnsAction, EditorLayoutTwoColumnsAction.ID, EditorLayoutTwoColumnsAction.LABEL), 'View: Two Columns Editor Layout', category); -registry.registerWorkbenchAction(new SyncActionDescriptor(EditorLayoutThreeColumnsAction, EditorLayoutThreeColumnsAction.ID, EditorLayoutThreeColumnsAction.LABEL), 'View: Three Columns Editor Layout', category); -registry.registerWorkbenchAction(new SyncActionDescriptor(EditorLayoutTwoRowsAction, EditorLayoutTwoRowsAction.ID, EditorLayoutTwoRowsAction.LABEL), 'View: Two Rows Editor Layout', category); -registry.registerWorkbenchAction(new SyncActionDescriptor(EditorLayoutThreeRowsAction, EditorLayoutThreeRowsAction.ID, EditorLayoutThreeRowsAction.LABEL), 'View: Three Rows Editor Layout', category); -registry.registerWorkbenchAction(new SyncActionDescriptor(EditorLayoutTwoByTwoGridAction, EditorLayoutTwoByTwoGridAction.ID, EditorLayoutTwoByTwoGridAction.LABEL), 'View: Grid Editor Layout (2x2)', category); -registry.registerWorkbenchAction(new SyncActionDescriptor(EditorLayoutTwoRowsRightAction, EditorLayoutTwoRowsRightAction.ID, EditorLayoutTwoRowsRightAction.LABEL), 'View: Two Rows Right Editor Layout', category); -registry.registerWorkbenchAction(new SyncActionDescriptor(EditorLayoutTwoColumnsBottomAction, EditorLayoutTwoColumnsBottomAction.ID, EditorLayoutTwoColumnsBottomAction.LABEL), 'View: Two Columns Bottom Editor Layout', category); +registry.registerWorkbenchAction(SyncActionDescriptor.create(OpenNextEditorInGroup, OpenNextEditorInGroup.ID, OpenNextEditorInGroup.LABEL), 'View: Open Next Editor in Group', category); +registry.registerWorkbenchAction(SyncActionDescriptor.create(OpenPreviousEditorInGroup, OpenPreviousEditorInGroup.ID, OpenPreviousEditorInGroup.LABEL), 'View: Open Previous Editor in Group', category); +registry.registerWorkbenchAction(SyncActionDescriptor.create(OpenLastEditorInGroup, OpenLastEditorInGroup.ID, OpenLastEditorInGroup.LABEL, { primary: KeyMod.Alt | KeyCode.KEY_0, secondary: [KeyMod.CtrlCmd | KeyCode.KEY_9], mac: { primary: KeyMod.WinCtrl | KeyCode.KEY_0, secondary: [KeyMod.CtrlCmd | KeyCode.KEY_9] } }), 'View: Open Last Editor in Group', category); +registry.registerWorkbenchAction(SyncActionDescriptor.create(OpenFirstEditorInGroup, OpenFirstEditorInGroup.ID, OpenFirstEditorInGroup.LABEL), 'View: Open First Editor in Group', category); +registry.registerWorkbenchAction(SyncActionDescriptor.create(OpenNextRecentlyUsedEditorAction, OpenNextRecentlyUsedEditorAction.ID, OpenNextRecentlyUsedEditorAction.LABEL), 'View: Open Next Recently Used Editor', category); +registry.registerWorkbenchAction(SyncActionDescriptor.create(OpenPreviousRecentlyUsedEditorAction, OpenPreviousRecentlyUsedEditorAction.ID, OpenPreviousRecentlyUsedEditorAction.LABEL), 'View: Open Previous Recently Used Editor', category); +registry.registerWorkbenchAction(SyncActionDescriptor.create(ShowAllEditorsAction, ShowAllEditorsAction.ID, ShowAllEditorsAction.LABEL, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.KEY_P), mac: { primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.Tab } }), 'View: Show All Editors', category); +registry.registerWorkbenchAction(SyncActionDescriptor.create(ShowEditorsInActiveGroupAction, ShowEditorsInActiveGroupAction.ID, ShowEditorsInActiveGroupAction.LABEL), 'View: Show Editors in Active Group', category); +registry.registerWorkbenchAction(SyncActionDescriptor.create(OpenNextEditor, OpenNextEditor.ID, OpenNextEditor.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.PageDown, mac: { primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.RightArrow, secondary: [KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.US_CLOSE_SQUARE_BRACKET] } }), 'View: Open Next Editor', category); +registry.registerWorkbenchAction(SyncActionDescriptor.create(OpenPreviousEditor, OpenPreviousEditor.ID, OpenPreviousEditor.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.PageUp, mac: { primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.LeftArrow, secondary: [KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.US_OPEN_SQUARE_BRACKET] } }), 'View: Open Previous Editor', category); +registry.registerWorkbenchAction(SyncActionDescriptor.create(ReopenClosedEditorAction, ReopenClosedEditorAction.ID, ReopenClosedEditorAction.LABEL, { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_T }), 'View: Reopen Closed Editor', category); +registry.registerWorkbenchAction(SyncActionDescriptor.create(ClearRecentFilesAction, ClearRecentFilesAction.ID, ClearRecentFilesAction.LABEL), 'File: Clear Recently Opened', nls.localize('file', "File")); +registry.registerWorkbenchAction(SyncActionDescriptor.create(CloseAllEditorsAction, CloseAllEditorsAction.ID, CloseAllEditorsAction.LABEL, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.KEY_W) }), 'View: Close All Editors', category); +registry.registerWorkbenchAction(SyncActionDescriptor.create(CloseAllEditorGroupsAction, CloseAllEditorGroupsAction.ID, CloseAllEditorGroupsAction.LABEL, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_W) }), 'View: Close All Editor Groups', category); +registry.registerWorkbenchAction(SyncActionDescriptor.create(CloseLeftEditorsInGroupAction, CloseLeftEditorsInGroupAction.ID, CloseLeftEditorsInGroupAction.LABEL), 'View: Close Editors to the Left in Group', category); +registry.registerWorkbenchAction(SyncActionDescriptor.create(CloseEditorsInOtherGroupsAction, CloseEditorsInOtherGroupsAction.ID, CloseEditorsInOtherGroupsAction.LABEL), 'View: Close Editors in Other Groups', category); +registry.registerWorkbenchAction(SyncActionDescriptor.create(CloseEditorInAllGroupsAction, CloseEditorInAllGroupsAction.ID, CloseEditorInAllGroupsAction.LABEL), 'View: Close Editor in All Groups', category); +registry.registerWorkbenchAction(SyncActionDescriptor.create(SplitEditorAction, SplitEditorAction.ID, SplitEditorAction.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.US_BACKSLASH }), 'View: Split Editor', category); +registry.registerWorkbenchAction(SyncActionDescriptor.create(SplitEditorOrthogonalAction, SplitEditorOrthogonalAction.ID, SplitEditorOrthogonalAction.LABEL, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.US_BACKSLASH) }), 'View: Split Editor Orthogonal', category); +registry.registerWorkbenchAction(SyncActionDescriptor.create(SplitEditorLeftAction, SplitEditorLeftAction.ID, SplitEditorLeftAction.LABEL), 'View: Split Editor Left', category); +registry.registerWorkbenchAction(SyncActionDescriptor.create(SplitEditorRightAction, SplitEditorRightAction.ID, SplitEditorRightAction.LABEL), 'View: Split Editor Right', category); +registry.registerWorkbenchAction(SyncActionDescriptor.create(SplitEditorUpAction, SplitEditorUpAction.ID, SplitEditorUpAction.LABEL), 'Split Editor Up', category); +registry.registerWorkbenchAction(SyncActionDescriptor.create(SplitEditorDownAction, SplitEditorDownAction.ID, SplitEditorDownAction.LABEL), 'View: Split Editor Down', category); +registry.registerWorkbenchAction(SyncActionDescriptor.create(JoinTwoGroupsAction, JoinTwoGroupsAction.ID, JoinTwoGroupsAction.LABEL), 'View: Join Editor Group with Next Group', category); +registry.registerWorkbenchAction(SyncActionDescriptor.create(JoinAllGroupsAction, JoinAllGroupsAction.ID, JoinAllGroupsAction.LABEL), 'View: Join All Editor Groups', category); +registry.registerWorkbenchAction(SyncActionDescriptor.create(NavigateBetweenGroupsAction, NavigateBetweenGroupsAction.ID, NavigateBetweenGroupsAction.LABEL), 'View: Navigate Between Editor Groups', category); +registry.registerWorkbenchAction(SyncActionDescriptor.create(ResetGroupSizesAction, ResetGroupSizesAction.ID, ResetGroupSizesAction.LABEL), 'View: Reset Editor Group Sizes', category); +registry.registerWorkbenchAction(SyncActionDescriptor.create(ToggleGroupSizesAction, ToggleGroupSizesAction.ID, ToggleGroupSizesAction.LABEL), 'View: Toggle Editor Group Sizes', category); +registry.registerWorkbenchAction(SyncActionDescriptor.create(MaximizeGroupAction, MaximizeGroupAction.ID, MaximizeGroupAction.LABEL), 'View: Maximize Editor Group and Hide Side Bar', category); +registry.registerWorkbenchAction(SyncActionDescriptor.create(MinimizeOtherGroupsAction, MinimizeOtherGroupsAction.ID, MinimizeOtherGroupsAction.LABEL), 'View: Maximize Editor Group', category); +registry.registerWorkbenchAction(SyncActionDescriptor.create(MoveEditorLeftInGroupAction, MoveEditorLeftInGroupAction.ID, MoveEditorLeftInGroupAction.LABEL, { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.PageUp, mac: { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.LeftArrow) } }), 'View: Move Editor Left', category); +registry.registerWorkbenchAction(SyncActionDescriptor.create(MoveEditorRightInGroupAction, MoveEditorRightInGroupAction.ID, MoveEditorRightInGroupAction.LABEL, { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.PageDown, mac: { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.RightArrow) } }), 'View: Move Editor Right', category); +registry.registerWorkbenchAction(SyncActionDescriptor.create(MoveGroupLeftAction, MoveGroupLeftAction.ID, MoveGroupLeftAction.LABEL, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyCode.LeftArrow) }), 'View: Move Editor Group Left', category); +registry.registerWorkbenchAction(SyncActionDescriptor.create(MoveGroupRightAction, MoveGroupRightAction.ID, MoveGroupRightAction.LABEL, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyCode.RightArrow) }), 'View: Move Editor Group Right', category); +registry.registerWorkbenchAction(SyncActionDescriptor.create(MoveGroupUpAction, MoveGroupUpAction.ID, MoveGroupUpAction.LABEL, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyCode.UpArrow) }), 'View: Move Editor Group Up', category); +registry.registerWorkbenchAction(SyncActionDescriptor.create(MoveGroupDownAction, MoveGroupDownAction.ID, MoveGroupDownAction.LABEL, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyCode.DownArrow) }), 'View: Move Editor Group Down', category); +registry.registerWorkbenchAction(SyncActionDescriptor.create(MoveEditorToPreviousGroupAction, MoveEditorToPreviousGroupAction.ID, MoveEditorToPreviousGroupAction.LABEL, { primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.LeftArrow, mac: { primary: KeyMod.CtrlCmd | KeyMod.WinCtrl | KeyCode.LeftArrow } }), 'View: Move Editor into Previous Group', category); +registry.registerWorkbenchAction(SyncActionDescriptor.create(MoveEditorToNextGroupAction, MoveEditorToNextGroupAction.ID, MoveEditorToNextGroupAction.LABEL, { primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.RightArrow, mac: { primary: KeyMod.CtrlCmd | KeyMod.WinCtrl | KeyCode.RightArrow } }), 'View: Move Editor into Next Group', category); +registry.registerWorkbenchAction(SyncActionDescriptor.create(MoveEditorToFirstGroupAction, MoveEditorToFirstGroupAction.ID, MoveEditorToFirstGroupAction.LABEL, { primary: KeyMod.Shift | KeyMod.Alt | KeyCode.KEY_1, mac: { primary: KeyMod.CtrlCmd | KeyMod.WinCtrl | KeyCode.KEY_1 } }), 'View: Move Editor into First Group', category); +registry.registerWorkbenchAction(SyncActionDescriptor.create(MoveEditorToLastGroupAction, MoveEditorToLastGroupAction.ID, MoveEditorToLastGroupAction.LABEL, { primary: KeyMod.Shift | KeyMod.Alt | KeyCode.KEY_9, mac: { primary: KeyMod.CtrlCmd | KeyMod.WinCtrl | KeyCode.KEY_9 } }), 'View: Move Editor into Last Group', category); +registry.registerWorkbenchAction(SyncActionDescriptor.create(MoveEditorToLeftGroupAction, MoveEditorToLeftGroupAction.ID, MoveEditorToLeftGroupAction.LABEL), 'View: Move Editor into Left Group', category); +registry.registerWorkbenchAction(SyncActionDescriptor.create(MoveEditorToRightGroupAction, MoveEditorToRightGroupAction.ID, MoveEditorToRightGroupAction.LABEL), 'View: Move Editor into Right Group', category); +registry.registerWorkbenchAction(SyncActionDescriptor.create(MoveEditorToAboveGroupAction, MoveEditorToAboveGroupAction.ID, MoveEditorToAboveGroupAction.LABEL), 'View: Move Editor into Above Group', category); +registry.registerWorkbenchAction(SyncActionDescriptor.create(MoveEditorToBelowGroupAction, MoveEditorToBelowGroupAction.ID, MoveEditorToBelowGroupAction.LABEL), 'View: Move Editor into Below Group', category); +registry.registerWorkbenchAction(SyncActionDescriptor.create(FocusActiveGroupAction, FocusActiveGroupAction.ID, FocusActiveGroupAction.LABEL), 'View: Focus Active Editor Group', category); +registry.registerWorkbenchAction(SyncActionDescriptor.create(FocusFirstGroupAction, FocusFirstGroupAction.ID, FocusFirstGroupAction.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.KEY_1 }), 'View: Focus First Editor Group', category); +registry.registerWorkbenchAction(SyncActionDescriptor.create(FocusLastGroupAction, FocusLastGroupAction.ID, FocusLastGroupAction.LABEL), 'View: Focus Last Editor Group', category); +registry.registerWorkbenchAction(SyncActionDescriptor.create(FocusPreviousGroup, FocusPreviousGroup.ID, FocusPreviousGroup.LABEL), 'View: Focus Previous Editor Group', category); +registry.registerWorkbenchAction(SyncActionDescriptor.create(FocusNextGroup, FocusNextGroup.ID, FocusNextGroup.LABEL), 'View: Focus Next Editor Group', category); +registry.registerWorkbenchAction(SyncActionDescriptor.create(FocusLeftGroup, FocusLeftGroup.ID, FocusLeftGroup.LABEL, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.LeftArrow) }), 'View: Focus Left Editor Group', category); +registry.registerWorkbenchAction(SyncActionDescriptor.create(FocusRightGroup, FocusRightGroup.ID, FocusRightGroup.LABEL, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.RightArrow) }), 'View: Focus Right Editor Group', category); +registry.registerWorkbenchAction(SyncActionDescriptor.create(FocusAboveGroup, FocusAboveGroup.ID, FocusAboveGroup.LABEL, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.UpArrow) }), 'View: Focus Above Editor Group', category); +registry.registerWorkbenchAction(SyncActionDescriptor.create(FocusBelowGroup, FocusBelowGroup.ID, FocusBelowGroup.LABEL, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.DownArrow) }), 'View: Focus Below Editor Group', category); +registry.registerWorkbenchAction(SyncActionDescriptor.create(NewEditorGroupLeftAction, NewEditorGroupLeftAction.ID, NewEditorGroupLeftAction.LABEL), 'View: New Editor Group to the Left', category); +registry.registerWorkbenchAction(SyncActionDescriptor.create(NewEditorGroupRightAction, NewEditorGroupRightAction.ID, NewEditorGroupRightAction.LABEL), 'View: New Editor Group to the Right', category); +registry.registerWorkbenchAction(SyncActionDescriptor.create(NewEditorGroupAboveAction, NewEditorGroupAboveAction.ID, NewEditorGroupAboveAction.LABEL), 'View: New Editor Group Above', category); +registry.registerWorkbenchAction(SyncActionDescriptor.create(NewEditorGroupBelowAction, NewEditorGroupBelowAction.ID, NewEditorGroupBelowAction.LABEL), 'View: New Editor Group Below', category); +registry.registerWorkbenchAction(SyncActionDescriptor.create(NavigateForwardAction, NavigateForwardAction.ID, NavigateForwardAction.LABEL, { primary: 0, win: { primary: KeyMod.Alt | KeyCode.RightArrow }, mac: { primary: KeyMod.WinCtrl | KeyMod.Shift | KeyCode.US_MINUS }, linux: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.US_MINUS } }), 'Go Forward'); +registry.registerWorkbenchAction(SyncActionDescriptor.create(NavigateBackwardsAction, NavigateBackwardsAction.ID, NavigateBackwardsAction.LABEL, { primary: 0, win: { primary: KeyMod.Alt | KeyCode.LeftArrow }, mac: { primary: KeyMod.WinCtrl | KeyCode.US_MINUS }, linux: { primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.US_MINUS } }), 'Go Back'); +registry.registerWorkbenchAction(SyncActionDescriptor.create(NavigateToLastEditLocationAction, NavigateToLastEditLocationAction.ID, NavigateToLastEditLocationAction.LABEL, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.KEY_Q) }), 'Go to Last Edit Location'); +registry.registerWorkbenchAction(SyncActionDescriptor.create(NavigateLastAction, NavigateLastAction.ID, NavigateLastAction.LABEL), 'Go Last'); +registry.registerWorkbenchAction(SyncActionDescriptor.create(OpenPreviousEditorFromHistoryAction, OpenPreviousEditorFromHistoryAction.ID, OpenPreviousEditorFromHistoryAction.LABEL), 'Open Previous Editor from History'); +registry.registerWorkbenchAction(SyncActionDescriptor.create(ClearEditorHistoryAction, ClearEditorHistoryAction.ID, ClearEditorHistoryAction.LABEL), 'Clear Editor History'); +registry.registerWorkbenchAction(SyncActionDescriptor.create(RevertAndCloseEditorAction, RevertAndCloseEditorAction.ID, RevertAndCloseEditorAction.LABEL), 'View: Revert and Close Editor', category); +registry.registerWorkbenchAction(SyncActionDescriptor.create(EditorLayoutSingleAction, EditorLayoutSingleAction.ID, EditorLayoutSingleAction.LABEL), 'View: Single Column Editor Layout', category); +registry.registerWorkbenchAction(SyncActionDescriptor.create(EditorLayoutTwoColumnsAction, EditorLayoutTwoColumnsAction.ID, EditorLayoutTwoColumnsAction.LABEL), 'View: Two Columns Editor Layout', category); +registry.registerWorkbenchAction(SyncActionDescriptor.create(EditorLayoutThreeColumnsAction, EditorLayoutThreeColumnsAction.ID, EditorLayoutThreeColumnsAction.LABEL), 'View: Three Columns Editor Layout', category); +registry.registerWorkbenchAction(SyncActionDescriptor.create(EditorLayoutTwoRowsAction, EditorLayoutTwoRowsAction.ID, EditorLayoutTwoRowsAction.LABEL), 'View: Two Rows Editor Layout', category); +registry.registerWorkbenchAction(SyncActionDescriptor.create(EditorLayoutThreeRowsAction, EditorLayoutThreeRowsAction.ID, EditorLayoutThreeRowsAction.LABEL), 'View: Three Rows Editor Layout', category); +registry.registerWorkbenchAction(SyncActionDescriptor.create(EditorLayoutTwoByTwoGridAction, EditorLayoutTwoByTwoGridAction.ID, EditorLayoutTwoByTwoGridAction.LABEL), 'View: Grid Editor Layout (2x2)', category); +registry.registerWorkbenchAction(SyncActionDescriptor.create(EditorLayoutTwoRowsRightAction, EditorLayoutTwoRowsRightAction.ID, EditorLayoutTwoRowsRightAction.LABEL), 'View: Two Rows Right Editor Layout', category); +registry.registerWorkbenchAction(SyncActionDescriptor.create(EditorLayoutTwoColumnsBottomAction, EditorLayoutTwoColumnsBottomAction.ID, EditorLayoutTwoColumnsBottomAction.LABEL), 'View: Two Columns Bottom Editor Layout', category); // Register Editor Picker Actions including quick navigate support const openNextEditorKeybinding = { primary: KeyMod.CtrlCmd | KeyCode.Tab, mac: { primary: KeyMod.WinCtrl | KeyCode.Tab } }; const openPreviousEditorKeybinding = { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.Tab, mac: { primary: KeyMod.WinCtrl | KeyMod.Shift | KeyCode.Tab } }; -registry.registerWorkbenchAction(new SyncActionDescriptor(OpenNextRecentlyUsedEditorInGroupAction, OpenNextRecentlyUsedEditorInGroupAction.ID, OpenNextRecentlyUsedEditorInGroupAction.LABEL, openNextEditorKeybinding), 'View: Open Next Recently Used Editor in Group', category); -registry.registerWorkbenchAction(new SyncActionDescriptor(OpenPreviousRecentlyUsedEditorInGroupAction, OpenPreviousRecentlyUsedEditorInGroupAction.ID, OpenPreviousRecentlyUsedEditorInGroupAction.LABEL, openPreviousEditorKeybinding), 'View: Open Previous Recently Used Editor in Group', category); +registry.registerWorkbenchAction(SyncActionDescriptor.create(OpenNextRecentlyUsedEditorInGroupAction, OpenNextRecentlyUsedEditorInGroupAction.ID, OpenNextRecentlyUsedEditorInGroupAction.LABEL, openNextEditorKeybinding), 'View: Open Next Recently Used Editor in Group', category); +registry.registerWorkbenchAction(SyncActionDescriptor.create(OpenPreviousRecentlyUsedEditorInGroupAction, OpenPreviousRecentlyUsedEditorInGroupAction.ID, OpenPreviousRecentlyUsedEditorInGroupAction.LABEL, openPreviousEditorKeybinding), 'View: Open Previous Recently Used Editor in Group', category); const quickOpenNavigateNextInEditorPickerId = 'workbench.action.quickOpenNavigateNextInEditorPicker'; KeybindingsRegistry.registerCommandAndKeybindingRule({ diff --git a/src/vs/workbench/browser/parts/panel/panelActions.ts b/src/vs/workbench/browser/parts/panel/panelActions.ts index 30de934006714..7c0ba38cc481d 100644 --- a/src/vs/workbench/browser/parts/panel/panelActions.ts +++ b/src/vs/workbench/browser/parts/panel/panelActions.ts @@ -243,14 +243,14 @@ export class NextPanelViewAction extends SwitchPanelViewAction { } const actionRegistry = Registry.as(WorkbenchExtensions.WorkbenchActions); -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(TogglePanelAction, TogglePanelAction.ID, TogglePanelAction.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.KEY_J }), 'View: Toggle Panel', nls.localize('view', "View")); -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(FocusPanelAction, FocusPanelAction.ID, FocusPanelAction.LABEL), 'View: Focus into Panel', nls.localize('view', "View")); -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ToggleMaximizedPanelAction, ToggleMaximizedPanelAction.ID, ToggleMaximizedPanelAction.LABEL), 'View: Toggle Maximized Panel', nls.localize('view', "View")); -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ClosePanelAction, ClosePanelAction.ID, ClosePanelAction.LABEL), 'View: Close Panel', nls.localize('view', "View")); -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(TogglePanelPositionAction, TogglePanelPositionAction.ID, TogglePanelPositionAction.LABEL), 'View: Toggle Panel Position', nls.localize('view', "View")); -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ToggleMaximizedPanelAction, ToggleMaximizedPanelAction.ID, undefined), 'View: Toggle Panel Position', nls.localize('view', "View")); -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(PreviousPanelViewAction, PreviousPanelViewAction.ID, PreviousPanelViewAction.LABEL), 'View: Previous Panel View', nls.localize('view', "View")); -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(NextPanelViewAction, NextPanelViewAction.ID, NextPanelViewAction.LABEL), 'View: Next Panel View', nls.localize('view', "View")); +actionRegistry.registerWorkbenchAction(SyncActionDescriptor.create(TogglePanelAction, TogglePanelAction.ID, TogglePanelAction.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.KEY_J }), 'View: Toggle Panel', nls.localize('view', "View")); +actionRegistry.registerWorkbenchAction(SyncActionDescriptor.create(FocusPanelAction, FocusPanelAction.ID, FocusPanelAction.LABEL), 'View: Focus into Panel', nls.localize('view', "View")); +actionRegistry.registerWorkbenchAction(SyncActionDescriptor.create(ToggleMaximizedPanelAction, ToggleMaximizedPanelAction.ID, ToggleMaximizedPanelAction.LABEL), 'View: Toggle Maximized Panel', nls.localize('view', "View")); +actionRegistry.registerWorkbenchAction(SyncActionDescriptor.create(ClosePanelAction, ClosePanelAction.ID, ClosePanelAction.LABEL), 'View: Close Panel', nls.localize('view', "View")); +actionRegistry.registerWorkbenchAction(SyncActionDescriptor.create(TogglePanelPositionAction, TogglePanelPositionAction.ID, TogglePanelPositionAction.LABEL), 'View: Toggle Panel Position', nls.localize('view', "View")); +actionRegistry.registerWorkbenchAction(SyncActionDescriptor.create(ToggleMaximizedPanelAction, ToggleMaximizedPanelAction.ID, undefined), 'View: Toggle Panel Position', nls.localize('view', "View")); +actionRegistry.registerWorkbenchAction(SyncActionDescriptor.create(PreviousPanelViewAction, PreviousPanelViewAction.ID, PreviousPanelViewAction.LABEL), 'View: Previous Panel View', nls.localize('view', "View")); +actionRegistry.registerWorkbenchAction(SyncActionDescriptor.create(NextPanelViewAction, NextPanelViewAction.ID, NextPanelViewAction.LABEL), 'View: Next Panel View', nls.localize('view', "View")); MenuRegistry.appendMenuItem(MenuId.MenubarAppearanceMenu, { group: '2_workbench_layout', diff --git a/src/vs/workbench/browser/parts/quickinput/quickInputActions.ts b/src/vs/workbench/browser/parts/quickinput/quickInputActions.ts index 04635f8493cdd..0e72c0e85765a 100644 --- a/src/vs/workbench/browser/parts/quickinput/quickInputActions.ts +++ b/src/vs/workbench/browser/parts/quickinput/quickInputActions.ts @@ -14,4 +14,4 @@ import { inQuickOpenContext } from 'vs/workbench/browser/parts/quickopen/quickop KeybindingsRegistry.registerCommandAndKeybindingRule(QuickPickManyToggle); const registry = Registry.as(ActionExtensions.WorkbenchActions); -registry.registerWorkbenchAction(new SyncActionDescriptor(BackAction, BackAction.ID, BackAction.LABEL, { primary: 0, win: { primary: KeyMod.Alt | KeyCode.LeftArrow }, mac: { primary: KeyMod.WinCtrl | KeyCode.US_MINUS }, linux: { primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.US_MINUS } }, inQuickOpenContext, KeybindingWeight.WorkbenchContrib + 50), 'Back'); +registry.registerWorkbenchAction(SyncActionDescriptor.create(BackAction, BackAction.ID, BackAction.LABEL, { primary: 0, win: { primary: KeyMod.Alt | KeyCode.LeftArrow }, mac: { primary: KeyMod.WinCtrl | KeyCode.US_MINUS }, linux: { primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.US_MINUS } }, inQuickOpenContext, KeybindingWeight.WorkbenchContrib + 50), 'Back'); diff --git a/src/vs/workbench/browser/parts/quickopen/quickOpenActions.ts b/src/vs/workbench/browser/parts/quickopen/quickOpenActions.ts index 6ff9d1b3496e9..0a8187a87592b 100644 --- a/src/vs/workbench/browser/parts/quickopen/quickOpenActions.ts +++ b/src/vs/workbench/browser/parts/quickopen/quickOpenActions.ts @@ -69,11 +69,11 @@ MenuRegistry.appendMenuItem(MenuId.CommandPalette, { command: { id: QUICKOPEN_ACTION_ID, title: { value: QUICKOPEN_ACION_LABEL, original: 'Go to File...' } } }); -registry.registerWorkbenchAction(new SyncActionDescriptor(QuickOpenSelectNextAction, QuickOpenSelectNextAction.ID, QuickOpenSelectNextAction.LABEL, { primary: 0, mac: { primary: KeyMod.WinCtrl | KeyCode.KEY_N } }, inQuickOpenContext, KeybindingWeight.WorkbenchContrib + 50), 'Select Next in Quick Open'); -registry.registerWorkbenchAction(new SyncActionDescriptor(QuickOpenSelectPreviousAction, QuickOpenSelectPreviousAction.ID, QuickOpenSelectPreviousAction.LABEL, { primary: 0, mac: { primary: KeyMod.WinCtrl | KeyCode.KEY_P } }, inQuickOpenContext, KeybindingWeight.WorkbenchContrib + 50), 'Select Previous in Quick Open'); -registry.registerWorkbenchAction(new SyncActionDescriptor(QuickOpenNavigateNextAction, QuickOpenNavigateNextAction.ID, QuickOpenNavigateNextAction.LABEL), 'Navigate Next in Quick Open'); -registry.registerWorkbenchAction(new SyncActionDescriptor(QuickOpenNavigatePreviousAction, QuickOpenNavigatePreviousAction.ID, QuickOpenNavigatePreviousAction.LABEL), 'Navigate Previous in Quick Open'); -registry.registerWorkbenchAction(new SyncActionDescriptor(RemoveFromEditorHistoryAction, RemoveFromEditorHistoryAction.ID, RemoveFromEditorHistoryAction.LABEL), 'Remove From History'); +registry.registerWorkbenchAction(SyncActionDescriptor.create(QuickOpenSelectNextAction, QuickOpenSelectNextAction.ID, QuickOpenSelectNextAction.LABEL, { primary: 0, mac: { primary: KeyMod.WinCtrl | KeyCode.KEY_N } }, inQuickOpenContext, KeybindingWeight.WorkbenchContrib + 50), 'Select Next in Quick Open'); +registry.registerWorkbenchAction(SyncActionDescriptor.create(QuickOpenSelectPreviousAction, QuickOpenSelectPreviousAction.ID, QuickOpenSelectPreviousAction.LABEL, { primary: 0, mac: { primary: KeyMod.WinCtrl | KeyCode.KEY_P } }, inQuickOpenContext, KeybindingWeight.WorkbenchContrib + 50), 'Select Previous in Quick Open'); +registry.registerWorkbenchAction(SyncActionDescriptor.create(QuickOpenNavigateNextAction, QuickOpenNavigateNextAction.ID, QuickOpenNavigateNextAction.LABEL), 'Navigate Next in Quick Open'); +registry.registerWorkbenchAction(SyncActionDescriptor.create(QuickOpenNavigatePreviousAction, QuickOpenNavigatePreviousAction.ID, QuickOpenNavigatePreviousAction.LABEL), 'Navigate Previous in Quick Open'); +registry.registerWorkbenchAction(SyncActionDescriptor.create(RemoveFromEditorHistoryAction, RemoveFromEditorHistoryAction.ID, RemoveFromEditorHistoryAction.LABEL), 'Remove From History'); const quickOpenNavigateNextInFilePickerId = 'workbench.action.quickOpenNavigateNextInFilePicker'; KeybindingsRegistry.registerCommandAndKeybindingRule({ @@ -98,4 +98,4 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({ primary: globalQuickOpenKeybinding.mac.primary | KeyMod.Shift, secondary: undefined } -}); \ No newline at end of file +}); diff --git a/src/vs/workbench/browser/parts/sidebar/sidebarPart.ts b/src/vs/workbench/browser/parts/sidebar/sidebarPart.ts index 809316c67776c..d9667ca633558 100644 --- a/src/vs/workbench/browser/parts/sidebar/sidebarPart.ts +++ b/src/vs/workbench/browser/parts/sidebar/sidebarPart.ts @@ -320,7 +320,7 @@ class FocusSideBarAction extends Action { } const registry = Registry.as(ActionExtensions.WorkbenchActions); -registry.registerWorkbenchAction(new SyncActionDescriptor(FocusSideBarAction, FocusSideBarAction.ID, FocusSideBarAction.LABEL, { +registry.registerWorkbenchAction(SyncActionDescriptor.create(FocusSideBarAction, FocusSideBarAction.ID, FocusSideBarAction.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.KEY_0 }), 'View: Focus into Side Bar', nls.localize('viewCategory', "View")); diff --git a/src/vs/workbench/contrib/cli/node/cli.contribution.ts b/src/vs/workbench/contrib/cli/node/cli.contribution.ts index b0dc1655169d3..5ef30f885ef5d 100644 --- a/src/vs/workbench/contrib/cli/node/cli.contribution.ts +++ b/src/vs/workbench/contrib/cli/node/cli.contribution.ts @@ -189,6 +189,6 @@ if (platform.isMacintosh) { const category = nls.localize('shellCommand', "Shell Command"); const workbenchActionsRegistry = Registry.as(ActionExtensions.WorkbenchActions); - workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(InstallAction, InstallAction.ID, InstallAction.LABEL), `Shell Command: Install \'${product.applicationName}\' command in PATH`, category); - workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(UninstallAction, UninstallAction.ID, UninstallAction.LABEL), `Shell Command: Uninstall \'${product.applicationName}\' command from PATH`, category); + workbenchActionsRegistry.registerWorkbenchAction(SyncActionDescriptor.create(InstallAction, InstallAction.ID, InstallAction.LABEL), `Shell Command: Install \'${product.applicationName}\' command in PATH`, category); + workbenchActionsRegistry.registerWorkbenchAction(SyncActionDescriptor.create(UninstallAction, UninstallAction.ID, UninstallAction.LABEL), `Shell Command: Uninstall \'${product.applicationName}\' command from PATH`, category); } diff --git a/src/vs/workbench/contrib/codeEditor/browser/inspectKeybindings.ts b/src/vs/workbench/contrib/codeEditor/browser/inspectKeybindings.ts index 218ba69adf928..396b76f4fcf92 100644 --- a/src/vs/workbench/contrib/codeEditor/browser/inspectKeybindings.ts +++ b/src/vs/workbench/contrib/codeEditor/browser/inspectKeybindings.ts @@ -54,4 +54,4 @@ class InspectKeyMapJSON extends Action { } const registry = Registry.as(ActionExtensions.WorkbenchActions); -registry.registerWorkbenchAction(new SyncActionDescriptor(InspectKeyMapJSON, InspectKeyMapJSON.ID, InspectKeyMapJSON.LABEL), 'Developer: Inspect Key Mappings (JSON)', nls.localize('developer', "Developer")); +registry.registerWorkbenchAction(SyncActionDescriptor.create(InspectKeyMapJSON, InspectKeyMapJSON.ID, InspectKeyMapJSON.LABEL), 'Developer: Inspect Key Mappings (JSON)', nls.localize('developer', "Developer")); diff --git a/src/vs/workbench/contrib/codeEditor/browser/toggleMinimap.ts b/src/vs/workbench/contrib/codeEditor/browser/toggleMinimap.ts index e1d040feb50df..5cf2381d1a2c0 100644 --- a/src/vs/workbench/contrib/codeEditor/browser/toggleMinimap.ts +++ b/src/vs/workbench/contrib/codeEditor/browser/toggleMinimap.ts @@ -30,7 +30,7 @@ export class ToggleMinimapAction extends Action { } const registry = Registry.as(ActionExtensions.WorkbenchActions); -registry.registerWorkbenchAction(new SyncActionDescriptor(ToggleMinimapAction, ToggleMinimapAction.ID, ToggleMinimapAction.LABEL), 'View: Toggle Minimap', nls.localize('view', "View")); +registry.registerWorkbenchAction(SyncActionDescriptor.create(ToggleMinimapAction, ToggleMinimapAction.ID, ToggleMinimapAction.LABEL), 'View: Toggle Minimap', nls.localize('view', "View")); MenuRegistry.appendMenuItem(MenuId.MenubarViewMenu, { group: '5_editor', diff --git a/src/vs/workbench/contrib/codeEditor/browser/toggleMultiCursorModifier.ts b/src/vs/workbench/contrib/codeEditor/browser/toggleMultiCursorModifier.ts index 5e1b6da2163b2..a41bea88b344d 100644 --- a/src/vs/workbench/contrib/codeEditor/browser/toggleMultiCursorModifier.ts +++ b/src/vs/workbench/contrib/codeEditor/browser/toggleMultiCursorModifier.ts @@ -66,7 +66,7 @@ Registry.as(WorkbenchExtensions.Workbench).regi const registry = Registry.as(Extensions.WorkbenchActions); -registry.registerWorkbenchAction(new SyncActionDescriptor(ToggleMultiCursorModifierAction, ToggleMultiCursorModifierAction.ID, ToggleMultiCursorModifierAction.LABEL), 'Toggle Multi-Cursor Modifier'); +registry.registerWorkbenchAction(SyncActionDescriptor.create(ToggleMultiCursorModifierAction, ToggleMultiCursorModifierAction.ID, ToggleMultiCursorModifierAction.LABEL), 'Toggle Multi-Cursor Modifier'); MenuRegistry.appendMenuItem(MenuId.MenubarSelectionMenu, { group: '3_multi', command: { @@ -88,4 +88,4 @@ MenuRegistry.appendMenuItem(MenuId.MenubarSelectionMenu, { }, when: multiCursorModifier.isEqualTo('altKey'), order: 1 -}); \ No newline at end of file +}); diff --git a/src/vs/workbench/contrib/codeEditor/browser/toggleRenderControlCharacter.ts b/src/vs/workbench/contrib/codeEditor/browser/toggleRenderControlCharacter.ts index e8c723989084a..fcf56ad264487 100644 --- a/src/vs/workbench/contrib/codeEditor/browser/toggleRenderControlCharacter.ts +++ b/src/vs/workbench/contrib/codeEditor/browser/toggleRenderControlCharacter.ts @@ -31,7 +31,7 @@ export class ToggleRenderControlCharacterAction extends Action { } const registry = Registry.as(ActionExtensions.WorkbenchActions); -registry.registerWorkbenchAction(new SyncActionDescriptor(ToggleRenderControlCharacterAction, ToggleRenderControlCharacterAction.ID, ToggleRenderControlCharacterAction.LABEL), 'View: Toggle Control Characters', nls.localize('view', "View")); +registry.registerWorkbenchAction(SyncActionDescriptor.create(ToggleRenderControlCharacterAction, ToggleRenderControlCharacterAction.ID, ToggleRenderControlCharacterAction.LABEL), 'View: Toggle Control Characters', nls.localize('view', "View")); MenuRegistry.appendMenuItem(MenuId.MenubarViewMenu, { group: '5_editor', diff --git a/src/vs/workbench/contrib/codeEditor/browser/toggleRenderWhitespace.ts b/src/vs/workbench/contrib/codeEditor/browser/toggleRenderWhitespace.ts index d2a6b4845d8a7..56aa45bc248f6 100644 --- a/src/vs/workbench/contrib/codeEditor/browser/toggleRenderWhitespace.ts +++ b/src/vs/workbench/contrib/codeEditor/browser/toggleRenderWhitespace.ts @@ -39,7 +39,7 @@ export class ToggleRenderWhitespaceAction extends Action { } const registry = Registry.as(ActionExtensions.WorkbenchActions); -registry.registerWorkbenchAction(new SyncActionDescriptor(ToggleRenderWhitespaceAction, ToggleRenderWhitespaceAction.ID, ToggleRenderWhitespaceAction.LABEL), 'View: Toggle Render Whitespace', nls.localize('view', "View")); +registry.registerWorkbenchAction(SyncActionDescriptor.create(ToggleRenderWhitespaceAction, ToggleRenderWhitespaceAction.ID, ToggleRenderWhitespaceAction.LABEL), 'View: Toggle Render Whitespace', nls.localize('view', "View")); MenuRegistry.appendMenuItem(MenuId.MenubarViewMenu, { group: '5_editor', diff --git a/src/vs/workbench/contrib/debug/browser/debug.contribution.ts b/src/vs/workbench/contrib/debug/browser/debug.contribution.ts index 3c68e97f7115d..ad44fc8554764 100644 --- a/src/vs/workbench/contrib/debug/browser/debug.contribution.ts +++ b/src/vs/workbench/contrib/debug/browser/debug.contribution.ts @@ -117,8 +117,8 @@ registerCommands(); // register action to open viewlet const registry = Registry.as(WorkbenchActionRegistryExtensions.WorkbenchActions); -registry.registerWorkbenchAction(new SyncActionDescriptor(OpenDebugPanelAction, OpenDebugPanelAction.ID, OpenDebugPanelAction.LABEL, openPanelKb), 'View: Debug Console', nls.localize('view', "View")); -registry.registerWorkbenchAction(new SyncActionDescriptor(OpenDebugViewletAction, OpenDebugViewletAction.ID, OpenDebugViewletAction.LABEL, openViewletKb), 'View: Show Debug', nls.localize('view', "View")); +registry.registerWorkbenchAction(SyncActionDescriptor.create(OpenDebugPanelAction, OpenDebugPanelAction.ID, OpenDebugPanelAction.LABEL, openPanelKb), 'View: Debug Console', nls.localize('view', "View")); +registry.registerWorkbenchAction(SyncActionDescriptor.create(OpenDebugViewletAction, OpenDebugViewletAction.ID, OpenDebugViewletAction.LABEL, openViewletKb), 'View: Show Debug', nls.localize('view', "View")); Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(DebugCallStackContribution, LifecyclePhase.Restored); Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(DebugToolBar, LifecyclePhase.Restored); @@ -127,16 +127,16 @@ Registry.as(WorkbenchExtensions.Workbench).regi const debugCategory = nls.localize('debugCategory', "Debug"); -registry.registerWorkbenchAction(new SyncActionDescriptor(StartAction, StartAction.ID, StartAction.LABEL, { primary: KeyCode.F5 }, CONTEXT_IN_DEBUG_MODE.toNegated()), 'Debug: Start Debugging', debugCategory); -registry.registerWorkbenchAction(new SyncActionDescriptor(ConfigureAction, ConfigureAction.ID, ConfigureAction.LABEL), 'Debug: Open launch.json', debugCategory); -registry.registerWorkbenchAction(new SyncActionDescriptor(AddFunctionBreakpointAction, AddFunctionBreakpointAction.ID, AddFunctionBreakpointAction.LABEL), 'Debug: Add Function Breakpoint', debugCategory); -registry.registerWorkbenchAction(new SyncActionDescriptor(ReapplyBreakpointsAction, ReapplyBreakpointsAction.ID, ReapplyBreakpointsAction.LABEL), 'Debug: Reapply All Breakpoints', debugCategory); -registry.registerWorkbenchAction(new SyncActionDescriptor(RunAction, RunAction.ID, RunAction.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.F5, mac: { primary: KeyMod.WinCtrl | KeyCode.F5 } }), 'Debug: Start Without Debugging', debugCategory); -registry.registerWorkbenchAction(new SyncActionDescriptor(RemoveAllBreakpointsAction, RemoveAllBreakpointsAction.ID, RemoveAllBreakpointsAction.LABEL), 'Debug: Remove All Breakpoints', debugCategory); -registry.registerWorkbenchAction(new SyncActionDescriptor(EnableAllBreakpointsAction, EnableAllBreakpointsAction.ID, EnableAllBreakpointsAction.LABEL), 'Debug: Enable All Breakpoints', debugCategory); -registry.registerWorkbenchAction(new SyncActionDescriptor(DisableAllBreakpointsAction, DisableAllBreakpointsAction.ID, DisableAllBreakpointsAction.LABEL), 'Debug: Disable All Breakpoints', debugCategory); -registry.registerWorkbenchAction(new SyncActionDescriptor(SelectAndStartAction, SelectAndStartAction.ID, SelectAndStartAction.LABEL), 'Debug: Select and Start Debugging', debugCategory); -registry.registerWorkbenchAction(new SyncActionDescriptor(ClearReplAction, ClearReplAction.ID, ClearReplAction.LABEL), 'Debug: Clear Console', debugCategory); +registry.registerWorkbenchAction(SyncActionDescriptor.create(StartAction, StartAction.ID, StartAction.LABEL, { primary: KeyCode.F5 }, CONTEXT_IN_DEBUG_MODE.toNegated()), 'Debug: Start Debugging', debugCategory); +registry.registerWorkbenchAction(SyncActionDescriptor.create(ConfigureAction, ConfigureAction.ID, ConfigureAction.LABEL), 'Debug: Open launch.json', debugCategory); +registry.registerWorkbenchAction(SyncActionDescriptor.create(AddFunctionBreakpointAction, AddFunctionBreakpointAction.ID, AddFunctionBreakpointAction.LABEL), 'Debug: Add Function Breakpoint', debugCategory); +registry.registerWorkbenchAction(SyncActionDescriptor.create(ReapplyBreakpointsAction, ReapplyBreakpointsAction.ID, ReapplyBreakpointsAction.LABEL), 'Debug: Reapply All Breakpoints', debugCategory); +registry.registerWorkbenchAction(SyncActionDescriptor.create(RunAction, RunAction.ID, RunAction.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.F5, mac: { primary: KeyMod.WinCtrl | KeyCode.F5 } }), 'Debug: Start Without Debugging', debugCategory); +registry.registerWorkbenchAction(SyncActionDescriptor.create(RemoveAllBreakpointsAction, RemoveAllBreakpointsAction.ID, RemoveAllBreakpointsAction.LABEL), 'Debug: Remove All Breakpoints', debugCategory); +registry.registerWorkbenchAction(SyncActionDescriptor.create(EnableAllBreakpointsAction, EnableAllBreakpointsAction.ID, EnableAllBreakpointsAction.LABEL), 'Debug: Enable All Breakpoints', debugCategory); +registry.registerWorkbenchAction(SyncActionDescriptor.create(DisableAllBreakpointsAction, DisableAllBreakpointsAction.ID, DisableAllBreakpointsAction.LABEL), 'Debug: Disable All Breakpoints', debugCategory); +registry.registerWorkbenchAction(SyncActionDescriptor.create(SelectAndStartAction, SelectAndStartAction.ID, SelectAndStartAction.LABEL), 'Debug: Select and Start Debugging', debugCategory); +registry.registerWorkbenchAction(SyncActionDescriptor.create(ClearReplAction, ClearReplAction.ID, ClearReplAction.LABEL), 'Debug: Clear Console', debugCategory); const registerDebugCommandPaletteItem = (id: string, title: string, when?: ContextKeyExpr, precondition?: ContextKeyExpr) => { MenuRegistry.appendMenuItem(MenuId.CommandPalette, { diff --git a/src/vs/workbench/contrib/extensions/browser/extensions.contribution.ts b/src/vs/workbench/contrib/extensions/browser/extensions.contribution.ts index b75b365641bad..acab3d418c76c 100644 --- a/src/vs/workbench/contrib/extensions/browser/extensions.contribution.ts +++ b/src/vs/workbench/contrib/extensions/browser/extensions.contribution.ts @@ -90,67 +90,67 @@ Registry.as(ViewletExtensions.Viewlets) // Global actions const actionRegistry = Registry.as(WorkbenchActionExtensions.WorkbenchActions); -const openViewletActionDescriptor = new SyncActionDescriptor(OpenExtensionsViewletAction, OpenExtensionsViewletAction.ID, OpenExtensionsViewletAction.LABEL, { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_X }); +const openViewletActionDescriptor = SyncActionDescriptor.create(OpenExtensionsViewletAction, OpenExtensionsViewletAction.ID, OpenExtensionsViewletAction.LABEL, { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_X }); actionRegistry.registerWorkbenchAction(openViewletActionDescriptor, 'View: Show Extensions', localize('view', "View")); -const installActionDescriptor = new SyncActionDescriptor(InstallExtensionsAction, InstallExtensionsAction.ID, InstallExtensionsAction.LABEL); +const installActionDescriptor = SyncActionDescriptor.create(InstallExtensionsAction, InstallExtensionsAction.ID, InstallExtensionsAction.LABEL); actionRegistry.registerWorkbenchAction(installActionDescriptor, 'Extensions: Install Extensions', ExtensionsLabel); -const listOutdatedActionDescriptor = new SyncActionDescriptor(ShowOutdatedExtensionsAction, ShowOutdatedExtensionsAction.ID, ShowOutdatedExtensionsAction.LABEL); +const listOutdatedActionDescriptor = SyncActionDescriptor.create(ShowOutdatedExtensionsAction, ShowOutdatedExtensionsAction.ID, ShowOutdatedExtensionsAction.LABEL); actionRegistry.registerWorkbenchAction(listOutdatedActionDescriptor, 'Extensions: Show Outdated Extensions', ExtensionsLabel); -const recommendationsActionDescriptor = new SyncActionDescriptor(ShowRecommendedExtensionsAction, ShowRecommendedExtensionsAction.ID, ShowRecommendedExtensionsAction.LABEL); +const recommendationsActionDescriptor = SyncActionDescriptor.create(ShowRecommendedExtensionsAction, ShowRecommendedExtensionsAction.ID, ShowRecommendedExtensionsAction.LABEL); actionRegistry.registerWorkbenchAction(recommendationsActionDescriptor, 'Extensions: Show Recommended Extensions', ExtensionsLabel); -const keymapRecommendationsActionDescriptor = new SyncActionDescriptor(ShowRecommendedKeymapExtensionsAction, ShowRecommendedKeymapExtensionsAction.ID, ShowRecommendedKeymapExtensionsAction.SHORT_LABEL, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.KEY_M) }); +const keymapRecommendationsActionDescriptor = SyncActionDescriptor.create(ShowRecommendedKeymapExtensionsAction, ShowRecommendedKeymapExtensionsAction.ID, ShowRecommendedKeymapExtensionsAction.SHORT_LABEL, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.KEY_M) }); actionRegistry.registerWorkbenchAction(keymapRecommendationsActionDescriptor, 'Preferences: Keymaps', PreferencesLabel); -const languageExtensionsActionDescriptor = new SyncActionDescriptor(ShowLanguageExtensionsAction, ShowLanguageExtensionsAction.ID, ShowLanguageExtensionsAction.SHORT_LABEL); +const languageExtensionsActionDescriptor = SyncActionDescriptor.create(ShowLanguageExtensionsAction, ShowLanguageExtensionsAction.ID, ShowLanguageExtensionsAction.SHORT_LABEL); actionRegistry.registerWorkbenchAction(languageExtensionsActionDescriptor, 'Preferences: Language Extensions', PreferencesLabel); -const azureExtensionsActionDescriptor = new SyncActionDescriptor(ShowAzureExtensionsAction, ShowAzureExtensionsAction.ID, ShowAzureExtensionsAction.SHORT_LABEL); +const azureExtensionsActionDescriptor = SyncActionDescriptor.create(ShowAzureExtensionsAction, ShowAzureExtensionsAction.ID, ShowAzureExtensionsAction.SHORT_LABEL); actionRegistry.registerWorkbenchAction(azureExtensionsActionDescriptor, 'Preferences: Azure Extensions', PreferencesLabel); -const popularActionDescriptor = new SyncActionDescriptor(ShowPopularExtensionsAction, ShowPopularExtensionsAction.ID, ShowPopularExtensionsAction.LABEL); +const popularActionDescriptor = SyncActionDescriptor.create(ShowPopularExtensionsAction, ShowPopularExtensionsAction.ID, ShowPopularExtensionsAction.LABEL); actionRegistry.registerWorkbenchAction(popularActionDescriptor, 'Extensions: Show Popular Extensions', ExtensionsLabel); -const enabledActionDescriptor = new SyncActionDescriptor(ShowEnabledExtensionsAction, ShowEnabledExtensionsAction.ID, ShowEnabledExtensionsAction.LABEL); +const enabledActionDescriptor = SyncActionDescriptor.create(ShowEnabledExtensionsAction, ShowEnabledExtensionsAction.ID, ShowEnabledExtensionsAction.LABEL); actionRegistry.registerWorkbenchAction(enabledActionDescriptor, 'Extensions: Show Enabled Extensions', ExtensionsLabel); -const installedActionDescriptor = new SyncActionDescriptor(ShowInstalledExtensionsAction, ShowInstalledExtensionsAction.ID, ShowInstalledExtensionsAction.LABEL); +const installedActionDescriptor = SyncActionDescriptor.create(ShowInstalledExtensionsAction, ShowInstalledExtensionsAction.ID, ShowInstalledExtensionsAction.LABEL); actionRegistry.registerWorkbenchAction(installedActionDescriptor, 'Extensions: Show Installed Extensions', ExtensionsLabel); -const disabledActionDescriptor = new SyncActionDescriptor(ShowDisabledExtensionsAction, ShowDisabledExtensionsAction.ID, ShowDisabledExtensionsAction.LABEL); +const disabledActionDescriptor = SyncActionDescriptor.create(ShowDisabledExtensionsAction, ShowDisabledExtensionsAction.ID, ShowDisabledExtensionsAction.LABEL); actionRegistry.registerWorkbenchAction(disabledActionDescriptor, 'Extensions: Show Disabled Extensions', ExtensionsLabel); -const builtinActionDescriptor = new SyncActionDescriptor(ShowBuiltInExtensionsAction, ShowBuiltInExtensionsAction.ID, ShowBuiltInExtensionsAction.LABEL); +const builtinActionDescriptor = SyncActionDescriptor.create(ShowBuiltInExtensionsAction, ShowBuiltInExtensionsAction.ID, ShowBuiltInExtensionsAction.LABEL); actionRegistry.registerWorkbenchAction(builtinActionDescriptor, 'Extensions: Show Built-in Extensions', ExtensionsLabel); -const updateAllActionDescriptor = new SyncActionDescriptor(UpdateAllAction, UpdateAllAction.ID, UpdateAllAction.LABEL); +const updateAllActionDescriptor = SyncActionDescriptor.create(UpdateAllAction, UpdateAllAction.ID, UpdateAllAction.LABEL); actionRegistry.registerWorkbenchAction(updateAllActionDescriptor, 'Extensions: Update All Extensions', ExtensionsLabel); -const installVSIXActionDescriptor = new SyncActionDescriptor(InstallVSIXAction, InstallVSIXAction.ID, InstallVSIXAction.LABEL); +const installVSIXActionDescriptor = SyncActionDescriptor.create(InstallVSIXAction, InstallVSIXAction.ID, InstallVSIXAction.LABEL); actionRegistry.registerWorkbenchAction(installVSIXActionDescriptor, 'Extensions: Install from VSIX...', ExtensionsLabel); -const disableAllAction = new SyncActionDescriptor(DisableAllAction, DisableAllAction.ID, DisableAllAction.LABEL); +const disableAllAction = SyncActionDescriptor.create(DisableAllAction, DisableAllAction.ID, DisableAllAction.LABEL); actionRegistry.registerWorkbenchAction(disableAllAction, 'Extensions: Disable All Installed Extensions', ExtensionsLabel); -const disableAllWorkspaceAction = new SyncActionDescriptor(DisableAllWorkspaceAction, DisableAllWorkspaceAction.ID, DisableAllWorkspaceAction.LABEL); +const disableAllWorkspaceAction = SyncActionDescriptor.create(DisableAllWorkspaceAction, DisableAllWorkspaceAction.ID, DisableAllWorkspaceAction.LABEL); actionRegistry.registerWorkbenchAction(disableAllWorkspaceAction, 'Extensions: Disable All Installed Extensions for this Workspace', ExtensionsLabel); -const enableAllAction = new SyncActionDescriptor(EnableAllAction, EnableAllAction.ID, EnableAllAction.LABEL); +const enableAllAction = SyncActionDescriptor.create(EnableAllAction, EnableAllAction.ID, EnableAllAction.LABEL); actionRegistry.registerWorkbenchAction(enableAllAction, 'Extensions: Enable All Extensions', ExtensionsLabel); -const enableAllWorkspaceAction = new SyncActionDescriptor(EnableAllWorkspaceAction, EnableAllWorkspaceAction.ID, EnableAllWorkspaceAction.LABEL); +const enableAllWorkspaceAction = SyncActionDescriptor.create(EnableAllWorkspaceAction, EnableAllWorkspaceAction.ID, EnableAllWorkspaceAction.LABEL); actionRegistry.registerWorkbenchAction(enableAllWorkspaceAction, 'Extensions: Enable All Extensions for this Workspace', ExtensionsLabel); -const checkForUpdatesAction = new SyncActionDescriptor(CheckForUpdatesAction, CheckForUpdatesAction.ID, CheckForUpdatesAction.LABEL); +const checkForUpdatesAction = SyncActionDescriptor.create(CheckForUpdatesAction, CheckForUpdatesAction.ID, CheckForUpdatesAction.LABEL); actionRegistry.registerWorkbenchAction(checkForUpdatesAction, `Extensions: Check for Extension Updates`, ExtensionsLabel); -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(EnableAutoUpdateAction, EnableAutoUpdateAction.ID, EnableAutoUpdateAction.LABEL), `Extensions: Enable Auto Updating Extensions`, ExtensionsLabel); -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(DisableAutoUpdateAction, DisableAutoUpdateAction.ID, DisableAutoUpdateAction.LABEL), `Extensions: Disable Auto Updating Extensions`, ExtensionsLabel); -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(InstallSpecificVersionOfExtensionAction, InstallSpecificVersionOfExtensionAction.ID, InstallSpecificVersionOfExtensionAction.LABEL), 'Install Specific Version of Extension...', ExtensionsLabel); -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ReinstallAction, ReinstallAction.ID, ReinstallAction.LABEL), 'Reinstall Extension...', localize('developer', "Developer")); +actionRegistry.registerWorkbenchAction(SyncActionDescriptor.create(EnableAutoUpdateAction, EnableAutoUpdateAction.ID, EnableAutoUpdateAction.LABEL), `Extensions: Enable Auto Updating Extensions`, ExtensionsLabel); +actionRegistry.registerWorkbenchAction(SyncActionDescriptor.create(DisableAutoUpdateAction, DisableAutoUpdateAction.ID, DisableAutoUpdateAction.LABEL), `Extensions: Disable Auto Updating Extensions`, ExtensionsLabel); +actionRegistry.registerWorkbenchAction(SyncActionDescriptor.create(InstallSpecificVersionOfExtensionAction, InstallSpecificVersionOfExtensionAction.ID, InstallSpecificVersionOfExtensionAction.LABEL), 'Install Specific Version of Extension...', ExtensionsLabel); +actionRegistry.registerWorkbenchAction(SyncActionDescriptor.create(ReinstallAction, ReinstallAction.ID, ReinstallAction.LABEL), 'Reinstall Extension...', localize('developer', "Developer")); Registry.as(ConfigurationExtensions.Configuration) .registerConfiguration({ diff --git a/src/vs/workbench/contrib/extensions/electron-browser/extensions.contribution.ts b/src/vs/workbench/contrib/extensions/electron-browser/extensions.contribution.ts index 19e5153bb5313..4b5d7b3f7e340 100644 --- a/src/vs/workbench/contrib/extensions/electron-browser/extensions.contribution.ts +++ b/src/vs/workbench/contrib/extensions/electron-browser/extensions.contribution.ts @@ -58,7 +58,7 @@ Registry.as(EditorInputExtensions.EditorInputFactor // Global actions const actionRegistry = Registry.as(WorkbenchActionExtensions.WorkbenchActions); -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ShowRuntimeExtensionsAction, ShowRuntimeExtensionsAction.ID, ShowRuntimeExtensionsAction.LABEL), 'Show Running Extensions', localize('developer', "Developer")); +actionRegistry.registerWorkbenchAction(SyncActionDescriptor.create(ShowRuntimeExtensionsAction, ShowRuntimeExtensionsAction.ID, ShowRuntimeExtensionsAction.LABEL), 'Show Running Extensions', localize('developer', "Developer")); class ExtensionsContributions implements IWorkbenchContribution { @@ -66,7 +66,7 @@ class ExtensionsContributions implements IWorkbenchContribution { @IWorkbenchEnvironmentService workbenchEnvironmentService: IWorkbenchEnvironmentService ) { if (workbenchEnvironmentService.extensionsPath) { - const openExtensionsFolderActionDescriptor = new SyncActionDescriptor(OpenExtensionsFolderAction, OpenExtensionsFolderAction.ID, OpenExtensionsFolderAction.LABEL); + const openExtensionsFolderActionDescriptor = SyncActionDescriptor.create(OpenExtensionsFolderAction, OpenExtensionsFolderAction.ID, OpenExtensionsFolderAction.LABEL); actionRegistry.registerWorkbenchAction(openExtensionsFolderActionDescriptor, 'Extensions: Open Extensions Folder', ExtensionsLabel); } } diff --git a/src/vs/workbench/contrib/files/browser/fileActions.contribution.ts b/src/vs/workbench/contrib/files/browser/fileActions.contribution.ts index 54c80ed215879..57456d500ea4d 100644 --- a/src/vs/workbench/contrib/files/browser/fileActions.contribution.ts +++ b/src/vs/workbench/contrib/files/browser/fileActions.contribution.ts @@ -34,26 +34,26 @@ import { registerAndGetAmdImageURL } from 'vs/base/common/amd'; const category = { value: nls.localize('filesCategory', "File"), original: 'File' }; const registry = Registry.as(ActionExtensions.WorkbenchActions); -registry.registerWorkbenchAction(new SyncActionDescriptor(SaveAllAction, SaveAllAction.ID, SaveAllAction.LABEL, { primary: undefined, mac: { primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.KEY_S }, win: { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyCode.KEY_S) } }), 'File: Save All', category.value); -registry.registerWorkbenchAction(new SyncActionDescriptor(GlobalCompareResourcesAction, GlobalCompareResourcesAction.ID, GlobalCompareResourcesAction.LABEL), 'File: Compare Active File With...', category.value); -registry.registerWorkbenchAction(new SyncActionDescriptor(FocusFilesExplorer, FocusFilesExplorer.ID, FocusFilesExplorer.LABEL), 'File: Focus on Files Explorer', category.value); -registry.registerWorkbenchAction(new SyncActionDescriptor(ShowActiveFileInExplorer, ShowActiveFileInExplorer.ID, ShowActiveFileInExplorer.LABEL), 'File: Reveal Active File in Side Bar', category.value); -registry.registerWorkbenchAction(new SyncActionDescriptor(CollapseExplorerView, CollapseExplorerView.ID, CollapseExplorerView.LABEL), 'File: Collapse Folders in Explorer', category.value); -registry.registerWorkbenchAction(new SyncActionDescriptor(RefreshExplorerView, RefreshExplorerView.ID, RefreshExplorerView.LABEL), 'File: Refresh Explorer', category.value); -registry.registerWorkbenchAction(new SyncActionDescriptor(GlobalNewUntitledFileAction, GlobalNewUntitledFileAction.ID, GlobalNewUntitledFileAction.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.KEY_N }), 'File: New Untitled File', category.value); -registry.registerWorkbenchAction(new SyncActionDescriptor(CompareWithClipboardAction, CompareWithClipboardAction.ID, CompareWithClipboardAction.LABEL, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyCode.KEY_C) }), 'File: Compare Active File with Clipboard', category.value); -registry.registerWorkbenchAction(new SyncActionDescriptor(ToggleAutoSaveAction, ToggleAutoSaveAction.ID, ToggleAutoSaveAction.LABEL), 'File: Toggle Auto Save', category.value); +registry.registerWorkbenchAction(SyncActionDescriptor.create(SaveAllAction, SaveAllAction.ID, SaveAllAction.LABEL, { primary: undefined, mac: { primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.KEY_S }, win: { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyCode.KEY_S) } }), 'File: Save All', category.value); +registry.registerWorkbenchAction(SyncActionDescriptor.create(GlobalCompareResourcesAction, GlobalCompareResourcesAction.ID, GlobalCompareResourcesAction.LABEL), 'File: Compare Active File With...', category.value); +registry.registerWorkbenchAction(SyncActionDescriptor.create(FocusFilesExplorer, FocusFilesExplorer.ID, FocusFilesExplorer.LABEL), 'File: Focus on Files Explorer', category.value); +registry.registerWorkbenchAction(SyncActionDescriptor.create(ShowActiveFileInExplorer, ShowActiveFileInExplorer.ID, ShowActiveFileInExplorer.LABEL), 'File: Reveal Active File in Side Bar', category.value); +registry.registerWorkbenchAction(SyncActionDescriptor.create(CollapseExplorerView, CollapseExplorerView.ID, CollapseExplorerView.LABEL), 'File: Collapse Folders in Explorer', category.value); +registry.registerWorkbenchAction(SyncActionDescriptor.create(RefreshExplorerView, RefreshExplorerView.ID, RefreshExplorerView.LABEL), 'File: Refresh Explorer', category.value); +registry.registerWorkbenchAction(SyncActionDescriptor.create(GlobalNewUntitledFileAction, GlobalNewUntitledFileAction.ID, GlobalNewUntitledFileAction.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.KEY_N }), 'File: New Untitled File', category.value); +registry.registerWorkbenchAction(SyncActionDescriptor.create(CompareWithClipboardAction, CompareWithClipboardAction.ID, CompareWithClipboardAction.LABEL, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyCode.KEY_C) }), 'File: Compare Active File with Clipboard', category.value); +registry.registerWorkbenchAction(SyncActionDescriptor.create(ToggleAutoSaveAction, ToggleAutoSaveAction.ID, ToggleAutoSaveAction.LABEL), 'File: Toggle Auto Save', category.value); const workspacesCategory = nls.localize('workspaces', "Workspaces"); -registry.registerWorkbenchAction(new SyncActionDescriptor(OpenWorkspaceAction, OpenWorkspaceAction.ID, OpenWorkspaceAction.LABEL), 'Workspaces: Open Workspace...', workspacesCategory); +registry.registerWorkbenchAction(SyncActionDescriptor.create(OpenWorkspaceAction, OpenWorkspaceAction.ID, OpenWorkspaceAction.LABEL), 'Workspaces: Open Workspace...', workspacesCategory); const fileCategory = nls.localize('file', "File"); if (isMacintosh) { - registry.registerWorkbenchAction(new SyncActionDescriptor(OpenFileFolderAction, OpenFileFolderAction.ID, OpenFileFolderAction.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.KEY_O }), 'File: Open...', fileCategory); + registry.registerWorkbenchAction(SyncActionDescriptor.create(OpenFileFolderAction, OpenFileFolderAction.ID, OpenFileFolderAction.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.KEY_O }), 'File: Open...', fileCategory); } else { - registry.registerWorkbenchAction(new SyncActionDescriptor(OpenFileAction, OpenFileAction.ID, OpenFileAction.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.KEY_O }), 'File: Open File...', fileCategory); - registry.registerWorkbenchAction(new SyncActionDescriptor(OpenFolderAction, OpenFolderAction.ID, OpenFolderAction.LABEL, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.KEY_O) }), 'File: Open Folder...', fileCategory); + registry.registerWorkbenchAction(SyncActionDescriptor.create(OpenFileAction, OpenFileAction.ID, OpenFileAction.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.KEY_O }), 'File: Open File...', fileCategory); + registry.registerWorkbenchAction(SyncActionDescriptor.create(OpenFolderAction, OpenFolderAction.ID, OpenFolderAction.LABEL, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.KEY_O) }), 'File: Open Folder...', fileCategory); } // Commands diff --git a/src/vs/workbench/contrib/files/browser/files.contribution.ts b/src/vs/workbench/contrib/files/browser/files.contribution.ts index f2332dd7eb5c8..5633cb728fd34 100644 --- a/src/vs/workbench/contrib/files/browser/files.contribution.ts +++ b/src/vs/workbench/contrib/files/browser/files.contribution.ts @@ -94,7 +94,7 @@ const openViewletKb: IKeybindings = { // Register Action to Open Viewlet const registry = Registry.as(ActionExtensions.WorkbenchActions); registry.registerWorkbenchAction( - new SyncActionDescriptor(OpenExplorerViewletAction, OpenExplorerViewletAction.ID, OpenExplorerViewletAction.LABEL, openViewletKb), + SyncActionDescriptor.create(OpenExplorerViewletAction, OpenExplorerViewletAction.ID, OpenExplorerViewletAction.LABEL, openViewletKb), 'View: Show Explorer', nls.localize('view', "View") ); diff --git a/src/vs/workbench/contrib/files/electron-browser/fileActions.contribution.ts b/src/vs/workbench/contrib/files/electron-browser/fileActions.contribution.ts index dd9caef709a25..9c63d009f8d3a 100644 --- a/src/vs/workbench/contrib/files/electron-browser/fileActions.contribution.ts +++ b/src/vs/workbench/contrib/files/electron-browser/fileActions.contribution.ts @@ -86,4 +86,4 @@ const category = { value: nls.localize('filesCategory', "File"), original: 'File appendToCommandPalette(REVEAL_IN_OS_COMMAND_ID, { value: REVEAL_IN_OS_LABEL, original: isWindows ? 'Reveal in Explorer' : isMacintosh ? 'Reveal in Finder' : 'Open Containing Folder' }, category); const registry = Registry.as(ActionExtensions.WorkbenchActions); -registry.registerWorkbenchAction(new SyncActionDescriptor(ShowOpenedFileInNewWindow, ShowOpenedFileInNewWindow.ID, ShowOpenedFileInNewWindow.LABEL, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyCode.KEY_O) }), 'File: Open Active File in New Window', category.value); +registry.registerWorkbenchAction(SyncActionDescriptor.create(ShowOpenedFileInNewWindow, ShowOpenedFileInNewWindow.ID, ShowOpenedFileInNewWindow.LABEL, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyCode.KEY_O) }), 'File: Open Active File in New Window', category.value); diff --git a/src/vs/workbench/contrib/issue/electron-browser/issue.contribution.ts b/src/vs/workbench/contrib/issue/electron-browser/issue.contribution.ts index c2ac341e3055e..b9316bb127103 100644 --- a/src/vs/workbench/contrib/issue/electron-browser/issue.contribution.ts +++ b/src/vs/workbench/contrib/issue/electron-browser/issue.contribution.ts @@ -19,7 +19,7 @@ const helpCategory = { value: nls.localize('help', "Help"), original: 'Help' }; const workbenchActionsRegistry = Registry.as(Extensions.WorkbenchActions); if (!!product.reportIssueUrl) { - workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(ReportPerformanceIssueUsingReporterAction, ReportPerformanceIssueUsingReporterAction.ID, ReportPerformanceIssueUsingReporterAction.LABEL), 'Help: Report Performance Issue', helpCategory.value); + workbenchActionsRegistry.registerWorkbenchAction(SyncActionDescriptor.create(ReportPerformanceIssueUsingReporterAction, ReportPerformanceIssueUsingReporterAction.ID, ReportPerformanceIssueUsingReporterAction.LABEL), 'Help: Report Performance Issue', helpCategory.value); const OpenIssueReporterActionId = 'workbench.action.openIssueReporter'; const OpenIssueReporterActionLabel = nls.localize({ key: 'reportIssueInEnglish', comment: ['Translate this to "Report Issue in English" in all languages please!'] }, "Report Issue"); @@ -43,10 +43,10 @@ if (!!product.reportIssueUrl) { } const developerCategory = nls.localize('developer', "Developer"); -workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(OpenProcessExplorer, OpenProcessExplorer.ID, OpenProcessExplorer.LABEL), 'Developer: Open Process Explorer', developerCategory); +workbenchActionsRegistry.registerWorkbenchAction(SyncActionDescriptor.create(OpenProcessExplorer, OpenProcessExplorer.ID, OpenProcessExplorer.LABEL), 'Developer: Open Process Explorer', developerCategory); registerSingleton(IWorkbenchIssueService, WorkbenchIssueService, true); CommandsRegistry.registerCommand('_issues.getSystemStatus', (accessor) => { return accessor.get(IIssueService).getSystemStatus(); -}); \ No newline at end of file +}); diff --git a/src/vs/workbench/contrib/localizations/browser/localizations.contribution.ts b/src/vs/workbench/contrib/localizations/browser/localizations.contribution.ts index 06b20c612ce73..798914273ebb9 100644 --- a/src/vs/workbench/contrib/localizations/browser/localizations.contribution.ts +++ b/src/vs/workbench/contrib/localizations/browser/localizations.contribution.ts @@ -29,7 +29,7 @@ import { ExtensionType } from 'vs/platform/extensions/common/extensions'; // Register action to configure locale and related settings const registry = Registry.as(Extensions.WorkbenchActions); -registry.registerWorkbenchAction(new SyncActionDescriptor(ConfigureLocaleAction, ConfigureLocaleAction.ID, ConfigureLocaleAction.LABEL), 'Configure Display Language'); +registry.registerWorkbenchAction(SyncActionDescriptor.create(ConfigureLocaleAction, ConfigureLocaleAction.ID, ConfigureLocaleAction.LABEL), 'Configure Display Language'); export class LocalizationWorkbenchContribution extends Disposable implements IWorkbenchContribution { constructor( diff --git a/src/vs/workbench/contrib/logs/common/logs.contribution.ts b/src/vs/workbench/contrib/logs/common/logs.contribution.ts index a85738f33512d..0479108f91c92 100644 --- a/src/vs/workbench/contrib/logs/common/logs.contribution.ts +++ b/src/vs/workbench/contrib/logs/common/logs.contribution.ts @@ -26,7 +26,7 @@ import { IProductService } from 'vs/platform/product/common/productService'; const workbenchActionsRegistry = Registry.as(WorkbenchActionExtensions.WorkbenchActions); const devCategory = nls.localize('developer', "Developer"); -workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(SetLogLevelAction, SetLogLevelAction.ID, SetLogLevelAction.LABEL), 'Developer: Set Log Level...', devCategory); +workbenchActionsRegistry.registerWorkbenchAction(SyncActionDescriptor.create(SetLogLevelAction, SetLogLevelAction.ID, SetLogLevelAction.LABEL), 'Developer: Set Log Level...', devCategory); class LogOutputChannels extends Disposable implements IWorkbenchContribution { @@ -58,7 +58,7 @@ class LogOutputChannels extends Disposable implements IWorkbenchContribution { const workbenchActionsRegistry = Registry.as(WorkbenchActionExtensions.WorkbenchActions); const devCategory = nls.localize('developer', "Developer"); - workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(OpenWindowSessionLogFileAction, OpenWindowSessionLogFileAction.ID, OpenWindowSessionLogFileAction.LABEL), 'Developer: Open Window Log File (Session)...', devCategory); + workbenchActionsRegistry.registerWorkbenchAction(SyncActionDescriptor.create(OpenWindowSessionLogFileAction, OpenWindowSessionLogFileAction.ID, OpenWindowSessionLogFileAction.LABEL), 'Developer: Open Window Log File (Session)...', devCategory); } private registerNativeContributions(): void { diff --git a/src/vs/workbench/contrib/logs/electron-browser/logs.contribution.ts b/src/vs/workbench/contrib/logs/electron-browser/logs.contribution.ts index f6ceef58f71a5..5aa0badb11e9b 100644 --- a/src/vs/workbench/contrib/logs/electron-browser/logs.contribution.ts +++ b/src/vs/workbench/contrib/logs/electron-browser/logs.contribution.ts @@ -11,4 +11,4 @@ import { OpenLogsFolderAction } from 'vs/workbench/contrib/logs/electron-browser const workbenchActionsRegistry = Registry.as(WorkbenchActionExtensions.WorkbenchActions); const devCategory = nls.localize('developer', "Developer"); -workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(OpenLogsFolderAction, OpenLogsFolderAction.ID, OpenLogsFolderAction.LABEL), 'Developer: Open Logs Folder', devCategory); +workbenchActionsRegistry.registerWorkbenchAction(SyncActionDescriptor.create(OpenLogsFolderAction, OpenLogsFolderAction.ID, OpenLogsFolderAction.LABEL), 'Developer: Open Logs Folder', devCategory); diff --git a/src/vs/workbench/contrib/markers/browser/markers.contribution.ts b/src/vs/workbench/contrib/markers/browser/markers.contribution.ts index 578642134276a..d28b9d0d7164a 100644 --- a/src/vs/workbench/contrib/markers/browser/markers.contribution.ts +++ b/src/vs/workbench/contrib/markers/browser/markers.contribution.ts @@ -107,10 +107,10 @@ workbenchRegistry.registerWorkbenchContribution(ActivityUpdater, LifecyclePhase. // actions const registry = Registry.as(ActionExtensions.WorkbenchActions); -registry.registerWorkbenchAction(new SyncActionDescriptor(ToggleMarkersPanelAction, ToggleMarkersPanelAction.ID, ToggleMarkersPanelAction.LABEL, { +registry.registerWorkbenchAction(SyncActionDescriptor.create(ToggleMarkersPanelAction, ToggleMarkersPanelAction.ID, ToggleMarkersPanelAction.LABEL, { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_M }), 'View: Toggle Problems (Errors, Warnings, Infos)', Messages.MARKERS_PANEL_VIEW_CATEGORY); -registry.registerWorkbenchAction(new SyncActionDescriptor(ShowProblemsPanelAction, ShowProblemsPanelAction.ID, ShowProblemsPanelAction.LABEL), 'View: Focus Problems (Errors, Warnings, Infos)', Messages.MARKERS_PANEL_VIEW_CATEGORY); +registry.registerWorkbenchAction(SyncActionDescriptor.create(ShowProblemsPanelAction, ShowProblemsPanelAction.ID, ShowProblemsPanelAction.LABEL), 'View: Focus Problems (Errors, Warnings, Infos)', Messages.MARKERS_PANEL_VIEW_CATEGORY); registerAction({ id: Constants.MARKER_COPY_ACTION_ID, title: { value: localize('copyMarker', "Copy"), original: 'Copy' }, diff --git a/src/vs/workbench/contrib/output/browser/output.contribution.ts b/src/vs/workbench/contrib/output/browser/output.contribution.ts index 273ac9f397ddf..b5032f1eacc08 100644 --- a/src/vs/workbench/contrib/output/browser/output.contribution.ts +++ b/src/vs/workbench/contrib/output/browser/output.contribution.ts @@ -74,19 +74,19 @@ Registry.as(WorkbenchExtensions.Workbench).regi // register toggle output action globally const actionRegistry = Registry.as(ActionExtensions.WorkbenchActions); -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ToggleOutputAction, ToggleOutputAction.ID, ToggleOutputAction.LABEL, { +actionRegistry.registerWorkbenchAction(SyncActionDescriptor.create(ToggleOutputAction, ToggleOutputAction.ID, ToggleOutputAction.LABEL, { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_U, linux: { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.KEY_H) // On Ubuntu Ctrl+Shift+U is taken by some global OS command } }), 'View: Toggle Output', nls.localize('viewCategory', "View")); -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ClearOutputAction, ClearOutputAction.ID, ClearOutputAction.LABEL), +actionRegistry.registerWorkbenchAction(SyncActionDescriptor.create(ClearOutputAction, ClearOutputAction.ID, ClearOutputAction.LABEL), 'View: Clear Output', nls.localize('viewCategory', "View")); const devCategory = nls.localize('developer', "Developer"); -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ShowLogsOutputChannelAction, ShowLogsOutputChannelAction.ID, ShowLogsOutputChannelAction.LABEL), 'Developer: Show Logs...', devCategory); -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(OpenOutputLogFileAction, OpenOutputLogFileAction.ID, OpenOutputLogFileAction.LABEL), 'Developer: Open Log File...', devCategory); +actionRegistry.registerWorkbenchAction(SyncActionDescriptor.create(ShowLogsOutputChannelAction, ShowLogsOutputChannelAction.ID, ShowLogsOutputChannelAction.LABEL), 'Developer: Show Logs...', devCategory); +actionRegistry.registerWorkbenchAction(SyncActionDescriptor.create(OpenOutputLogFileAction, OpenOutputLogFileAction.ID, OpenOutputLogFileAction.LABEL), 'Developer: Open Log File...', devCategory); // Define clear command, contribute to editor context menu registerAction({ diff --git a/src/vs/workbench/contrib/preferences/browser/keyboardLayoutPicker.ts b/src/vs/workbench/contrib/preferences/browser/keyboardLayoutPicker.ts index b076def7c83f5..77136d27d2f98 100644 --- a/src/vs/workbench/contrib/preferences/browser/keyboardLayoutPicker.ts +++ b/src/vs/workbench/contrib/preferences/browser/keyboardLayoutPicker.ts @@ -176,4 +176,4 @@ export class KeyboardLayoutPickerAction extends Action { } const registry = Registry.as(ActionExtensions.WorkbenchActions); -registry.registerWorkbenchAction(new SyncActionDescriptor(KeyboardLayoutPickerAction, KeyboardLayoutPickerAction.ID, KeyboardLayoutPickerAction.LABEL, {}), 'Preferences: Change Keyboard Layout', nls.localize('preferences', "Preferences")); +registry.registerWorkbenchAction(SyncActionDescriptor.create(KeyboardLayoutPickerAction, KeyboardLayoutPickerAction.ID, KeyboardLayoutPickerAction.LABEL, {}), 'Preferences: Change Keyboard Layout', nls.localize('preferences', "Preferences")); diff --git a/src/vs/workbench/contrib/preferences/browser/preferences.contribution.ts b/src/vs/workbench/contrib/preferences/browser/preferences.contribution.ts index 36d2c63d1b0aa..4580b8d23eff1 100644 --- a/src/vs/workbench/contrib/preferences/browser/preferences.contribution.ts +++ b/src/vs/workbench/contrib/preferences/browser/preferences.contribution.ts @@ -199,15 +199,15 @@ Registry.as(EditorInputExtensions.EditorInputFactor // Contribute Global Actions const category = nls.localize('preferences', "Preferences"); const registry = Registry.as(Extensions.WorkbenchActions); -registry.registerWorkbenchAction(new SyncActionDescriptor(OpenRawDefaultSettingsAction, OpenRawDefaultSettingsAction.ID, OpenRawDefaultSettingsAction.LABEL), 'Preferences: Open Default Settings (JSON)', category); -registry.registerWorkbenchAction(new SyncActionDescriptor(OpenSettingsJsonAction, OpenSettingsJsonAction.ID, OpenSettingsJsonAction.LABEL), 'Preferences: Open Settings (JSON)', category); -registry.registerWorkbenchAction(new SyncActionDescriptor(OpenSettings2Action, OpenSettings2Action.ID, OpenSettings2Action.LABEL), 'Preferences: Open Settings (UI)', category); -registry.registerWorkbenchAction(new SyncActionDescriptor(OpenGlobalSettingsAction, OpenGlobalSettingsAction.ID, OpenGlobalSettingsAction.LABEL), 'Preferences: Open User Settings', category); - -registry.registerWorkbenchAction(new SyncActionDescriptor(OpenGlobalKeybindingsAction, OpenGlobalKeybindingsAction.ID, OpenGlobalKeybindingsAction.LABEL, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.KEY_S) }), 'Preferences: Open Keyboard Shortcuts', category); -registry.registerWorkbenchAction(new SyncActionDescriptor(OpenDefaultKeybindingsFileAction, OpenDefaultKeybindingsFileAction.ID, OpenDefaultKeybindingsFileAction.LABEL), 'Preferences: Open Default Keyboard Shortcuts (JSON)', category); -registry.registerWorkbenchAction(new SyncActionDescriptor(OpenGlobalKeybindingsFileAction, OpenGlobalKeybindingsFileAction.ID, OpenGlobalKeybindingsFileAction.LABEL, { primary: 0 }), 'Preferences: Open Keyboard Shortcuts (JSON)', category); -registry.registerWorkbenchAction(new SyncActionDescriptor(ConfigureLanguageBasedSettingsAction, ConfigureLanguageBasedSettingsAction.ID, ConfigureLanguageBasedSettingsAction.LABEL), 'Preferences: Configure Language Specific Settings...', category); +registry.registerWorkbenchAction(SyncActionDescriptor.create(OpenRawDefaultSettingsAction, OpenRawDefaultSettingsAction.ID, OpenRawDefaultSettingsAction.LABEL), 'Preferences: Open Default Settings (JSON)', category); +registry.registerWorkbenchAction(SyncActionDescriptor.create(OpenSettingsJsonAction, OpenSettingsJsonAction.ID, OpenSettingsJsonAction.LABEL), 'Preferences: Open Settings (JSON)', category); +registry.registerWorkbenchAction(SyncActionDescriptor.create(OpenSettings2Action, OpenSettings2Action.ID, OpenSettings2Action.LABEL), 'Preferences: Open Settings (UI)', category); +registry.registerWorkbenchAction(SyncActionDescriptor.create(OpenGlobalSettingsAction, OpenGlobalSettingsAction.ID, OpenGlobalSettingsAction.LABEL), 'Preferences: Open User Settings', category); + +registry.registerWorkbenchAction(SyncActionDescriptor.create(OpenGlobalKeybindingsAction, OpenGlobalKeybindingsAction.ID, OpenGlobalKeybindingsAction.LABEL, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.KEY_S) }), 'Preferences: Open Keyboard Shortcuts', category); +registry.registerWorkbenchAction(SyncActionDescriptor.create(OpenDefaultKeybindingsFileAction, OpenDefaultKeybindingsFileAction.ID, OpenDefaultKeybindingsFileAction.LABEL), 'Preferences: Open Default Keyboard Shortcuts (JSON)', category); +registry.registerWorkbenchAction(SyncActionDescriptor.create(OpenGlobalKeybindingsFileAction, OpenGlobalKeybindingsFileAction.ID, OpenGlobalKeybindingsFileAction.LABEL, { primary: 0 }), 'Preferences: Open Keyboard Shortcuts (JSON)', category); +registry.registerWorkbenchAction(SyncActionDescriptor.create(ConfigureLanguageBasedSettingsAction, ConfigureLanguageBasedSettingsAction.ID, ConfigureLanguageBasedSettingsAction.LABEL), 'Preferences: Configure Language Specific Settings...', category); KeybindingsRegistry.registerCommandAndKeybindingRule({ id: SETTINGS_COMMAND_OPEN_SETTINGS, diff --git a/src/vs/workbench/contrib/quickopen/browser/quickopen.contribution.ts b/src/vs/workbench/contrib/quickopen/browser/quickopen.contribution.ts index 98a93b09c379d..87639a7409aa6 100644 --- a/src/vs/workbench/contrib/quickopen/browser/quickopen.contribution.ts +++ b/src/vs/workbench/contrib/quickopen/browser/quickopen.contribution.ts @@ -21,18 +21,18 @@ import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/co // Register Actions const registry = Registry.as(ActionExtensions.WorkbenchActions); -registry.registerWorkbenchAction(new SyncActionDescriptor(ClearCommandHistoryAction, ClearCommandHistoryAction.ID, ClearCommandHistoryAction.LABEL), 'Clear Command History'); -registry.registerWorkbenchAction(new SyncActionDescriptor(ShowAllCommandsAction, ShowAllCommandsAction.ID, ShowAllCommandsAction.LABEL, { +registry.registerWorkbenchAction(SyncActionDescriptor.create(ClearCommandHistoryAction, ClearCommandHistoryAction.ID, ClearCommandHistoryAction.LABEL), 'Clear Command History'); +registry.registerWorkbenchAction(SyncActionDescriptor.create(ShowAllCommandsAction, ShowAllCommandsAction.ID, ShowAllCommandsAction.LABEL, { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_P, secondary: [KeyCode.F1] }), 'Show All Commands'); -registry.registerWorkbenchAction(new SyncActionDescriptor(GotoLineAction, GotoLineAction.ID, GotoLineAction.LABEL, { +registry.registerWorkbenchAction(SyncActionDescriptor.create(GotoLineAction, GotoLineAction.ID, GotoLineAction.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.KEY_G, mac: { primary: KeyMod.WinCtrl | KeyCode.KEY_G } }), 'Go to Line...'); -registry.registerWorkbenchAction(new SyncActionDescriptor(GotoSymbolAction, GotoSymbolAction.ID, GotoSymbolAction.LABEL, { +registry.registerWorkbenchAction(SyncActionDescriptor.create(GotoSymbolAction, GotoSymbolAction.ID, GotoSymbolAction.LABEL, { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_O }), 'Go to Symbol in File...'); @@ -42,8 +42,8 @@ const inViewsPickerContext = ContextKeyExpr.and(inQuickOpenContext, ContextKeyEx const viewPickerKeybinding = { primary: KeyMod.CtrlCmd | KeyCode.KEY_Q, mac: { primary: KeyMod.WinCtrl | KeyCode.KEY_Q }, linux: { primary: 0 } }; const viewCategory = nls.localize('view', "View"); -registry.registerWorkbenchAction(new SyncActionDescriptor(OpenViewPickerAction, OpenViewPickerAction.ID, OpenViewPickerAction.LABEL), 'View: Open View', viewCategory); -registry.registerWorkbenchAction(new SyncActionDescriptor(QuickOpenViewPickerAction, QuickOpenViewPickerAction.ID, QuickOpenViewPickerAction.LABEL, viewPickerKeybinding), 'View: Quick Open View', viewCategory); +registry.registerWorkbenchAction(SyncActionDescriptor.create(OpenViewPickerAction, OpenViewPickerAction.ID, OpenViewPickerAction.LABEL), 'View: Open View', viewCategory); +registry.registerWorkbenchAction(SyncActionDescriptor.create(QuickOpenViewPickerAction, QuickOpenViewPickerAction.ID, QuickOpenViewPickerAction.LABEL, viewPickerKeybinding), 'View: Quick Open View', viewCategory); const quickOpenNavigateNextInViewPickerId = 'workbench.action.quickOpenNavigateNextInViewPicker'; KeybindingsRegistry.registerCommandAndKeybindingRule({ diff --git a/src/vs/workbench/contrib/remote/browser/remote.ts b/src/vs/workbench/contrib/remote/browser/remote.ts index 5901752fe70f0..6608c97946621 100644 --- a/src/vs/workbench/contrib/remote/browser/remote.ts +++ b/src/vs/workbench/contrib/remote/browser/remote.ts @@ -294,7 +294,7 @@ class OpenRemoteViewletAction extends ShowViewletAction { // Register Action to Open Viewlet Registry.as(WorkbenchActionExtensions.WorkbenchActions).registerWorkbenchAction( - new SyncActionDescriptor(OpenRemoteViewletAction, VIEWLET_ID, nls.localize('toggleRemoteViewlet', "Show Remote Explorer"), { + SyncActionDescriptor.create(OpenRemoteViewletAction, VIEWLET_ID, nls.localize('toggleRemoteViewlet', "Show Remote Explorer"), { primary: 0 }), 'View: Show Remote Explorer', diff --git a/src/vs/workbench/contrib/scm/browser/scm.contribution.ts b/src/vs/workbench/contrib/scm/browser/scm.contribution.ts index 8f269704ca078..ce51e05887cc0 100644 --- a/src/vs/workbench/contrib/scm/browser/scm.contribution.ts +++ b/src/vs/workbench/contrib/scm/browser/scm.contribution.ts @@ -51,7 +51,7 @@ Registry.as(WorkbenchExtensions.Workbench) // Register Action to Open Viewlet Registry.as(WorkbenchActionExtensions.WorkbenchActions).registerWorkbenchAction( - new SyncActionDescriptor(OpenSCMViewletAction, VIEWLET_ID, localize('toggleSCMViewlet', "Show SCM"), { + SyncActionDescriptor.create(OpenSCMViewletAction, VIEWLET_ID, localize('toggleSCMViewlet', "Show SCM"), { primary: 0, win: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_G }, linux: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_G }, diff --git a/src/vs/workbench/contrib/search/browser/search.contribution.ts b/src/vs/workbench/contrib/search/browser/search.contribution.ts index 7343939e042ad..07e88ed203436 100644 --- a/src/vs/workbench/contrib/search/browser/search.contribution.ts +++ b/src/vs/workbench/contrib/search/browser/search.contribution.ts @@ -564,7 +564,7 @@ const registry = Registry.as(ActionExtensions.Workbenc // Show Search and Find in Files are redundant, but we can't break keybindings by removing one. So it's the same action, same keybinding, registered to different IDs. // Show Search 'when' is redundant but if the two conflict with exactly the same keybinding and 'when' clause, then they can show up as "unbound" - #51780 -registry.registerWorkbenchAction(new SyncActionDescriptor(OpenSearchViewletAction, VIEWLET_ID, OpenSearchViewletAction.LABEL, { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_F }, Constants.SearchViewVisibleKey.toNegated()), 'View: Show Search', nls.localize('view', "View")); +registry.registerWorkbenchAction(SyncActionDescriptor.create(OpenSearchViewletAction, VIEWLET_ID, OpenSearchViewletAction.LABEL, { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_F }, Constants.SearchViewVisibleKey.toNegated()), 'View: Show Search', nls.localize('view', "View")); KeybindingsRegistry.registerCommandAndKeybindingRule({ id: Constants.FindInFilesActionId, weight: KeybindingWeight.WorkbenchContrib, @@ -582,10 +582,10 @@ MenuRegistry.appendMenuItem(MenuId.MenubarEditMenu, { order: 1 }); -registry.registerWorkbenchAction(new SyncActionDescriptor(FocusNextSearchResultAction, FocusNextSearchResultAction.ID, FocusNextSearchResultAction.LABEL, { primary: KeyCode.F4 }, ContextKeyExpr.and(Constants.HasSearchResults)), 'Focus Next Search Result', category); -registry.registerWorkbenchAction(new SyncActionDescriptor(FocusPreviousSearchResultAction, FocusPreviousSearchResultAction.ID, FocusPreviousSearchResultAction.LABEL, { primary: KeyMod.Shift | KeyCode.F4 }, ContextKeyExpr.and(Constants.HasSearchResults)), 'Focus Previous Search Result', category); +registry.registerWorkbenchAction(SyncActionDescriptor.create(FocusNextSearchResultAction, FocusNextSearchResultAction.ID, FocusNextSearchResultAction.LABEL, { primary: KeyCode.F4 }, ContextKeyExpr.and(Constants.HasSearchResults)), 'Focus Next Search Result', category); +registry.registerWorkbenchAction(SyncActionDescriptor.create(FocusPreviousSearchResultAction, FocusPreviousSearchResultAction.ID, FocusPreviousSearchResultAction.LABEL, { primary: KeyMod.Shift | KeyCode.F4 }, ContextKeyExpr.and(Constants.HasSearchResults)), 'Focus Previous Search Result', category); -registry.registerWorkbenchAction(new SyncActionDescriptor(ReplaceInFilesAction, ReplaceInFilesAction.ID, ReplaceInFilesAction.LABEL, { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_H }), 'Replace in Files', category); +registry.registerWorkbenchAction(SyncActionDescriptor.create(ReplaceInFilesAction, ReplaceInFilesAction.ID, ReplaceInFilesAction.LABEL, { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_H }), 'Replace in Files', category); MenuRegistry.appendMenuItem(MenuId.MenubarEditMenu, { group: '4_find_global', command: { @@ -616,12 +616,12 @@ KeybindingsRegistry.registerCommandAndKeybindingRule(objects.assign({ handler: toggleRegexCommand }, ToggleRegexKeybinding)); -registry.registerWorkbenchAction(new SyncActionDescriptor(CollapseDeepestExpandedLevelAction, CollapseDeepestExpandedLevelAction.ID, CollapseDeepestExpandedLevelAction.LABEL), 'Search: Collapse All', category); -registry.registerWorkbenchAction(new SyncActionDescriptor(ShowAllSymbolsAction, ShowAllSymbolsAction.ID, ShowAllSymbolsAction.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.KEY_T }), 'Go to Symbol in Workspace...'); +registry.registerWorkbenchAction(SyncActionDescriptor.create(CollapseDeepestExpandedLevelAction, CollapseDeepestExpandedLevelAction.ID, CollapseDeepestExpandedLevelAction.LABEL), 'Search: Collapse All', category); +registry.registerWorkbenchAction(SyncActionDescriptor.create(ShowAllSymbolsAction, ShowAllSymbolsAction.ID, ShowAllSymbolsAction.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.KEY_T }), 'Go to Symbol in Workspace...'); -registry.registerWorkbenchAction(new SyncActionDescriptor(ToggleSearchOnTypeAction, ToggleSearchOnTypeAction.ID, ToggleSearchOnTypeAction.LABEL), 'Search: Toggle Search on Type', category); -registry.registerWorkbenchAction(new SyncActionDescriptor(RefreshAction, RefreshAction.ID, RefreshAction.LABEL), 'Search: Refresh', category); -registry.registerWorkbenchAction(new SyncActionDescriptor(ClearSearchResultsAction, ClearSearchResultsAction.ID, ClearSearchResultsAction.LABEL), 'Search: Clear Search Results', category); +registry.registerWorkbenchAction(SyncActionDescriptor.create(ToggleSearchOnTypeAction, ToggleSearchOnTypeAction.ID, ToggleSearchOnTypeAction.LABEL), 'Search: Toggle Search on Type', category); +registry.registerWorkbenchAction(SyncActionDescriptor.create(RefreshAction, RefreshAction.ID, RefreshAction.LABEL), 'Search: Refresh', category); +registry.registerWorkbenchAction(SyncActionDescriptor.create(ClearSearchResultsAction, ClearSearchResultsAction.ID, ClearSearchResultsAction.LABEL), 'Search: Clear Search Results', category); // Register Quick Open Handler diff --git a/src/vs/workbench/contrib/tasks/browser/task.contribution.ts b/src/vs/workbench/contrib/tasks/browser/task.contribution.ts index ab806797f1eb3..9e352e4b9ce3b 100644 --- a/src/vs/workbench/contrib/tasks/browser/task.contribution.ts +++ b/src/vs/workbench/contrib/tasks/browser/task.contribution.ts @@ -45,7 +45,7 @@ const workbenchRegistry = Registry.as(Workbench workbenchRegistry.registerWorkbenchContribution(RunAutomaticTasks, LifecyclePhase.Eventually); const actionRegistry = Registry.as(ActionExtensions.WorkbenchActions); -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ManageAutomaticTaskRunning, ManageAutomaticTaskRunning.ID, ManageAutomaticTaskRunning.LABEL), 'Tasks: Manage Automatic Tasks in Folder', tasksCategory); +actionRegistry.registerWorkbenchAction(SyncActionDescriptor.create(ManageAutomaticTaskRunning, ManageAutomaticTaskRunning.ID, ManageAutomaticTaskRunning.LABEL), 'Tasks: Manage Automatic Tasks in Folder', tasksCategory); export class TaskStatusBarContributions extends Disposable implements IWorkbenchContribution { private runningTasksStatusItem: IStatusbarEntryAccessor | undefined; diff --git a/src/vs/workbench/contrib/terminal/browser/terminal.contribution.ts b/src/vs/workbench/contrib/terminal/browser/terminal.contribution.ts index 485539d452b99..81eb57fddd66e 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminal.contribution.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminal.contribution.ts @@ -327,7 +327,7 @@ configurationRegistry.registerConfiguration({ }); const registry = Registry.as(ActionExtensions.WorkbenchActions); -registry.registerWorkbenchAction(new SyncActionDescriptor(QuickOpenTermAction, QuickOpenTermAction.ID, QuickOpenTermAction.LABEL), 'Terminal: Switch Active Terminal', nls.localize('terminal', "Terminal")); +registry.registerWorkbenchAction(SyncActionDescriptor.create(QuickOpenTermAction, QuickOpenTermAction.ID, QuickOpenTermAction.LABEL), 'Terminal: Switch Active Terminal', nls.localize('terminal', "Terminal")); const actionBarRegistry = Registry.as(ActionBarExtensions.Actionbar); actionBarRegistry.registerActionBarContributor(Scope.VIEWER, QuickOpenActionTermContributor); @@ -344,20 +344,20 @@ Registry.as(panel.Extensions.Panels).setDefaultPanelId(TERM // On mac cmd+` is reserved to cycle between windows, that's why the keybindings use WinCtrl const category = TERMINAL_ACTION_CATEGORY; const actionRegistry = Registry.as(ActionExtensions.WorkbenchActions); -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(KillTerminalAction, KillTerminalAction.ID, KillTerminalAction.LABEL), 'Terminal: Kill the Active Terminal Instance', category); -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(CreateNewTerminalAction, CreateNewTerminalAction.ID, CreateNewTerminalAction.LABEL, { +actionRegistry.registerWorkbenchAction(SyncActionDescriptor.create(KillTerminalAction, KillTerminalAction.ID, KillTerminalAction.LABEL), 'Terminal: Kill the Active Terminal Instance', category); +actionRegistry.registerWorkbenchAction(SyncActionDescriptor.create(CreateNewTerminalAction, CreateNewTerminalAction.ID, CreateNewTerminalAction.LABEL, { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.US_BACKTICK, mac: { primary: KeyMod.WinCtrl | KeyMod.Shift | KeyCode.US_BACKTICK } }), 'Terminal: Create New Integrated Terminal', category); -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ClearSelectionTerminalAction, ClearSelectionTerminalAction.ID, ClearSelectionTerminalAction.LABEL, { +actionRegistry.registerWorkbenchAction(SyncActionDescriptor.create(ClearSelectionTerminalAction, ClearSelectionTerminalAction.ID, ClearSelectionTerminalAction.LABEL, { primary: KeyCode.Escape, linux: { primary: KeyCode.Escape } }, ContextKeyExpr.and(KEYBINDING_CONTEXT_TERMINAL_FOCUS, KEYBINDING_CONTEXT_TERMINAL_TEXT_SELECTED, KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_NOT_VISIBLE)), 'Terminal: Clear Selection', category); -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(CreateNewInActiveWorkspaceTerminalAction, CreateNewInActiveWorkspaceTerminalAction.ID, CreateNewInActiveWorkspaceTerminalAction.LABEL), 'Terminal: Create New Integrated Terminal (In Active Workspace)', category); -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(FocusActiveTerminalAction, FocusActiveTerminalAction.ID, FocusActiveTerminalAction.LABEL), 'Terminal: Focus Terminal', category); -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(FocusNextTerminalAction, FocusNextTerminalAction.ID, FocusNextTerminalAction.LABEL), 'Terminal: Focus Next Terminal', category); -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(FocusPreviousTerminalAction, FocusPreviousTerminalAction.ID, FocusPreviousTerminalAction.LABEL), 'Terminal: Focus Previous Terminal', category); -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(SelectAllTerminalAction, SelectAllTerminalAction.ID, SelectAllTerminalAction.LABEL, { +actionRegistry.registerWorkbenchAction(SyncActionDescriptor.create(CreateNewInActiveWorkspaceTerminalAction, CreateNewInActiveWorkspaceTerminalAction.ID, CreateNewInActiveWorkspaceTerminalAction.LABEL), 'Terminal: Create New Integrated Terminal (In Active Workspace)', category); +actionRegistry.registerWorkbenchAction(SyncActionDescriptor.create(FocusActiveTerminalAction, FocusActiveTerminalAction.ID, FocusActiveTerminalAction.LABEL), 'Terminal: Focus Terminal', category); +actionRegistry.registerWorkbenchAction(SyncActionDescriptor.create(FocusNextTerminalAction, FocusNextTerminalAction.ID, FocusNextTerminalAction.LABEL), 'Terminal: Focus Next Terminal', category); +actionRegistry.registerWorkbenchAction(SyncActionDescriptor.create(FocusPreviousTerminalAction, FocusPreviousTerminalAction.ID, FocusPreviousTerminalAction.LABEL), 'Terminal: Focus Previous Terminal', category); +actionRegistry.registerWorkbenchAction(SyncActionDescriptor.create(SelectAllTerminalAction, SelectAllTerminalAction.ID, SelectAllTerminalAction.LABEL, { // Don't use ctrl+a by default as that would override the common go to start // of prompt shell binding primary: 0, @@ -366,82 +366,82 @@ actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(SelectAllTermina // makes it easier for users to see how it works though. mac: { primary: KeyMod.CtrlCmd | KeyCode.KEY_A } }, KEYBINDING_CONTEXT_TERMINAL_FOCUS), 'Terminal: Select All', category); -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(RunSelectedTextInTerminalAction, RunSelectedTextInTerminalAction.ID, RunSelectedTextInTerminalAction.LABEL), 'Terminal: Run Selected Text In Active Terminal', category); -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(RunActiveFileInTerminalAction, RunActiveFileInTerminalAction.ID, RunActiveFileInTerminalAction.LABEL), 'Terminal: Run Active File In Active Terminal', category); -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ToggleTerminalAction, ToggleTerminalAction.ID, ToggleTerminalAction.LABEL, { +actionRegistry.registerWorkbenchAction(SyncActionDescriptor.create(RunSelectedTextInTerminalAction, RunSelectedTextInTerminalAction.ID, RunSelectedTextInTerminalAction.LABEL), 'Terminal: Run Selected Text In Active Terminal', category); +actionRegistry.registerWorkbenchAction(SyncActionDescriptor.create(RunActiveFileInTerminalAction, RunActiveFileInTerminalAction.ID, RunActiveFileInTerminalAction.LABEL), 'Terminal: Run Active File In Active Terminal', category); +actionRegistry.registerWorkbenchAction(SyncActionDescriptor.create(ToggleTerminalAction, ToggleTerminalAction.ID, ToggleTerminalAction.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.US_BACKTICK, mac: { primary: KeyMod.WinCtrl | KeyCode.US_BACKTICK } }), 'View: Toggle Integrated Terminal', nls.localize('viewCategory', "View")); -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ScrollDownTerminalAction, ScrollDownTerminalAction.ID, ScrollDownTerminalAction.LABEL, { +actionRegistry.registerWorkbenchAction(SyncActionDescriptor.create(ScrollDownTerminalAction, ScrollDownTerminalAction.ID, ScrollDownTerminalAction.LABEL, { primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.PageDown, linux: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.DownArrow } }, KEYBINDING_CONTEXT_TERMINAL_FOCUS), 'Terminal: Scroll Down (Line)', category); -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ScrollDownPageTerminalAction, ScrollDownPageTerminalAction.ID, ScrollDownPageTerminalAction.LABEL, { +actionRegistry.registerWorkbenchAction(SyncActionDescriptor.create(ScrollDownPageTerminalAction, ScrollDownPageTerminalAction.ID, ScrollDownPageTerminalAction.LABEL, { primary: KeyMod.Shift | KeyCode.PageDown, mac: { primary: KeyCode.PageDown } }, KEYBINDING_CONTEXT_TERMINAL_FOCUS), 'Terminal: Scroll Down (Page)', category); -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ScrollToBottomTerminalAction, ScrollToBottomTerminalAction.ID, ScrollToBottomTerminalAction.LABEL, { +actionRegistry.registerWorkbenchAction(SyncActionDescriptor.create(ScrollToBottomTerminalAction, ScrollToBottomTerminalAction.ID, ScrollToBottomTerminalAction.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.End, linux: { primary: KeyMod.Shift | KeyCode.End } }, KEYBINDING_CONTEXT_TERMINAL_FOCUS), 'Terminal: Scroll to Bottom', category); -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ScrollUpTerminalAction, ScrollUpTerminalAction.ID, ScrollUpTerminalAction.LABEL, { +actionRegistry.registerWorkbenchAction(SyncActionDescriptor.create(ScrollUpTerminalAction, ScrollUpTerminalAction.ID, ScrollUpTerminalAction.LABEL, { primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.PageUp, linux: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.UpArrow }, }, KEYBINDING_CONTEXT_TERMINAL_FOCUS), 'Terminal: Scroll Up (Line)', category); -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ScrollUpPageTerminalAction, ScrollUpPageTerminalAction.ID, ScrollUpPageTerminalAction.LABEL, { +actionRegistry.registerWorkbenchAction(SyncActionDescriptor.create(ScrollUpPageTerminalAction, ScrollUpPageTerminalAction.ID, ScrollUpPageTerminalAction.LABEL, { primary: KeyMod.Shift | KeyCode.PageUp, mac: { primary: KeyCode.PageUp } }, KEYBINDING_CONTEXT_TERMINAL_FOCUS), 'Terminal: Scroll Up (Page)', category); -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ScrollToTopTerminalAction, ScrollToTopTerminalAction.ID, ScrollToTopTerminalAction.LABEL, { +actionRegistry.registerWorkbenchAction(SyncActionDescriptor.create(ScrollToTopTerminalAction, ScrollToTopTerminalAction.ID, ScrollToTopTerminalAction.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.Home, linux: { primary: KeyMod.Shift | KeyCode.Home } }, KEYBINDING_CONTEXT_TERMINAL_FOCUS), 'Terminal: Scroll to Top', category); -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ClearTerminalAction, ClearTerminalAction.ID, ClearTerminalAction.LABEL, { +actionRegistry.registerWorkbenchAction(SyncActionDescriptor.create(ClearTerminalAction, ClearTerminalAction.ID, ClearTerminalAction.LABEL, { primary: 0, mac: { primary: KeyMod.CtrlCmd | KeyCode.KEY_K } }, KEYBINDING_CONTEXT_TERMINAL_FOCUS, KeybindingWeight.WorkbenchContrib + 1), 'Terminal: Clear', category); -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(SelectDefaultShellWindowsTerminalAction, SelectDefaultShellWindowsTerminalAction.ID, SelectDefaultShellWindowsTerminalAction.LABEL), 'Terminal: Select Default Shell', category); -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ManageWorkspaceShellPermissionsTerminalCommand, ManageWorkspaceShellPermissionsTerminalCommand.ID, ManageWorkspaceShellPermissionsTerminalCommand.LABEL), 'Terminal: Manage Workspace Shell Permissions', category); -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(RenameTerminalAction, RenameTerminalAction.ID, RenameTerminalAction.LABEL), 'Terminal: Rename', category); -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(FocusTerminalFindWidgetAction, FocusTerminalFindWidgetAction.ID, FocusTerminalFindWidgetAction.LABEL, { +actionRegistry.registerWorkbenchAction(SyncActionDescriptor.create(SelectDefaultShellWindowsTerminalAction, SelectDefaultShellWindowsTerminalAction.ID, SelectDefaultShellWindowsTerminalAction.LABEL), 'Terminal: Select Default Shell', category); +actionRegistry.registerWorkbenchAction(SyncActionDescriptor.create(ManageWorkspaceShellPermissionsTerminalCommand, ManageWorkspaceShellPermissionsTerminalCommand.ID, ManageWorkspaceShellPermissionsTerminalCommand.LABEL), 'Terminal: Manage Workspace Shell Permissions', category); +actionRegistry.registerWorkbenchAction(SyncActionDescriptor.create(RenameTerminalAction, RenameTerminalAction.ID, RenameTerminalAction.LABEL), 'Terminal: Rename', category); +actionRegistry.registerWorkbenchAction(SyncActionDescriptor.create(FocusTerminalFindWidgetAction, FocusTerminalFindWidgetAction.ID, FocusTerminalFindWidgetAction.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.KEY_F }, KEYBINDING_CONTEXT_TERMINAL_FOCUS), 'Terminal: Focus Find Widget', category); -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(FocusTerminalFindWidgetAction, FocusTerminalFindWidgetAction.ID, FocusTerminalFindWidgetAction.LABEL, { +actionRegistry.registerWorkbenchAction(SyncActionDescriptor.create(FocusTerminalFindWidgetAction, FocusTerminalFindWidgetAction.ID, FocusTerminalFindWidgetAction.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.KEY_F }, KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_FOCUSED), 'Terminal: Focus Find Widget', category); -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(HideTerminalFindWidgetAction, HideTerminalFindWidgetAction.ID, HideTerminalFindWidgetAction.LABEL, { +actionRegistry.registerWorkbenchAction(SyncActionDescriptor.create(HideTerminalFindWidgetAction, HideTerminalFindWidgetAction.ID, HideTerminalFindWidgetAction.LABEL, { primary: KeyCode.Escape, secondary: [KeyMod.Shift | KeyCode.Escape] }, ContextKeyExpr.and(KEYBINDING_CONTEXT_TERMINAL_FOCUS, KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_VISIBLE)), 'Terminal: Hide Find Widget', category); -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(DeleteWordLeftTerminalAction, DeleteWordLeftTerminalAction.ID, DeleteWordLeftTerminalAction.LABEL, { +actionRegistry.registerWorkbenchAction(SyncActionDescriptor.create(DeleteWordLeftTerminalAction, DeleteWordLeftTerminalAction.ID, DeleteWordLeftTerminalAction.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.Backspace, mac: { primary: KeyMod.Alt | KeyCode.Backspace } }, KEYBINDING_CONTEXT_TERMINAL_FOCUS), 'Terminal: Delete Word Left', category); -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(DeleteWordRightTerminalAction, DeleteWordRightTerminalAction.ID, DeleteWordRightTerminalAction.LABEL, { +actionRegistry.registerWorkbenchAction(SyncActionDescriptor.create(DeleteWordRightTerminalAction, DeleteWordRightTerminalAction.ID, DeleteWordRightTerminalAction.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.Delete, mac: { primary: KeyMod.Alt | KeyCode.Delete } }, KEYBINDING_CONTEXT_TERMINAL_FOCUS), 'Terminal: Delete Word Right', category); -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(DeleteToLineStartTerminalAction, DeleteToLineStartTerminalAction.ID, DeleteToLineStartTerminalAction.LABEL, { +actionRegistry.registerWorkbenchAction(SyncActionDescriptor.create(DeleteToLineStartTerminalAction, DeleteToLineStartTerminalAction.ID, DeleteToLineStartTerminalAction.LABEL, { primary: 0, mac: { primary: KeyMod.CtrlCmd | KeyCode.Backspace } }, KEYBINDING_CONTEXT_TERMINAL_FOCUS), 'Terminal: Delete To Line Start', category); -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(MoveToLineStartTerminalAction, MoveToLineStartTerminalAction.ID, MoveToLineStartTerminalAction.LABEL, { +actionRegistry.registerWorkbenchAction(SyncActionDescriptor.create(MoveToLineStartTerminalAction, MoveToLineStartTerminalAction.ID, MoveToLineStartTerminalAction.LABEL, { primary: 0, mac: { primary: KeyMod.CtrlCmd | KeyCode.LeftArrow } }, KEYBINDING_CONTEXT_TERMINAL_FOCUS), 'Terminal: Move To Line Start', category); -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(MoveToLineEndTerminalAction, MoveToLineEndTerminalAction.ID, MoveToLineEndTerminalAction.LABEL, { +actionRegistry.registerWorkbenchAction(SyncActionDescriptor.create(MoveToLineEndTerminalAction, MoveToLineEndTerminalAction.ID, MoveToLineEndTerminalAction.LABEL, { primary: 0, mac: { primary: KeyMod.CtrlCmd | KeyCode.RightArrow } }, KEYBINDING_CONTEXT_TERMINAL_FOCUS), 'Terminal: Move To Line End', category); -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(SplitTerminalAction, SplitTerminalAction.ID, SplitTerminalAction.LABEL, { +actionRegistry.registerWorkbenchAction(SyncActionDescriptor.create(SplitTerminalAction, SplitTerminalAction.ID, SplitTerminalAction.LABEL, { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_5, mac: { primary: KeyMod.CtrlCmd | KeyCode.US_BACKSLASH, secondary: [KeyMod.WinCtrl | KeyMod.Shift | KeyCode.KEY_5] } }, KEYBINDING_CONTEXT_TERMINAL_FOCUS), 'Terminal: Split Terminal', category); -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(SplitInActiveWorkspaceTerminalAction, SplitInActiveWorkspaceTerminalAction.ID, SplitInActiveWorkspaceTerminalAction.LABEL), 'Terminal: Split Terminal (In Active Workspace)', category); -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(FocusPreviousPaneTerminalAction, FocusPreviousPaneTerminalAction.ID, FocusPreviousPaneTerminalAction.LABEL, { +actionRegistry.registerWorkbenchAction(SyncActionDescriptor.create(SplitInActiveWorkspaceTerminalAction, SplitInActiveWorkspaceTerminalAction.ID, SplitInActiveWorkspaceTerminalAction.LABEL), 'Terminal: Split Terminal (In Active Workspace)', category); +actionRegistry.registerWorkbenchAction(SyncActionDescriptor.create(FocusPreviousPaneTerminalAction, FocusPreviousPaneTerminalAction.ID, FocusPreviousPaneTerminalAction.LABEL, { primary: KeyMod.Alt | KeyCode.LeftArrow, secondary: [KeyMod.Alt | KeyCode.UpArrow], mac: { @@ -449,7 +449,7 @@ actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(FocusPreviousPan secondary: [KeyMod.Alt | KeyMod.CtrlCmd | KeyCode.UpArrow] } }, KEYBINDING_CONTEXT_TERMINAL_FOCUS), 'Terminal: Focus Previous Pane', category); -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(FocusNextPaneTerminalAction, FocusNextPaneTerminalAction.ID, FocusNextPaneTerminalAction.LABEL, { +actionRegistry.registerWorkbenchAction(SyncActionDescriptor.create(FocusNextPaneTerminalAction, FocusNextPaneTerminalAction.ID, FocusNextPaneTerminalAction.LABEL, { primary: KeyMod.Alt | KeyCode.RightArrow, secondary: [KeyMod.Alt | KeyCode.DownArrow], mac: { @@ -457,96 +457,96 @@ actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(FocusNextPaneTer secondary: [KeyMod.Alt | KeyMod.CtrlCmd | KeyCode.DownArrow] } }, KEYBINDING_CONTEXT_TERMINAL_FOCUS), 'Terminal: Focus Next Pane', category); -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ResizePaneLeftTerminalAction, ResizePaneLeftTerminalAction.ID, ResizePaneLeftTerminalAction.LABEL, { +actionRegistry.registerWorkbenchAction(SyncActionDescriptor.create(ResizePaneLeftTerminalAction, ResizePaneLeftTerminalAction.ID, ResizePaneLeftTerminalAction.LABEL, { primary: 0, linux: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.LeftArrow }, mac: { primary: KeyMod.CtrlCmd | KeyMod.WinCtrl | KeyCode.LeftArrow } }, KEYBINDING_CONTEXT_TERMINAL_FOCUS), 'Terminal: Resize Pane Left', category); -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ResizePaneRightTerminalAction, ResizePaneRightTerminalAction.ID, ResizePaneRightTerminalAction.LABEL, { +actionRegistry.registerWorkbenchAction(SyncActionDescriptor.create(ResizePaneRightTerminalAction, ResizePaneRightTerminalAction.ID, ResizePaneRightTerminalAction.LABEL, { primary: 0, linux: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.RightArrow }, mac: { primary: KeyMod.CtrlCmd | KeyMod.WinCtrl | KeyCode.RightArrow } }, KEYBINDING_CONTEXT_TERMINAL_FOCUS), 'Terminal: Resize Pane Right', category); -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ResizePaneUpTerminalAction, ResizePaneUpTerminalAction.ID, ResizePaneUpTerminalAction.LABEL, { +actionRegistry.registerWorkbenchAction(SyncActionDescriptor.create(ResizePaneUpTerminalAction, ResizePaneUpTerminalAction.ID, ResizePaneUpTerminalAction.LABEL, { primary: 0, mac: { primary: KeyMod.CtrlCmd | KeyMod.WinCtrl | KeyCode.UpArrow } }, KEYBINDING_CONTEXT_TERMINAL_FOCUS), 'Terminal: Resize Pane Up', category); -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ResizePaneDownTerminalAction, ResizePaneDownTerminalAction.ID, ResizePaneDownTerminalAction.LABEL, { +actionRegistry.registerWorkbenchAction(SyncActionDescriptor.create(ResizePaneDownTerminalAction, ResizePaneDownTerminalAction.ID, ResizePaneDownTerminalAction.LABEL, { primary: 0, mac: { primary: KeyMod.CtrlCmd | KeyMod.WinCtrl | KeyCode.DownArrow } }, KEYBINDING_CONTEXT_TERMINAL_FOCUS), 'Terminal: Resize Pane Down', category); -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ScrollToPreviousCommandAction, ScrollToPreviousCommandAction.ID, ScrollToPreviousCommandAction.LABEL, { +actionRegistry.registerWorkbenchAction(SyncActionDescriptor.create(ScrollToPreviousCommandAction, ScrollToPreviousCommandAction.ID, ScrollToPreviousCommandAction.LABEL, { primary: 0, mac: { primary: KeyMod.CtrlCmd | KeyCode.UpArrow } }, ContextKeyExpr.and(KEYBINDING_CONTEXT_TERMINAL_FOCUS, CONTEXT_ACCESSIBILITY_MODE_ENABLED.negate())), 'Terminal: Scroll To Previous Command', category); -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ScrollToNextCommandAction, ScrollToNextCommandAction.ID, ScrollToNextCommandAction.LABEL, { +actionRegistry.registerWorkbenchAction(SyncActionDescriptor.create(ScrollToNextCommandAction, ScrollToNextCommandAction.ID, ScrollToNextCommandAction.LABEL, { primary: 0, mac: { primary: KeyMod.CtrlCmd | KeyCode.DownArrow } }, ContextKeyExpr.and(KEYBINDING_CONTEXT_TERMINAL_FOCUS, CONTEXT_ACCESSIBILITY_MODE_ENABLED.negate())), 'Terminal: Scroll To Next Command', category); -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(SelectToPreviousCommandAction, SelectToPreviousCommandAction.ID, SelectToPreviousCommandAction.LABEL, { +actionRegistry.registerWorkbenchAction(SyncActionDescriptor.create(SelectToPreviousCommandAction, SelectToPreviousCommandAction.ID, SelectToPreviousCommandAction.LABEL, { primary: 0, mac: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.UpArrow } }, KEYBINDING_CONTEXT_TERMINAL_FOCUS), 'Terminal: Select To Previous Command', category); -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(SelectToNextCommandAction, SelectToNextCommandAction.ID, SelectToNextCommandAction.LABEL, { +actionRegistry.registerWorkbenchAction(SyncActionDescriptor.create(SelectToNextCommandAction, SelectToNextCommandAction.ID, SelectToNextCommandAction.LABEL, { primary: 0, mac: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.DownArrow } }, KEYBINDING_CONTEXT_TERMINAL_FOCUS), 'Terminal: Select To Next Command', category); -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(NavigationModeExitTerminalAction, NavigationModeExitTerminalAction.ID, NavigationModeExitTerminalAction.LABEL, { +actionRegistry.registerWorkbenchAction(SyncActionDescriptor.create(NavigationModeExitTerminalAction, NavigationModeExitTerminalAction.ID, NavigationModeExitTerminalAction.LABEL, { primary: KeyCode.Escape }, ContextKeyExpr.and(KEYBINDING_CONTEXT_TERMINAL_A11Y_TREE_FOCUS, CONTEXT_ACCESSIBILITY_MODE_ENABLED)), 'Terminal: Exit Navigation Mode', category); -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(NavigationModeFocusPreviousTerminalAction, NavigationModeFocusPreviousTerminalAction.ID, NavigationModeFocusPreviousTerminalAction.LABEL, { +actionRegistry.registerWorkbenchAction(SyncActionDescriptor.create(NavigationModeFocusPreviousTerminalAction, NavigationModeFocusPreviousTerminalAction.ID, NavigationModeFocusPreviousTerminalAction.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.UpArrow }, ContextKeyExpr.and(KEYBINDING_CONTEXT_TERMINAL_FOCUS, CONTEXT_ACCESSIBILITY_MODE_ENABLED)), 'Terminal: Focus Previous Line (Navigation Mode)', category); -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(NavigationModeFocusPreviousTerminalAction, NavigationModeFocusPreviousTerminalAction.ID, NavigationModeFocusPreviousTerminalAction.LABEL, { +actionRegistry.registerWorkbenchAction(SyncActionDescriptor.create(NavigationModeFocusPreviousTerminalAction, NavigationModeFocusPreviousTerminalAction.ID, NavigationModeFocusPreviousTerminalAction.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.UpArrow }, ContextKeyExpr.and(KEYBINDING_CONTEXT_TERMINAL_A11Y_TREE_FOCUS, CONTEXT_ACCESSIBILITY_MODE_ENABLED)), 'Terminal: Focus Previous Line (Navigation Mode)', category); -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(NavigationModeFocusNextTerminalAction, NavigationModeFocusNextTerminalAction.ID, NavigationModeFocusNextTerminalAction.LABEL, { +actionRegistry.registerWorkbenchAction(SyncActionDescriptor.create(NavigationModeFocusNextTerminalAction, NavigationModeFocusNextTerminalAction.ID, NavigationModeFocusNextTerminalAction.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.DownArrow }, ContextKeyExpr.and(KEYBINDING_CONTEXT_TERMINAL_FOCUS, CONTEXT_ACCESSIBILITY_MODE_ENABLED)), 'Terminal: Focus Next Line (Navigation Mode)', category); -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(NavigationModeFocusNextTerminalAction, NavigationModeFocusNextTerminalAction.ID, NavigationModeFocusNextTerminalAction.LABEL, { +actionRegistry.registerWorkbenchAction(SyncActionDescriptor.create(NavigationModeFocusNextTerminalAction, NavigationModeFocusNextTerminalAction.ID, NavigationModeFocusNextTerminalAction.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.DownArrow }, ContextKeyExpr.and(KEYBINDING_CONTEXT_TERMINAL_A11Y_TREE_FOCUS, CONTEXT_ACCESSIBILITY_MODE_ENABLED)), 'Terminal: Focus Next Line (Navigation Mode)', category); -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(SelectToPreviousLineAction, SelectToPreviousLineAction.ID, SelectToPreviousLineAction.LABEL), 'Terminal: Select To Previous Line', category); -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(SelectToNextLineAction, SelectToNextLineAction.ID, SelectToNextLineAction.LABEL), 'Terminal: Select To Next Line', category); -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ToggleEscapeSequenceLoggingAction, ToggleEscapeSequenceLoggingAction.ID, ToggleEscapeSequenceLoggingAction.LABEL), 'Terminal: Toggle Escape Sequence Logging', category); -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ToggleRegexCommand, ToggleRegexCommand.ID, ToggleRegexCommand.LABEL, { +actionRegistry.registerWorkbenchAction(SyncActionDescriptor.create(SelectToPreviousLineAction, SelectToPreviousLineAction.ID, SelectToPreviousLineAction.LABEL), 'Terminal: Select To Previous Line', category); +actionRegistry.registerWorkbenchAction(SyncActionDescriptor.create(SelectToNextLineAction, SelectToNextLineAction.ID, SelectToNextLineAction.LABEL), 'Terminal: Select To Next Line', category); +actionRegistry.registerWorkbenchAction(SyncActionDescriptor.create(ToggleEscapeSequenceLoggingAction, ToggleEscapeSequenceLoggingAction.ID, ToggleEscapeSequenceLoggingAction.LABEL), 'Terminal: Toggle Escape Sequence Logging', category); +actionRegistry.registerWorkbenchAction(SyncActionDescriptor.create(ToggleRegexCommand, ToggleRegexCommand.ID, ToggleRegexCommand.LABEL, { primary: KeyMod.Alt | KeyCode.KEY_R, mac: { primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.KEY_R } }, KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_FOCUSED), 'Terminal: Toggle find using regex', category); -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ToggleRegexCommand, ToggleRegexCommand.ID, ToggleRegexCommand.LABEL, { +actionRegistry.registerWorkbenchAction(SyncActionDescriptor.create(ToggleRegexCommand, ToggleRegexCommand.ID, ToggleRegexCommand.LABEL, { primary: KeyMod.Alt | KeyCode.KEY_R, mac: { primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.KEY_R } }, KEYBINDING_CONTEXT_TERMINAL_FOCUS), 'Terminal: Toggle find using regex', category); -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ToggleWholeWordCommand, ToggleWholeWordCommand.ID, ToggleWholeWordCommand.LABEL, { +actionRegistry.registerWorkbenchAction(SyncActionDescriptor.create(ToggleWholeWordCommand, ToggleWholeWordCommand.ID, ToggleWholeWordCommand.LABEL, { primary: KeyMod.Alt | KeyCode.KEY_W, mac: { primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.KEY_W } }, KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_FOCUSED), 'Terminal: Toggle find using whole word', category); -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ToggleWholeWordCommand, ToggleWholeWordCommand.ID, ToggleWholeWordCommand.LABEL, { +actionRegistry.registerWorkbenchAction(SyncActionDescriptor.create(ToggleWholeWordCommand, ToggleWholeWordCommand.ID, ToggleWholeWordCommand.LABEL, { primary: KeyMod.Alt | KeyCode.KEY_W, mac: { primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.KEY_W } }, KEYBINDING_CONTEXT_TERMINAL_FOCUS), 'Terminal: Toggle find using whole word', category); -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ToggleCaseSensitiveCommand, ToggleCaseSensitiveCommand.ID, ToggleCaseSensitiveCommand.LABEL, { +actionRegistry.registerWorkbenchAction(SyncActionDescriptor.create(ToggleCaseSensitiveCommand, ToggleCaseSensitiveCommand.ID, ToggleCaseSensitiveCommand.LABEL, { primary: KeyMod.Alt | KeyCode.KEY_C, mac: { primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.KEY_C } }, KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_FOCUSED), 'Terminal: Toggle find using case sensitive', category); -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ToggleCaseSensitiveCommand, ToggleCaseSensitiveCommand.ID, ToggleCaseSensitiveCommand.LABEL, { +actionRegistry.registerWorkbenchAction(SyncActionDescriptor.create(ToggleCaseSensitiveCommand, ToggleCaseSensitiveCommand.ID, ToggleCaseSensitiveCommand.LABEL, { primary: KeyMod.Alt | KeyCode.KEY_C, mac: { primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.KEY_C } }, KEYBINDING_CONTEXT_TERMINAL_FOCUS), 'Terminal: Toggle find using case sensitive', category); -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(FindNext, FindNext.ID, FindNext.LABEL, { +actionRegistry.registerWorkbenchAction(SyncActionDescriptor.create(FindNext, FindNext.ID, FindNext.LABEL, { primary: KeyCode.F3, mac: { primary: KeyMod.CtrlCmd | KeyCode.KEY_G, secondary: [KeyCode.F3] } }, KEYBINDING_CONTEXT_TERMINAL_FOCUS), 'Terminal: Find next', category); -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(FindNext, FindNext.ID, FindNext.LABEL, { +actionRegistry.registerWorkbenchAction(SyncActionDescriptor.create(FindNext, FindNext.ID, FindNext.LABEL, { primary: KeyCode.F3, secondary: [KeyMod.Shift | KeyCode.Enter], mac: { primary: KeyMod.CtrlCmd | KeyCode.KEY_G, secondary: [KeyCode.F3, KeyMod.Shift | KeyCode.Enter] } }, KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_FOCUSED), 'Terminal: Find next', category); -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(FindPrevious, FindPrevious.ID, FindPrevious.LABEL, { +actionRegistry.registerWorkbenchAction(SyncActionDescriptor.create(FindPrevious, FindPrevious.ID, FindPrevious.LABEL, { primary: KeyMod.Shift | KeyCode.F3, mac: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_G, secondary: [KeyMod.Shift | KeyCode.F3] }, }, KEYBINDING_CONTEXT_TERMINAL_FOCUS), 'Terminal: Find previous', category); -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(FindPrevious, FindPrevious.ID, FindPrevious.LABEL, { +actionRegistry.registerWorkbenchAction(SyncActionDescriptor.create(FindPrevious, FindPrevious.ID, FindPrevious.LABEL, { primary: KeyMod.Shift | KeyCode.F3, secondary: [KeyCode.Enter], mac: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_G, secondary: [KeyMod.Shift | KeyCode.F3, KeyCode.Enter] }, @@ -554,13 +554,13 @@ actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(FindPrevious, Fi // Commands miht be affected by Web restrictons if (BrowserFeatures.clipboard.writeText) { - actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(CopyTerminalSelectionAction, CopyTerminalSelectionAction.ID, CopyTerminalSelectionAction.LABEL, { + actionRegistry.registerWorkbenchAction(SyncActionDescriptor.create(CopyTerminalSelectionAction, CopyTerminalSelectionAction.ID, CopyTerminalSelectionAction.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.KEY_C, linux: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_C } }, ContextKeyExpr.and(KEYBINDING_CONTEXT_TERMINAL_TEXT_SELECTED, KEYBINDING_CONTEXT_TERMINAL_FOCUS)), 'Terminal: Copy Selection', category); } if (BrowserFeatures.clipboard.readText) { - actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(TerminalPasteAction, TerminalPasteAction.ID, TerminalPasteAction.LABEL, { + actionRegistry.registerWorkbenchAction(SyncActionDescriptor.create(TerminalPasteAction, TerminalPasteAction.ID, TerminalPasteAction.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.KEY_V, linux: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_V } }, KEYBINDING_CONTEXT_TERMINAL_FOCUS), 'Terminal: Paste into Active Terminal', category); diff --git a/src/vs/workbench/contrib/terminal/electron-browser/terminalRemote.ts b/src/vs/workbench/contrib/terminal/electron-browser/terminalRemote.ts index 2b7d5e39af35e..1aa467187c2c5 100644 --- a/src/vs/workbench/contrib/terminal/electron-browser/terminalRemote.ts +++ b/src/vs/workbench/contrib/terminal/electron-browser/terminalRemote.ts @@ -15,7 +15,7 @@ import { ITerminalService } from 'vs/workbench/contrib/terminal/browser/terminal export function registerRemoteContributions() { const actionRegistry = Registry.as(ActionExtensions.WorkbenchActions); - actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(CreateNewLocalTerminalAction, CreateNewLocalTerminalAction.ID, CreateNewLocalTerminalAction.LABEL), 'Terminal: Create New Integrated Terminal (Local)', TERMINAL_ACTION_CATEGORY); + actionRegistry.registerWorkbenchAction(SyncActionDescriptor.create(CreateNewLocalTerminalAction, CreateNewLocalTerminalAction.ID, CreateNewLocalTerminalAction.LABEL), 'Terminal: Create New Integrated Terminal (Local)', TERMINAL_ACTION_CATEGORY); } export class CreateNewLocalTerminalAction extends Action { diff --git a/src/vs/workbench/contrib/testCustomEditors/browser/testCustomEditors.ts b/src/vs/workbench/contrib/testCustomEditors/browser/testCustomEditors.ts index 1a43978f69281..358e503f4ad62 100644 --- a/src/vs/workbench/contrib/testCustomEditors/browser/testCustomEditors.ts +++ b/src/vs/workbench/contrib/testCustomEditors/browser/testCustomEditors.ts @@ -219,7 +219,7 @@ if (ENABLE) { const registry = Registry.as(Extensions.WorkbenchActions); - registry.registerWorkbenchAction(new SyncActionDescriptor(TestCustomEditorsAction, TestCustomEditorsAction.ID, TestCustomEditorsAction.LABEL), 'Test Open Custom Editor'); + registry.registerWorkbenchAction(SyncActionDescriptor.create(TestCustomEditorsAction, TestCustomEditorsAction.ID, TestCustomEditorsAction.LABEL), 'Test Open Custom Editor'); class TestCustomEditorInputFactory implements IEditorInputFactory { diff --git a/src/vs/workbench/contrib/themes/browser/themes.contribution.ts b/src/vs/workbench/contrib/themes/browser/themes.contribution.ts index 268b0fcda80a7..ac4567e81c4dd 100644 --- a/src/vs/workbench/contrib/themes/browser/themes.contribution.ts +++ b/src/vs/workbench/contrib/themes/browser/themes.contribution.ts @@ -285,16 +285,16 @@ class GenerateColorThemeAction extends Action { const category = localize('preferences', "Preferences"); -const colorThemeDescriptor = new SyncActionDescriptor(SelectColorThemeAction, SelectColorThemeAction.ID, SelectColorThemeAction.LABEL, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.KEY_T) }); +const colorThemeDescriptor = SyncActionDescriptor.create(SelectColorThemeAction, SelectColorThemeAction.ID, SelectColorThemeAction.LABEL, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.KEY_T) }); Registry.as(Extensions.WorkbenchActions).registerWorkbenchAction(colorThemeDescriptor, 'Preferences: Color Theme', category); -const iconThemeDescriptor = new SyncActionDescriptor(SelectIconThemeAction, SelectIconThemeAction.ID, SelectIconThemeAction.LABEL); +const iconThemeDescriptor = SyncActionDescriptor.create(SelectIconThemeAction, SelectIconThemeAction.ID, SelectIconThemeAction.LABEL); Registry.as(Extensions.WorkbenchActions).registerWorkbenchAction(iconThemeDescriptor, 'Preferences: File Icon Theme', category); const developerCategory = localize('developer', "Developer"); -const generateColorThemeDescriptor = new SyncActionDescriptor(GenerateColorThemeAction, GenerateColorThemeAction.ID, GenerateColorThemeAction.LABEL); +const generateColorThemeDescriptor = SyncActionDescriptor.create(GenerateColorThemeAction, GenerateColorThemeAction.ID, GenerateColorThemeAction.LABEL); Registry.as(Extensions.WorkbenchActions).registerWorkbenchAction(generateColorThemeDescriptor, 'Developer: Generate Color Theme From Current Settings', developerCategory); MenuRegistry.appendMenuItem(MenuId.MenubarPreferencesMenu, { diff --git a/src/vs/workbench/contrib/update/browser/update.contribution.ts b/src/vs/workbench/contrib/update/browser/update.contribution.ts index 6f872f2f97fba..d8b0f3754581b 100644 --- a/src/vs/workbench/contrib/update/browser/update.contribution.ts +++ b/src/vs/workbench/contrib/update/browser/update.contribution.ts @@ -23,10 +23,10 @@ const actionRegistry = Registry.as(ActionExtensions.Wo // Editor actionRegistry - .registerWorkbenchAction(new SyncActionDescriptor(ShowCurrentReleaseNotesAction, ShowCurrentReleaseNotesAction.ID, ShowCurrentReleaseNotesAction.LABEL), `${product.nameShort}: Show Release Notes`, product.nameShort); + .registerWorkbenchAction(SyncActionDescriptor.create(ShowCurrentReleaseNotesAction, ShowCurrentReleaseNotesAction.ID, ShowCurrentReleaseNotesAction.LABEL), `${product.nameShort}: Show Release Notes`, product.nameShort); actionRegistry - .registerWorkbenchAction(new SyncActionDescriptor(CheckForVSCodeUpdateAction, CheckForVSCodeUpdateAction.ID, CheckForVSCodeUpdateAction.LABEL), `${product.nameShort}: Check for Update`, product.nameShort, CONTEXT_UPDATE_STATE.isEqualTo(StateType.Idle)); + .registerWorkbenchAction(SyncActionDescriptor.create(CheckForVSCodeUpdateAction, CheckForVSCodeUpdateAction.ID, CheckForVSCodeUpdateAction.LABEL), `${product.nameShort}: Check for Update`, product.nameShort, CONTEXT_UPDATE_STATE.isEqualTo(StateType.Idle)); // Menu if (ShowCurrentReleaseNotesAction.AVAILABE) { diff --git a/src/vs/workbench/contrib/url/common/url.contribution.ts b/src/vs/workbench/contrib/url/common/url.contribution.ts index 86add42f8ce83..af5564e40639b 100644 --- a/src/vs/workbench/contrib/url/common/url.contribution.ts +++ b/src/vs/workbench/contrib/url/common/url.contribution.ts @@ -41,7 +41,7 @@ export class OpenUrlAction extends Action { } Registry.as(ActionExtensions.WorkbenchActions).registerWorkbenchAction( - new SyncActionDescriptor(OpenUrlAction, OpenUrlAction.ID, OpenUrlAction.LABEL), + SyncActionDescriptor.create(OpenUrlAction, OpenUrlAction.ID, OpenUrlAction.LABEL), 'Open URL', localize('developer', 'Developer') ); diff --git a/src/vs/workbench/contrib/webview/browser/webview.contribution.ts b/src/vs/workbench/contrib/webview/browser/webview.contribution.ts index 2189e68d81fde..445f190e1b24e 100644 --- a/src/vs/workbench/contrib/webview/browser/webview.contribution.ts +++ b/src/vs/workbench/contrib/webview/browser/webview.contribution.ts @@ -85,6 +85,6 @@ function registerWebViewCommands(editorId: string): void { registerWebViewCommands(WebviewEditor.ID); actionRegistry.registerWorkbenchAction( - new SyncActionDescriptor(ReloadWebviewAction, ReloadWebviewAction.ID, ReloadWebviewAction.LABEL), + SyncActionDescriptor.create(ReloadWebviewAction, ReloadWebviewAction.ID, ReloadWebviewAction.LABEL), 'Reload Webviews', webviewDeveloperCategory); diff --git a/src/vs/workbench/contrib/webview/electron-browser/webview.contribution.ts b/src/vs/workbench/contrib/webview/electron-browser/webview.contribution.ts index 627d57bd3fd24..1e47c68737b7d 100644 --- a/src/vs/workbench/contrib/webview/electron-browser/webview.contribution.ts +++ b/src/vs/workbench/contrib/webview/electron-browser/webview.contribution.ts @@ -22,7 +22,7 @@ registerSingleton(IWebviewService, ElectronWebviewService, true); const actionRegistry = Registry.as(ActionExtensions.WorkbenchActions); actionRegistry.registerWorkbenchAction( - new SyncActionDescriptor(webviewCommands.OpenWebviewDeveloperToolsAction, webviewCommands.OpenWebviewDeveloperToolsAction.ID, webviewCommands.OpenWebviewDeveloperToolsAction.LABEL), + SyncActionDescriptor.create(webviewCommands.OpenWebviewDeveloperToolsAction, webviewCommands.OpenWebviewDeveloperToolsAction.ID, webviewCommands.OpenWebviewDeveloperToolsAction.LABEL), webviewCommands.OpenWebviewDeveloperToolsAction.ALIAS, webviewDeveloperCategory); diff --git a/src/vs/workbench/contrib/welcome/overlay/browser/welcomeOverlay.ts b/src/vs/workbench/contrib/welcome/overlay/browser/welcomeOverlay.ts index 9dc2d3703703d..81c711a0380c1 100644 --- a/src/vs/workbench/contrib/welcome/overlay/browser/welcomeOverlay.ts +++ b/src/vs/workbench/contrib/welcome/overlay/browser/welcomeOverlay.ts @@ -258,10 +258,10 @@ class WelcomeOverlay extends Disposable { } Registry.as(Extensions.WorkbenchActions) - .registerWorkbenchAction(new SyncActionDescriptor(WelcomeOverlayAction, WelcomeOverlayAction.ID, WelcomeOverlayAction.LABEL), 'Help: User Interface Overview', localize('help', "Help")); + .registerWorkbenchAction(SyncActionDescriptor.create(WelcomeOverlayAction, WelcomeOverlayAction.ID, WelcomeOverlayAction.LABEL), 'Help: User Interface Overview', localize('help', "Help")); Registry.as(Extensions.WorkbenchActions) - .registerWorkbenchAction(new SyncActionDescriptor(HideWelcomeOverlayAction, HideWelcomeOverlayAction.ID, HideWelcomeOverlayAction.LABEL, { primary: KeyCode.Escape }, OVERLAY_VISIBLE), 'Help: Hide Interface Overview', localize('help', "Help")); + .registerWorkbenchAction(SyncActionDescriptor.create(HideWelcomeOverlayAction, HideWelcomeOverlayAction.ID, HideWelcomeOverlayAction.LABEL, { primary: KeyCode.Escape }, OVERLAY_VISIBLE), 'Help: Hide Interface Overview', localize('help', "Help")); // theming diff --git a/src/vs/workbench/contrib/welcome/page/browser/welcomePage.contribution.ts b/src/vs/workbench/contrib/welcome/page/browser/welcomePage.contribution.ts index 42978506c8cc1..eaebdb8420567 100644 --- a/src/vs/workbench/contrib/welcome/page/browser/welcomePage.contribution.ts +++ b/src/vs/workbench/contrib/welcome/page/browser/welcomePage.contribution.ts @@ -39,7 +39,7 @@ Registry.as(WorkbenchExtensions.Workbench) .registerWorkbenchContribution(WelcomePageContribution, LifecyclePhase.Restored); Registry.as(ActionExtensions.WorkbenchActions) - .registerWorkbenchAction(new SyncActionDescriptor(WelcomePageAction, WelcomePageAction.ID, WelcomePageAction.LABEL), 'Help: Welcome', localize('help', "Help")); + .registerWorkbenchAction(SyncActionDescriptor.create(WelcomePageAction, WelcomePageAction.ID, WelcomePageAction.LABEL), 'Help: Welcome', localize('help', "Help")); Registry.as(EditorExtensions.EditorInputFactories).registerEditorInputFactory(WelcomeInputFactory.ID, WelcomeInputFactory); diff --git a/src/vs/workbench/contrib/welcome/walkThrough/browser/walkThrough.contribution.ts b/src/vs/workbench/contrib/welcome/walkThrough/browser/walkThrough.contribution.ts index 8a91091c6b706..0538dd38b27da 100644 --- a/src/vs/workbench/contrib/welcome/walkThrough/browser/walkThrough.contribution.ts +++ b/src/vs/workbench/contrib/welcome/walkThrough/browser/walkThrough.contribution.ts @@ -29,7 +29,7 @@ Registry.as(EditorExtensions.Editors) Registry.as(Extensions.WorkbenchActions) .registerWorkbenchAction( - new SyncActionDescriptor(EditorWalkThroughAction, EditorWalkThroughAction.ID, EditorWalkThroughAction.LABEL), + SyncActionDescriptor.create(EditorWalkThroughAction, EditorWalkThroughAction.ID, EditorWalkThroughAction.LABEL), 'Help: Interactive Playground', localize('help', "Help")); Registry.as(EditorInputExtensions.EditorInputFactories).registerEditorInputFactory(EditorWalkThroughInputFactory.ID, EditorWalkThroughInputFactory); diff --git a/src/vs/workbench/electron-browser/desktop.contribution.ts b/src/vs/workbench/electron-browser/desktop.contribution.ts index 2afbed6f4ced0..af5f55407ef29 100644 --- a/src/vs/workbench/electron-browser/desktop.contribution.ts +++ b/src/vs/workbench/electron-browser/desktop.contribution.ts @@ -31,16 +31,16 @@ import product from 'vs/platform/product/common/product'; (function registerZoomActions(): void { const viewCategory = nls.localize('view', "View"); - registry.registerWorkbenchAction(new SyncActionDescriptor(ZoomInAction, ZoomInAction.ID, ZoomInAction.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.US_EQUAL, secondary: [KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.US_EQUAL, KeyMod.CtrlCmd | KeyCode.NUMPAD_ADD] }), 'View: Zoom In', viewCategory); - registry.registerWorkbenchAction(new SyncActionDescriptor(ZoomOutAction, ZoomOutAction.ID, ZoomOutAction.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.US_MINUS, secondary: [KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.US_MINUS, KeyMod.CtrlCmd | KeyCode.NUMPAD_SUBTRACT], linux: { primary: KeyMod.CtrlCmd | KeyCode.US_MINUS, secondary: [KeyMod.CtrlCmd | KeyCode.NUMPAD_SUBTRACT] } }), 'View: Zoom Out', viewCategory); - registry.registerWorkbenchAction(new SyncActionDescriptor(ZoomResetAction, ZoomResetAction.ID, ZoomResetAction.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.NUMPAD_0 }), 'View: Reset Zoom', viewCategory); + registry.registerWorkbenchAction(SyncActionDescriptor.create(ZoomInAction, ZoomInAction.ID, ZoomInAction.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.US_EQUAL, secondary: [KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.US_EQUAL, KeyMod.CtrlCmd | KeyCode.NUMPAD_ADD] }), 'View: Zoom In', viewCategory); + registry.registerWorkbenchAction(SyncActionDescriptor.create(ZoomOutAction, ZoomOutAction.ID, ZoomOutAction.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.US_MINUS, secondary: [KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.US_MINUS, KeyMod.CtrlCmd | KeyCode.NUMPAD_SUBTRACT], linux: { primary: KeyMod.CtrlCmd | KeyCode.US_MINUS, secondary: [KeyMod.CtrlCmd | KeyCode.NUMPAD_SUBTRACT] } }), 'View: Zoom Out', viewCategory); + registry.registerWorkbenchAction(SyncActionDescriptor.create(ZoomResetAction, ZoomResetAction.ID, ZoomResetAction.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.NUMPAD_0 }), 'View: Reset Zoom', viewCategory); })(); // Actions: Window (function registerWindowActions(): void { - registry.registerWorkbenchAction(new SyncActionDescriptor(CloseCurrentWindowAction, CloseCurrentWindowAction.ID, CloseCurrentWindowAction.LABEL, { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_W }), 'Close Window'); - registry.registerWorkbenchAction(new SyncActionDescriptor(SwitchWindow, SwitchWindow.ID, SwitchWindow.LABEL, { primary: 0, mac: { primary: KeyMod.WinCtrl | KeyCode.KEY_W } }), 'Switch Window...'); - registry.registerWorkbenchAction(new SyncActionDescriptor(QuickSwitchWindow, QuickSwitchWindow.ID, QuickSwitchWindow.LABEL), 'Quick Switch Window...'); + registry.registerWorkbenchAction(SyncActionDescriptor.create(CloseCurrentWindowAction, CloseCurrentWindowAction.ID, CloseCurrentWindowAction.LABEL, { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_W }), 'Close Window'); + registry.registerWorkbenchAction(SyncActionDescriptor.create(SwitchWindow, SwitchWindow.ID, SwitchWindow.LABEL, { primary: 0, mac: { primary: KeyMod.WinCtrl | KeyCode.KEY_W } }), 'Switch Window...'); + registry.registerWorkbenchAction(SyncActionDescriptor.create(QuickSwitchWindow, QuickSwitchWindow.ID, QuickSwitchWindow.LABEL), 'Quick Switch Window...'); KeybindingsRegistry.registerCommandAndKeybindingRule({ id: CloseCurrentWindowAction.ID, // close the window when the last editor is closed by reusing the same keybinding @@ -90,9 +90,9 @@ import product from 'vs/platform/product/common/product'; // Actions: Developer (function registerDeveloperActions(): void { const developerCategory = nls.localize('developer', "Developer"); - registry.registerWorkbenchAction(new SyncActionDescriptor(ToggleSharedProcessAction, ToggleSharedProcessAction.ID, ToggleSharedProcessAction.LABEL), 'Developer: Toggle Shared Process', developerCategory); - registry.registerWorkbenchAction(new SyncActionDescriptor(ReloadWindowWithExtensionsDisabledAction, ReloadWindowWithExtensionsDisabledAction.ID, ReloadWindowWithExtensionsDisabledAction.LABEL), 'Developer: Reload With Extensions Disabled', developerCategory); - registry.registerWorkbenchAction(new SyncActionDescriptor(ToggleDevToolsAction, ToggleDevToolsAction.ID, ToggleDevToolsAction.LABEL), 'Developer: Toggle Developer Tools', developerCategory); + registry.registerWorkbenchAction(SyncActionDescriptor.create(ToggleSharedProcessAction, ToggleSharedProcessAction.ID, ToggleSharedProcessAction.LABEL), 'Developer: Toggle Shared Process', developerCategory); + registry.registerWorkbenchAction(SyncActionDescriptor.create(ReloadWindowWithExtensionsDisabledAction, ReloadWindowWithExtensionsDisabledAction.ID, ReloadWindowWithExtensionsDisabledAction.LABEL), 'Developer: Reload With Extensions Disabled', developerCategory); + registry.registerWorkbenchAction(SyncActionDescriptor.create(ToggleDevToolsAction, ToggleDevToolsAction.ID, ToggleDevToolsAction.LABEL), 'Developer: Toggle Developer Tools', developerCategory); KeybindingsRegistry.registerKeybindingRule({ id: ToggleDevToolsAction.ID, @@ -106,7 +106,7 @@ import product from 'vs/platform/product/common/product'; // Actions: Runtime Arguments (function registerRuntimeArgumentsAction(): void { const preferencesCategory = nls.localize('preferences', "Preferences"); - registry.registerWorkbenchAction(new SyncActionDescriptor(ConfigureRuntimeArgumentsAction, ConfigureRuntimeArgumentsAction.ID, ConfigureRuntimeArgumentsAction.LABEL), 'Preferences: Configure Runtime Arguments', preferencesCategory); + registry.registerWorkbenchAction(SyncActionDescriptor.create(ConfigureRuntimeArgumentsAction, ConfigureRuntimeArgumentsAction.ID, ConfigureRuntimeArgumentsAction.LABEL), 'Preferences: Configure Runtime Arguments', preferencesCategory); })(); })(); diff --git a/src/vs/workbench/services/extensions/browser/extensionUrlHandler.ts b/src/vs/workbench/services/extensions/browser/extensionUrlHandler.ts index c63f391949e13..e1d8c4de6f534 100644 --- a/src/vs/workbench/services/extensions/browser/extensionUrlHandler.ts +++ b/src/vs/workbench/services/extensions/browser/extensionUrlHandler.ts @@ -420,4 +420,4 @@ export class ManageAuthorizedExtensionURIsAction extends Action { } const actionRegistry = Registry.as(WorkbenchActionExtensions.WorkbenchActions); -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ManageAuthorizedExtensionURIsAction, ManageAuthorizedExtensionURIsAction.ID, ManageAuthorizedExtensionURIsAction.LABEL), `Extensions: Manage Authorized Extension URIs...`, ExtensionsLabel); +actionRegistry.registerWorkbenchAction(SyncActionDescriptor.create(ManageAuthorizedExtensionURIsAction, ManageAuthorizedExtensionURIsAction.ID, ManageAuthorizedExtensionURIsAction.LABEL), `Extensions: Manage Authorized Extension URIs...`, ExtensionsLabel); diff --git a/src/vs/workbench/services/extensions/common/extensionHostProcessManager.ts b/src/vs/workbench/services/extensions/common/extensionHostProcessManager.ts index dc4b8bf9690f2..cb638f64361c1 100644 --- a/src/vs/workbench/services/extensions/common/extensionHostProcessManager.ts +++ b/src/vs/workbench/services/extensions/common/extensionHostProcessManager.ts @@ -422,4 +422,4 @@ export class MeasureExtHostLatencyAction extends Action { } const registry = Registry.as(ActionExtensions.WorkbenchActions); -registry.registerWorkbenchAction(new SyncActionDescriptor(MeasureExtHostLatencyAction, MeasureExtHostLatencyAction.ID, MeasureExtHostLatencyAction.LABEL), 'Developer: Measure Extension Host Latency', nls.localize('developer', "Developer")); +registry.registerWorkbenchAction(SyncActionDescriptor.create(MeasureExtHostLatencyAction, MeasureExtHostLatencyAction.ID, MeasureExtHostLatencyAction.LABEL), 'Developer: Measure Extension Host Latency', nls.localize('developer', "Developer")); diff --git a/src/vs/workbench/services/preferences/test/common/keybindingsEditorModel.test.ts b/src/vs/workbench/services/preferences/test/common/keybindingsEditorModel.test.ts index 675c17c8b9518..8a445d39a2030 100644 --- a/src/vs/workbench/services/preferences/test/common/keybindingsEditorModel.test.ts +++ b/src/vs/workbench/services/preferences/test/common/keybindingsEditorModel.test.ts @@ -577,7 +577,7 @@ suite('KeybindingsEditorModel test', () => { function registerCommandWithTitle(command: string, title: string): void { const registry = Registry.as(ActionExtensions.WorkbenchActions); - registry.registerWorkbenchAction(new SyncActionDescriptor(AnAction, command, title, { primary: 0 }), ''); + registry.registerWorkbenchAction(SyncActionDescriptor.create(AnAction, command, title, { primary: 0 }), ''); } function assertKeybindingItems(actual: ResolvedKeybindingItem[], expected: ResolvedKeybindingItem[]) { From dfda354bb8f7e4165563b5a33c747b83d10a496a Mon Sep 17 00:00:00 2001 From: Peng Lyu Date: Thu, 14 Nov 2019 16:48:04 -0800 Subject: [PATCH 299/352] Safari on macOS has PointerEvents as well ... --- src/vs/editor/browser/controller/pointerHandler.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/editor/browser/controller/pointerHandler.ts b/src/vs/editor/browser/controller/pointerHandler.ts index 4c7ad07a75939..28ebcf990affb 100644 --- a/src/vs/editor/browser/controller/pointerHandler.ts +++ b/src/vs/editor/browser/controller/pointerHandler.ts @@ -11,7 +11,7 @@ import { IMouseTarget } from 'vs/editor/browser/editorBrowser'; import { EditorMouseEvent, EditorPointerEventFactory } from 'vs/editor/browser/editorDom'; import { ViewController } from 'vs/editor/browser/view/viewController'; import { ViewContext } from 'vs/editor/common/view/viewContext'; -import { isSafari } from 'vs/base/browser/browser'; +import { BrowserFeatures } from 'vs/base/browser/canIUse'; interface IThrottledGestureEvent { translationX: number; @@ -283,7 +283,7 @@ export class PointerHandler extends Disposable { super(); if (window.navigator.msPointerEnabled) { this.handler = this._register(new MsPointerHandler(context, viewController, viewHelper)); - } else if (((window).PointerEvent && isSafari)) { + } else if (((window).PointerEvent && BrowserFeatures.pointerEvents)) { this.handler = this._register(new PointerEventHandler(context, viewController, viewHelper)); } else if ((window).TouchEvent) { this.handler = this._register(new TouchHandler(context, viewController, viewHelper)); From a7d86df09fad1efe26f14de7f21e02784e2cbacf Mon Sep 17 00:00:00 2001 From: Peng Lyu Date: Thu, 14 Nov 2019 16:51:38 -0800 Subject: [PATCH 300/352] window.PointerEvent --- src/vs/base/browser/canIUse.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/base/browser/canIUse.ts b/src/vs/base/browser/canIUse.ts index 989b11c370f50..a8fc3db9d80a8 100644 --- a/src/vs/base/browser/canIUse.ts +++ b/src/vs/base/browser/canIUse.ts @@ -56,5 +56,5 @@ export const BrowserFeatures = { })(), touch: 'ontouchstart' in window || navigator.maxTouchPoints > 0 || window.navigator.msMaxTouchPoints > 0, - pointerEvents: browser.isSafari && ('ontouchstart' in window || navigator.maxTouchPoints > 0 || window.navigator.msMaxTouchPoints > 0) + pointerEvents: browser.isSafari && window.PointerEvent && ('ontouchstart' in window || navigator.maxTouchPoints > 0 || window.navigator.msMaxTouchPoints > 0) }; From bf9370040444655883f5070b071ddb1d64767bf1 Mon Sep 17 00:00:00 2001 From: Peng Lyu Date: Thu, 14 Nov 2019 16:52:54 -0800 Subject: [PATCH 301/352] do not allow touch to scroll on body. --- src/vs/workbench/browser/style.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/vs/workbench/browser/style.ts b/src/vs/workbench/browser/style.ts index 23b39b5f4f37e..d38931efc44fc 100644 --- a/src/vs/workbench/browser/style.ts +++ b/src/vs/workbench/browser/style.ts @@ -175,6 +175,9 @@ registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => { // allow to select text in monaco editor instances. if (isSafari) { collector.addRule(` + body.web { + touch-action: none; + } .monaco-workbench .monaco-editor .view-lines { user-select: text; -webkit-user-select: text; From 5370653cf83722783520cd864a43dd19394c0495 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Thu, 14 Nov 2019 17:10:34 -0800 Subject: [PATCH 302/352] Use `create` functions for more descriptors For #81574 This applies the fix from #84878 to a number of other descriptor classes in our codebase --- .../workbench/api/browser/mainThreadComments.ts | 2 +- .../workbench/api/browser/viewsExtensionPoint.ts | 2 +- src/vs/workbench/browser/editor.ts | 10 +++++++++- src/vs/workbench/browser/panel.ts | 8 ++++++-- .../browser/parts/editor/editor.contribution.ts | 12 ++++++------ src/vs/workbench/browser/quickopen.ts | 12 ++++++++---- src/vs/workbench/browser/viewlet.ts | 15 +++++++++++++-- .../browser/webviewEditor.contribution.ts | 2 +- .../contrib/debug/browser/debug.contribution.ts | 6 +++--- .../extensions/browser/extensions.contribution.ts | 8 ++++---- .../electron-browser/extensions.contribution.ts | 2 +- .../contrib/files/browser/files.contribution.ts | 4 ++-- .../files/browser/files.web.contribution.ts | 2 +- .../files/electron-browser/files.contribution.ts | 2 +- .../markers/browser/markers.contribution.ts | 2 +- .../contrib/output/browser/output.contribution.ts | 4 ++-- .../browser/preferences.contribution.ts | 6 +++--- .../quickopen/browser/quickopen.contribution.ts | 10 +++++----- src/vs/workbench/contrib/remote/browser/remote.ts | 2 +- .../contrib/scm/browser/scm.contribution.ts | 2 +- .../contrib/search/browser/search.contribution.ts | 10 +++++----- .../contrib/tasks/browser/task.contribution.ts | 2 +- .../terminal/browser/terminal.contribution.ts | 2 +- .../browser/testCustomEditors.ts | 2 +- .../webview/browser/webview.contribution.ts | 2 +- .../browser/walkThrough.contribution.ts | 2 +- .../test/browser/editorGroupsService.test.ts | 2 +- .../editor/test/browser/editorService.test.ts | 2 +- .../test/browser/parts/editor/baseEditor.test.ts | 12 ++++++------ src/vs/workbench/test/browser/quickopen.test.ts | 4 ++-- src/vs/workbench/test/browser/viewlet.test.ts | 8 ++++---- 31 files changed, 94 insertions(+), 67 deletions(-) diff --git a/src/vs/workbench/api/browser/mainThreadComments.ts b/src/vs/workbench/api/browser/mainThreadComments.ts index 3f18e9c1a05c4..bbe5edd3b6b2e 100644 --- a/src/vs/workbench/api/browser/mainThreadComments.ts +++ b/src/vs/workbench/api/browser/mainThreadComments.ts @@ -446,7 +446,7 @@ export class MainThreadComments extends Disposable implements MainThreadComments private registerPanel(commentsPanelAlreadyConstructed: boolean) { if (!commentsPanelAlreadyConstructed) { - Registry.as(PanelExtensions.Panels).registerPanel(new PanelDescriptor( + Registry.as(PanelExtensions.Panels).registerPanel(PanelDescriptor.create( CommentsPanel, COMMENTS_PANEL_ID, COMMENTS_PANEL_TITLE, diff --git a/src/vs/workbench/api/browser/viewsExtensionPoint.ts b/src/vs/workbench/api/browser/viewsExtensionPoint.ts index efbc23c293f29..061381129610c 100644 --- a/src/vs/workbench/api/browser/viewsExtensionPoint.ts +++ b/src/vs/workbench/api/browser/viewsExtensionPoint.ts @@ -335,7 +335,7 @@ class ViewsExtensionHandler implements IWorkbenchContribution { super(id, `${id}.state`, true, configurationService, layoutService, telemetryService, storageService, instantiationService, themeService, contextMenuService, extensionService, contextService); } } - const viewletDescriptor = new ViewletDescriptor( + const viewletDescriptor = ViewletDescriptor.create( CustomViewlet, id, title, diff --git a/src/vs/workbench/browser/editor.ts b/src/vs/workbench/browser/editor.ts index d441fb2f0d910..e03a20900a511 100644 --- a/src/vs/workbench/browser/editor.ts +++ b/src/vs/workbench/browser/editor.ts @@ -7,7 +7,7 @@ import { EditorInput } from 'vs/workbench/common/editor'; import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; import { Registry } from 'vs/platform/registry/common/platform'; import { BaseEditor } from 'vs/workbench/browser/parts/editor/baseEditor'; -import { IConstructorSignature0, IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; +import { IConstructorSignature0, IInstantiationService, BrandedService } from 'vs/platform/instantiation/common/instantiation'; import { find } from 'vs/base/common/arrays'; export interface IEditorDescriptor { @@ -54,6 +54,14 @@ export interface IEditorRegistry { */ export class EditorDescriptor implements IEditorDescriptor { + public static create( + ctor: { new(...services: Services): BaseEditor }, + id: string, + name: string + ): EditorDescriptor { + return new EditorDescriptor(ctor as IConstructorSignature0, id, name); + } + constructor( private readonly ctor: IConstructorSignature0, private readonly id: string, diff --git a/src/vs/workbench/browser/panel.ts b/src/vs/workbench/browser/panel.ts index cbe865fe623ef..666029c78ae7b 100644 --- a/src/vs/workbench/browser/panel.ts +++ b/src/vs/workbench/browser/panel.ts @@ -9,7 +9,7 @@ import { Composite, CompositeDescriptor, CompositeRegistry } from 'vs/workbench/ import { Action } from 'vs/base/common/actions'; import { IPanelService } from 'vs/workbench/services/panel/common/panelService'; import { IWorkbenchLayoutService, Parts } from 'vs/workbench/services/layout/browser/layoutService'; -import { IConstructorSignature0 } from 'vs/platform/instantiation/common/instantiation'; +import { IConstructorSignature0, BrandedService } from 'vs/platform/instantiation/common/instantiation'; import { isAncestor } from 'vs/base/browser/dom'; import { assertIsDefined } from 'vs/base/common/types'; @@ -20,7 +20,11 @@ export abstract class Panel extends Composite implements IPanel { } */ export class PanelDescriptor extends CompositeDescriptor { - constructor(ctor: IConstructorSignature0, id: string, name: string, cssClass?: string, order?: number, _commandId?: string) { + public static create(ctor: { new(...services: Services): Panel }, id: string, name: string, cssClass?: string, order?: number, _commandId?: string): PanelDescriptor { + return new PanelDescriptor(ctor as IConstructorSignature0, id, name, cssClass, order, _commandId); + } + + private constructor(ctor: IConstructorSignature0, id: string, name: string, cssClass?: string, order?: number, _commandId?: string) { super(ctor, id, name, cssClass, order, _commandId); } } diff --git a/src/vs/workbench/browser/parts/editor/editor.contribution.ts b/src/vs/workbench/browser/parts/editor/editor.contribution.ts index 2e25ce67d18cc..7dee5c30a3abb 100644 --- a/src/vs/workbench/browser/parts/editor/editor.contribution.ts +++ b/src/vs/workbench/browser/parts/editor/editor.contribution.ts @@ -57,7 +57,7 @@ import { IFilesConfigurationService } from 'vs/workbench/services/filesConfigura // Register String Editor Registry.as(EditorExtensions.Editors).registerEditor( - new EditorDescriptor( + EditorDescriptor.create( TextResourceEditor, TextResourceEditor.ID, nls.localize('textEditor', "Text Editor"), @@ -70,7 +70,7 @@ Registry.as(EditorExtensions.Editors).registerEditor( // Register Text Diff Editor Registry.as(EditorExtensions.Editors).registerEditor( - new EditorDescriptor( + EditorDescriptor.create( TextDiffEditor, TextDiffEditor.ID, nls.localize('textDiffEditor', "Text Diff Editor") @@ -82,7 +82,7 @@ Registry.as(EditorExtensions.Editors).registerEditor( // Register Binary Resource Diff Editor Registry.as(EditorExtensions.Editors).registerEditor( - new EditorDescriptor( + EditorDescriptor.create( BinaryResourceDiffEditor, BinaryResourceDiffEditor.ID, nls.localize('binaryDiffEditor', "Binary Diff Editor") @@ -93,7 +93,7 @@ Registry.as(EditorExtensions.Editors).registerEditor( ); Registry.as(EditorExtensions.Editors).registerEditor( - new EditorDescriptor( + EditorDescriptor.create( SideBySideEditor, SideBySideEditor.ID, nls.localize('sideBySideEditor', "Side by Side Editor") @@ -279,7 +279,7 @@ const editorPickerContextKey = 'inEditorsPicker'; const editorPickerContext = ContextKeyExpr.and(inQuickOpenContext, ContextKeyExpr.has(editorPickerContextKey)); Registry.as(QuickOpenExtensions.Quickopen).registerQuickOpenHandler( - new QuickOpenHandlerDescriptor( + QuickOpenHandlerDescriptor.create( ActiveEditorGroupPicker, ActiveEditorGroupPicker.ID, editorCommands.NAVIGATE_IN_ACTIVE_GROUP_PREFIX, @@ -295,7 +295,7 @@ Registry.as(QuickOpenExtensions.Quickopen).registerQuickOpen ); Registry.as(QuickOpenExtensions.Quickopen).registerQuickOpenHandler( - new QuickOpenHandlerDescriptor( + QuickOpenHandlerDescriptor.create( AllEditorsPicker, AllEditorsPicker.ID, editorCommands.NAVIGATE_ALL_EDITORS_GROUP_PREFIX, diff --git a/src/vs/workbench/browser/quickopen.ts b/src/vs/workbench/browser/quickopen.ts index 0c4b67f1f29b3..2dda51f6ef2af 100644 --- a/src/vs/workbench/browser/quickopen.ts +++ b/src/vs/workbench/browser/quickopen.ts @@ -15,7 +15,7 @@ import { QuickOpenEntry, QuickOpenEntryGroup } from 'vs/base/parts/quickopen/bro import { EditorOptions, EditorInput, IEditorInput } from 'vs/workbench/common/editor'; import { IResourceInput, IEditorOptions } from 'vs/platform/editor/common/editor'; import { IQuickOpenService } from 'vs/platform/quickOpen/common/quickOpen'; -import { IConstructorSignature0, IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; +import { IConstructorSignature0, IInstantiationService, BrandedService } from 'vs/platform/instantiation/common/instantiation'; import { IEditorService, SIDE_GROUP, ACTIVE_GROUP } from 'vs/workbench/services/editor/common/editorService'; import { CancellationToken } from 'vs/base/common/cancellation'; @@ -136,9 +136,13 @@ export class QuickOpenHandlerDescriptor { private id: string; private ctor: IConstructorSignature0; - constructor(ctor: IConstructorSignature0, id: string, prefix: string, contextKey: string | undefined, description: string, instantProgress?: boolean); - constructor(ctor: IConstructorSignature0, id: string, prefix: string, contextKey: string | undefined, helpEntries: QuickOpenHandlerHelpEntry[], instantProgress?: boolean); - constructor(ctor: IConstructorSignature0, id: string, prefix: string, contextKey: string | undefined, param: string | QuickOpenHandlerHelpEntry[], instantProgress: boolean = false) { + public static create(ctor: { new(...services: Services): QuickOpenHandler }, id: string, prefix: string, contextKey: string | undefined, description: string, instantProgress?: boolean): QuickOpenHandlerDescriptor; + public static create(ctor: { new(...services: Services): QuickOpenHandler }, id: string, prefix: string, contextKey: string | undefined, helpEntries: QuickOpenHandlerHelpEntry[], instantProgress?: boolean): QuickOpenHandlerDescriptor; + public static create(ctor: { new(...services: Services): QuickOpenHandler }, id: string, prefix: string, contextKey: string | undefined, param: string | QuickOpenHandlerHelpEntry[], instantProgress: boolean = false): QuickOpenHandlerDescriptor { + return new QuickOpenHandlerDescriptor(ctor as IConstructorSignature0, id, prefix, contextKey, param, instantProgress); + } + + private constructor(ctor: IConstructorSignature0, id: string, prefix: string, contextKey: string | undefined, param: string | QuickOpenHandlerHelpEntry[], instantProgress: boolean = false) { this.ctor = ctor; this.id = id; this.prefix = prefix; diff --git a/src/vs/workbench/browser/viewlet.ts b/src/vs/workbench/browser/viewlet.ts index 6ddf85eb74bbd..5591737dd017f 100644 --- a/src/vs/workbench/browser/viewlet.ts +++ b/src/vs/workbench/browser/viewlet.ts @@ -10,7 +10,7 @@ import { Action, IAction } from 'vs/base/common/actions'; import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet'; import { IViewlet } from 'vs/workbench/common/viewlet'; import { Composite, CompositeDescriptor, CompositeRegistry } from 'vs/workbench/browser/composite'; -import { IConstructorSignature0 } from 'vs/platform/instantiation/common/instantiation'; +import { IConstructorSignature0, BrandedService } from 'vs/platform/instantiation/common/instantiation'; import { ToggleSidebarVisibilityAction, ToggleSidebarPositionAction } from 'vs/workbench/browser/actions/layoutActions'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IWorkbenchLayoutService, Parts } from 'vs/workbench/services/layout/browser/layoutService'; @@ -56,7 +56,18 @@ export abstract class Viewlet extends Composite implements IViewlet { */ export class ViewletDescriptor extends CompositeDescriptor { - constructor( + public static create( + ctor: { new(...services: Services): Viewlet }, + id: string, + name: string, + cssClass?: string, + order?: number, + iconUrl?: URI + ): ViewletDescriptor { + return new ViewletDescriptor(ctor as IConstructorSignature0, id, name, cssClass, order, iconUrl); + } + + private constructor( ctor: IConstructorSignature0, id: string, name: string, diff --git a/src/vs/workbench/contrib/customEditor/browser/webviewEditor.contribution.ts b/src/vs/workbench/contrib/customEditor/browser/webviewEditor.contribution.ts index d544ec1ee51e7..c5aa8b431bbaf 100644 --- a/src/vs/workbench/contrib/customEditor/browser/webviewEditor.contribution.ts +++ b/src/vs/workbench/contrib/customEditor/browser/webviewEditor.contribution.ts @@ -26,7 +26,7 @@ Registry.as(WorkbenchExtensions.Workbench) .registerWorkbenchContribution(CustomEditorContribution, LifecyclePhase.Starting); Registry.as(EditorExtensions.Editors).registerEditor( - new EditorDescriptor( + EditorDescriptor.create( WebviewEditor, WebviewEditor.ID, 'Webview Editor', diff --git a/src/vs/workbench/contrib/debug/browser/debug.contribution.ts b/src/vs/workbench/contrib/debug/browser/debug.contribution.ts index ad44fc8554764..a25124564aeac 100644 --- a/src/vs/workbench/contrib/debug/browser/debug.contribution.ts +++ b/src/vs/workbench/contrib/debug/browser/debug.contribution.ts @@ -80,7 +80,7 @@ class OpenDebugPanelAction extends TogglePanelAction { } // register viewlet -Registry.as(ViewletExtensions.Viewlets).registerViewlet(new ViewletDescriptor( +Registry.as(ViewletExtensions.Viewlets).registerViewlet(ViewletDescriptor.create( DebugViewlet, VIEWLET_ID, nls.localize('debug', "Debug"), @@ -96,7 +96,7 @@ const openPanelKb: IKeybindings = { }; // register repl panel -Registry.as(PanelExtensions.Panels).registerPanel(new PanelDescriptor( +Registry.as(PanelExtensions.Panels).registerPanel(PanelDescriptor.create( Repl, REPL_ID, nls.localize({ comment: ['Debug is a noun in this context, not a verb.'], key: 'debugPanel' }, 'Debug Console'), @@ -166,7 +166,7 @@ registerDebugCommandPaletteItem(TOGGLE_INLINE_BREAKPOINT_ID, nls.localize('inlin // Register Quick Open (Registry.as(QuickOpenExtensions.Quickopen)).registerQuickOpenHandler( - new QuickOpenHandlerDescriptor( + QuickOpenHandlerDescriptor.create( DebugQuickOpenHandler, DebugQuickOpenHandler.ID, 'debug ', diff --git a/src/vs/workbench/contrib/extensions/browser/extensions.contribution.ts b/src/vs/workbench/contrib/extensions/browser/extensions.contribution.ts index acab3d418c76c..c624c7956b2a6 100644 --- a/src/vs/workbench/contrib/extensions/browser/extensions.contribution.ts +++ b/src/vs/workbench/contrib/extensions/browser/extensions.contribution.ts @@ -54,7 +54,7 @@ Registry.as(OutputExtensions.OutputChannels) // Quickopen Registry.as(Extensions.Quickopen).registerQuickOpenHandler( - new QuickOpenHandlerDescriptor( + QuickOpenHandlerDescriptor.create( ExtensionsHandler, ExtensionsHandler.ID, 'ext ', @@ -66,7 +66,7 @@ Registry.as(Extensions.Quickopen).registerQuickOpenHandler( // Editor Registry.as(EditorExtensions.Editors).registerEditor( - new EditorDescriptor( + EditorDescriptor.create( ExtensionEditor, ExtensionEditor.ID, localize('extension', "Extension") @@ -76,7 +76,7 @@ Registry.as(EditorExtensions.Editors).registerEditor( ]); // Viewlet -const viewletDescriptor = new ViewletDescriptor( +const viewletDescriptor = ViewletDescriptor.create( ExtensionsViewlet, VIEWLET_ID, localize('extensions', "Extensions"), @@ -350,7 +350,7 @@ class ExtensionsContributions implements IWorkbenchContribution { if (canManageExtensions) { Registry.as(Extensions.Quickopen).registerQuickOpenHandler( - new QuickOpenHandlerDescriptor( + QuickOpenHandlerDescriptor.create( GalleryExtensionsHandler, GalleryExtensionsHandler.ID, 'ext install ', diff --git a/src/vs/workbench/contrib/extensions/electron-browser/extensions.contribution.ts b/src/vs/workbench/contrib/extensions/electron-browser/extensions.contribution.ts index 4b5d7b3f7e340..7a080e779e5f6 100644 --- a/src/vs/workbench/contrib/extensions/electron-browser/extensions.contribution.ts +++ b/src/vs/workbench/contrib/extensions/electron-browser/extensions.contribution.ts @@ -34,7 +34,7 @@ workbenchRegistry.registerWorkbenchContribution(ExtensionsAutoProfiler, Lifecycl // Running Extensions Editor -const runtimeExtensionsEditorDescriptor = new EditorDescriptor( +const runtimeExtensionsEditorDescriptor = EditorDescriptor.create( RuntimeExtensionsEditor, RuntimeExtensionsEditor.ID, localize('runtimeExtension', "Running Extensions") diff --git a/src/vs/workbench/contrib/files/browser/files.contribution.ts b/src/vs/workbench/contrib/files/browser/files.contribution.ts index 5633cb728fd34..59fba1cfeaf45 100644 --- a/src/vs/workbench/contrib/files/browser/files.contribution.ts +++ b/src/vs/workbench/contrib/files/browser/files.contribution.ts @@ -75,7 +75,7 @@ class FileUriLabelContribution implements IWorkbenchContribution { } // Register Viewlet -Registry.as(ViewletExtensions.Viewlets).registerViewlet(new ViewletDescriptor( +Registry.as(ViewletExtensions.Viewlets).registerViewlet(ViewletDescriptor.create( ExplorerViewlet, VIEWLET_ID, nls.localize('explore', "Explorer"), @@ -101,7 +101,7 @@ registry.registerWorkbenchAction( // Register file editors Registry.as(EditorExtensions.Editors).registerEditor( - new EditorDescriptor( + EditorDescriptor.create( BinaryFileEditor, BinaryFileEditor.ID, nls.localize('binaryFileEditor', "Binary File Editor") diff --git a/src/vs/workbench/contrib/files/browser/files.web.contribution.ts b/src/vs/workbench/contrib/files/browser/files.web.contribution.ts index 44d91d66b91c1..494bdac348892 100644 --- a/src/vs/workbench/contrib/files/browser/files.web.contribution.ts +++ b/src/vs/workbench/contrib/files/browser/files.web.contribution.ts @@ -13,7 +13,7 @@ import { TextFileEditor } from 'vs/workbench/contrib/files/browser/editors/textF // Register file editor Registry.as(EditorExtensions.Editors).registerEditor( - new EditorDescriptor( + EditorDescriptor.create( TextFileEditor, TextFileEditor.ID, nls.localize('textFileEditor', "Text File Editor") diff --git a/src/vs/workbench/contrib/files/electron-browser/files.contribution.ts b/src/vs/workbench/contrib/files/electron-browser/files.contribution.ts index d5d18ac24ea86..eda8317d40d60 100644 --- a/src/vs/workbench/contrib/files/electron-browser/files.contribution.ts +++ b/src/vs/workbench/contrib/files/electron-browser/files.contribution.ts @@ -13,7 +13,7 @@ import { NativeTextFileEditor } from 'vs/workbench/contrib/files/electron-browse // Register file editor Registry.as(EditorExtensions.Editors).registerEditor( - new EditorDescriptor( + EditorDescriptor.create( NativeTextFileEditor, NativeTextFileEditor.ID, nls.localize('textFileEditor', "Text File Editor") diff --git a/src/vs/workbench/contrib/markers/browser/markers.contribution.ts b/src/vs/workbench/contrib/markers/browser/markers.contribution.ts index d28b9d0d7164a..42fd074794f9d 100644 --- a/src/vs/workbench/contrib/markers/browser/markers.contribution.ts +++ b/src/vs/workbench/contrib/markers/browser/markers.contribution.ts @@ -92,7 +92,7 @@ Registry.as(Extensions.Configuration).registerConfigurat // markers panel -Registry.as(PanelExtensions.Panels).registerPanel(new PanelDescriptor( +Registry.as(PanelExtensions.Panels).registerPanel(PanelDescriptor.create( MarkersPanel, Constants.MARKERS_PANEL_ID, Messages.MARKERS_PANEL_TITLE_PROBLEMS, diff --git a/src/vs/workbench/contrib/output/browser/output.contribution.ts b/src/vs/workbench/contrib/output/browser/output.contribution.ts index b5032f1eacc08..ec68b3b855639 100644 --- a/src/vs/workbench/contrib/output/browser/output.contribution.ts +++ b/src/vs/workbench/contrib/output/browser/output.contribution.ts @@ -41,7 +41,7 @@ ModesRegistry.registerLanguage({ }); // Register Output Panel -Registry.as(Extensions.Panels).registerPanel(new PanelDescriptor( +Registry.as(Extensions.Panels).registerPanel(PanelDescriptor.create( OutputPanel, OUTPUT_PANEL_ID, nls.localize('output', "Output"), @@ -51,7 +51,7 @@ Registry.as(Extensions.Panels).registerPanel(new PanelDescriptor( )); Registry.as(EditorExtensions.Editors).registerEditor( - new EditorDescriptor( + EditorDescriptor.create( LogViewer, LogViewer.LOG_VIEWER_EDITOR_ID, nls.localize('logViewer', "Log Viewer") diff --git a/src/vs/workbench/contrib/preferences/browser/preferences.contribution.ts b/src/vs/workbench/contrib/preferences/browser/preferences.contribution.ts index 4580b8d23eff1..cd52141866ddd 100644 --- a/src/vs/workbench/contrib/preferences/browser/preferences.contribution.ts +++ b/src/vs/workbench/contrib/preferences/browser/preferences.contribution.ts @@ -42,7 +42,7 @@ import { REMOTE_HOST_SCHEME } from 'vs/platform/remote/common/remoteHosts'; import { registerAndGetAmdImageURL } from 'vs/base/common/amd'; Registry.as(EditorExtensions.Editors).registerEditor( - new EditorDescriptor( + EditorDescriptor.create( PreferencesEditor, PreferencesEditor.ID, nls.localize('defaultPreferencesEditor', "Default Preferences Editor") @@ -53,7 +53,7 @@ Registry.as(EditorExtensions.Editors).registerEditor( ); Registry.as(EditorExtensions.Editors).registerEditor( - new EditorDescriptor( + EditorDescriptor.create( SettingsEditor2, SettingsEditor2.ID, nls.localize('settingsEditor2', "Settings Editor 2") @@ -64,7 +64,7 @@ Registry.as(EditorExtensions.Editors).registerEditor( ); Registry.as(EditorExtensions.Editors).registerEditor( - new EditorDescriptor( + EditorDescriptor.create( KeybindingsEditor, KeybindingsEditor.ID, nls.localize('keybindingsEditor', "Keybindings Editor") diff --git a/src/vs/workbench/contrib/quickopen/browser/quickopen.contribution.ts b/src/vs/workbench/contrib/quickopen/browser/quickopen.contribution.ts index 87639a7409aa6..ecac0bf8cc01d 100644 --- a/src/vs/workbench/contrib/quickopen/browser/quickopen.contribution.ts +++ b/src/vs/workbench/contrib/quickopen/browser/quickopen.contribution.ts @@ -72,7 +72,7 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({ // Register Quick Open Handler Registry.as(QuickOpenExtensions.Quickopen).registerQuickOpenHandler( - new QuickOpenHandlerDescriptor( + QuickOpenHandlerDescriptor.create( CommandsHandler, CommandsHandler.ID, ALL_COMMANDS_PREFIX, @@ -82,7 +82,7 @@ Registry.as(QuickOpenExtensions.Quickopen).registerQuickOpen ); Registry.as(QuickOpenExtensions.Quickopen).registerQuickOpenHandler( - new QuickOpenHandlerDescriptor( + QuickOpenHandlerDescriptor.create( GotoLineHandler, GotoLineHandler.ID, GOTO_LINE_PREFIX, @@ -98,7 +98,7 @@ Registry.as(QuickOpenExtensions.Quickopen).registerQuickOpen ); Registry.as(QuickOpenExtensions.Quickopen).registerQuickOpenHandler( - new QuickOpenHandlerDescriptor( + QuickOpenHandlerDescriptor.create( GotoSymbolHandler, GotoSymbolHandler.ID, GOTO_SYMBOL_PREFIX, @@ -119,7 +119,7 @@ Registry.as(QuickOpenExtensions.Quickopen).registerQuickOpen ); Registry.as(QuickOpenExtensions.Quickopen).registerQuickOpenHandler( - new QuickOpenHandlerDescriptor( + QuickOpenHandlerDescriptor.create( HelpHandler, HelpHandler.ID, HELP_PREFIX, @@ -129,7 +129,7 @@ Registry.as(QuickOpenExtensions.Quickopen).registerQuickOpen ); Registry.as(QuickOpenExtensions.Quickopen).registerQuickOpenHandler( - new QuickOpenHandlerDescriptor( + QuickOpenHandlerDescriptor.create( ViewPickerHandler, ViewPickerHandler.ID, VIEW_PICKER_PREFIX, diff --git a/src/vs/workbench/contrib/remote/browser/remote.ts b/src/vs/workbench/contrib/remote/browser/remote.ts index 6608c97946621..e4d5e233034de 100644 --- a/src/vs/workbench/contrib/remote/browser/remote.ts +++ b/src/vs/workbench/contrib/remote/browser/remote.ts @@ -274,7 +274,7 @@ export class RemoteViewlet extends FilterViewContainerViewlet { } } -Registry.as(ViewletExtensions.Viewlets).registerViewlet(new ViewletDescriptor( +Registry.as(ViewletExtensions.Viewlets).registerViewlet(ViewletDescriptor.create( RemoteViewlet, VIEWLET_ID, nls.localize('remote.explorer', "Remote Explorer"), diff --git a/src/vs/workbench/contrib/scm/browser/scm.contribution.ts b/src/vs/workbench/contrib/scm/browser/scm.contribution.ts index ce51e05887cc0..0c40988389f3d 100644 --- a/src/vs/workbench/contrib/scm/browser/scm.contribution.ts +++ b/src/vs/workbench/contrib/scm/browser/scm.contribution.ts @@ -38,7 +38,7 @@ class OpenSCMViewletAction extends ShowViewletAction { Registry.as(WorkbenchExtensions.Workbench) .registerWorkbenchContribution(DirtyDiffWorkbenchController, LifecyclePhase.Restored); -Registry.as(ViewletExtensions.Viewlets).registerViewlet(new ViewletDescriptor( +Registry.as(ViewletExtensions.Viewlets).registerViewlet(ViewletDescriptor.create( SCMViewlet, VIEWLET_ID, localize('source control', "Source Control"), diff --git a/src/vs/workbench/contrib/search/browser/search.contribution.ts b/src/vs/workbench/contrib/search/browser/search.contribution.ts index 07e88ed203436..22f4f3467de35 100644 --- a/src/vs/workbench/contrib/search/browser/search.contribution.ts +++ b/src/vs/workbench/contrib/search/browser/search.contribution.ts @@ -502,7 +502,7 @@ class ShowAllSymbolsAction extends Action { } } -Registry.as(ViewletExtensions.Viewlets).registerViewlet(new ViewletDescriptor( +Registry.as(ViewletExtensions.Viewlets).registerViewlet(ViewletDescriptor.create( SearchViewlet, VIEWLET_ID, nls.localize('name', "Search"), @@ -510,7 +510,7 @@ Registry.as(ViewletExtensions.Viewlets).registerViewlet(new Vie 1 )); -Registry.as(PanelExtensions.Panels).registerPanel(new PanelDescriptor( +Registry.as(PanelExtensions.Panels).registerPanel(PanelDescriptor.create( SearchPanel, PANEL_ID, nls.localize('name', "Search"), @@ -530,7 +530,7 @@ class RegisterSearchViewContribution implements IWorkbenchContribution { const config = configurationService.getValue(); if (config.search.location === 'panel') { viewsRegistry.deregisterViews(viewsRegistry.getViews(VIEW_CONTAINER), VIEW_CONTAINER); - Registry.as(PanelExtensions.Panels).registerPanel(new PanelDescriptor( + Registry.as(PanelExtensions.Panels).registerPanel(PanelDescriptor.create( SearchPanel, PANEL_ID, nls.localize('name', "Search"), @@ -626,7 +626,7 @@ registry.registerWorkbenchAction(SyncActionDescriptor.create(ClearSearchResultsA // Register Quick Open Handler Registry.as(QuickOpenExtensions.Quickopen).registerDefaultQuickOpenHandler( - new QuickOpenHandlerDescriptor( + QuickOpenHandlerDescriptor.create( OpenAnythingHandler, OpenAnythingHandler.ID, '', @@ -636,7 +636,7 @@ Registry.as(QuickOpenExtensions.Quickopen).registerDefaultQu ); Registry.as(QuickOpenExtensions.Quickopen).registerQuickOpenHandler( - new QuickOpenHandlerDescriptor( + QuickOpenHandlerDescriptor.create( OpenSymbolHandler, OpenSymbolHandler.ID, ShowAllSymbolsAction.ALL_SYMBOLS_PREFIX, diff --git a/src/vs/workbench/contrib/tasks/browser/task.contribution.ts b/src/vs/workbench/contrib/tasks/browser/task.contribution.ts index 9e352e4b9ce3b..a01d38e521f6d 100644 --- a/src/vs/workbench/contrib/tasks/browser/task.contribution.ts +++ b/src/vs/workbench/contrib/tasks/browser/task.contribution.ts @@ -254,7 +254,7 @@ const quickOpenRegistry = (Registry.as(QuickOpenExtensions.Q const tasksPickerContextKey = 'inTasksPicker'; quickOpenRegistry.registerQuickOpenHandler( - new QuickOpenHandlerDescriptor( + QuickOpenHandlerDescriptor.create( QuickOpenHandler, QuickOpenHandler.ID, 'task ', diff --git a/src/vs/workbench/contrib/terminal/browser/terminal.contribution.ts b/src/vs/workbench/contrib/terminal/browser/terminal.contribution.ts index 81eb57fddd66e..01699c0800635 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminal.contribution.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminal.contribution.ts @@ -48,7 +48,7 @@ const quickOpenRegistry = (Registry.as(QuickOpenExtensions.Q const inTerminalsPicker = 'inTerminalPicker'; quickOpenRegistry.registerQuickOpenHandler( - new QuickOpenHandlerDescriptor( + QuickOpenHandlerDescriptor.create( TerminalPickerHandler, TerminalPickerHandler.ID, TERMINAL_PICKER_PREFIX, diff --git a/src/vs/workbench/contrib/testCustomEditors/browser/testCustomEditors.ts b/src/vs/workbench/contrib/testCustomEditors/browser/testCustomEditors.ts index 358e503f4ad62..1a716bb01805c 100644 --- a/src/vs/workbench/contrib/testCustomEditors/browser/testCustomEditors.ts +++ b/src/vs/workbench/contrib/testCustomEditors/browser/testCustomEditors.ts @@ -207,7 +207,7 @@ class TestCustomEditorModel extends EditorModel { if (ENABLE) { Registry.as(EditorExtensions.Editors).registerEditor( - new EditorDescriptor( + EditorDescriptor.create( TestCustomEditor, TestCustomEditor.ID, nls.localize('testCustomEditor', "Test Custom Editor") diff --git a/src/vs/workbench/contrib/webview/browser/webview.contribution.ts b/src/vs/workbench/contrib/webview/browser/webview.contribution.ts index 445f190e1b24e..f7339e7f206aa 100644 --- a/src/vs/workbench/contrib/webview/browser/webview.contribution.ts +++ b/src/vs/workbench/contrib/webview/browser/webview.contribution.ts @@ -21,7 +21,7 @@ import { WebviewEditor } from '../browser/webviewEditor'; import { WebviewInput } from '../browser/webviewEditorInput'; import { IWebviewWorkbenchService, WebviewEditorService } from './webviewWorkbenchService'; -(Registry.as(EditorExtensions.Editors)).registerEditor(new EditorDescriptor( +(Registry.as(EditorExtensions.Editors)).registerEditor(EditorDescriptor.create( WebviewEditor, WebviewEditor.ID, localize('webview.editor.label', "webview editor")), diff --git a/src/vs/workbench/contrib/welcome/walkThrough/browser/walkThrough.contribution.ts b/src/vs/workbench/contrib/welcome/walkThrough/browser/walkThrough.contribution.ts index 0538dd38b27da..dfd947a4a7f11 100644 --- a/src/vs/workbench/contrib/welcome/walkThrough/browser/walkThrough.contribution.ts +++ b/src/vs/workbench/contrib/welcome/walkThrough/browser/walkThrough.contribution.ts @@ -20,7 +20,7 @@ import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle'; import { KeybindingsRegistry } from 'vs/platform/keybinding/common/keybindingsRegistry'; Registry.as(EditorExtensions.Editors) - .registerEditor(new EditorDescriptor( + .registerEditor(EditorDescriptor.create( WalkThroughPart, WalkThroughPart.ID, localize('walkThrough.editor.label', "Interactive Playground"), diff --git a/src/vs/workbench/services/editor/test/browser/editorGroupsService.test.ts b/src/vs/workbench/services/editor/test/browser/editorGroupsService.test.ts index 98e93a57adbe3..ca86ecb8744fc 100644 --- a/src/vs/workbench/services/editor/test/browser/editorGroupsService.test.ts +++ b/src/vs/workbench/services/editor/test/browser/editorGroupsService.test.ts @@ -78,7 +78,7 @@ suite('EditorGroupsService', () => { } (Registry.as(EditorExtensions.EditorInputFactories)).registerEditorInputFactory('testEditorInputForGroupsService', TestEditorInputFactory); - (Registry.as(Extensions.Editors)).registerEditor(new EditorDescriptor(TestEditorControl, 'MyTestEditorForGroupsService', 'My Test File Editor'), [new SyncDescriptor(TestEditorInput)]); + (Registry.as(Extensions.Editors)).registerEditor(EditorDescriptor.create(TestEditorControl, 'MyTestEditorForGroupsService', 'My Test File Editor'), [new SyncDescriptor(TestEditorInput)]); } registerTestEditorInput(); diff --git a/src/vs/workbench/services/editor/test/browser/editorService.test.ts b/src/vs/workbench/services/editor/test/browser/editorService.test.ts index 9bfe2984f58bf..ad798f5ce43f7 100644 --- a/src/vs/workbench/services/editor/test/browser/editorService.test.ts +++ b/src/vs/workbench/services/editor/test/browser/editorService.test.ts @@ -83,7 +83,7 @@ class FileServiceProvider extends Disposable { suite('EditorService', () => { function registerTestEditorInput(): void { - Registry.as(Extensions.Editors).registerEditor(new EditorDescriptor(TestEditorControl, 'MyTestEditorForEditorService', 'My Test Editor For Next Editor Service'), [new SyncDescriptor(TestEditorInput)]); + Registry.as(Extensions.Editors).registerEditor(EditorDescriptor.create(TestEditorControl, 'MyTestEditorForEditorService', 'My Test Editor For Next Editor Service'), [new SyncDescriptor(TestEditorInput)]); } registerTestEditorInput(); diff --git a/src/vs/workbench/test/browser/parts/editor/baseEditor.test.ts b/src/vs/workbench/test/browser/parts/editor/baseEditor.test.ts index 8e9d984ffe5c6..d75e7af6977a3 100644 --- a/src/vs/workbench/test/browser/parts/editor/baseEditor.test.ts +++ b/src/vs/workbench/test/browser/parts/editor/baseEditor.test.ts @@ -115,14 +115,14 @@ suite('Workbench base editor', () => { }); test('EditorDescriptor', () => { - let d = new EditorDescriptor(MyEditor, 'id', 'name'); + let d = EditorDescriptor.create(MyEditor, 'id', 'name'); assert.strictEqual(d.getId(), 'id'); assert.strictEqual(d.getName(), 'name'); }); test('Editor Registration', function () { - let d1 = new EditorDescriptor(MyEditor, 'id1', 'name'); - let d2 = new EditorDescriptor(MyOtherEditor, 'id2', 'name'); + let d1 = EditorDescriptor.create(MyEditor, 'id1', 'name'); + let d2 = EditorDescriptor.create(MyOtherEditor, 'id2', 'name'); let oldEditorsCnt = EditorRegistry.getEditors().length; let oldInputCnt = (EditorRegistry).getEditorInputs().length; @@ -142,8 +142,8 @@ suite('Workbench base editor', () => { }); test('Editor Lookup favors specific class over superclass (match on specific class)', function () { - let d1 = new EditorDescriptor(MyEditor, 'id1', 'name'); - let d2 = new EditorDescriptor(MyOtherEditor, 'id2', 'name'); + let d1 = EditorDescriptor.create(MyEditor, 'id1', 'name'); + let d2 = EditorDescriptor.create(MyOtherEditor, 'id2', 'name'); let oldEditors = EditorRegistry.getEditors(); (EditorRegistry).setEditors([]); @@ -163,7 +163,7 @@ suite('Workbench base editor', () => { }); test('Editor Lookup favors specific class over superclass (match on super class)', function () { - let d1 = new EditorDescriptor(MyOtherEditor, 'id1', 'name'); + let d1 = EditorDescriptor.create(MyOtherEditor, 'id1', 'name'); let oldEditors = EditorRegistry.getEditors(); (EditorRegistry).setEditors([]); diff --git a/src/vs/workbench/test/browser/quickopen.test.ts b/src/vs/workbench/test/browser/quickopen.test.ts index 1a264a7e25c61..696bb972574ec 100644 --- a/src/vs/workbench/test/browser/quickopen.test.ts +++ b/src/vs/workbench/test/browser/quickopen.test.ts @@ -54,7 +54,7 @@ suite('QuickOpen', () => { test('QuickOpen Handler and Registry', () => { let registry = (Registry.as(QuickOpenExtensions.Quickopen)); - let handler = new QuickOpenHandlerDescriptor( + let handler = QuickOpenHandlerDescriptor.create( TestHandler, 'testhandler', ',', @@ -77,4 +77,4 @@ suite('QuickOpen', () => { defaultAction.run(); prefixAction.run(); }); -}); \ No newline at end of file +}); diff --git a/src/vs/workbench/test/browser/viewlet.test.ts b/src/vs/workbench/test/browser/viewlet.test.ts index 6545d38ced2be..2698de8973831 100644 --- a/src/vs/workbench/test/browser/viewlet.test.ts +++ b/src/vs/workbench/test/browser/viewlet.test.ts @@ -22,7 +22,7 @@ suite('Viewlets', () => { } test('ViewletDescriptor API', function () { - let d = new ViewletDescriptor(TestViewlet, 'id', 'name', 'class', 5); + let d = ViewletDescriptor.create(TestViewlet, 'id', 'name', 'class', 5); assert.strictEqual(d.id, 'id'); assert.strictEqual(d.name, 'name'); assert.strictEqual(d.cssClass, 'class'); @@ -30,11 +30,11 @@ suite('Viewlets', () => { }); test('Editor Aware ViewletDescriptor API', function () { - let d = new ViewletDescriptor(TestViewlet, 'id', 'name', 'class', 5); + let d = ViewletDescriptor.create(TestViewlet, 'id', 'name', 'class', 5); assert.strictEqual(d.id, 'id'); assert.strictEqual(d.name, 'name'); - d = new ViewletDescriptor(TestViewlet, 'id', 'name', 'class', 5); + d = ViewletDescriptor.create(TestViewlet, 'id', 'name', 'class', 5); assert.strictEqual(d.id, 'id'); assert.strictEqual(d.name, 'name'); }); @@ -45,7 +45,7 @@ suite('Viewlets', () => { assert(Types.isFunction(Platform.Registry.as(Extensions.Viewlets).getViewlets)); let oldCount = Platform.Registry.as(Extensions.Viewlets).getViewlets().length; - let d = new ViewletDescriptor(TestViewlet, 'reg-test-id', 'name'); + let d = ViewletDescriptor.create(TestViewlet, 'reg-test-id', 'name'); Platform.Registry.as(Extensions.Viewlets).registerViewlet(d); assert(d === Platform.Registry.as(Extensions.Viewlets).getViewlet('reg-test-id')); From 23947ea1ffeafb94cab47c9cc6d21f56460eb029 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Thu, 14 Nov 2019 17:27:18 -0800 Subject: [PATCH 303/352] Add strict function type task For #81574 Replaces the strict property task since this is no longer needed --- .vscode/tasks.json | 6 +++--- package.json | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.vscode/tasks.json b/.vscode/tasks.json index d1a697bb41daa..598d82214ce22 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -33,15 +33,15 @@ }, { "type": "npm", - "script": "strict-initialization-watch", - "label": "TS - Strict Initialization", + "script": "strict-function-types-watch", + "label": "TS - Strict Function Types", "isBackground": true, "presentation": { "reveal": "never" }, "problemMatcher": { "base": "$tsc-watch", - "owner": "typescript-strict-initialization", + "owner": "typescript-function-types", "applyTo": "allDocuments" } }, diff --git a/package.json b/package.json index ec7cd7ba956a5..10caabb82adcb 100644 --- a/package.json +++ b/package.json @@ -25,7 +25,7 @@ "smoketest": "cd test/smoke && node test/index.js", "download-builtin-extensions": "node build/lib/builtInExtensions.js", "monaco-compile-check": "tsc -p src/tsconfig.monaco.json --noEmit", - "strict-initialization-watch": "tsc --watch -p src/tsconfig.json --noEmit --strictPropertyInitialization", + "strict-function-types-watch": "tsc --watch -p src/tsconfig.json --noEmit --strictFunctionTypes", "update-distro": "node build/npm/update-distro.js", "web": "node scripts/code-web.js" }, From d420e20fcd4b4bd9312cfd95cba2522f29b7ff27 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Thu, 14 Nov 2019 17:35:14 -0800 Subject: [PATCH 304/352] Fix implicit casts in tests For #81574 --- .../codeAction/test/codeActionModel.test.ts | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/src/vs/editor/contrib/codeAction/test/codeActionModel.test.ts b/src/vs/editor/contrib/codeAction/test/codeActionModel.test.ts index c2ef449356292..e394f6838c11c 100644 --- a/src/vs/editor/contrib/codeAction/test/codeActionModel.test.ts +++ b/src/vs/editor/contrib/codeAction/test/codeActionModel.test.ts @@ -5,6 +5,7 @@ import * as assert from 'assert'; import { DisposableStore } from 'vs/base/common/lifecycle'; +import { assertType } from 'vs/base/common/types'; import { URI } from 'vs/base/common/uri'; import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; import { Selection } from 'vs/editor/common/core/selection'; @@ -55,8 +56,10 @@ suite('CodeActionModel', () => { const contextKeys = new MockContextKeyService(); const model = disposables.add(new CodeActionModel(editor, markerService, contextKeys, undefined)); - disposables.add(model.onDidChangeState((e: CodeActionsState.Triggered) => { - assert.equal(e.trigger.type, 'auto'); + disposables.add(model.onDidChangeState((e: CodeActionsState.State) => { + assertType(e.type === CodeActionsState.Type.Triggered); + + assert.strictEqual(e.trigger.type, 'auto'); assert.ok(e.actions); e.actions.then(fixes => { @@ -94,7 +97,9 @@ suite('CodeActionModel', () => { return new Promise((resolve, reject) => { const contextKeys = new MockContextKeyService(); const model = disposables.add(new CodeActionModel(editor, markerService, contextKeys, undefined)); - disposables.add(model.onDidChangeState((e: CodeActionsState.Triggered) => { + disposables.add(model.onDidChangeState((e: CodeActionsState.State) => { + assertType(e.type === CodeActionsState.Type.Triggered); + assert.equal(e.trigger.type, 'auto'); assert.ok(e.actions); e.actions.then(fixes => { @@ -130,7 +135,9 @@ suite('CodeActionModel', () => { await new Promise(resolve => { const contextKeys = new MockContextKeyService(); const model = disposables.add(new CodeActionModel(editor, markerService, contextKeys, undefined)); - disposables.add(model.onDidChangeState((e: CodeActionsState.Triggered) => { + disposables.add(model.onDidChangeState((e: CodeActionsState.State) => { + assertType(e.type === CodeActionsState.Type.Triggered); + assert.equal(e.trigger.type, 'auto'); const selection = e.rangeOrSelection; assert.deepEqual(selection.selectionStartLineNumber, 1); @@ -153,7 +160,9 @@ suite('CodeActionModel', () => { let triggerCount = 0; const contextKeys = new MockContextKeyService(); const model = disposables.add(new CodeActionModel(editor, markerService, contextKeys, undefined)); - disposables.add(model.onDidChangeState((e: CodeActionsState.Triggered) => { + disposables.add(model.onDidChangeState((e: CodeActionsState.State) => { + assertType(e.type === CodeActionsState.Type.Triggered); + assert.equal(e.trigger.type, 'auto'); ++triggerCount; From 87387677d31efe0914ab65c19273ee13c814c108 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Thu, 14 Nov 2019 17:37:24 -0800 Subject: [PATCH 305/352] Fix strict function types for registerEditorInputFactory #81574 --- src/vs/workbench/common/editor.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/common/editor.ts b/src/vs/workbench/common/editor.ts index e2dcb62669cf0..1764e7ed83280 100644 --- a/src/vs/workbench/common/editor.ts +++ b/src/vs/workbench/common/editor.ts @@ -10,7 +10,7 @@ import { URI } from 'vs/base/common/uri'; import { IDisposable, Disposable } from 'vs/base/common/lifecycle'; import { IEditor as ICodeEditor, IEditorViewState, ScrollType, IDiffEditor } from 'vs/editor/common/editorCommon'; import { IEditorModel, IEditorOptions, ITextEditorOptions, IBaseResourceInput, IResourceInput, EditorActivation, EditorOpenContext } from 'vs/platform/editor/common/editor'; -import { IInstantiationService, IConstructorSignature0, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; +import { IInstantiationService, IConstructorSignature0, ServicesAccessor, BrandedService } from 'vs/platform/instantiation/common/instantiation'; import { RawContextKey, ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; import { Registry } from 'vs/platform/registry/common/platform'; import { ITextModel } from 'vs/editor/common/model'; @@ -175,7 +175,7 @@ export interface IEditorInputFactoryRegistry { * @param editorInputId the identifier of the editor input * @param factory the editor input factory for serialization/deserialization */ - registerEditorInputFactory(editorInputId: string, ctor: IConstructorSignature0): void; + registerEditorInputFactory(editorInputId: string, ctor: { new(...Services: Services): IEditorInputFactory }): void; /** * Returns the editor input factory for the given editor input. From bf7d03bf88732af0b46e473c663c49e18e839f9c Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Thu, 14 Nov 2019 17:52:02 -0800 Subject: [PATCH 306/352] Fix one reference to new PanelDescriptor that should have been converted to create --- .../workbench/contrib/terminal/browser/terminal.contribution.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/terminal/browser/terminal.contribution.ts b/src/vs/workbench/contrib/terminal/browser/terminal.contribution.ts index 01699c0800635..f166e7aacdd81 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminal.contribution.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminal.contribution.ts @@ -331,7 +331,7 @@ registry.registerWorkbenchAction(SyncActionDescriptor.create(QuickOpenTermAction const actionBarRegistry = Registry.as(ActionBarExtensions.Actionbar); actionBarRegistry.registerActionBarContributor(Scope.VIEWER, QuickOpenActionTermContributor); -(Registry.as(panel.Extensions.Panels)).registerPanel(new panel.PanelDescriptor( +(Registry.as(panel.Extensions.Panels)).registerPanel(panel.PanelDescriptor.create( TerminalPanel, TERMINAL_PANEL_ID, nls.localize('terminal', "Terminal"), From bfe5a684238b119d913f6a4b052cca9f8dc5704f Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Fri, 15 Nov 2019 08:38:25 +0100 Subject: [PATCH 307/352] use shared CSS-style element instead of repeated inline styles, only access dom when having contents, #84726 --- .../contrib/codelens/codelensController.ts | 33 ++++++++++++++----- .../contrib/codelens/codelensWidget.css | 4 --- .../editor/contrib/codelens/codelensWidget.ts | 33 ++++++------------- 3 files changed, 34 insertions(+), 36 deletions(-) diff --git a/src/vs/editor/contrib/codelens/codelensController.ts b/src/vs/editor/contrib/codelens/codelensController.ts index b50d4508fe3b0..6c259a207c053 100644 --- a/src/vs/editor/contrib/codelens/codelensController.ts +++ b/src/vs/editor/contrib/codelens/codelensController.ts @@ -18,6 +18,8 @@ import { ICommandService } from 'vs/platform/commands/common/commands'; import { INotificationService } from 'vs/platform/notification/common/notification'; import { ICodeLensCache } from 'vs/editor/contrib/codelens/codeLensCache'; import { EditorOption } from 'vs/editor/common/config/editorOptions'; +import { createStyleSheet } from 'vs/base/browser/dom'; +import { hash } from 'vs/base/common/hash'; export class CodeLensContribution implements editorCommon.IEditorContribution { @@ -27,6 +29,8 @@ export class CodeLensContribution implements editorCommon.IEditorContribution { private readonly _globalToDispose = new DisposableStore(); private readonly _localToDispose = new DisposableStore(); + private readonly _styleElement: HTMLStyleElement; + private readonly _styleClassName: string; private _lenses: CodeLensWidget[] = []; private _currentFindCodeLensSymbolsPromise: CancelablePromise | undefined; private _oldCodeLensModels = new DisposableStore(); @@ -53,7 +57,16 @@ export class CodeLensContribution implements editorCommon.IEditorContribution { } })); this._globalToDispose.add(CodeLensProviderRegistry.onDidChange(this._onModelChange, this)); + this._globalToDispose.add(this._editor.onDidChangeConfiguration(e => { + if (e.hasChanged(EditorOption.fontInfo)) { + this._updateLensStyle(); + } + })); this._onModelChange(); + + this._styleClassName = hash(this._editor.getId()).toString(16); + this._styleElement = createStyleSheet(); + this._updateLensStyle(); } dispose(): void { @@ -63,6 +76,15 @@ export class CodeLensContribution implements editorCommon.IEditorContribution { dispose(this._currentCodeLensModel); } + private _updateLensStyle(): void { + const options = this._editor.getOptions(); + const fontInfo = options.get(EditorOption.fontInfo); + const lineHeight = options.get(EditorOption.lineHeight); + + const newStyle = `.monaco-editor .codelens-decoration.${this._styleClassName} { height: ${Math.round(lineHeight * 1.1)}px; line-height: ${lineHeight}px; font-size: ${Math.round(fontInfo.fontSize * 0.9)}px; padding-right: ${Math.round(fontInfo.fontSize * 0.45)}px;}`; + this._styleElement.innerHTML = newStyle; + } + private _localDispose(): void { if (this._currentFindCodeLensSymbolsPromise) { this._currentFindCodeLensSymbolsPromise.cancel(); @@ -200,13 +222,6 @@ export class CodeLensContribution implements editorCommon.IEditorContribution { this._disposeAllLenses(undefined, undefined); } })); - this._localToDispose.add(this._editor.onDidChangeConfiguration(e => { - if (e.hasChanged(EditorOption.fontInfo)) { - for (const lens of this._lenses) { - lens.updateHeight(); - } - } - })); this._localToDispose.add(this._editor.onMouseUp(e => { if (e.target.type === editorBrowser.MouseTargetType.CONTENT_WIDGET && e.target.element && e.target.element.tagName === 'A') { for (const lens of this._lenses) { @@ -278,7 +293,7 @@ export class CodeLensContribution implements editorCommon.IEditorContribution { groupsIndex++; codeLensIndex++; } else { - this._lenses.splice(codeLensIndex, 0, new CodeLensWidget(groups[groupsIndex], this._editor, helper, viewZoneAccessor, () => this._detectVisibleLenses && this._detectVisibleLenses.schedule())); + this._lenses.splice(codeLensIndex, 0, new CodeLensWidget(groups[groupsIndex], this._editor, this._styleClassName, helper, viewZoneAccessor, () => this._detectVisibleLenses && this._detectVisibleLenses.schedule())); codeLensIndex++; groupsIndex++; } @@ -292,7 +307,7 @@ export class CodeLensContribution implements editorCommon.IEditorContribution { // Create extra symbols while (groupsIndex < groups.length) { - this._lenses.push(new CodeLensWidget(groups[groupsIndex], this._editor, helper, viewZoneAccessor, () => this._detectVisibleLenses && this._detectVisibleLenses.schedule())); + this._lenses.push(new CodeLensWidget(groups[groupsIndex], this._editor, this._styleClassName, helper, viewZoneAccessor, () => this._detectVisibleLenses && this._detectVisibleLenses.schedule())); groupsIndex++; } diff --git a/src/vs/editor/contrib/codelens/codelensWidget.css b/src/vs/editor/contrib/codelens/codelensWidget.css index e266cf8b6a826..031a0558f2594 100644 --- a/src/vs/editor/contrib/codelens/codelensWidget.css +++ b/src/vs/editor/contrib/codelens/codelensWidget.css @@ -27,10 +27,6 @@ cursor: pointer; } -.monaco-editor .codelens-decoration.invisible-cl { - opacity: 0; -} - @keyframes fadein { 0% { opacity: 0; visibility: visible;} 100% { opacity: 1; } diff --git a/src/vs/editor/contrib/codelens/codelensWidget.ts b/src/vs/editor/contrib/codelens/codelensWidget.ts index 546cdfd028e14..fe1e9f2f2e05e 100644 --- a/src/vs/editor/contrib/codelens/codelensWidget.ts +++ b/src/vs/editor/contrib/codelens/codelensWidget.ts @@ -15,7 +15,6 @@ import { editorCodeLensForeground } from 'vs/editor/common/view/editorColorRegis import { CodeLensItem } from 'vs/editor/contrib/codelens/codelens'; import { editorActiveLinkForeground } from 'vs/platform/theme/common/colorRegistry'; import { registerThemingParticipant } from 'vs/platform/theme/common/themeService'; -import { EditorOption } from 'vs/editor/common/config/editorOptions'; class CodeLensViewZone implements editorBrowser.IViewZone { @@ -61,33 +60,24 @@ class CodeLensContentWidget implements editorBrowser.IContentWidget { private readonly _commands = new Map(); private _widgetPosition?: editorBrowser.IContentWidgetPosition; + private _isEmpty: boolean = true; constructor( editor: editorBrowser.ICodeEditor, + className: string, symbolRange: Range, lenses: Array ) { - this._id = 'codeLensWidget' + (++CodeLensContentWidget._idPool); this._editor = editor; + this._id = (CodeLensContentWidget._idPool++).toString(); this.setSymbolRange(symbolRange); this._domNode = document.createElement('span'); - this._domNode.className = 'codelens-decoration'; - this.updateHeight(); + this._domNode.className = `codelens-decoration ${className}`; this.withCommands(lenses, false); } - updateHeight(): void { - const options = this._editor.getOptions(); - const fontInfo = options.get(EditorOption.fontInfo); - const lineHeight = options.get(EditorOption.lineHeight); - this._domNode.style.height = `${Math.round(lineHeight * 1.1)}px`; - this._domNode.style.lineHeight = `${lineHeight}px`; - this._domNode.style.fontSize = `${Math.round(fontInfo.fontSize * 0.9)}px`; - this._domNode.style.paddingRight = `${Math.round(fontInfo.fontSize * 0.45)}px`; - } - withCommands(lenses: Array, animate: boolean): void { this._commands.clear(); @@ -117,14 +107,14 @@ class CodeLensContentWidget implements editorBrowser.IContentWidget { // symbols but no commands this._domNode.innerHTML = 'no commands'; - } else { + } else if (innerHtml) { // symbols and commands - const wasEmpty = this._domNode.innerHTML === '' || this._domNode.innerHTML === ' '; - this._domNode.innerHTML = innerHtml || ' '; + this._domNode.innerHTML = innerHtml; this._editor.layoutContentWidget(this); - if (wasEmpty && animate) { + if (this._isEmpty && animate) { dom.addClass(this._domNode, 'fadein'); } + this._isEmpty = false; } } @@ -208,6 +198,7 @@ export class CodeLensWidget { constructor( data: CodeLensItem[], editor: editorBrowser.ICodeEditor, + className: string, helper: CodeLensHelper, viewZoneChangeAccessor: editorBrowser.IViewZoneChangeAccessor, updateCallback: Function @@ -236,7 +227,7 @@ export class CodeLensWidget { }); if (range) { - this._contentWidget = new CodeLensContentWidget(editor, range, lenses); + this._contentWidget = new CodeLensContentWidget(editor, className, range, lenses); this._viewZone = new CodeLensViewZone(range.startLineNumber - 1, updateCallback); this._viewZoneId = viewZoneChangeAccessor.addZone(this._viewZone); @@ -306,10 +297,6 @@ export class CodeLensWidget { } } - updateHeight(): void { - this._contentWidget.updateHeight(); - } - getCommand(link: HTMLLinkElement): Command | undefined { return this._contentWidget.getCommand(link); } From 03ef538d3d6603a2cf9e3d8bebaaa288b243da00 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Fri, 15 Nov 2019 09:09:21 +0100 Subject: [PATCH 308/352] code lens must not be empty... #84726 --- src/vs/editor/contrib/codelens/codelensWidget.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/vs/editor/contrib/codelens/codelensWidget.ts b/src/vs/editor/contrib/codelens/codelensWidget.ts index fe1e9f2f2e05e..54318b98678b8 100644 --- a/src/vs/editor/contrib/codelens/codelensWidget.ts +++ b/src/vs/editor/contrib/codelens/codelensWidget.ts @@ -107,8 +107,11 @@ class CodeLensContentWidget implements editorBrowser.IContentWidget { // symbols but no commands this._domNode.innerHTML = 'no commands'; - } else if (innerHtml) { + } else { // symbols and commands + if (!innerHtml) { + innerHtml = ' '; + } this._domNode.innerHTML = innerHtml; this._editor.layoutContentWidget(this); if (this._isEmpty && animate) { From e97c0c2070eec5bd953750cef0cc8ee2166bb7d8 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Fri, 15 Nov 2019 09:20:33 +0100 Subject: [PATCH 309/352] fix #84787 --- src/vs/base/common/filters.ts | 2 +- src/vs/base/test/common/filters.test.ts | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/vs/base/common/filters.ts b/src/vs/base/common/filters.ts index 5e3150d33080a..8e8fd433fb2cc 100644 --- a/src/vs/base/common/filters.ts +++ b/src/vs/base/common/filters.ts @@ -543,7 +543,7 @@ export function fuzzyScore(pattern: string, patternLow: string, patternStart: nu const patternLen = pattern.length > _maxLen ? _maxLen : pattern.length; const wordLen = word.length > _maxLen ? _maxLen : word.length; - if (patternStart >= patternLen || wordStart >= wordLen || patternLen > wordLen) { + if (patternStart >= patternLen || wordStart >= wordLen || (patternLen - patternStart) > (wordLen - wordStart)) { return undefined; } diff --git a/src/vs/base/test/common/filters.test.ts b/src/vs/base/test/common/filters.test.ts index 6f96e22f47e97..f41838588a598 100644 --- a/src/vs/base/test/common/filters.test.ts +++ b/src/vs/base/test/common/filters.test.ts @@ -498,4 +498,9 @@ suite('Filters', () => { fuzzyScore ); }); + + test('"Go to Symbol" with the exact method name doesn\'t work as expected #84787', function () { + const match = fuzzyScore(':get', ':get', 1, 'get', 'get', 0, true); + assert.ok(Boolean(match)); + }); }); From 0083c78aa4c906d9ac0b8fe91e1a548313dc9678 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Fri, 15 Nov 2019 09:28:21 +0100 Subject: [PATCH 310/352] Revert "add URI.from(url)-overload" This reverts commit e24fefe0a89205ce519efd8bd4ee53bde4bfe90c. --- src/vs/base/common/uri.ts | 9 +-------- src/vs/monaco.d.ts | 2 +- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/src/vs/base/common/uri.ts b/src/vs/base/common/uri.ts index 3df1ee149e2ee..19f89eec62678 100644 --- a/src/vs/base/common/uri.ts +++ b/src/vs/base/common/uri.ts @@ -323,14 +323,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 } | URL): URI { - - if (components instanceof URL) { - const value = <_URI>_URI.parse(components.href); - value._formatted = components.href; - return value; - } - + static from(components: { scheme: string; authority?: string; path?: string; query?: string; fragment?: string }): URI { return new _URI( components.scheme, components.authority, diff --git a/src/vs/monaco.d.ts b/src/vs/monaco.d.ts index ff535f4bfbcf3..2fa74f0ac351d 100644 --- a/src/vs/monaco.d.ts +++ b/src/vs/monaco.d.ts @@ -160,7 +160,7 @@ declare namespace monaco { path?: string; query?: string; fragment?: string; - } | URL): Uri; + }): Uri; /** * Creates a string representation for this Uri. It's guaranteed that calling * `Uri.parse` with the result of this function creates an Uri which is equal From ee3a3406c639bffdc48bc0eefd7d7c5414771143 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Fri, 15 Nov 2019 09:38:41 +0100 Subject: [PATCH 311/352] lcd - put tabs on their own layer to enable proper rendering --- .../parts/editor/media/editorgroupview.css | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/vs/workbench/browser/parts/editor/media/editorgroupview.css b/src/vs/workbench/browser/parts/editor/media/editorgroupview.css index 582eac233e20b..15fb7042231e3 100644 --- a/src/vs/workbench/browser/parts/editor/media/editorgroupview.css +++ b/src/vs/workbench/browser/parts/editor/media/editorgroupview.css @@ -48,6 +48,21 @@ overflow: hidden; } +.monaco-workbench.windows .part.editor > .content .editor-group-container > .title, +.monaco-workbench.linux .part.editor > .content .editor-group-container > .title, +.monaco-workbench.web .part.editor > .content .editor-group-container > .title { + /* + * Explicitly put the part onto its own layer to help Chrome to + * render the content with LCD-anti-aliasing. By partioning the + * workbench into multiple layers, we can ensure that a bad + * behaving part is not making another part fallback to greyscale + * rendering. + * + * macOS: does not render LCD-anti-aliased. + */ + transform: translate3d(0px, 0px, 0px); +} + .monaco-workbench .part.editor > .content .editor-group-container > .title:not(.tabs) { display: flex; /* when tabs are not shown, use flex layout */ flex-wrap: nowrap; From 655df8fe0d4e8d83ebe5a796d4f1203dfdba81e0 Mon Sep 17 00:00:00 2001 From: Alex Ross Date: Fri, 15 Nov 2019 10:05:32 +0100 Subject: [PATCH 312/352] Make sure tha allViews are ready in remote explorer Part of https://github.com/microsoft/vscode-remote-release/issues/1847 --- .../browser/parts/views/viewsViewlet.ts | 34 ++++++++++++------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/src/vs/workbench/browser/parts/views/viewsViewlet.ts b/src/vs/workbench/browser/parts/views/viewsViewlet.ts index 874677282dd2f..f934a70b2dd80 100644 --- a/src/vs/workbench/browser/parts/views/viewsViewlet.ts +++ b/src/vs/workbench/browser/parts/views/viewsViewlet.ts @@ -350,22 +350,26 @@ export abstract class FilterViewContainerViewlet extends ViewContainerViewlet { })); this._register(this.viewsModel.onDidChangeActiveViews((viewDescriptors) => { - viewDescriptors.forEach(descriptor => { - let filterOnValue = this.getFilterOn(descriptor); - if (!filterOnValue) { - return; - } - if (!this.allViews.has(filterOnValue)) { - this.allViews.set(filterOnValue, new Map()); - } - this.allViews.get(filterOnValue)!.set(descriptor.id, descriptor); - if (filterOnValue !== this.filterValue) { - this.viewsModel.setVisible(descriptor.id, false); - } - }); + this.updateAllViews(viewDescriptors); })); } + private updateAllViews(viewDescriptors: IViewDescriptor[]) { + viewDescriptors.forEach(descriptor => { + let filterOnValue = this.getFilterOn(descriptor); + if (!filterOnValue) { + return; + } + if (!this.allViews.has(filterOnValue)) { + this.allViews.set(filterOnValue, new Map()); + } + this.allViews.get(filterOnValue)!.set(descriptor.id, descriptor); + if (filterOnValue !== this.filterValue) { + this.viewsModel.setVisible(descriptor.id, false); + } + }); + } + protected addConstantViewDescriptors(constantViewDescriptors: IViewDescriptor[]) { constantViewDescriptors.forEach(viewDescriptor => this.constantViewDescriptors.set(viewDescriptor.id, viewDescriptor)); } @@ -415,6 +419,10 @@ export abstract class FilterViewContainerViewlet extends ViewContainerViewlet { } onDidAddViews(added: IAddedViewDescriptorRef[]): ViewletPanel[] { + // Check that allViews is ready + if (this.allViews.size === 0) { + this.updateAllViews(this.viewsModel.viewDescriptors); + } const panels: ViewletPanel[] = super.onDidAddViews(added); for (let i = 0; i < added.length; i++) { if (this.constantViewDescriptors.has(added[i].viewDescriptor.id)) { From f651ccac7e2806d8f8c57c47429293c2435c2200 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Fri, 15 Nov 2019 10:13:48 +0100 Subject: [PATCH 313/352] extract openers --- .../editor/browser/services/openerService.ts | 143 +++++++++--------- 1 file changed, 71 insertions(+), 72 deletions(-) diff --git a/src/vs/editor/browser/services/openerService.ts b/src/vs/editor/browser/services/openerService.ts index b92275c5cf0f7..ead9bd31bfb4c 100644 --- a/src/vs/editor/browser/services/openerService.ts +++ b/src/vs/editor/browser/services/openerService.ts @@ -16,6 +16,71 @@ import { IOpener, IOpenerService, IValidator, IExternalUriResolver, OpenOptions, import { EditorOpenContext } from 'vs/platform/editor/common/editor'; +class CommandOpener implements IOpener { + + constructor(@ICommandService private readonly _commandService: ICommandService) { } + + async open(target: URI | string) { + if (!matchesScheme(target, Schemas.command)) { + return false; + } + // run command or bail out if command isn't known + if (typeof target === 'string') { + target = URI.parse(target); + } + if (!CommandsRegistry.getCommand(target.path)) { + throw new Error(`command '${target.path}' NOT known`); + } + // execute as command + let args: any = []; + try { + args = parse(target.query); + if (!Array.isArray(args)) { + args = [args]; + } + } catch (e) { + // ignore error + } + await this._commandService.executeCommand(target.path, ...args); + return true; + } +} + +class EditorOpener implements IOpener { + + constructor(@ICodeEditorService private readonly _editorService: ICodeEditorService) { } + + async open(target: URI | string, options: OpenOptions) { + if (typeof target === 'string') { + target = URI.parse(target); + } + let selection: { startLineNumber: number; startColumn: number; } | undefined = undefined; + const match = /^L?(\d+)(?:,(\d+))?/.exec(target.fragment); + if (match) { + // support file:///some/file.js#73,84 + // support file:///some/file.js#L73 + selection = { + startLineNumber: parseInt(match[1]), + startColumn: match[2] ? parseInt(match[2]) : 1 + }; + // remove fragment + target = target.with({ fragment: '' }); + } + + if (target.scheme === Schemas.file) { + target = normalizePath(target); // workaround for non-normalized paths (https://github.com/Microsoft/vscode/issues/12954) + } + + await this._editorService.openCodeEditor( + { resource: target, options: { selection, context: options?.fromUserGesture ? EditorOpenContext.USER : EditorOpenContext.API } }, + this._editorService.getFocusedCodeEditor(), + options?.openToSide + ); + + return true; + } +} + export class OpenerService implements IOpenerService { _serviceBrand: undefined; @@ -25,9 +90,6 @@ export class OpenerService implements IOpenerService { private readonly _resolvers = new LinkedList(); private _externalOpener: IExternalOpener; - private _openerAsExternal: IOpener; - private _openerAsCommand: IOpener; - private _openerAsEditor: IOpener; constructor( @ICodeEditorService editorService: ICodeEditorService, @@ -42,7 +104,7 @@ export class OpenerService implements IOpenerService { }; // Default opener: maito, http(s), command, and catch-all-editors - this._openerAsExternal = { + this._openers.push({ open: async (target: URI | string, options?: OpenOptions) => { if (options?.openExternal || matchesScheme(target, Schemas.mailto) || matchesScheme(target, Schemas.http) || matchesScheme(target, Schemas.https)) { // open externally @@ -51,70 +113,13 @@ export class OpenerService implements IOpenerService { } return false; } - }; - - this._openerAsCommand = { - open: async (target) => { - if (!matchesScheme(target, Schemas.command)) { - return false; - } - // run command or bail out if command isn't known - if (typeof target === 'string') { - target = URI.parse(target); - } - if (!CommandsRegistry.getCommand(target.path)) { - throw new Error(`command '${target.path}' NOT known`); - } - // execute as command - let args: any = []; - try { - args = parse(target.query); - if (!Array.isArray(args)) { - args = [args]; - } - } catch (e) { - // ignore error - } - await commandService.executeCommand(target.path, ...args); - return true; - } - }; - - this._openerAsEditor = { - open: async (target, options: OpenOptions) => { - if (typeof target === 'string') { - target = URI.parse(target); - } - let selection: { startLineNumber: number; startColumn: number; } | undefined = undefined; - const match = /^L?(\d+)(?:,(\d+))?/.exec(target.fragment); - if (match) { - // support file:///some/file.js#73,84 - // support file:///some/file.js#L73 - selection = { - startLineNumber: parseInt(match[1]), - startColumn: match[2] ? parseInt(match[2]) : 1 - }; - // remove fragment - target = target.with({ fragment: '' }); - } - - if (target.scheme === Schemas.file) { - target = normalizePath(target); // workaround for non-normalized paths (https://github.com/Microsoft/vscode/issues/12954) - } - - await editorService.openCodeEditor( - { resource: target, options: { selection, context: options?.fromUserGesture ? EditorOpenContext.USER : EditorOpenContext.API } }, - editorService.getFocusedCodeEditor(), - options?.openToSide - ); - - return true; - } - }; + }); + this._openers.push(new CommandOpener(commandService)); + this._openers.push(new EditorOpener(editorService)); } registerOpener(opener: IOpener): IDisposable { - const remove = this._openers.push(opener); + const remove = this._openers.unshift(opener); return { dispose: remove }; } @@ -149,13 +154,7 @@ export class OpenerService implements IOpenerService { } } - // use default openers - for (const opener of [this._openerAsExternal, this._openerAsCommand, this._openerAsEditor]) { - if (await opener.open(target, options)) { - break; - } - } - return true; + return false; } async resolveExternalUri(resource: URI, options?: ResolveExternalUriOptions): Promise { From 7a4a4deffcebaa826d57dd828527a1e153deda34 Mon Sep 17 00:00:00 2001 From: Martin Aeschlimann Date: Fri, 15 Nov 2019 10:14:35 +0100 Subject: [PATCH 314/352] New window uses old theme. Fixes #84539 --- .../splash/electron-browser/partsSplash.contribution.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/contrib/splash/electron-browser/partsSplash.contribution.ts b/src/vs/workbench/contrib/splash/electron-browser/partsSplash.contribution.ts index 7e511a8449dc4..15a23398c987b 100644 --- a/src/vs/workbench/contrib/splash/electron-browser/partsSplash.contribution.ts +++ b/src/vs/workbench/contrib/splash/electron-browser/partsSplash.contribution.ts @@ -60,10 +60,12 @@ class PartsSplash { if (e.affectsConfiguration('window.titleBarStyle')) { this._didChangeTitleBarStyle = true; this._savePartsSplash(); - } else if (e.affectsConfiguration('workbench.colorTheme') || e.affectsConfiguration('workbench.colorCustomizations')) { - this._savePartsSplash(); } }, this, this._disposables); + + _themeService.onThemeChange(_ => { + this._savePartsSplash(); + }, this, this._disposables); } dispose(): void { From 544b0abf5bc125d63a8c141d3268aa36d8cd4f92 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Fri, 15 Nov 2019 10:28:03 +0100 Subject: [PATCH 315/352] allow $openUri to accept a URI and string, adopt consumer but keep the API as is --- .../workbench/api/browser/mainThreadWindow.ts | 24 ++++++++++++++++--- .../workbench/api/common/extHost.protocol.ts | 2 +- .../api/common/extHostRequireInterceptor.ts | 12 ++++++---- src/vs/workbench/api/common/extHostWindow.ts | 12 ---------- 4 files changed, 29 insertions(+), 21 deletions(-) diff --git a/src/vs/workbench/api/browser/mainThreadWindow.ts b/src/vs/workbench/api/browser/mainThreadWindow.ts index bbce19a33881d..e03411f182326 100644 --- a/src/vs/workbench/api/browser/mainThreadWindow.ts +++ b/src/vs/workbench/api/browser/mainThreadWindow.ts @@ -10,6 +10,8 @@ import { IOpenerService } from 'vs/platform/opener/common/opener'; import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers'; import { ExtHostContext, ExtHostWindowShape, IExtHostContext, IOpenUriOptions, MainContext, MainThreadWindowShape } from '../common/extHost.protocol'; import { IHostService } from 'vs/workbench/services/host/browser/host'; +import { Schemas } from 'vs/base/common/network'; +import { isFalsyOrWhitespace } from 'vs/base/common/strings'; @extHostNamedCustomer(MainContext.MainThreadWindow) export class MainThreadWindow implements MainThreadWindowShape { @@ -42,9 +44,25 @@ export class MainThreadWindow implements MainThreadWindowShape { return Promise.resolve(this.hostService.hasFocus); } - async $openUri(uriComponents: UriComponents, options: IOpenUriOptions): Promise { - const uri = URI.from(uriComponents); - return this.openerService.open(uri, { openExternal: true, allowTunneling: options.allowTunneling }); + async $openUri(stringOrComp: UriComponents | string, options: IOpenUriOptions): Promise { + + const uri = typeof stringOrComp === 'string' + ? URI.parse(stringOrComp) + : URI.revive(stringOrComp); + + // validate + if (isFalsyOrWhitespace(uri.scheme)) { + return Promise.reject('Invalid scheme - cannot be empty'); + } else if (uri.scheme === Schemas.command) { + return Promise.reject(`Invalid scheme '${uri.scheme}'`); + } + + // open AS-IS, keep string alive + if (typeof stringOrComp === 'string') { + return this.openerService.open(stringOrComp, { openExternal: true, allowTunneling: options.allowTunneling }); + } else { + return this.openerService.open(uri, { openExternal: true, allowTunneling: options.allowTunneling }); + } } async $asExternalUri(uriComponents: UriComponents, options: IOpenUriOptions): Promise { diff --git a/src/vs/workbench/api/common/extHost.protocol.ts b/src/vs/workbench/api/common/extHost.protocol.ts index 9bc433a17277d..3ce804969140c 100644 --- a/src/vs/workbench/api/common/extHost.protocol.ts +++ b/src/vs/workbench/api/common/extHost.protocol.ts @@ -759,7 +759,7 @@ export interface IOpenUriOptions { export interface MainThreadWindowShape extends IDisposable { $getWindowVisibility(): Promise; - $openUri(uri: UriComponents, options: IOpenUriOptions): Promise; + $openUri(uri: UriComponents | string, options: IOpenUriOptions): Promise; $asExternalUri(uri: UriComponents, options: IOpenUriOptions): Promise; } diff --git a/src/vs/workbench/api/common/extHostRequireInterceptor.ts b/src/vs/workbench/api/common/extHostRequireInterceptor.ts index b6f94048fbd3b..6f8fc58d0b8bd 100644 --- a/src/vs/workbench/api/common/extHostRequireInterceptor.ts +++ b/src/vs/workbench/api/common/extHostRequireInterceptor.ts @@ -19,6 +19,8 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti import { IExtHostExtensionService } from 'vs/workbench/api/common/extHostExtensionService'; import { platform } from 'vs/base/common/process'; import { ILogService } from 'vs/platform/log/common/log'; +import { matchesScheme } from 'vs/platform/opener/common/opener'; +import { Schemas } from 'vs/base/common/network'; interface LoadFunction { @@ -239,15 +241,15 @@ class OpenNodeModuleFactory implements INodeModuleFactory { const mainThreadWindow = rpcService.getProxy(MainContext.MainThreadWindow); this._impl = (target, options) => { - const uri: URI = URI.parse(target); // If we have options use the original method. if (options) { return this.callOriginal(target, options); } - if (uri.scheme === 'http' || uri.scheme === 'https') { - return mainThreadWindow.$openUri(uri, { allowTunneling: true }); - } else if (uri.scheme === 'mailto' || uri.scheme === this._appUriScheme) { - return mainThreadWindow.$openUri(uri, {}); + if (matchesScheme(target, Schemas.http) || matchesScheme(target, Schemas.https)) { + return mainThreadWindow.$openUri(target, { allowTunneling: true }); + + } else if (matchesScheme(target, Schemas.mailto) || matchesScheme(target, this._appUriScheme)) { + return mainThreadWindow.$openUri(target, {}); } return this.callOriginal(target, options); }; diff --git a/src/vs/workbench/api/common/extHostWindow.ts b/src/vs/workbench/api/common/extHostWindow.ts index 8ce82ac8b2dcb..d86a9203f3c08 100644 --- a/src/vs/workbench/api/common/extHostWindow.ts +++ b/src/vs/workbench/api/common/extHostWindow.ts @@ -39,18 +39,6 @@ export class ExtHostWindow implements ExtHostWindowShape { } openUri(stringOrUri: string | URI, options: IOpenUriOptions): Promise { - if (typeof stringOrUri === 'string') { - try { - stringOrUri = URI.parse(stringOrUri); - } catch (e) { - return Promise.reject(`Invalid uri - '${stringOrUri}'`); - } - } - if (isFalsyOrWhitespace(stringOrUri.scheme)) { - return Promise.reject('Invalid scheme - cannot be empty'); - } else if (stringOrUri.scheme === Schemas.command) { - return Promise.reject(`Invalid scheme '${stringOrUri.scheme}'`); - } return this._proxy.$openUri(stringOrUri, options); } From e51ef85bcbcd1d4f9f9af274235de79890c09504 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Fri, 15 Nov 2019 10:29:29 +0100 Subject: [PATCH 316/352] Revert "allow $openUri to accept a URI and string, adopt consumer but keep the API as is" This reverts commit 544b0abf5bc125d63a8c141d3268aa36d8cd4f92. --- .../workbench/api/browser/mainThreadWindow.ts | 24 +++---------------- .../workbench/api/common/extHost.protocol.ts | 2 +- .../api/common/extHostRequireInterceptor.ts | 12 ++++------ src/vs/workbench/api/common/extHostWindow.ts | 12 ++++++++++ 4 files changed, 21 insertions(+), 29 deletions(-) diff --git a/src/vs/workbench/api/browser/mainThreadWindow.ts b/src/vs/workbench/api/browser/mainThreadWindow.ts index e03411f182326..bbce19a33881d 100644 --- a/src/vs/workbench/api/browser/mainThreadWindow.ts +++ b/src/vs/workbench/api/browser/mainThreadWindow.ts @@ -10,8 +10,6 @@ import { IOpenerService } from 'vs/platform/opener/common/opener'; import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers'; import { ExtHostContext, ExtHostWindowShape, IExtHostContext, IOpenUriOptions, MainContext, MainThreadWindowShape } from '../common/extHost.protocol'; import { IHostService } from 'vs/workbench/services/host/browser/host'; -import { Schemas } from 'vs/base/common/network'; -import { isFalsyOrWhitespace } from 'vs/base/common/strings'; @extHostNamedCustomer(MainContext.MainThreadWindow) export class MainThreadWindow implements MainThreadWindowShape { @@ -44,25 +42,9 @@ export class MainThreadWindow implements MainThreadWindowShape { return Promise.resolve(this.hostService.hasFocus); } - async $openUri(stringOrComp: UriComponents | string, options: IOpenUriOptions): Promise { - - const uri = typeof stringOrComp === 'string' - ? URI.parse(stringOrComp) - : URI.revive(stringOrComp); - - // validate - if (isFalsyOrWhitespace(uri.scheme)) { - return Promise.reject('Invalid scheme - cannot be empty'); - } else if (uri.scheme === Schemas.command) { - return Promise.reject(`Invalid scheme '${uri.scheme}'`); - } - - // open AS-IS, keep string alive - if (typeof stringOrComp === 'string') { - return this.openerService.open(stringOrComp, { openExternal: true, allowTunneling: options.allowTunneling }); - } else { - return this.openerService.open(uri, { openExternal: true, allowTunneling: options.allowTunneling }); - } + async $openUri(uriComponents: UriComponents, options: IOpenUriOptions): Promise { + const uri = URI.from(uriComponents); + return this.openerService.open(uri, { openExternal: true, allowTunneling: options.allowTunneling }); } async $asExternalUri(uriComponents: UriComponents, options: IOpenUriOptions): Promise { diff --git a/src/vs/workbench/api/common/extHost.protocol.ts b/src/vs/workbench/api/common/extHost.protocol.ts index 3ce804969140c..9bc433a17277d 100644 --- a/src/vs/workbench/api/common/extHost.protocol.ts +++ b/src/vs/workbench/api/common/extHost.protocol.ts @@ -759,7 +759,7 @@ export interface IOpenUriOptions { export interface MainThreadWindowShape extends IDisposable { $getWindowVisibility(): Promise; - $openUri(uri: UriComponents | string, options: IOpenUriOptions): Promise; + $openUri(uri: UriComponents, options: IOpenUriOptions): Promise; $asExternalUri(uri: UriComponents, options: IOpenUriOptions): Promise; } diff --git a/src/vs/workbench/api/common/extHostRequireInterceptor.ts b/src/vs/workbench/api/common/extHostRequireInterceptor.ts index 6f8fc58d0b8bd..b6f94048fbd3b 100644 --- a/src/vs/workbench/api/common/extHostRequireInterceptor.ts +++ b/src/vs/workbench/api/common/extHostRequireInterceptor.ts @@ -19,8 +19,6 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti import { IExtHostExtensionService } from 'vs/workbench/api/common/extHostExtensionService'; import { platform } from 'vs/base/common/process'; import { ILogService } from 'vs/platform/log/common/log'; -import { matchesScheme } from 'vs/platform/opener/common/opener'; -import { Schemas } from 'vs/base/common/network'; interface LoadFunction { @@ -241,15 +239,15 @@ class OpenNodeModuleFactory implements INodeModuleFactory { const mainThreadWindow = rpcService.getProxy(MainContext.MainThreadWindow); this._impl = (target, options) => { + const uri: URI = URI.parse(target); // If we have options use the original method. if (options) { return this.callOriginal(target, options); } - if (matchesScheme(target, Schemas.http) || matchesScheme(target, Schemas.https)) { - return mainThreadWindow.$openUri(target, { allowTunneling: true }); - - } else if (matchesScheme(target, Schemas.mailto) || matchesScheme(target, this._appUriScheme)) { - return mainThreadWindow.$openUri(target, {}); + if (uri.scheme === 'http' || uri.scheme === 'https') { + return mainThreadWindow.$openUri(uri, { allowTunneling: true }); + } else if (uri.scheme === 'mailto' || uri.scheme === this._appUriScheme) { + return mainThreadWindow.$openUri(uri, {}); } return this.callOriginal(target, options); }; diff --git a/src/vs/workbench/api/common/extHostWindow.ts b/src/vs/workbench/api/common/extHostWindow.ts index d86a9203f3c08..8ce82ac8b2dcb 100644 --- a/src/vs/workbench/api/common/extHostWindow.ts +++ b/src/vs/workbench/api/common/extHostWindow.ts @@ -39,6 +39,18 @@ export class ExtHostWindow implements ExtHostWindowShape { } openUri(stringOrUri: string | URI, options: IOpenUriOptions): Promise { + if (typeof stringOrUri === 'string') { + try { + stringOrUri = URI.parse(stringOrUri); + } catch (e) { + return Promise.reject(`Invalid uri - '${stringOrUri}'`); + } + } + if (isFalsyOrWhitespace(stringOrUri.scheme)) { + return Promise.reject('Invalid scheme - cannot be empty'); + } else if (stringOrUri.scheme === Schemas.command) { + return Promise.reject(`Invalid scheme '${stringOrUri.scheme}'`); + } return this._proxy.$openUri(stringOrUri, options); } From db07506b859efa01cfc6fef5133cd402acee20b2 Mon Sep 17 00:00:00 2001 From: Alexandru Dima Date: Fri, 15 Nov 2019 10:34:29 +0100 Subject: [PATCH 317/352] Move tests to use LinesLayout --- .../editor/common/viewLayout/linesLayout.ts | 64 +- .../viewLayout/whitespaceComputer.test.ts | 685 +++++++++--------- 2 files changed, 406 insertions(+), 343 deletions(-) diff --git a/src/vs/editor/common/viewLayout/linesLayout.ts b/src/vs/editor/common/viewLayout/linesLayout.ts index d6673ac8b8fbe..f95b15741bc87 100644 --- a/src/vs/editor/common/viewLayout/linesLayout.ts +++ b/src/vs/editor/common/viewLayout/linesLayout.ts @@ -12,7 +12,6 @@ import { IViewWhitespaceViewportData } from 'vs/editor/common/viewModel/viewMode * * These objects are basically either text (lines) or spaces between those lines (whitespaces). * This provides commodity operations for working with lines that contain whitespace that pushes lines lower (vertically). - * This is written with no knowledge of an editor in mind. */ export class LinesLayout { @@ -475,4 +474,67 @@ export class LinesLayout { public getWhitespaces(): IEditorWhitespace[] { return this._whitespaces.getWhitespaces(this._lineHeight); } + + /** + * The number of whitespaces. + */ + public getWhitespacesCount(): number { + return this._whitespaces.getCount(); + } + + /** + * Get the `id` for whitespace at index `index`. + * + * @param index The index of the whitespace. + * @return `id` of whitespace at `index`. + */ + public getIdForWhitespaceIndex(index: number): string { + return this._whitespaces.getIdForWhitespaceIndex(index); + } + + /** + * Get the `afterLineNumber` for whitespace at index `index`. + * + * @param index The index of the whitespace. + * @return `afterLineNumber` of whitespace at `index`. + */ + public getAfterLineNumberForWhitespaceIndex(index: number): number { + return this._whitespaces.getAfterLineNumberForWhitespaceIndex(index); + } + + /** + * Get the `height` for whitespace at index `index`. + * + * @param index The index of the whitespace. + * @return `height` of whitespace at `index`. + */ + public getHeightForWhitespaceIndex(index: number): number { + return this._whitespaces.getHeightForWhitespaceIndex(index); + } + + /** + * Find the index of the first whitespace which has `afterLineNumber` >= `lineNumber`. + * @return The index of the first whitespace with `afterLineNumber` >= `lineNumber` or -1 if no whitespace is found. + */ + public getFirstWhitespaceIndexAfterLineNumber(lineNumber: number): number { + return this._whitespaces.getFirstWhitespaceIndexAfterLineNumber(lineNumber); + } + + /** + * Return the sum of the heights of the whitespaces at [0..index]. + * This includes the whitespace at `index`. + * + * @param index The index of the whitespace. + * @return The sum of the heights of all whitespaces before the one at `index`, including the one at `index`. + */ + public getWhitespacesAccumulatedHeight(index: number): number { + return this._whitespaces.getAccumulatedHeight(index); + } + + /** + * Get the sum of all the whitespaces. + */ + public getWhitespacesTotalHeight(): number { + return this._whitespaces.getTotalHeight(); + } } diff --git a/src/vs/editor/test/common/viewLayout/whitespaceComputer.test.ts b/src/vs/editor/test/common/viewLayout/whitespaceComputer.test.ts index d9ade64f3a52d..df7527d6b9b72 100644 --- a/src/vs/editor/test/common/viewLayout/whitespaceComputer.test.ts +++ b/src/vs/editor/test/common/viewLayout/whitespaceComputer.test.ts @@ -4,245 +4,246 @@ *--------------------------------------------------------------------------------------------*/ import * as assert from 'assert'; import { WhitespaceComputer } from 'vs/editor/common/viewLayout/whitespaceComputer'; +import { LinesLayout } from 'vs/editor/common/viewLayout/linesLayout'; suite('Editor ViewLayout - WhitespaceComputer', () => { test('WhitespaceComputer', () => { - let whitespaceComputer = new WhitespaceComputer(); + const linesLayout = new LinesLayout(100, 20); // Insert a whitespace after line number 2, of height 10 - let a = whitespaceComputer.insertWhitespace(2, 0, 10, 0); + const a = linesLayout.insertWhitespace(2, 0, 10, 0); // whitespaces: a(2, 10) - assert.equal(whitespaceComputer.getCount(), 1); - assert.equal(whitespaceComputer.getAfterLineNumberForWhitespaceIndex(0), 2); - assert.equal(whitespaceComputer.getHeightForWhitespaceIndex(0), 10); - assert.equal(whitespaceComputer.getAccumulatedHeight(0), 10); - assert.equal(whitespaceComputer.getTotalHeight(), 10); - assert.equal(whitespaceComputer.getAccumulatedHeightBeforeLineNumber(1), 0); - assert.equal(whitespaceComputer.getAccumulatedHeightBeforeLineNumber(2), 0); - assert.equal(whitespaceComputer.getAccumulatedHeightBeforeLineNumber(3), 10); - assert.equal(whitespaceComputer.getAccumulatedHeightBeforeLineNumber(4), 10); + assert.equal(linesLayout.getWhitespacesCount(), 1); + assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(0), 2); + assert.equal(linesLayout.getHeightForWhitespaceIndex(0), 10); + assert.equal(linesLayout.getWhitespacesAccumulatedHeight(0), 10); + assert.equal(linesLayout.getWhitespacesTotalHeight(), 10); + assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(1), 0); + assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(2), 0); + assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(3), 10); + assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(4), 10); // Insert a whitespace again after line number 2, of height 20 - let b = whitespaceComputer.insertWhitespace(2, 0, 20, 0); + let b = linesLayout.insertWhitespace(2, 0, 20, 0); // whitespaces: a(2, 10), b(2, 20) - assert.equal(whitespaceComputer.getCount(), 2); - assert.equal(whitespaceComputer.getAfterLineNumberForWhitespaceIndex(0), 2); - assert.equal(whitespaceComputer.getHeightForWhitespaceIndex(0), 10); - assert.equal(whitespaceComputer.getAfterLineNumberForWhitespaceIndex(1), 2); - assert.equal(whitespaceComputer.getHeightForWhitespaceIndex(1), 20); - assert.equal(whitespaceComputer.getAccumulatedHeight(0), 10); - assert.equal(whitespaceComputer.getAccumulatedHeight(1), 30); - assert.equal(whitespaceComputer.getTotalHeight(), 30); - assert.equal(whitespaceComputer.getAccumulatedHeightBeforeLineNumber(1), 0); - assert.equal(whitespaceComputer.getAccumulatedHeightBeforeLineNumber(2), 0); - assert.equal(whitespaceComputer.getAccumulatedHeightBeforeLineNumber(3), 30); - assert.equal(whitespaceComputer.getAccumulatedHeightBeforeLineNumber(4), 30); + assert.equal(linesLayout.getWhitespacesCount(), 2); + assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(0), 2); + assert.equal(linesLayout.getHeightForWhitespaceIndex(0), 10); + assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(1), 2); + assert.equal(linesLayout.getHeightForWhitespaceIndex(1), 20); + assert.equal(linesLayout.getWhitespacesAccumulatedHeight(0), 10); + assert.equal(linesLayout.getWhitespacesAccumulatedHeight(1), 30); + assert.equal(linesLayout.getWhitespacesTotalHeight(), 30); + assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(1), 0); + assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(2), 0); + assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(3), 30); + assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(4), 30); // Change last inserted whitespace height to 30 - whitespaceComputer.changeWhitespaceHeight(b, 30); + linesLayout.changeWhitespace(b, 2, 30); // whitespaces: a(2, 10), b(2, 30) - assert.equal(whitespaceComputer.getCount(), 2); - assert.equal(whitespaceComputer.getAfterLineNumberForWhitespaceIndex(0), 2); - assert.equal(whitespaceComputer.getHeightForWhitespaceIndex(0), 10); - assert.equal(whitespaceComputer.getAfterLineNumberForWhitespaceIndex(1), 2); - assert.equal(whitespaceComputer.getHeightForWhitespaceIndex(1), 30); - assert.equal(whitespaceComputer.getAccumulatedHeight(0), 10); - assert.equal(whitespaceComputer.getAccumulatedHeight(1), 40); - assert.equal(whitespaceComputer.getTotalHeight(), 40); - assert.equal(whitespaceComputer.getAccumulatedHeightBeforeLineNumber(1), 0); - assert.equal(whitespaceComputer.getAccumulatedHeightBeforeLineNumber(2), 0); - assert.equal(whitespaceComputer.getAccumulatedHeightBeforeLineNumber(3), 40); - assert.equal(whitespaceComputer.getAccumulatedHeightBeforeLineNumber(4), 40); + assert.equal(linesLayout.getWhitespacesCount(), 2); + assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(0), 2); + assert.equal(linesLayout.getHeightForWhitespaceIndex(0), 10); + assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(1), 2); + assert.equal(linesLayout.getHeightForWhitespaceIndex(1), 30); + assert.equal(linesLayout.getWhitespacesAccumulatedHeight(0), 10); + assert.equal(linesLayout.getWhitespacesAccumulatedHeight(1), 40); + assert.equal(linesLayout.getWhitespacesTotalHeight(), 40); + assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(1), 0); + assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(2), 0); + assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(3), 40); + assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(4), 40); // Remove last inserted whitespace - whitespaceComputer.removeWhitespace(b); + linesLayout.removeWhitespace(b); // whitespaces: a(2, 10) - assert.equal(whitespaceComputer.getCount(), 1); - assert.equal(whitespaceComputer.getAfterLineNumberForWhitespaceIndex(0), 2); - assert.equal(whitespaceComputer.getHeightForWhitespaceIndex(0), 10); - assert.equal(whitespaceComputer.getAccumulatedHeight(0), 10); - assert.equal(whitespaceComputer.getTotalHeight(), 10); - assert.equal(whitespaceComputer.getAccumulatedHeightBeforeLineNumber(1), 0); - assert.equal(whitespaceComputer.getAccumulatedHeightBeforeLineNumber(2), 0); - assert.equal(whitespaceComputer.getAccumulatedHeightBeforeLineNumber(3), 10); - assert.equal(whitespaceComputer.getAccumulatedHeightBeforeLineNumber(4), 10); + assert.equal(linesLayout.getWhitespacesCount(), 1); + assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(0), 2); + assert.equal(linesLayout.getHeightForWhitespaceIndex(0), 10); + assert.equal(linesLayout.getWhitespacesAccumulatedHeight(0), 10); + assert.equal(linesLayout.getWhitespacesTotalHeight(), 10); + assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(1), 0); + assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(2), 0); + assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(3), 10); + assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(4), 10); // Add a whitespace before the first line of height 50 - b = whitespaceComputer.insertWhitespace(0, 0, 50, 0); + b = linesLayout.insertWhitespace(0, 0, 50, 0); // whitespaces: b(0, 50), a(2, 10) - assert.equal(whitespaceComputer.getCount(), 2); - assert.equal(whitespaceComputer.getAfterLineNumberForWhitespaceIndex(0), 0); - assert.equal(whitespaceComputer.getHeightForWhitespaceIndex(0), 50); - assert.equal(whitespaceComputer.getAfterLineNumberForWhitespaceIndex(1), 2); - assert.equal(whitespaceComputer.getHeightForWhitespaceIndex(1), 10); - assert.equal(whitespaceComputer.getAccumulatedHeight(0), 50); - assert.equal(whitespaceComputer.getAccumulatedHeight(1), 60); - assert.equal(whitespaceComputer.getTotalHeight(), 60); - assert.equal(whitespaceComputer.getAccumulatedHeightBeforeLineNumber(1), 50); - assert.equal(whitespaceComputer.getAccumulatedHeightBeforeLineNumber(2), 50); - assert.equal(whitespaceComputer.getAccumulatedHeightBeforeLineNumber(3), 60); - assert.equal(whitespaceComputer.getAccumulatedHeightBeforeLineNumber(4), 60); + assert.equal(linesLayout.getWhitespacesCount(), 2); + assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(0), 0); + assert.equal(linesLayout.getHeightForWhitespaceIndex(0), 50); + assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(1), 2); + assert.equal(linesLayout.getHeightForWhitespaceIndex(1), 10); + assert.equal(linesLayout.getWhitespacesAccumulatedHeight(0), 50); + assert.equal(linesLayout.getWhitespacesAccumulatedHeight(1), 60); + assert.equal(linesLayout.getWhitespacesTotalHeight(), 60); + assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(1), 50); + assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(2), 50); + assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(3), 60); + assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(4), 60); // Add a whitespace after line 4 of height 20 - whitespaceComputer.insertWhitespace(4, 0, 20, 0); + linesLayout.insertWhitespace(4, 0, 20, 0); // whitespaces: b(0, 50), a(2, 10), c(4, 20) - assert.equal(whitespaceComputer.getCount(), 3); - assert.equal(whitespaceComputer.getAfterLineNumberForWhitespaceIndex(0), 0); - assert.equal(whitespaceComputer.getHeightForWhitespaceIndex(0), 50); - assert.equal(whitespaceComputer.getAfterLineNumberForWhitespaceIndex(1), 2); - assert.equal(whitespaceComputer.getHeightForWhitespaceIndex(1), 10); - assert.equal(whitespaceComputer.getAfterLineNumberForWhitespaceIndex(2), 4); - assert.equal(whitespaceComputer.getHeightForWhitespaceIndex(2), 20); - assert.equal(whitespaceComputer.getAccumulatedHeight(0), 50); - assert.equal(whitespaceComputer.getAccumulatedHeight(1), 60); - assert.equal(whitespaceComputer.getAccumulatedHeight(2), 80); - assert.equal(whitespaceComputer.getTotalHeight(), 80); - assert.equal(whitespaceComputer.getAccumulatedHeightBeforeLineNumber(1), 50); - assert.equal(whitespaceComputer.getAccumulatedHeightBeforeLineNumber(2), 50); - assert.equal(whitespaceComputer.getAccumulatedHeightBeforeLineNumber(3), 60); - assert.equal(whitespaceComputer.getAccumulatedHeightBeforeLineNumber(4), 60); - assert.equal(whitespaceComputer.getAccumulatedHeightBeforeLineNumber(5), 80); + assert.equal(linesLayout.getWhitespacesCount(), 3); + assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(0), 0); + assert.equal(linesLayout.getHeightForWhitespaceIndex(0), 50); + assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(1), 2); + assert.equal(linesLayout.getHeightForWhitespaceIndex(1), 10); + assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(2), 4); + assert.equal(linesLayout.getHeightForWhitespaceIndex(2), 20); + assert.equal(linesLayout.getWhitespacesAccumulatedHeight(0), 50); + assert.equal(linesLayout.getWhitespacesAccumulatedHeight(1), 60); + assert.equal(linesLayout.getWhitespacesAccumulatedHeight(2), 80); + assert.equal(linesLayout.getWhitespacesTotalHeight(), 80); + assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(1), 50); + assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(2), 50); + assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(3), 60); + assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(4), 60); + assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(5), 80); // Add a whitespace after line 3 of height 30 - whitespaceComputer.insertWhitespace(3, 0, 30, 0); + linesLayout.insertWhitespace(3, 0, 30, 0); // whitespaces: b(0, 50), a(2, 10), d(3, 30), c(4, 20) - assert.equal(whitespaceComputer.getCount(), 4); - assert.equal(whitespaceComputer.getAfterLineNumberForWhitespaceIndex(0), 0); - assert.equal(whitespaceComputer.getHeightForWhitespaceIndex(0), 50); - assert.equal(whitespaceComputer.getAfterLineNumberForWhitespaceIndex(1), 2); - assert.equal(whitespaceComputer.getHeightForWhitespaceIndex(1), 10); - assert.equal(whitespaceComputer.getAfterLineNumberForWhitespaceIndex(2), 3); - assert.equal(whitespaceComputer.getHeightForWhitespaceIndex(2), 30); - assert.equal(whitespaceComputer.getAfterLineNumberForWhitespaceIndex(3), 4); - assert.equal(whitespaceComputer.getHeightForWhitespaceIndex(3), 20); - assert.equal(whitespaceComputer.getAccumulatedHeight(0), 50); - assert.equal(whitespaceComputer.getAccumulatedHeight(1), 60); - assert.equal(whitespaceComputer.getAccumulatedHeight(2), 90); - assert.equal(whitespaceComputer.getAccumulatedHeight(3), 110); - assert.equal(whitespaceComputer.getTotalHeight(), 110); - assert.equal(whitespaceComputer.getAccumulatedHeightBeforeLineNumber(1), 50); - assert.equal(whitespaceComputer.getAccumulatedHeightBeforeLineNumber(2), 50); - assert.equal(whitespaceComputer.getAccumulatedHeightBeforeLineNumber(3), 60); - assert.equal(whitespaceComputer.getAccumulatedHeightBeforeLineNumber(4), 90); - assert.equal(whitespaceComputer.getAccumulatedHeightBeforeLineNumber(5), 110); + assert.equal(linesLayout.getWhitespacesCount(), 4); + assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(0), 0); + assert.equal(linesLayout.getHeightForWhitespaceIndex(0), 50); + assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(1), 2); + assert.equal(linesLayout.getHeightForWhitespaceIndex(1), 10); + assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(2), 3); + assert.equal(linesLayout.getHeightForWhitespaceIndex(2), 30); + assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(3), 4); + assert.equal(linesLayout.getHeightForWhitespaceIndex(3), 20); + assert.equal(linesLayout.getWhitespacesAccumulatedHeight(0), 50); + assert.equal(linesLayout.getWhitespacesAccumulatedHeight(1), 60); + assert.equal(linesLayout.getWhitespacesAccumulatedHeight(2), 90); + assert.equal(linesLayout.getWhitespacesAccumulatedHeight(3), 110); + assert.equal(linesLayout.getWhitespacesTotalHeight(), 110); + assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(1), 50); + assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(2), 50); + assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(3), 60); + assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(4), 90); + assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(5), 110); // Change whitespace after line 2 to height of 100 - whitespaceComputer.changeWhitespaceHeight(a, 100); + linesLayout.changeWhitespace(a, 2, 100); // whitespaces: b(0, 50), a(2, 100), d(3, 30), c(4, 20) - assert.equal(whitespaceComputer.getCount(), 4); - assert.equal(whitespaceComputer.getAfterLineNumberForWhitespaceIndex(0), 0); - assert.equal(whitespaceComputer.getHeightForWhitespaceIndex(0), 50); - assert.equal(whitespaceComputer.getAfterLineNumberForWhitespaceIndex(1), 2); - assert.equal(whitespaceComputer.getHeightForWhitespaceIndex(1), 100); - assert.equal(whitespaceComputer.getAfterLineNumberForWhitespaceIndex(2), 3); - assert.equal(whitespaceComputer.getHeightForWhitespaceIndex(2), 30); - assert.equal(whitespaceComputer.getAfterLineNumberForWhitespaceIndex(3), 4); - assert.equal(whitespaceComputer.getHeightForWhitespaceIndex(3), 20); - assert.equal(whitespaceComputer.getAccumulatedHeight(0), 50); - assert.equal(whitespaceComputer.getAccumulatedHeight(1), 150); - assert.equal(whitespaceComputer.getAccumulatedHeight(2), 180); - assert.equal(whitespaceComputer.getAccumulatedHeight(3), 200); - assert.equal(whitespaceComputer.getTotalHeight(), 200); - assert.equal(whitespaceComputer.getAccumulatedHeightBeforeLineNumber(1), 50); - assert.equal(whitespaceComputer.getAccumulatedHeightBeforeLineNumber(2), 50); - assert.equal(whitespaceComputer.getAccumulatedHeightBeforeLineNumber(3), 150); - assert.equal(whitespaceComputer.getAccumulatedHeightBeforeLineNumber(4), 180); - assert.equal(whitespaceComputer.getAccumulatedHeightBeforeLineNumber(5), 200); + assert.equal(linesLayout.getWhitespacesCount(), 4); + assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(0), 0); + assert.equal(linesLayout.getHeightForWhitespaceIndex(0), 50); + assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(1), 2); + assert.equal(linesLayout.getHeightForWhitespaceIndex(1), 100); + assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(2), 3); + assert.equal(linesLayout.getHeightForWhitespaceIndex(2), 30); + assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(3), 4); + assert.equal(linesLayout.getHeightForWhitespaceIndex(3), 20); + assert.equal(linesLayout.getWhitespacesAccumulatedHeight(0), 50); + assert.equal(linesLayout.getWhitespacesAccumulatedHeight(1), 150); + assert.equal(linesLayout.getWhitespacesAccumulatedHeight(2), 180); + assert.equal(linesLayout.getWhitespacesAccumulatedHeight(3), 200); + assert.equal(linesLayout.getWhitespacesTotalHeight(), 200); + assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(1), 50); + assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(2), 50); + assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(3), 150); + assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(4), 180); + assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(5), 200); // Remove whitespace after line 2 - whitespaceComputer.removeWhitespace(a); + linesLayout.removeWhitespace(a); // whitespaces: b(0, 50), d(3, 30), c(4, 20) - assert.equal(whitespaceComputer.getCount(), 3); - assert.equal(whitespaceComputer.getAfterLineNumberForWhitespaceIndex(0), 0); - assert.equal(whitespaceComputer.getHeightForWhitespaceIndex(0), 50); - assert.equal(whitespaceComputer.getAfterLineNumberForWhitespaceIndex(1), 3); - assert.equal(whitespaceComputer.getHeightForWhitespaceIndex(1), 30); - assert.equal(whitespaceComputer.getAfterLineNumberForWhitespaceIndex(2), 4); - assert.equal(whitespaceComputer.getHeightForWhitespaceIndex(2), 20); - assert.equal(whitespaceComputer.getAccumulatedHeight(0), 50); - assert.equal(whitespaceComputer.getAccumulatedHeight(1), 80); - assert.equal(whitespaceComputer.getAccumulatedHeight(2), 100); - assert.equal(whitespaceComputer.getTotalHeight(), 100); - assert.equal(whitespaceComputer.getAccumulatedHeightBeforeLineNumber(1), 50); - assert.equal(whitespaceComputer.getAccumulatedHeightBeforeLineNumber(2), 50); - assert.equal(whitespaceComputer.getAccumulatedHeightBeforeLineNumber(3), 50); - assert.equal(whitespaceComputer.getAccumulatedHeightBeforeLineNumber(4), 80); - assert.equal(whitespaceComputer.getAccumulatedHeightBeforeLineNumber(5), 100); + assert.equal(linesLayout.getWhitespacesCount(), 3); + assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(0), 0); + assert.equal(linesLayout.getHeightForWhitespaceIndex(0), 50); + assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(1), 3); + assert.equal(linesLayout.getHeightForWhitespaceIndex(1), 30); + assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(2), 4); + assert.equal(linesLayout.getHeightForWhitespaceIndex(2), 20); + assert.equal(linesLayout.getWhitespacesAccumulatedHeight(0), 50); + assert.equal(linesLayout.getWhitespacesAccumulatedHeight(1), 80); + assert.equal(linesLayout.getWhitespacesAccumulatedHeight(2), 100); + assert.equal(linesLayout.getWhitespacesTotalHeight(), 100); + assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(1), 50); + assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(2), 50); + assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(3), 50); + assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(4), 80); + assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(5), 100); // Remove whitespace before line 1 - whitespaceComputer.removeWhitespace(b); + linesLayout.removeWhitespace(b); // whitespaces: d(3, 30), c(4, 20) - assert.equal(whitespaceComputer.getCount(), 2); - assert.equal(whitespaceComputer.getAfterLineNumberForWhitespaceIndex(0), 3); - assert.equal(whitespaceComputer.getHeightForWhitespaceIndex(0), 30); - assert.equal(whitespaceComputer.getAfterLineNumberForWhitespaceIndex(1), 4); - assert.equal(whitespaceComputer.getHeightForWhitespaceIndex(1), 20); - assert.equal(whitespaceComputer.getAccumulatedHeight(0), 30); - assert.equal(whitespaceComputer.getAccumulatedHeight(1), 50); - assert.equal(whitespaceComputer.getTotalHeight(), 50); - assert.equal(whitespaceComputer.getAccumulatedHeightBeforeLineNumber(1), 0); - assert.equal(whitespaceComputer.getAccumulatedHeightBeforeLineNumber(2), 0); - assert.equal(whitespaceComputer.getAccumulatedHeightBeforeLineNumber(3), 0); - assert.equal(whitespaceComputer.getAccumulatedHeightBeforeLineNumber(4), 30); - assert.equal(whitespaceComputer.getAccumulatedHeightBeforeLineNumber(5), 50); + assert.equal(linesLayout.getWhitespacesCount(), 2); + assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(0), 3); + assert.equal(linesLayout.getHeightForWhitespaceIndex(0), 30); + assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(1), 4); + assert.equal(linesLayout.getHeightForWhitespaceIndex(1), 20); + assert.equal(linesLayout.getWhitespacesAccumulatedHeight(0), 30); + assert.equal(linesLayout.getWhitespacesAccumulatedHeight(1), 50); + assert.equal(linesLayout.getWhitespacesTotalHeight(), 50); + assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(1), 0); + assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(2), 0); + assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(3), 0); + assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(4), 30); + assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(5), 50); // Delete line 1 - whitespaceComputer.onLinesDeleted(1, 1); + linesLayout.onLinesDeleted(1, 1); // whitespaces: d(2, 30), c(3, 20) - assert.equal(whitespaceComputer.getCount(), 2); - assert.equal(whitespaceComputer.getAfterLineNumberForWhitespaceIndex(0), 2); - assert.equal(whitespaceComputer.getHeightForWhitespaceIndex(0), 30); - assert.equal(whitespaceComputer.getAfterLineNumberForWhitespaceIndex(1), 3); - assert.equal(whitespaceComputer.getHeightForWhitespaceIndex(1), 20); - assert.equal(whitespaceComputer.getAccumulatedHeight(0), 30); - assert.equal(whitespaceComputer.getAccumulatedHeight(1), 50); - assert.equal(whitespaceComputer.getTotalHeight(), 50); - assert.equal(whitespaceComputer.getAccumulatedHeightBeforeLineNumber(1), 0); - assert.equal(whitespaceComputer.getAccumulatedHeightBeforeLineNumber(2), 0); - assert.equal(whitespaceComputer.getAccumulatedHeightBeforeLineNumber(3), 30); - assert.equal(whitespaceComputer.getAccumulatedHeightBeforeLineNumber(4), 50); - assert.equal(whitespaceComputer.getAccumulatedHeightBeforeLineNumber(5), 50); + assert.equal(linesLayout.getWhitespacesCount(), 2); + assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(0), 2); + assert.equal(linesLayout.getHeightForWhitespaceIndex(0), 30); + assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(1), 3); + assert.equal(linesLayout.getHeightForWhitespaceIndex(1), 20); + assert.equal(linesLayout.getWhitespacesAccumulatedHeight(0), 30); + assert.equal(linesLayout.getWhitespacesAccumulatedHeight(1), 50); + assert.equal(linesLayout.getWhitespacesTotalHeight(), 50); + assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(1), 0); + assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(2), 0); + assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(3), 30); + assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(4), 50); + assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(5), 50); // Insert a line before line 1 - whitespaceComputer.onLinesInserted(1, 1); + linesLayout.onLinesInserted(1, 1); // whitespaces: d(3, 30), c(4, 20) - assert.equal(whitespaceComputer.getCount(), 2); - assert.equal(whitespaceComputer.getAfterLineNumberForWhitespaceIndex(0), 3); - assert.equal(whitespaceComputer.getHeightForWhitespaceIndex(0), 30); - assert.equal(whitespaceComputer.getAfterLineNumberForWhitespaceIndex(1), 4); - assert.equal(whitespaceComputer.getHeightForWhitespaceIndex(1), 20); - assert.equal(whitespaceComputer.getAccumulatedHeight(0), 30); - assert.equal(whitespaceComputer.getAccumulatedHeight(1), 50); - assert.equal(whitespaceComputer.getTotalHeight(), 50); - assert.equal(whitespaceComputer.getAccumulatedHeightBeforeLineNumber(1), 0); - assert.equal(whitespaceComputer.getAccumulatedHeightBeforeLineNumber(2), 0); - assert.equal(whitespaceComputer.getAccumulatedHeightBeforeLineNumber(3), 0); - assert.equal(whitespaceComputer.getAccumulatedHeightBeforeLineNumber(4), 30); - assert.equal(whitespaceComputer.getAccumulatedHeightBeforeLineNumber(5), 50); + assert.equal(linesLayout.getWhitespacesCount(), 2); + assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(0), 3); + assert.equal(linesLayout.getHeightForWhitespaceIndex(0), 30); + assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(1), 4); + assert.equal(linesLayout.getHeightForWhitespaceIndex(1), 20); + assert.equal(linesLayout.getWhitespacesAccumulatedHeight(0), 30); + assert.equal(linesLayout.getWhitespacesAccumulatedHeight(1), 50); + assert.equal(linesLayout.getWhitespacesTotalHeight(), 50); + assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(1), 0); + assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(2), 0); + assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(3), 0); + assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(4), 30); + assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(5), 50); // Delete line 4 - whitespaceComputer.onLinesDeleted(4, 4); + linesLayout.onLinesDeleted(4, 4); // whitespaces: d(3, 30), c(3, 20) - assert.equal(whitespaceComputer.getCount(), 2); - assert.equal(whitespaceComputer.getAfterLineNumberForWhitespaceIndex(0), 3); - assert.equal(whitespaceComputer.getHeightForWhitespaceIndex(0), 30); - assert.equal(whitespaceComputer.getAfterLineNumberForWhitespaceIndex(1), 3); - assert.equal(whitespaceComputer.getHeightForWhitespaceIndex(1), 20); - assert.equal(whitespaceComputer.getAccumulatedHeight(0), 30); - assert.equal(whitespaceComputer.getAccumulatedHeight(1), 50); - assert.equal(whitespaceComputer.getTotalHeight(), 50); - assert.equal(whitespaceComputer.getAccumulatedHeightBeforeLineNumber(1), 0); - assert.equal(whitespaceComputer.getAccumulatedHeightBeforeLineNumber(2), 0); - assert.equal(whitespaceComputer.getAccumulatedHeightBeforeLineNumber(3), 0); - assert.equal(whitespaceComputer.getAccumulatedHeightBeforeLineNumber(4), 50); - assert.equal(whitespaceComputer.getAccumulatedHeightBeforeLineNumber(5), 50); + assert.equal(linesLayout.getWhitespacesCount(), 2); + assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(0), 3); + assert.equal(linesLayout.getHeightForWhitespaceIndex(0), 30); + assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(1), 3); + assert.equal(linesLayout.getHeightForWhitespaceIndex(1), 20); + assert.equal(linesLayout.getWhitespacesAccumulatedHeight(0), 30); + assert.equal(linesLayout.getWhitespacesAccumulatedHeight(1), 50); + assert.equal(linesLayout.getWhitespacesTotalHeight(), 50); + assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(1), 0); + assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(2), 0); + assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(3), 0); + assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(4), 50); + assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(5), 50); }); test('WhitespaceComputer findInsertionIndex', () => { - let makeArray = (size: number, fillValue: number) => { + const makeArray = (size: number, fillValue: number) => { let r: number[] = []; for (let i = 0; i < size; i++) { r[i] = fillValue; @@ -375,184 +376,184 @@ suite('Editor ViewLayout - WhitespaceComputer', () => { }); test('WhitespaceComputer changeWhitespaceAfterLineNumber & getFirstWhitespaceIndexAfterLineNumber', () => { - let whitespaceComputer = new WhitespaceComputer(); - - let a = whitespaceComputer.insertWhitespace(0, 0, 1, 0); - let b = whitespaceComputer.insertWhitespace(7, 0, 1, 0); - let c = whitespaceComputer.insertWhitespace(3, 0, 1, 0); - - assert.equal(whitespaceComputer.getIdForWhitespaceIndex(0), a); // 0 - assert.equal(whitespaceComputer.getAfterLineNumberForWhitespaceIndex(0), 0); - assert.equal(whitespaceComputer.getIdForWhitespaceIndex(1), c); // 3 - assert.equal(whitespaceComputer.getAfterLineNumberForWhitespaceIndex(1), 3); - assert.equal(whitespaceComputer.getIdForWhitespaceIndex(2), b); // 7 - assert.equal(whitespaceComputer.getAfterLineNumberForWhitespaceIndex(2), 7); - - assert.equal(whitespaceComputer.getFirstWhitespaceIndexAfterLineNumber(1), 1); // c - assert.equal(whitespaceComputer.getFirstWhitespaceIndexAfterLineNumber(2), 1); // c - assert.equal(whitespaceComputer.getFirstWhitespaceIndexAfterLineNumber(3), 1); // c - assert.equal(whitespaceComputer.getFirstWhitespaceIndexAfterLineNumber(4), 2); // b - assert.equal(whitespaceComputer.getFirstWhitespaceIndexAfterLineNumber(5), 2); // b - assert.equal(whitespaceComputer.getFirstWhitespaceIndexAfterLineNumber(6), 2); // b - assert.equal(whitespaceComputer.getFirstWhitespaceIndexAfterLineNumber(7), 2); // b - assert.equal(whitespaceComputer.getFirstWhitespaceIndexAfterLineNumber(8), -1); // -- + const linesLayout = new LinesLayout(100, 20); + + const a = linesLayout.insertWhitespace(0, 0, 1, 0); + const b = linesLayout.insertWhitespace(7, 0, 1, 0); + const c = linesLayout.insertWhitespace(3, 0, 1, 0); + + assert.equal(linesLayout.getIdForWhitespaceIndex(0), a); // 0 + assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(0), 0); + assert.equal(linesLayout.getIdForWhitespaceIndex(1), c); // 3 + assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(1), 3); + assert.equal(linesLayout.getIdForWhitespaceIndex(2), b); // 7 + assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(2), 7); + + assert.equal(linesLayout.getFirstWhitespaceIndexAfterLineNumber(1), 1); // c + assert.equal(linesLayout.getFirstWhitespaceIndexAfterLineNumber(2), 1); // c + assert.equal(linesLayout.getFirstWhitespaceIndexAfterLineNumber(3), 1); // c + assert.equal(linesLayout.getFirstWhitespaceIndexAfterLineNumber(4), 2); // b + assert.equal(linesLayout.getFirstWhitespaceIndexAfterLineNumber(5), 2); // b + assert.equal(linesLayout.getFirstWhitespaceIndexAfterLineNumber(6), 2); // b + assert.equal(linesLayout.getFirstWhitespaceIndexAfterLineNumber(7), 2); // b + assert.equal(linesLayout.getFirstWhitespaceIndexAfterLineNumber(8), -1); // -- // Do not really move a - whitespaceComputer.changeWhitespaceAfterLineNumber(a, 1); + linesLayout.changeWhitespace(a, 1, 1); - assert.equal(whitespaceComputer.getIdForWhitespaceIndex(0), a); // 1 - assert.equal(whitespaceComputer.getAfterLineNumberForWhitespaceIndex(0), 1); - assert.equal(whitespaceComputer.getIdForWhitespaceIndex(1), c); // 3 - assert.equal(whitespaceComputer.getAfterLineNumberForWhitespaceIndex(1), 3); - assert.equal(whitespaceComputer.getIdForWhitespaceIndex(2), b); // 7 - assert.equal(whitespaceComputer.getAfterLineNumberForWhitespaceIndex(2), 7); + assert.equal(linesLayout.getIdForWhitespaceIndex(0), a); // 1 + assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(0), 1); + assert.equal(linesLayout.getIdForWhitespaceIndex(1), c); // 3 + assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(1), 3); + assert.equal(linesLayout.getIdForWhitespaceIndex(2), b); // 7 + assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(2), 7); - assert.equal(whitespaceComputer.getFirstWhitespaceIndexAfterLineNumber(1), 0); // a - assert.equal(whitespaceComputer.getFirstWhitespaceIndexAfterLineNumber(2), 1); // c - assert.equal(whitespaceComputer.getFirstWhitespaceIndexAfterLineNumber(3), 1); // c - assert.equal(whitespaceComputer.getFirstWhitespaceIndexAfterLineNumber(4), 2); // b - assert.equal(whitespaceComputer.getFirstWhitespaceIndexAfterLineNumber(5), 2); // b - assert.equal(whitespaceComputer.getFirstWhitespaceIndexAfterLineNumber(6), 2); // b - assert.equal(whitespaceComputer.getFirstWhitespaceIndexAfterLineNumber(7), 2); // b - assert.equal(whitespaceComputer.getFirstWhitespaceIndexAfterLineNumber(8), -1); // -- + assert.equal(linesLayout.getFirstWhitespaceIndexAfterLineNumber(1), 0); // a + assert.equal(linesLayout.getFirstWhitespaceIndexAfterLineNumber(2), 1); // c + assert.equal(linesLayout.getFirstWhitespaceIndexAfterLineNumber(3), 1); // c + assert.equal(linesLayout.getFirstWhitespaceIndexAfterLineNumber(4), 2); // b + assert.equal(linesLayout.getFirstWhitespaceIndexAfterLineNumber(5), 2); // b + assert.equal(linesLayout.getFirstWhitespaceIndexAfterLineNumber(6), 2); // b + assert.equal(linesLayout.getFirstWhitespaceIndexAfterLineNumber(7), 2); // b + assert.equal(linesLayout.getFirstWhitespaceIndexAfterLineNumber(8), -1); // -- // Do not really move a - whitespaceComputer.changeWhitespaceAfterLineNumber(a, 2); + linesLayout.changeWhitespace(a, 2, 1); - assert.equal(whitespaceComputer.getIdForWhitespaceIndex(0), a); // 2 - assert.equal(whitespaceComputer.getAfterLineNumberForWhitespaceIndex(0), 2); - assert.equal(whitespaceComputer.getIdForWhitespaceIndex(1), c); // 3 - assert.equal(whitespaceComputer.getAfterLineNumberForWhitespaceIndex(1), 3); - assert.equal(whitespaceComputer.getIdForWhitespaceIndex(2), b); // 7 - assert.equal(whitespaceComputer.getAfterLineNumberForWhitespaceIndex(2), 7); + assert.equal(linesLayout.getIdForWhitespaceIndex(0), a); // 2 + assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(0), 2); + assert.equal(linesLayout.getIdForWhitespaceIndex(1), c); // 3 + assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(1), 3); + assert.equal(linesLayout.getIdForWhitespaceIndex(2), b); // 7 + assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(2), 7); - assert.equal(whitespaceComputer.getFirstWhitespaceIndexAfterLineNumber(1), 0); // a - assert.equal(whitespaceComputer.getFirstWhitespaceIndexAfterLineNumber(2), 0); // a - assert.equal(whitespaceComputer.getFirstWhitespaceIndexAfterLineNumber(3), 1); // c - assert.equal(whitespaceComputer.getFirstWhitespaceIndexAfterLineNumber(4), 2); // b - assert.equal(whitespaceComputer.getFirstWhitespaceIndexAfterLineNumber(5), 2); // b - assert.equal(whitespaceComputer.getFirstWhitespaceIndexAfterLineNumber(6), 2); // b - assert.equal(whitespaceComputer.getFirstWhitespaceIndexAfterLineNumber(7), 2); // b - assert.equal(whitespaceComputer.getFirstWhitespaceIndexAfterLineNumber(8), -1); // -- + assert.equal(linesLayout.getFirstWhitespaceIndexAfterLineNumber(1), 0); // a + assert.equal(linesLayout.getFirstWhitespaceIndexAfterLineNumber(2), 0); // a + assert.equal(linesLayout.getFirstWhitespaceIndexAfterLineNumber(3), 1); // c + assert.equal(linesLayout.getFirstWhitespaceIndexAfterLineNumber(4), 2); // b + assert.equal(linesLayout.getFirstWhitespaceIndexAfterLineNumber(5), 2); // b + assert.equal(linesLayout.getFirstWhitespaceIndexAfterLineNumber(6), 2); // b + assert.equal(linesLayout.getFirstWhitespaceIndexAfterLineNumber(7), 2); // b + assert.equal(linesLayout.getFirstWhitespaceIndexAfterLineNumber(8), -1); // -- // Change a to conflict with c => a gets placed after c - whitespaceComputer.changeWhitespaceAfterLineNumber(a, 3); + linesLayout.changeWhitespace(a, 3, 1); - assert.equal(whitespaceComputer.getIdForWhitespaceIndex(0), c); // 3 - assert.equal(whitespaceComputer.getAfterLineNumberForWhitespaceIndex(0), 3); - assert.equal(whitespaceComputer.getIdForWhitespaceIndex(1), a); // 3 - assert.equal(whitespaceComputer.getAfterLineNumberForWhitespaceIndex(1), 3); - assert.equal(whitespaceComputer.getIdForWhitespaceIndex(2), b); // 7 - assert.equal(whitespaceComputer.getAfterLineNumberForWhitespaceIndex(2), 7); + assert.equal(linesLayout.getIdForWhitespaceIndex(0), c); // 3 + assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(0), 3); + assert.equal(linesLayout.getIdForWhitespaceIndex(1), a); // 3 + assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(1), 3); + assert.equal(linesLayout.getIdForWhitespaceIndex(2), b); // 7 + assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(2), 7); - assert.equal(whitespaceComputer.getFirstWhitespaceIndexAfterLineNumber(1), 0); // c - assert.equal(whitespaceComputer.getFirstWhitespaceIndexAfterLineNumber(2), 0); // c - assert.equal(whitespaceComputer.getFirstWhitespaceIndexAfterLineNumber(3), 0); // c - assert.equal(whitespaceComputer.getFirstWhitespaceIndexAfterLineNumber(4), 2); // b - assert.equal(whitespaceComputer.getFirstWhitespaceIndexAfterLineNumber(5), 2); // b - assert.equal(whitespaceComputer.getFirstWhitespaceIndexAfterLineNumber(6), 2); // b - assert.equal(whitespaceComputer.getFirstWhitespaceIndexAfterLineNumber(7), 2); // b - assert.equal(whitespaceComputer.getFirstWhitespaceIndexAfterLineNumber(8), -1); // -- + assert.equal(linesLayout.getFirstWhitespaceIndexAfterLineNumber(1), 0); // c + assert.equal(linesLayout.getFirstWhitespaceIndexAfterLineNumber(2), 0); // c + assert.equal(linesLayout.getFirstWhitespaceIndexAfterLineNumber(3), 0); // c + assert.equal(linesLayout.getFirstWhitespaceIndexAfterLineNumber(4), 2); // b + assert.equal(linesLayout.getFirstWhitespaceIndexAfterLineNumber(5), 2); // b + assert.equal(linesLayout.getFirstWhitespaceIndexAfterLineNumber(6), 2); // b + assert.equal(linesLayout.getFirstWhitespaceIndexAfterLineNumber(7), 2); // b + assert.equal(linesLayout.getFirstWhitespaceIndexAfterLineNumber(8), -1); // -- // Make a no-op - whitespaceComputer.changeWhitespaceAfterLineNumber(c, 3); + linesLayout.changeWhitespace(c, 3, 1); - assert.equal(whitespaceComputer.getIdForWhitespaceIndex(0), c); // 3 - assert.equal(whitespaceComputer.getAfterLineNumberForWhitespaceIndex(0), 3); - assert.equal(whitespaceComputer.getIdForWhitespaceIndex(1), a); // 3 - assert.equal(whitespaceComputer.getAfterLineNumberForWhitespaceIndex(1), 3); - assert.equal(whitespaceComputer.getIdForWhitespaceIndex(2), b); // 7 - assert.equal(whitespaceComputer.getAfterLineNumberForWhitespaceIndex(2), 7); + assert.equal(linesLayout.getIdForWhitespaceIndex(0), c); // 3 + assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(0), 3); + assert.equal(linesLayout.getIdForWhitespaceIndex(1), a); // 3 + assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(1), 3); + assert.equal(linesLayout.getIdForWhitespaceIndex(2), b); // 7 + assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(2), 7); - assert.equal(whitespaceComputer.getFirstWhitespaceIndexAfterLineNumber(1), 0); // c - assert.equal(whitespaceComputer.getFirstWhitespaceIndexAfterLineNumber(2), 0); // c - assert.equal(whitespaceComputer.getFirstWhitespaceIndexAfterLineNumber(3), 0); // c - assert.equal(whitespaceComputer.getFirstWhitespaceIndexAfterLineNumber(4), 2); // b - assert.equal(whitespaceComputer.getFirstWhitespaceIndexAfterLineNumber(5), 2); // b - assert.equal(whitespaceComputer.getFirstWhitespaceIndexAfterLineNumber(6), 2); // b - assert.equal(whitespaceComputer.getFirstWhitespaceIndexAfterLineNumber(7), 2); // b - assert.equal(whitespaceComputer.getFirstWhitespaceIndexAfterLineNumber(8), -1); // -- + assert.equal(linesLayout.getFirstWhitespaceIndexAfterLineNumber(1), 0); // c + assert.equal(linesLayout.getFirstWhitespaceIndexAfterLineNumber(2), 0); // c + assert.equal(linesLayout.getFirstWhitespaceIndexAfterLineNumber(3), 0); // c + assert.equal(linesLayout.getFirstWhitespaceIndexAfterLineNumber(4), 2); // b + assert.equal(linesLayout.getFirstWhitespaceIndexAfterLineNumber(5), 2); // b + assert.equal(linesLayout.getFirstWhitespaceIndexAfterLineNumber(6), 2); // b + assert.equal(linesLayout.getFirstWhitespaceIndexAfterLineNumber(7), 2); // b + assert.equal(linesLayout.getFirstWhitespaceIndexAfterLineNumber(8), -1); // -- // Conflict c with b => c gets placed after b - whitespaceComputer.changeWhitespaceAfterLineNumber(c, 7); - - assert.equal(whitespaceComputer.getIdForWhitespaceIndex(0), a); // 3 - assert.equal(whitespaceComputer.getAfterLineNumberForWhitespaceIndex(0), 3); - assert.equal(whitespaceComputer.getIdForWhitespaceIndex(1), b); // 7 - assert.equal(whitespaceComputer.getAfterLineNumberForWhitespaceIndex(1), 7); - assert.equal(whitespaceComputer.getIdForWhitespaceIndex(2), c); // 7 - assert.equal(whitespaceComputer.getAfterLineNumberForWhitespaceIndex(2), 7); - - assert.equal(whitespaceComputer.getFirstWhitespaceIndexAfterLineNumber(1), 0); // a - assert.equal(whitespaceComputer.getFirstWhitespaceIndexAfterLineNumber(2), 0); // a - assert.equal(whitespaceComputer.getFirstWhitespaceIndexAfterLineNumber(3), 0); // a - assert.equal(whitespaceComputer.getFirstWhitespaceIndexAfterLineNumber(4), 1); // b - assert.equal(whitespaceComputer.getFirstWhitespaceIndexAfterLineNumber(5), 1); // b - assert.equal(whitespaceComputer.getFirstWhitespaceIndexAfterLineNumber(6), 1); // b - assert.equal(whitespaceComputer.getFirstWhitespaceIndexAfterLineNumber(7), 1); // b - assert.equal(whitespaceComputer.getFirstWhitespaceIndexAfterLineNumber(8), -1); // -- + linesLayout.changeWhitespace(c, 7, 1); + + assert.equal(linesLayout.getIdForWhitespaceIndex(0), a); // 3 + assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(0), 3); + assert.equal(linesLayout.getIdForWhitespaceIndex(1), b); // 7 + assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(1), 7); + assert.equal(linesLayout.getIdForWhitespaceIndex(2), c); // 7 + assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(2), 7); + + assert.equal(linesLayout.getFirstWhitespaceIndexAfterLineNumber(1), 0); // a + assert.equal(linesLayout.getFirstWhitespaceIndexAfterLineNumber(2), 0); // a + assert.equal(linesLayout.getFirstWhitespaceIndexAfterLineNumber(3), 0); // a + assert.equal(linesLayout.getFirstWhitespaceIndexAfterLineNumber(4), 1); // b + assert.equal(linesLayout.getFirstWhitespaceIndexAfterLineNumber(5), 1); // b + assert.equal(linesLayout.getFirstWhitespaceIndexAfterLineNumber(6), 1); // b + assert.equal(linesLayout.getFirstWhitespaceIndexAfterLineNumber(7), 1); // b + assert.equal(linesLayout.getFirstWhitespaceIndexAfterLineNumber(8), -1); // -- }); test('WhitespaceComputer Bug', () => { - let whitespaceComputer = new WhitespaceComputer(); - - let a = whitespaceComputer.insertWhitespace(0, 0, 1, 0); - let b = whitespaceComputer.insertWhitespace(7, 0, 1, 0); - - assert.equal(whitespaceComputer.getIdForWhitespaceIndex(0), a); // 0 - assert.equal(whitespaceComputer.getIdForWhitespaceIndex(1), b); // 7 - - let c = whitespaceComputer.insertWhitespace(3, 0, 1, 0); - - assert.equal(whitespaceComputer.getIdForWhitespaceIndex(0), a); // 0 - assert.equal(whitespaceComputer.getIdForWhitespaceIndex(1), c); // 3 - assert.equal(whitespaceComputer.getIdForWhitespaceIndex(2), b); // 7 - - let d = whitespaceComputer.insertWhitespace(2, 0, 1, 0); - assert.equal(whitespaceComputer.getIdForWhitespaceIndex(0), a); // 0 - assert.equal(whitespaceComputer.getIdForWhitespaceIndex(1), d); // 2 - assert.equal(whitespaceComputer.getIdForWhitespaceIndex(2), c); // 3 - assert.equal(whitespaceComputer.getIdForWhitespaceIndex(3), b); // 7 - - let e = whitespaceComputer.insertWhitespace(8, 0, 1, 0); - assert.equal(whitespaceComputer.getIdForWhitespaceIndex(0), a); // 0 - assert.equal(whitespaceComputer.getIdForWhitespaceIndex(1), d); // 2 - assert.equal(whitespaceComputer.getIdForWhitespaceIndex(2), c); // 3 - assert.equal(whitespaceComputer.getIdForWhitespaceIndex(3), b); // 7 - assert.equal(whitespaceComputer.getIdForWhitespaceIndex(4), e); // 8 - - let f = whitespaceComputer.insertWhitespace(11, 0, 1, 0); - assert.equal(whitespaceComputer.getIdForWhitespaceIndex(0), a); // 0 - assert.equal(whitespaceComputer.getIdForWhitespaceIndex(1), d); // 2 - assert.equal(whitespaceComputer.getIdForWhitespaceIndex(2), c); // 3 - assert.equal(whitespaceComputer.getIdForWhitespaceIndex(3), b); // 7 - assert.equal(whitespaceComputer.getIdForWhitespaceIndex(4), e); // 8 - assert.equal(whitespaceComputer.getIdForWhitespaceIndex(5), f); // 11 - - let g = whitespaceComputer.insertWhitespace(10, 0, 1, 0); - assert.equal(whitespaceComputer.getIdForWhitespaceIndex(0), a); // 0 - assert.equal(whitespaceComputer.getIdForWhitespaceIndex(1), d); // 2 - assert.equal(whitespaceComputer.getIdForWhitespaceIndex(2), c); // 3 - assert.equal(whitespaceComputer.getIdForWhitespaceIndex(3), b); // 7 - assert.equal(whitespaceComputer.getIdForWhitespaceIndex(4), e); // 8 - assert.equal(whitespaceComputer.getIdForWhitespaceIndex(5), g); // 10 - assert.equal(whitespaceComputer.getIdForWhitespaceIndex(6), f); // 11 - - let h = whitespaceComputer.insertWhitespace(0, 0, 1, 0); - assert.equal(whitespaceComputer.getIdForWhitespaceIndex(0), a); // 0 - assert.equal(whitespaceComputer.getIdForWhitespaceIndex(1), h); // 0 - assert.equal(whitespaceComputer.getIdForWhitespaceIndex(2), d); // 2 - assert.equal(whitespaceComputer.getIdForWhitespaceIndex(3), c); // 3 - assert.equal(whitespaceComputer.getIdForWhitespaceIndex(4), b); // 7 - assert.equal(whitespaceComputer.getIdForWhitespaceIndex(5), e); // 8 - assert.equal(whitespaceComputer.getIdForWhitespaceIndex(6), g); // 10 - assert.equal(whitespaceComputer.getIdForWhitespaceIndex(7), f); // 11 + const linesLayout = new LinesLayout(100, 20); + + const a = linesLayout.insertWhitespace(0, 0, 1, 0); + const b = linesLayout.insertWhitespace(7, 0, 1, 0); + + assert.equal(linesLayout.getIdForWhitespaceIndex(0), a); // 0 + assert.equal(linesLayout.getIdForWhitespaceIndex(1), b); // 7 + + const c = linesLayout.insertWhitespace(3, 0, 1, 0); + + assert.equal(linesLayout.getIdForWhitespaceIndex(0), a); // 0 + assert.equal(linesLayout.getIdForWhitespaceIndex(1), c); // 3 + assert.equal(linesLayout.getIdForWhitespaceIndex(2), b); // 7 + + const d = linesLayout.insertWhitespace(2, 0, 1, 0); + assert.equal(linesLayout.getIdForWhitespaceIndex(0), a); // 0 + assert.equal(linesLayout.getIdForWhitespaceIndex(1), d); // 2 + assert.equal(linesLayout.getIdForWhitespaceIndex(2), c); // 3 + assert.equal(linesLayout.getIdForWhitespaceIndex(3), b); // 7 + + const e = linesLayout.insertWhitespace(8, 0, 1, 0); + assert.equal(linesLayout.getIdForWhitespaceIndex(0), a); // 0 + assert.equal(linesLayout.getIdForWhitespaceIndex(1), d); // 2 + assert.equal(linesLayout.getIdForWhitespaceIndex(2), c); // 3 + assert.equal(linesLayout.getIdForWhitespaceIndex(3), b); // 7 + assert.equal(linesLayout.getIdForWhitespaceIndex(4), e); // 8 + + const f = linesLayout.insertWhitespace(11, 0, 1, 0); + assert.equal(linesLayout.getIdForWhitespaceIndex(0), a); // 0 + assert.equal(linesLayout.getIdForWhitespaceIndex(1), d); // 2 + assert.equal(linesLayout.getIdForWhitespaceIndex(2), c); // 3 + assert.equal(linesLayout.getIdForWhitespaceIndex(3), b); // 7 + assert.equal(linesLayout.getIdForWhitespaceIndex(4), e); // 8 + assert.equal(linesLayout.getIdForWhitespaceIndex(5), f); // 11 + + const g = linesLayout.insertWhitespace(10, 0, 1, 0); + assert.equal(linesLayout.getIdForWhitespaceIndex(0), a); // 0 + assert.equal(linesLayout.getIdForWhitespaceIndex(1), d); // 2 + assert.equal(linesLayout.getIdForWhitespaceIndex(2), c); // 3 + assert.equal(linesLayout.getIdForWhitespaceIndex(3), b); // 7 + assert.equal(linesLayout.getIdForWhitespaceIndex(4), e); // 8 + assert.equal(linesLayout.getIdForWhitespaceIndex(5), g); // 10 + assert.equal(linesLayout.getIdForWhitespaceIndex(6), f); // 11 + + const h = linesLayout.insertWhitespace(0, 0, 1, 0); + assert.equal(linesLayout.getIdForWhitespaceIndex(0), a); // 0 + assert.equal(linesLayout.getIdForWhitespaceIndex(1), h); // 0 + assert.equal(linesLayout.getIdForWhitespaceIndex(2), d); // 2 + assert.equal(linesLayout.getIdForWhitespaceIndex(3), c); // 3 + assert.equal(linesLayout.getIdForWhitespaceIndex(4), b); // 7 + assert.equal(linesLayout.getIdForWhitespaceIndex(5), e); // 8 + assert.equal(linesLayout.getIdForWhitespaceIndex(6), g); // 10 + assert.equal(linesLayout.getIdForWhitespaceIndex(7), f); // 11 }); }); From 6ff2985fba6675897df9e9951b1979c7ef4f78f2 Mon Sep 17 00:00:00 2001 From: Alexandru Dima Date: Fri, 15 Nov 2019 10:50:05 +0100 Subject: [PATCH 318/352] Merge WhitespaceComputer into LinesLayout --- src/vs/editor/browser/editorBrowser.ts | 2 +- .../editor/browser/widget/codeEditorWidget.ts | 2 +- .../editor/browser/widget/diffEditorWidget.ts | 2 +- .../editor/common/viewLayout/linesLayout.ts | 481 ++++++++++++--- src/vs/editor/common/viewLayout/viewLayout.ts | 3 +- .../common/viewLayout/whitespaceComputer.ts | 493 --------------- src/vs/editor/common/viewModel/viewModel.ts | 2 +- .../common/viewLayout/linesLayout.test.ts | 548 ++++++++++++++++- .../viewLayout/whitespaceComputer.test.ts | 559 ------------------ 9 files changed, 959 insertions(+), 1133 deletions(-) delete mode 100644 src/vs/editor/common/viewLayout/whitespaceComputer.ts delete mode 100644 src/vs/editor/test/common/viewLayout/whitespaceComputer.test.ts diff --git a/src/vs/editor/browser/editorBrowser.ts b/src/vs/editor/browser/editorBrowser.ts index 50eed2efb08e5..bcd0995f8430c 100644 --- a/src/vs/editor/browser/editorBrowser.ts +++ b/src/vs/editor/browser/editorBrowser.ts @@ -16,7 +16,7 @@ import * as editorCommon from 'vs/editor/common/editorCommon'; import { IIdentifiedSingleEditOperation, IModelDecoration, IModelDeltaDecoration, ITextModel, ICursorStateComputer } from 'vs/editor/common/model'; import { IModelContentChangedEvent, IModelDecorationsChangedEvent, IModelLanguageChangedEvent, IModelLanguageConfigurationChangedEvent, IModelOptionsChangedEvent } from 'vs/editor/common/model/textModelEvents'; import { OverviewRulerZone } from 'vs/editor/common/view/overviewZoneManager'; -import { IEditorWhitespace } from 'vs/editor/common/viewLayout/whitespaceComputer'; +import { IEditorWhitespace } from 'vs/editor/common/viewLayout/linesLayout'; import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { IDiffComputationResult } from 'vs/editor/common/services/editorWorkerService'; diff --git a/src/vs/editor/browser/widget/codeEditorWidget.ts b/src/vs/editor/browser/widget/codeEditorWidget.ts index 83e47a48f1dd3..357eeab2a9f22 100644 --- a/src/vs/editor/browser/widget/codeEditorWidget.ts +++ b/src/vs/editor/browser/widget/codeEditorWidget.ts @@ -40,7 +40,7 @@ import * as modes from 'vs/editor/common/modes'; import { editorUnnecessaryCodeBorder, editorUnnecessaryCodeOpacity } from 'vs/editor/common/view/editorColorRegistry'; import { editorErrorBorder, editorErrorForeground, editorHintBorder, editorHintForeground, editorInfoBorder, editorInfoForeground, editorWarningBorder, editorWarningForeground, editorForeground } from 'vs/platform/theme/common/colorRegistry'; import { VerticalRevealType } from 'vs/editor/common/view/viewEvents'; -import { IEditorWhitespace } from 'vs/editor/common/viewLayout/whitespaceComputer'; +import { IEditorWhitespace } from 'vs/editor/common/viewLayout/linesLayout'; import { ViewModel } from 'vs/editor/common/viewModel/viewModelImpl'; import { ICommandService } from 'vs/platform/commands/common/commands'; import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; diff --git a/src/vs/editor/browser/widget/diffEditorWidget.ts b/src/vs/editor/browser/widget/diffEditorWidget.ts index 0bd9f2788ffa8..e03249c867a6c 100644 --- a/src/vs/editor/browser/widget/diffEditorWidget.ts +++ b/src/vs/editor/browser/widget/diffEditorWidget.ts @@ -32,7 +32,7 @@ import { IDiffComputationResult, IEditorWorkerService } from 'vs/editor/common/s import { OverviewRulerZone } from 'vs/editor/common/view/overviewZoneManager'; import { LineDecoration } from 'vs/editor/common/viewLayout/lineDecorations'; import { RenderLineInput, renderViewLine } from 'vs/editor/common/viewLayout/viewLineRenderer'; -import { IEditorWhitespace } from 'vs/editor/common/viewLayout/whitespaceComputer'; +import { IEditorWhitespace } from 'vs/editor/common/viewLayout/linesLayout'; import { InlineDecoration, InlineDecorationType, ViewLineRenderingData } from 'vs/editor/common/viewModel/viewModel'; import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; diff --git a/src/vs/editor/common/viewLayout/linesLayout.ts b/src/vs/editor/common/viewLayout/linesLayout.ts index f95b15741bc87..e18482b2ef4a2 100644 --- a/src/vs/editor/common/viewLayout/linesLayout.ts +++ b/src/vs/editor/common/viewLayout/linesLayout.ts @@ -4,8 +4,14 @@ *--------------------------------------------------------------------------------------------*/ import { IPartialViewLinesViewportData } from 'vs/editor/common/viewLayout/viewLinesViewportData'; -import { IEditorWhitespace, WhitespaceComputer } from 'vs/editor/common/viewLayout/whitespaceComputer'; import { IViewWhitespaceViewportData } from 'vs/editor/common/viewModel/viewModel'; +import * as strings from 'vs/base/common/strings'; + +export interface IEditorWhitespace { + readonly id: string; + readonly afterLineNumber: number; + readonly heightInLines: number; +} /** * Layouting of objects that take vertical space (by having a height) and push down other objects. @@ -15,6 +21,59 @@ import { IViewWhitespaceViewportData } from 'vs/editor/common/viewModel/viewMode */ export class LinesLayout { + private static INSTANCE_COUNT = 0; + + private readonly _instanceId: string; + + /** + * heights[i] is the height in pixels for whitespace at index i + */ + private readonly _heights: number[]; + + /** + * minWidths[i] is the min width in pixels for whitespace at index i + */ + private readonly _minWidths: number[]; + + /** + * afterLineNumbers[i] is the line number whitespace at index i is after + */ + private readonly _afterLineNumbers: number[]; + + /** + * ordinals[i] is the orinal of the whitespace at index i + */ + private readonly _ordinals: number[]; + + /** + * prefixSum[i] = SUM(heights[j]), 1 <= j <= i + */ + private readonly _prefixSum: number[]; + + /** + * prefixSum[i], 1 <= i <= prefixSumValidIndex can be trusted + */ + private _prefixSumValidIndex: number; + + /** + * ids[i] is the whitespace id of whitespace at index i + */ + private readonly _ids: string[]; + + /** + * index at which a whitespace is positioned (inside heights, afterLineNumbers, prefixSum members) + */ + private readonly _whitespaceId2Index: { + [id: string]: number; + }; + + /** + * last whitespace id issued + */ + private _lastWhitespaceId: number; + + private _minWidth: number; + /** * Keep track of the total number of lines. * This is useful for doing binary searches or for doing hit-testing. @@ -26,15 +85,47 @@ export class LinesLayout { */ private _lineHeight: number; - /** - * Contains whitespace information in pixels - */ - private readonly _whitespaces: WhitespaceComputer; - constructor(lineCount: number, lineHeight: number) { + this._instanceId = strings.singleLetterHash(++LinesLayout.INSTANCE_COUNT); + this._heights = []; + this._minWidths = []; + this._ids = []; + this._afterLineNumbers = []; + this._ordinals = []; + this._prefixSum = []; + this._prefixSumValidIndex = -1; + this._whitespaceId2Index = {}; + this._lastWhitespaceId = 0; + this._minWidth = -1; /* marker for not being computed */ this._lineCount = lineCount; this._lineHeight = lineHeight; - this._whitespaces = new WhitespaceComputer(); + } + + /** + * Find the insertion index for a new value inside a sorted array of values. + * If the value is already present in the sorted array, the insertion index will be after the already existing value. + */ + public static findInsertionIndex(sortedArray: number[], value: number, ordinals: number[], valueOrdinal: number): number { + let low = 0; + let high = sortedArray.length; + + while (low < high) { + let mid = ((low + high) >>> 1); + + if (value === sortedArray[mid]) { + if (valueOrdinal < ordinals[mid]) { + high = mid; + } else { + low = mid + 1; + } + } else if (value < sortedArray[mid]) { + high = mid; + } else { + low = mid + 1; + } + } + + return low; } /** @@ -63,14 +154,114 @@ export class LinesLayout { * @return An id that can be used later to mutate or delete the whitespace */ public insertWhitespace(afterLineNumber: number, ordinal: number, heightInPx: number, minWidth: number): string { - return this._whitespaces.insertWhitespace(afterLineNumber, ordinal, heightInPx, minWidth); + afterLineNumber = afterLineNumber | 0; + ordinal = ordinal | 0; + heightInPx = heightInPx | 0; + minWidth = minWidth | 0; + + let id = this._instanceId + (++this._lastWhitespaceId); + let insertionIndex = LinesLayout.findInsertionIndex(this._afterLineNumbers, afterLineNumber, this._ordinals, ordinal); + this._insertWhitespaceAtIndex(id, insertionIndex, afterLineNumber, ordinal, heightInPx, minWidth); + this._minWidth = -1; /* marker for not being computed */ + return id; + } + + private _insertWhitespaceAtIndex(id: string, insertIndex: number, afterLineNumber: number, ordinal: number, heightInPx: number, minWidth: number): void { + insertIndex = insertIndex | 0; + afterLineNumber = afterLineNumber | 0; + ordinal = ordinal | 0; + heightInPx = heightInPx | 0; + minWidth = minWidth | 0; + + this._heights.splice(insertIndex, 0, heightInPx); + this._minWidths.splice(insertIndex, 0, minWidth); + this._ids.splice(insertIndex, 0, id); + this._afterLineNumbers.splice(insertIndex, 0, afterLineNumber); + this._ordinals.splice(insertIndex, 0, ordinal); + this._prefixSum.splice(insertIndex, 0, 0); + + let keys = Object.keys(this._whitespaceId2Index); + for (let i = 0, len = keys.length; i < len; i++) { + let sid = keys[i]; + let oldIndex = this._whitespaceId2Index[sid]; + if (oldIndex >= insertIndex) { + this._whitespaceId2Index[sid] = oldIndex + 1; + } + } + + this._whitespaceId2Index[id] = insertIndex; + this._prefixSumValidIndex = Math.min(this._prefixSumValidIndex, insertIndex - 1); } /** * Change properties associated with a certain whitespace. */ public changeWhitespace(id: string, newAfterLineNumber: number, newHeight: number): boolean { - return this._whitespaces.changeWhitespace(id, newAfterLineNumber, newHeight); + newAfterLineNumber = newAfterLineNumber | 0; + newHeight = newHeight | 0; + + let hasChanges = false; + hasChanges = this.changeWhitespaceHeight(id, newHeight) || hasChanges; + hasChanges = this.changeWhitespaceAfterLineNumber(id, newAfterLineNumber) || hasChanges; + return hasChanges; + } + + /** + * Change the height of an existing whitespace + * + * @param id The whitespace to change + * @param newHeightInPx The new height of the whitespace, in pixels + * @return Returns true if the whitespace is found and if the new height is different than the old height + */ + public changeWhitespaceHeight(id: string, newHeightInPx: number): boolean { + newHeightInPx = newHeightInPx | 0; + + if (this._whitespaceId2Index.hasOwnProperty(id)) { + let index = this._whitespaceId2Index[id]; + if (this._heights[index] !== newHeightInPx) { + this._heights[index] = newHeightInPx; + this._prefixSumValidIndex = Math.min(this._prefixSumValidIndex, index - 1); + return true; + } + } + return false; + } + + /** + * Change the line number after which an existing whitespace flows. + * + * @param id The whitespace to change + * @param newAfterLineNumber The new line number the whitespace will follow + * @return Returns true if the whitespace is found and if the new line number is different than the old line number + */ + public changeWhitespaceAfterLineNumber(id: string, newAfterLineNumber: number): boolean { + newAfterLineNumber = newAfterLineNumber | 0; + + if (this._whitespaceId2Index.hasOwnProperty(id)) { + let index = this._whitespaceId2Index[id]; + if (this._afterLineNumbers[index] !== newAfterLineNumber) { + // `afterLineNumber` changed for this whitespace + + // Record old ordinal + let ordinal = this._ordinals[index]; + + // Record old height + let heightInPx = this._heights[index]; + + // Record old min width + let minWidth = this._minWidths[index]; + + // Since changing `afterLineNumber` can trigger a reordering, we're gonna remove this whitespace + this.removeWhitespace(id); + + // And add it again + let insertionIndex = LinesLayout.findInsertionIndex(this._afterLineNumbers, newAfterLineNumber, this._ordinals, ordinal); + this._insertWhitespaceAtIndex(id, insertionIndex, newAfterLineNumber, ordinal, heightInPx, minWidth); + + return true; + } + } + return false; } /** @@ -80,7 +271,36 @@ export class LinesLayout { * @return Returns true if the whitespace is found and it is removed. */ public removeWhitespace(id: string): boolean { - return this._whitespaces.removeWhitespace(id); + if (this._whitespaceId2Index.hasOwnProperty(id)) { + let index = this._whitespaceId2Index[id]; + delete this._whitespaceId2Index[id]; + this._removeWhitespaceAtIndex(index); + this._minWidth = -1; /* marker for not being computed */ + return true; + } + + return false; + } + + private _removeWhitespaceAtIndex(removeIndex: number): void { + removeIndex = removeIndex | 0; + + this._heights.splice(removeIndex, 1); + this._minWidths.splice(removeIndex, 1); + this._ids.splice(removeIndex, 1); + this._afterLineNumbers.splice(removeIndex, 1); + this._ordinals.splice(removeIndex, 1); + this._prefixSum.splice(removeIndex, 1); + this._prefixSumValidIndex = Math.min(this._prefixSumValidIndex, removeIndex - 1); + + let keys = Object.keys(this._whitespaceId2Index); + for (let i = 0, len = keys.length; i < len; i++) { + let sid = keys[i]; + let oldIndex = this._whitespaceId2Index[sid]; + if (oldIndex >= removeIndex) { + this._whitespaceId2Index[sid] = oldIndex - 1; + } + } } /** @@ -90,8 +310,23 @@ export class LinesLayout { * @param toLineNumber The line number at which the deletion ended, inclusive */ public onLinesDeleted(fromLineNumber: number, toLineNumber: number): void { + fromLineNumber = fromLineNumber | 0; + toLineNumber = toLineNumber | 0; + this._lineCount -= (toLineNumber - fromLineNumber + 1); - this._whitespaces.onLinesDeleted(fromLineNumber, toLineNumber); + for (let i = 0, len = this._afterLineNumbers.length; i < len; i++) { + let afterLineNumber = this._afterLineNumbers[i]; + + if (fromLineNumber <= afterLineNumber && afterLineNumber <= toLineNumber) { + // The line this whitespace was after has been deleted + // => move whitespace to before first deleted line + this._afterLineNumbers[i] = fromLineNumber - 1; + } else if (afterLineNumber > toLineNumber) { + // The line this whitespace was after has been moved up + // => move whitespace up + this._afterLineNumbers[i] -= (toLineNumber - fromLineNumber + 1); + } + } } /** @@ -101,8 +336,50 @@ export class LinesLayout { * @param toLineNumber The line number at which the insertion ended, inclusive. */ public onLinesInserted(fromLineNumber: number, toLineNumber: number): void { + fromLineNumber = fromLineNumber | 0; + toLineNumber = toLineNumber | 0; + this._lineCount += (toLineNumber - fromLineNumber + 1); - this._whitespaces.onLinesInserted(fromLineNumber, toLineNumber); + for (let i = 0, len = this._afterLineNumbers.length; i < len; i++) { + let afterLineNumber = this._afterLineNumbers[i]; + + if (fromLineNumber <= afterLineNumber) { + this._afterLineNumbers[i] += (toLineNumber - fromLineNumber + 1); + } + } + } + + /** + * Get the sum of all the whitespaces. + */ + public getWhitespacesTotalHeight(): number { + if (this._heights.length === 0) { + return 0; + } + return this.getWhitespacesAccumulatedHeight(this._heights.length - 1); + } + + /** + * Return the sum of the heights of the whitespaces at [0..index]. + * This includes the whitespace at `index`. + * + * @param index The index of the whitespace. + * @return The sum of the heights of all whitespaces before the one at `index`, including the one at `index`. + */ + public getWhitespacesAccumulatedHeight(index: number): number { + index = index | 0; + + let startIndex = Math.max(0, this._prefixSumValidIndex + 1); + if (startIndex === 0) { + this._prefixSum[0] = this._heights[0]; + startIndex++; + } + + for (let i = startIndex; i <= index; i++) { + this._prefixSum[i] = this._prefixSum[i - 1] + this._heights[i]; + } + this._prefixSumValidIndex = Math.max(this._prefixSumValidIndex, index); + return this._prefixSum[index]; } /** @@ -112,10 +389,77 @@ export class LinesLayout { */ public getLinesTotalHeight(): number { let linesHeight = this._lineHeight * this._lineCount; - let whitespacesHeight = this._whitespaces.getTotalHeight(); + let whitespacesHeight = this.getWhitespacesTotalHeight(); return linesHeight + whitespacesHeight; } + /** + * Returns the accumulated height of whitespaces before the given line number. + * + * @param lineNumber The line number + */ + public getWhitespaceAccumulatedHeightBeforeLineNumber(lineNumber: number): number { + lineNumber = lineNumber | 0; + + let lastWhitespaceBeforeLineNumber = this._findLastWhitespaceBeforeLineNumber(lineNumber); + + if (lastWhitespaceBeforeLineNumber === -1) { + return 0; + } + + return this.getWhitespacesAccumulatedHeight(lastWhitespaceBeforeLineNumber); + } + + private _findLastWhitespaceBeforeLineNumber(lineNumber: number): number { + lineNumber = lineNumber | 0; + + // Find the whitespace before line number + let afterLineNumbers = this._afterLineNumbers; + let low = 0; + let high = afterLineNumbers.length - 1; + + while (low <= high) { + let delta = (high - low) | 0; + let halfDelta = (delta / 2) | 0; + let mid = (low + halfDelta) | 0; + + if (afterLineNumbers[mid] < lineNumber) { + if (mid + 1 >= afterLineNumbers.length || afterLineNumbers[mid + 1] >= lineNumber) { + return mid; + } else { + low = (mid + 1) | 0; + } + } else { + high = (mid - 1) | 0; + } + } + + return -1; + } + + private _findFirstWhitespaceAfterLineNumber(lineNumber: number): number { + lineNumber = lineNumber | 0; + + let lastWhitespaceBeforeLineNumber = this._findLastWhitespaceBeforeLineNumber(lineNumber); + let firstWhitespaceAfterLineNumber = lastWhitespaceBeforeLineNumber + 1; + + if (firstWhitespaceAfterLineNumber < this._heights.length) { + return firstWhitespaceAfterLineNumber; + } + + return -1; + } + + /** + * Find the index of the first whitespace which has `afterLineNumber` >= `lineNumber`. + * @return The index of the first whitespace with `afterLineNumber` >= `lineNumber` or -1 if no whitespace is found. + */ + public getFirstWhitespaceIndexAfterLineNumber(lineNumber: number): number { + lineNumber = lineNumber | 0; + + return this._findFirstWhitespaceAfterLineNumber(lineNumber); + } + /** * Get the vertical offset (the sum of heights for all objects above) a certain line number. * @@ -132,29 +476,30 @@ export class LinesLayout { previousLinesHeight = 0; } - let previousWhitespacesHeight = this._whitespaces.getAccumulatedHeightBeforeLineNumber(lineNumber); + let previousWhitespacesHeight = this.getWhitespaceAccumulatedHeightBeforeLineNumber(lineNumber); return previousLinesHeight + previousWhitespacesHeight; } - /** - * Returns the accumulated height of whitespaces before the given line number. - * - * @param lineNumber The line number - */ - public getWhitespaceAccumulatedHeightBeforeLineNumber(lineNumber: number): number { - return this._whitespaces.getAccumulatedHeightBeforeLineNumber(lineNumber); - } - /** * Returns if there is any whitespace in the document. */ public hasWhitespace(): boolean { - return this._whitespaces.getCount() > 0; + return this.getWhitespacesCount() > 0; } + /** + * The maximum min width for all whitespaces. + */ public getWhitespaceMinWidth(): number { - return this._whitespaces.getMinWidth(); + if (this._minWidth === -1) { + let minWidth = 0; + for (let i = 0, len = this._minWidths.length; i < len; i++) { + minWidth = Math.max(minWidth, this._minWidths[i]); + } + this._minWidth = minWidth; + } + return this._minWidth; } /** @@ -229,8 +574,8 @@ export class LinesLayout { let endLineNumber = this._lineCount | 0; // Also keep track of what whitespace we've got - let whitespaceIndex = this._whitespaces.getFirstWhitespaceIndexAfterLineNumber(startLineNumber) | 0; - const whitespaceCount = this._whitespaces.getCount() | 0; + let whitespaceIndex = this.getFirstWhitespaceIndexAfterLineNumber(startLineNumber) | 0; + const whitespaceCount = this.getWhitespacesCount() | 0; let currentWhitespaceHeight: number; let currentWhitespaceAfterLineNumber: number; @@ -239,8 +584,8 @@ export class LinesLayout { currentWhitespaceAfterLineNumber = endLineNumber + 1; currentWhitespaceHeight = 0; } else { - currentWhitespaceAfterLineNumber = this._whitespaces.getAfterLineNumberForWhitespaceIndex(whitespaceIndex) | 0; - currentWhitespaceHeight = this._whitespaces.getHeightForWhitespaceIndex(whitespaceIndex) | 0; + currentWhitespaceAfterLineNumber = this.getAfterLineNumberForWhitespaceIndex(whitespaceIndex) | 0; + currentWhitespaceHeight = this.getHeightForWhitespaceIndex(whitespaceIndex) | 0; } let currentVerticalOffset = startLineNumberVerticalOffset; @@ -290,8 +635,8 @@ export class LinesLayout { if (whitespaceIndex >= whitespaceCount) { currentWhitespaceAfterLineNumber = endLineNumber + 1; } else { - currentWhitespaceAfterLineNumber = this._whitespaces.getAfterLineNumberForWhitespaceIndex(whitespaceIndex) | 0; - currentWhitespaceHeight = this._whitespaces.getHeightForWhitespaceIndex(whitespaceIndex) | 0; + currentWhitespaceAfterLineNumber = this.getAfterLineNumberForWhitespaceIndex(whitespaceIndex) | 0; + currentWhitespaceHeight = this.getHeightForWhitespaceIndex(whitespaceIndex) | 0; } } @@ -336,7 +681,7 @@ export class LinesLayout { public getVerticalOffsetForWhitespaceIndex(whitespaceIndex: number): number { whitespaceIndex = whitespaceIndex | 0; - let afterLineNumber = this._whitespaces.getAfterLineNumberForWhitespaceIndex(whitespaceIndex); + let afterLineNumber = this.getAfterLineNumberForWhitespaceIndex(whitespaceIndex); let previousLinesHeight: number; if (afterLineNumber >= 1) { @@ -347,7 +692,7 @@ export class LinesLayout { let previousWhitespacesHeight: number; if (whitespaceIndex > 0) { - previousWhitespacesHeight = this._whitespaces.getAccumulatedHeight(whitespaceIndex - 1); + previousWhitespacesHeight = this.getWhitespacesAccumulatedHeight(whitespaceIndex - 1); } else { previousWhitespacesHeight = 0; } @@ -359,7 +704,7 @@ export class LinesLayout { let midWhitespaceIndex: number, minWhitespaceIndex = 0, - maxWhitespaceIndex = this._whitespaces.getCount() - 1, + maxWhitespaceIndex = this.getWhitespacesCount() - 1, midWhitespaceVerticalOffset: number, midWhitespaceHeight: number; @@ -369,7 +714,7 @@ export class LinesLayout { // Special case: nothing to be found let maxWhitespaceVerticalOffset = this.getVerticalOffsetForWhitespaceIndex(maxWhitespaceIndex); - let maxWhitespaceHeight = this._whitespaces.getHeightForWhitespaceIndex(maxWhitespaceIndex); + let maxWhitespaceHeight = this.getHeightForWhitespaceIndex(maxWhitespaceIndex); if (verticalOffset >= maxWhitespaceVerticalOffset + maxWhitespaceHeight) { return -1; } @@ -378,7 +723,7 @@ export class LinesLayout { midWhitespaceIndex = Math.floor((minWhitespaceIndex + maxWhitespaceIndex) / 2); midWhitespaceVerticalOffset = this.getVerticalOffsetForWhitespaceIndex(midWhitespaceIndex); - midWhitespaceHeight = this._whitespaces.getHeightForWhitespaceIndex(midWhitespaceIndex); + midWhitespaceHeight = this.getHeightForWhitespaceIndex(midWhitespaceIndex); if (verticalOffset >= midWhitespaceVerticalOffset + midWhitespaceHeight) { // vertical offset is after whitespace @@ -409,7 +754,7 @@ export class LinesLayout { return null; } - if (candidateIndex >= this._whitespaces.getCount()) { + if (candidateIndex >= this.getWhitespacesCount()) { return null; } @@ -419,9 +764,9 @@ export class LinesLayout { return null; } - let candidateHeight = this._whitespaces.getHeightForWhitespaceIndex(candidateIndex); - let candidateId = this._whitespaces.getIdForWhitespaceIndex(candidateIndex); - let candidateAfterLineNumber = this._whitespaces.getAfterLineNumberForWhitespaceIndex(candidateIndex); + let candidateHeight = this.getHeightForWhitespaceIndex(candidateIndex); + let candidateId = this.getIdForWhitespaceIndex(candidateIndex); + let candidateAfterLineNumber = this.getAfterLineNumberForWhitespaceIndex(candidateIndex); return { id: candidateId, @@ -443,7 +788,7 @@ export class LinesLayout { verticalOffset2 = verticalOffset2 | 0; let startIndex = this.getWhitespaceIndexAtOrAfterVerticallOffset(verticalOffset1); - let endIndex = this._whitespaces.getCount() - 1; + let endIndex = this.getWhitespacesCount() - 1; if (startIndex < 0) { return []; @@ -452,14 +797,14 @@ export class LinesLayout { let result: IViewWhitespaceViewportData[] = []; for (let i = startIndex; i <= endIndex; i++) { let top = this.getVerticalOffsetForWhitespaceIndex(i); - let height = this._whitespaces.getHeightForWhitespaceIndex(i); + let height = this.getHeightForWhitespaceIndex(i); if (top >= verticalOffset2) { break; } result.push({ - id: this._whitespaces.getIdForWhitespaceIndex(i), - afterLineNumber: this._whitespaces.getAfterLineNumberForWhitespaceIndex(i), + id: this.getIdForWhitespaceIndex(i), + afterLineNumber: this.getAfterLineNumberForWhitespaceIndex(i), verticalOffset: top, height: height }); @@ -472,14 +817,22 @@ export class LinesLayout { * Get all whitespaces. */ public getWhitespaces(): IEditorWhitespace[] { - return this._whitespaces.getWhitespaces(this._lineHeight); + let result: IEditorWhitespace[] = []; + for (let i = 0; i < this._heights.length; i++) { + result.push({ + id: this._ids[i], + afterLineNumber: this._afterLineNumbers[i], + heightInLines: this._heights[i] / this._lineHeight + }); + } + return result; } /** * The number of whitespaces. */ public getWhitespacesCount(): number { - return this._whitespaces.getCount(); + return this._heights.length; } /** @@ -489,7 +842,9 @@ export class LinesLayout { * @return `id` of whitespace at `index`. */ public getIdForWhitespaceIndex(index: number): string { - return this._whitespaces.getIdForWhitespaceIndex(index); + index = index | 0; + + return this._ids[index]; } /** @@ -499,7 +854,9 @@ export class LinesLayout { * @return `afterLineNumber` of whitespace at `index`. */ public getAfterLineNumberForWhitespaceIndex(index: number): number { - return this._whitespaces.getAfterLineNumberForWhitespaceIndex(index); + index = index | 0; + + return this._afterLineNumbers[index]; } /** @@ -509,32 +866,8 @@ export class LinesLayout { * @return `height` of whitespace at `index`. */ public getHeightForWhitespaceIndex(index: number): number { - return this._whitespaces.getHeightForWhitespaceIndex(index); - } - - /** - * Find the index of the first whitespace which has `afterLineNumber` >= `lineNumber`. - * @return The index of the first whitespace with `afterLineNumber` >= `lineNumber` or -1 if no whitespace is found. - */ - public getFirstWhitespaceIndexAfterLineNumber(lineNumber: number): number { - return this._whitespaces.getFirstWhitespaceIndexAfterLineNumber(lineNumber); - } + index = index | 0; - /** - * Return the sum of the heights of the whitespaces at [0..index]. - * This includes the whitespace at `index`. - * - * @param index The index of the whitespace. - * @return The sum of the heights of all whitespaces before the one at `index`, including the one at `index`. - */ - public getWhitespacesAccumulatedHeight(index: number): number { - return this._whitespaces.getAccumulatedHeight(index); - } - - /** - * Get the sum of all the whitespaces. - */ - public getWhitespacesTotalHeight(): number { - return this._whitespaces.getTotalHeight(); + return this._heights[index]; } } diff --git a/src/vs/editor/common/viewLayout/viewLayout.ts b/src/vs/editor/common/viewLayout/viewLayout.ts index 74fca28d02999..cab08b23f440f 100644 --- a/src/vs/editor/common/viewLayout/viewLayout.ts +++ b/src/vs/editor/common/viewLayout/viewLayout.ts @@ -8,9 +8,8 @@ import { Disposable, IDisposable } from 'vs/base/common/lifecycle'; import { IScrollPosition, ScrollEvent, Scrollable, ScrollbarVisibility } from 'vs/base/common/scrollable'; import { ConfigurationChangedEvent, EditorOption } from 'vs/editor/common/config/editorOptions'; import * as editorCommon from 'vs/editor/common/editorCommon'; -import { LinesLayout } from 'vs/editor/common/viewLayout/linesLayout'; +import { LinesLayout, IEditorWhitespace } from 'vs/editor/common/viewLayout/linesLayout'; import { IPartialViewLinesViewportData } from 'vs/editor/common/viewLayout/viewLinesViewportData'; -import { IEditorWhitespace } from 'vs/editor/common/viewLayout/whitespaceComputer'; import { IViewLayout, IViewWhitespaceViewportData, Viewport } from 'vs/editor/common/viewModel/viewModel'; const SMOOTH_SCROLLING_TIME = 125; diff --git a/src/vs/editor/common/viewLayout/whitespaceComputer.ts b/src/vs/editor/common/viewLayout/whitespaceComputer.ts deleted file mode 100644 index 8e5dd347e8306..0000000000000 --- a/src/vs/editor/common/viewLayout/whitespaceComputer.ts +++ /dev/null @@ -1,493 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import * as strings from 'vs/base/common/strings'; - -export interface IEditorWhitespace { - readonly id: string; - readonly afterLineNumber: number; - readonly heightInLines: number; -} - -/** - * Represent whitespaces in between lines and provide fast CRUD management methods. - * The whitespaces are sorted ascending by `afterLineNumber`. - */ -export class WhitespaceComputer { - - private static INSTANCE_COUNT = 0; - - private readonly _instanceId: string; - - /** - * heights[i] is the height in pixels for whitespace at index i - */ - private readonly _heights: number[]; - - /** - * minWidths[i] is the min width in pixels for whitespace at index i - */ - private readonly _minWidths: number[]; - - /** - * afterLineNumbers[i] is the line number whitespace at index i is after - */ - private readonly _afterLineNumbers: number[]; - - /** - * ordinals[i] is the orinal of the whitespace at index i - */ - private readonly _ordinals: number[]; - - /** - * prefixSum[i] = SUM(heights[j]), 1 <= j <= i - */ - private readonly _prefixSum: number[]; - - /** - * prefixSum[i], 1 <= i <= prefixSumValidIndex can be trusted - */ - private _prefixSumValidIndex: number; - - /** - * ids[i] is the whitespace id of whitespace at index i - */ - private readonly _ids: string[]; - - /** - * index at which a whitespace is positioned (inside heights, afterLineNumbers, prefixSum members) - */ - private readonly _whitespaceId2Index: { - [id: string]: number; - }; - - /** - * last whitespace id issued - */ - private _lastWhitespaceId: number; - - private _minWidth: number; - - constructor() { - this._instanceId = strings.singleLetterHash(++WhitespaceComputer.INSTANCE_COUNT); - this._heights = []; - this._minWidths = []; - this._ids = []; - this._afterLineNumbers = []; - this._ordinals = []; - this._prefixSum = []; - this._prefixSumValidIndex = -1; - this._whitespaceId2Index = {}; - this._lastWhitespaceId = 0; - this._minWidth = -1; /* marker for not being computed */ - } - - /** - * Find the insertion index for a new value inside a sorted array of values. - * If the value is already present in the sorted array, the insertion index will be after the already existing value. - */ - public static findInsertionIndex(sortedArray: number[], value: number, ordinals: number[], valueOrdinal: number): number { - let low = 0; - let high = sortedArray.length; - - while (low < high) { - let mid = ((low + high) >>> 1); - - if (value === sortedArray[mid]) { - if (valueOrdinal < ordinals[mid]) { - high = mid; - } else { - low = mid + 1; - } - } else if (value < sortedArray[mid]) { - high = mid; - } else { - low = mid + 1; - } - } - - return low; - } - - /** - * Insert a new whitespace of a certain height after a line number. - * The whitespace has a "sticky" characteristic. - * Irrespective of edits above or below `afterLineNumber`, the whitespace will follow the initial line. - * - * @param afterLineNumber The conceptual position of this whitespace. The whitespace will follow this line as best as possible even when deleting/inserting lines above/below. - * @param heightInPx The height of the whitespace, in pixels. - * @return An id that can be used later to mutate or delete the whitespace - */ - public insertWhitespace(afterLineNumber: number, ordinal: number, heightInPx: number, minWidth: number): string { - afterLineNumber = afterLineNumber | 0; - ordinal = ordinal | 0; - heightInPx = heightInPx | 0; - minWidth = minWidth | 0; - - let id = this._instanceId + (++this._lastWhitespaceId); - let insertionIndex = WhitespaceComputer.findInsertionIndex(this._afterLineNumbers, afterLineNumber, this._ordinals, ordinal); - this._insertWhitespaceAtIndex(id, insertionIndex, afterLineNumber, ordinal, heightInPx, minWidth); - this._minWidth = -1; /* marker for not being computed */ - return id; - } - - private _insertWhitespaceAtIndex(id: string, insertIndex: number, afterLineNumber: number, ordinal: number, heightInPx: number, minWidth: number): void { - insertIndex = insertIndex | 0; - afterLineNumber = afterLineNumber | 0; - ordinal = ordinal | 0; - heightInPx = heightInPx | 0; - minWidth = minWidth | 0; - - this._heights.splice(insertIndex, 0, heightInPx); - this._minWidths.splice(insertIndex, 0, minWidth); - this._ids.splice(insertIndex, 0, id); - this._afterLineNumbers.splice(insertIndex, 0, afterLineNumber); - this._ordinals.splice(insertIndex, 0, ordinal); - this._prefixSum.splice(insertIndex, 0, 0); - - let keys = Object.keys(this._whitespaceId2Index); - for (let i = 0, len = keys.length; i < len; i++) { - let sid = keys[i]; - let oldIndex = this._whitespaceId2Index[sid]; - if (oldIndex >= insertIndex) { - this._whitespaceId2Index[sid] = oldIndex + 1; - } - } - - this._whitespaceId2Index[id] = insertIndex; - this._prefixSumValidIndex = Math.min(this._prefixSumValidIndex, insertIndex - 1); - } - - /** - * Change properties associated with a certain whitespace. - */ - public changeWhitespace(id: string, newAfterLineNumber: number, newHeight: number): boolean { - newAfterLineNumber = newAfterLineNumber | 0; - newHeight = newHeight | 0; - - let hasChanges = false; - hasChanges = this.changeWhitespaceHeight(id, newHeight) || hasChanges; - hasChanges = this.changeWhitespaceAfterLineNumber(id, newAfterLineNumber) || hasChanges; - return hasChanges; - } - - /** - * Change the height of an existing whitespace - * - * @param id The whitespace to change - * @param newHeightInPx The new height of the whitespace, in pixels - * @return Returns true if the whitespace is found and if the new height is different than the old height - */ - public changeWhitespaceHeight(id: string, newHeightInPx: number): boolean { - newHeightInPx = newHeightInPx | 0; - - if (this._whitespaceId2Index.hasOwnProperty(id)) { - let index = this._whitespaceId2Index[id]; - if (this._heights[index] !== newHeightInPx) { - this._heights[index] = newHeightInPx; - this._prefixSumValidIndex = Math.min(this._prefixSumValidIndex, index - 1); - return true; - } - } - return false; - } - - /** - * Change the line number after which an existing whitespace flows. - * - * @param id The whitespace to change - * @param newAfterLineNumber The new line number the whitespace will follow - * @return Returns true if the whitespace is found and if the new line number is different than the old line number - */ - public changeWhitespaceAfterLineNumber(id: string, newAfterLineNumber: number): boolean { - newAfterLineNumber = newAfterLineNumber | 0; - - if (this._whitespaceId2Index.hasOwnProperty(id)) { - let index = this._whitespaceId2Index[id]; - if (this._afterLineNumbers[index] !== newAfterLineNumber) { - // `afterLineNumber` changed for this whitespace - - // Record old ordinal - let ordinal = this._ordinals[index]; - - // Record old height - let heightInPx = this._heights[index]; - - // Record old min width - let minWidth = this._minWidths[index]; - - // Since changing `afterLineNumber` can trigger a reordering, we're gonna remove this whitespace - this.removeWhitespace(id); - - // And add it again - let insertionIndex = WhitespaceComputer.findInsertionIndex(this._afterLineNumbers, newAfterLineNumber, this._ordinals, ordinal); - this._insertWhitespaceAtIndex(id, insertionIndex, newAfterLineNumber, ordinal, heightInPx, minWidth); - - return true; - } - } - return false; - } - - /** - * Remove an existing whitespace. - * - * @param id The whitespace to remove - * @return Returns true if the whitespace is found and it is removed. - */ - public removeWhitespace(id: string): boolean { - if (this._whitespaceId2Index.hasOwnProperty(id)) { - let index = this._whitespaceId2Index[id]; - delete this._whitespaceId2Index[id]; - this._removeWhitespaceAtIndex(index); - this._minWidth = -1; /* marker for not being computed */ - return true; - } - - return false; - } - - private _removeWhitespaceAtIndex(removeIndex: number): void { - removeIndex = removeIndex | 0; - - this._heights.splice(removeIndex, 1); - this._minWidths.splice(removeIndex, 1); - this._ids.splice(removeIndex, 1); - this._afterLineNumbers.splice(removeIndex, 1); - this._ordinals.splice(removeIndex, 1); - this._prefixSum.splice(removeIndex, 1); - this._prefixSumValidIndex = Math.min(this._prefixSumValidIndex, removeIndex - 1); - - let keys = Object.keys(this._whitespaceId2Index); - for (let i = 0, len = keys.length; i < len; i++) { - let sid = keys[i]; - let oldIndex = this._whitespaceId2Index[sid]; - if (oldIndex >= removeIndex) { - this._whitespaceId2Index[sid] = oldIndex - 1; - } - } - } - - /** - * Notify the computer that lines have been deleted (a continuous zone of lines). - * This gives it a chance to update `afterLineNumber` for whitespaces, giving the "sticky" characteristic. - * - * @param fromLineNumber The line number at which the deletion started, inclusive - * @param toLineNumber The line number at which the deletion ended, inclusive - */ - public onLinesDeleted(fromLineNumber: number, toLineNumber: number): void { - fromLineNumber = fromLineNumber | 0; - toLineNumber = toLineNumber | 0; - - for (let i = 0, len = this._afterLineNumbers.length; i < len; i++) { - let afterLineNumber = this._afterLineNumbers[i]; - - if (fromLineNumber <= afterLineNumber && afterLineNumber <= toLineNumber) { - // The line this whitespace was after has been deleted - // => move whitespace to before first deleted line - this._afterLineNumbers[i] = fromLineNumber - 1; - } else if (afterLineNumber > toLineNumber) { - // The line this whitespace was after has been moved up - // => move whitespace up - this._afterLineNumbers[i] -= (toLineNumber - fromLineNumber + 1); - } - } - } - - /** - * Notify the computer that lines have been inserted (a continuous zone of lines). - * This gives it a chance to update `afterLineNumber` for whitespaces, giving the "sticky" characteristic. - * - * @param fromLineNumber The line number at which the insertion started, inclusive - * @param toLineNumber The line number at which the insertion ended, inclusive. - */ - public onLinesInserted(fromLineNumber: number, toLineNumber: number): void { - fromLineNumber = fromLineNumber | 0; - toLineNumber = toLineNumber | 0; - - for (let i = 0, len = this._afterLineNumbers.length; i < len; i++) { - let afterLineNumber = this._afterLineNumbers[i]; - - if (fromLineNumber <= afterLineNumber) { - this._afterLineNumbers[i] += (toLineNumber - fromLineNumber + 1); - } - } - } - - /** - * Get the sum of all the whitespaces. - */ - public getTotalHeight(): number { - if (this._heights.length === 0) { - return 0; - } - return this.getAccumulatedHeight(this._heights.length - 1); - } - - /** - * Return the sum of the heights of the whitespaces at [0..index]. - * This includes the whitespace at `index`. - * - * @param index The index of the whitespace. - * @return The sum of the heights of all whitespaces before the one at `index`, including the one at `index`. - */ - public getAccumulatedHeight(index: number): number { - index = index | 0; - - let startIndex = Math.max(0, this._prefixSumValidIndex + 1); - if (startIndex === 0) { - this._prefixSum[0] = this._heights[0]; - startIndex++; - } - - for (let i = startIndex; i <= index; i++) { - this._prefixSum[i] = this._prefixSum[i - 1] + this._heights[i]; - } - this._prefixSumValidIndex = Math.max(this._prefixSumValidIndex, index); - return this._prefixSum[index]; - } - - /** - * Find all whitespaces with `afterLineNumber` < `lineNumber` and return the sum of their heights. - * - * @param lineNumber The line number whitespaces should be before. - * @return The sum of the heights of the whitespaces before `lineNumber`. - */ - public getAccumulatedHeightBeforeLineNumber(lineNumber: number): number { - lineNumber = lineNumber | 0; - - let lastWhitespaceBeforeLineNumber = this._findLastWhitespaceBeforeLineNumber(lineNumber); - - if (lastWhitespaceBeforeLineNumber === -1) { - return 0; - } - - return this.getAccumulatedHeight(lastWhitespaceBeforeLineNumber); - } - - private _findLastWhitespaceBeforeLineNumber(lineNumber: number): number { - lineNumber = lineNumber | 0; - - // Find the whitespace before line number - let afterLineNumbers = this._afterLineNumbers; - let low = 0; - let high = afterLineNumbers.length - 1; - - while (low <= high) { - let delta = (high - low) | 0; - let halfDelta = (delta / 2) | 0; - let mid = (low + halfDelta) | 0; - - if (afterLineNumbers[mid] < lineNumber) { - if (mid + 1 >= afterLineNumbers.length || afterLineNumbers[mid + 1] >= lineNumber) { - return mid; - } else { - low = (mid + 1) | 0; - } - } else { - high = (mid - 1) | 0; - } - } - - return -1; - } - - private _findFirstWhitespaceAfterLineNumber(lineNumber: number): number { - lineNumber = lineNumber | 0; - - let lastWhitespaceBeforeLineNumber = this._findLastWhitespaceBeforeLineNumber(lineNumber); - let firstWhitespaceAfterLineNumber = lastWhitespaceBeforeLineNumber + 1; - - if (firstWhitespaceAfterLineNumber < this._heights.length) { - return firstWhitespaceAfterLineNumber; - } - - return -1; - } - - /** - * Find the index of the first whitespace which has `afterLineNumber` >= `lineNumber`. - * @return The index of the first whitespace with `afterLineNumber` >= `lineNumber` or -1 if no whitespace is found. - */ - public getFirstWhitespaceIndexAfterLineNumber(lineNumber: number): number { - lineNumber = lineNumber | 0; - - return this._findFirstWhitespaceAfterLineNumber(lineNumber); - } - - /** - * The number of whitespaces. - */ - public getCount(): number { - return this._heights.length; - } - - /** - * The maximum min width for all whitespaces. - */ - public getMinWidth(): number { - if (this._minWidth === -1) { - let minWidth = 0; - for (let i = 0, len = this._minWidths.length; i < len; i++) { - minWidth = Math.max(minWidth, this._minWidths[i]); - } - this._minWidth = minWidth; - } - return this._minWidth; - } - - /** - * Get the `afterLineNumber` for whitespace at index `index`. - * - * @param index The index of the whitespace. - * @return `afterLineNumber` of whitespace at `index`. - */ - public getAfterLineNumberForWhitespaceIndex(index: number): number { - index = index | 0; - - return this._afterLineNumbers[index]; - } - - /** - * Get the `id` for whitespace at index `index`. - * - * @param index The index of the whitespace. - * @return `id` of whitespace at `index`. - */ - public getIdForWhitespaceIndex(index: number): string { - index = index | 0; - - return this._ids[index]; - } - - /** - * Get the `height` for whitespace at index `index`. - * - * @param index The index of the whitespace. - * @return `height` of whitespace at `index`. - */ - public getHeightForWhitespaceIndex(index: number): number { - index = index | 0; - - return this._heights[index]; - } - - /** - * Get all whitespaces. - */ - public getWhitespaces(deviceLineHeight: number): IEditorWhitespace[] { - deviceLineHeight = deviceLineHeight | 0; - - let result: IEditorWhitespace[] = []; - for (let i = 0; i < this._heights.length; i++) { - result.push({ - id: this._ids[i], - afterLineNumber: this._afterLineNumbers[i], - heightInLines: this._heights[i] / deviceLineHeight - }); - } - return result; - } -} diff --git a/src/vs/editor/common/viewModel/viewModel.ts b/src/vs/editor/common/viewModel/viewModel.ts index 0f16d0a84a299..3dd75a94d4ba6 100644 --- a/src/vs/editor/common/viewModel/viewModel.ts +++ b/src/vs/editor/common/viewModel/viewModel.ts @@ -13,7 +13,7 @@ import { INewScrollPosition } from 'vs/editor/common/editorCommon'; import { EndOfLinePreference, IActiveIndentGuideInfo, IModelDecorationOptions, TextModelResolvedOptions } from 'vs/editor/common/model'; import { IViewEventListener } from 'vs/editor/common/view/viewEvents'; import { IPartialViewLinesViewportData } from 'vs/editor/common/viewLayout/viewLinesViewportData'; -import { IEditorWhitespace } from 'vs/editor/common/viewLayout/whitespaceComputer'; +import { IEditorWhitespace } from 'vs/editor/common/viewLayout/linesLayout'; import { ITheme } from 'vs/platform/theme/common/themeService'; export interface IViewWhitespaceViewportData { diff --git a/src/vs/editor/test/common/viewLayout/linesLayout.test.ts b/src/vs/editor/test/common/viewLayout/linesLayout.test.ts index dceeaab37b0b6..a88c5c16c6d35 100644 --- a/src/vs/editor/test/common/viewLayout/linesLayout.test.ts +++ b/src/vs/editor/test/common/viewLayout/linesLayout.test.ts @@ -479,7 +479,6 @@ suite('Editor ViewLayout - LinesLayout', () => { assert.deepEqual(viewportData.relativeVerticalOffset, [160, 170, 180, 190]); }); - test('LinesLayout getLinesViewportData 2 & getWhitespaceViewportData', () => { let linesLayout = new LinesLayout(10, 10); let a = linesLayout.insertWhitespace(6, 0, 100, 0); @@ -592,4 +591,551 @@ suite('Editor ViewLayout - LinesLayout', () => { whitespace = linesLayout.getWhitespaceAtVerticalOffset(220); assert.equal(whitespace, null); }); + + test('LinesLayout', () => { + + const linesLayout = new LinesLayout(100, 20); + + // Insert a whitespace after line number 2, of height 10 + const a = linesLayout.insertWhitespace(2, 0, 10, 0); + // whitespaces: a(2, 10) + assert.equal(linesLayout.getWhitespacesCount(), 1); + assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(0), 2); + assert.equal(linesLayout.getHeightForWhitespaceIndex(0), 10); + assert.equal(linesLayout.getWhitespacesAccumulatedHeight(0), 10); + assert.equal(linesLayout.getWhitespacesTotalHeight(), 10); + assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(1), 0); + assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(2), 0); + assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(3), 10); + assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(4), 10); + + // Insert a whitespace again after line number 2, of height 20 + let b = linesLayout.insertWhitespace(2, 0, 20, 0); + // whitespaces: a(2, 10), b(2, 20) + assert.equal(linesLayout.getWhitespacesCount(), 2); + assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(0), 2); + assert.equal(linesLayout.getHeightForWhitespaceIndex(0), 10); + assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(1), 2); + assert.equal(linesLayout.getHeightForWhitespaceIndex(1), 20); + assert.equal(linesLayout.getWhitespacesAccumulatedHeight(0), 10); + assert.equal(linesLayout.getWhitespacesAccumulatedHeight(1), 30); + assert.equal(linesLayout.getWhitespacesTotalHeight(), 30); + assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(1), 0); + assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(2), 0); + assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(3), 30); + assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(4), 30); + + // Change last inserted whitespace height to 30 + linesLayout.changeWhitespace(b, 2, 30); + // whitespaces: a(2, 10), b(2, 30) + assert.equal(linesLayout.getWhitespacesCount(), 2); + assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(0), 2); + assert.equal(linesLayout.getHeightForWhitespaceIndex(0), 10); + assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(1), 2); + assert.equal(linesLayout.getHeightForWhitespaceIndex(1), 30); + assert.equal(linesLayout.getWhitespacesAccumulatedHeight(0), 10); + assert.equal(linesLayout.getWhitespacesAccumulatedHeight(1), 40); + assert.equal(linesLayout.getWhitespacesTotalHeight(), 40); + assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(1), 0); + assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(2), 0); + assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(3), 40); + assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(4), 40); + + // Remove last inserted whitespace + linesLayout.removeWhitespace(b); + // whitespaces: a(2, 10) + assert.equal(linesLayout.getWhitespacesCount(), 1); + assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(0), 2); + assert.equal(linesLayout.getHeightForWhitespaceIndex(0), 10); + assert.equal(linesLayout.getWhitespacesAccumulatedHeight(0), 10); + assert.equal(linesLayout.getWhitespacesTotalHeight(), 10); + assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(1), 0); + assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(2), 0); + assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(3), 10); + assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(4), 10); + + // Add a whitespace before the first line of height 50 + b = linesLayout.insertWhitespace(0, 0, 50, 0); + // whitespaces: b(0, 50), a(2, 10) + assert.equal(linesLayout.getWhitespacesCount(), 2); + assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(0), 0); + assert.equal(linesLayout.getHeightForWhitespaceIndex(0), 50); + assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(1), 2); + assert.equal(linesLayout.getHeightForWhitespaceIndex(1), 10); + assert.equal(linesLayout.getWhitespacesAccumulatedHeight(0), 50); + assert.equal(linesLayout.getWhitespacesAccumulatedHeight(1), 60); + assert.equal(linesLayout.getWhitespacesTotalHeight(), 60); + assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(1), 50); + assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(2), 50); + assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(3), 60); + assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(4), 60); + + // Add a whitespace after line 4 of height 20 + linesLayout.insertWhitespace(4, 0, 20, 0); + // whitespaces: b(0, 50), a(2, 10), c(4, 20) + assert.equal(linesLayout.getWhitespacesCount(), 3); + assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(0), 0); + assert.equal(linesLayout.getHeightForWhitespaceIndex(0), 50); + assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(1), 2); + assert.equal(linesLayout.getHeightForWhitespaceIndex(1), 10); + assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(2), 4); + assert.equal(linesLayout.getHeightForWhitespaceIndex(2), 20); + assert.equal(linesLayout.getWhitespacesAccumulatedHeight(0), 50); + assert.equal(linesLayout.getWhitespacesAccumulatedHeight(1), 60); + assert.equal(linesLayout.getWhitespacesAccumulatedHeight(2), 80); + assert.equal(linesLayout.getWhitespacesTotalHeight(), 80); + assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(1), 50); + assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(2), 50); + assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(3), 60); + assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(4), 60); + assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(5), 80); + + // Add a whitespace after line 3 of height 30 + linesLayout.insertWhitespace(3, 0, 30, 0); + // whitespaces: b(0, 50), a(2, 10), d(3, 30), c(4, 20) + assert.equal(linesLayout.getWhitespacesCount(), 4); + assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(0), 0); + assert.equal(linesLayout.getHeightForWhitespaceIndex(0), 50); + assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(1), 2); + assert.equal(linesLayout.getHeightForWhitespaceIndex(1), 10); + assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(2), 3); + assert.equal(linesLayout.getHeightForWhitespaceIndex(2), 30); + assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(3), 4); + assert.equal(linesLayout.getHeightForWhitespaceIndex(3), 20); + assert.equal(linesLayout.getWhitespacesAccumulatedHeight(0), 50); + assert.equal(linesLayout.getWhitespacesAccumulatedHeight(1), 60); + assert.equal(linesLayout.getWhitespacesAccumulatedHeight(2), 90); + assert.equal(linesLayout.getWhitespacesAccumulatedHeight(3), 110); + assert.equal(linesLayout.getWhitespacesTotalHeight(), 110); + assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(1), 50); + assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(2), 50); + assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(3), 60); + assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(4), 90); + assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(5), 110); + + // Change whitespace after line 2 to height of 100 + linesLayout.changeWhitespace(a, 2, 100); + // whitespaces: b(0, 50), a(2, 100), d(3, 30), c(4, 20) + assert.equal(linesLayout.getWhitespacesCount(), 4); + assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(0), 0); + assert.equal(linesLayout.getHeightForWhitespaceIndex(0), 50); + assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(1), 2); + assert.equal(linesLayout.getHeightForWhitespaceIndex(1), 100); + assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(2), 3); + assert.equal(linesLayout.getHeightForWhitespaceIndex(2), 30); + assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(3), 4); + assert.equal(linesLayout.getHeightForWhitespaceIndex(3), 20); + assert.equal(linesLayout.getWhitespacesAccumulatedHeight(0), 50); + assert.equal(linesLayout.getWhitespacesAccumulatedHeight(1), 150); + assert.equal(linesLayout.getWhitespacesAccumulatedHeight(2), 180); + assert.equal(linesLayout.getWhitespacesAccumulatedHeight(3), 200); + assert.equal(linesLayout.getWhitespacesTotalHeight(), 200); + assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(1), 50); + assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(2), 50); + assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(3), 150); + assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(4), 180); + assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(5), 200); + + // Remove whitespace after line 2 + linesLayout.removeWhitespace(a); + // whitespaces: b(0, 50), d(3, 30), c(4, 20) + assert.equal(linesLayout.getWhitespacesCount(), 3); + assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(0), 0); + assert.equal(linesLayout.getHeightForWhitespaceIndex(0), 50); + assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(1), 3); + assert.equal(linesLayout.getHeightForWhitespaceIndex(1), 30); + assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(2), 4); + assert.equal(linesLayout.getHeightForWhitespaceIndex(2), 20); + assert.equal(linesLayout.getWhitespacesAccumulatedHeight(0), 50); + assert.equal(linesLayout.getWhitespacesAccumulatedHeight(1), 80); + assert.equal(linesLayout.getWhitespacesAccumulatedHeight(2), 100); + assert.equal(linesLayout.getWhitespacesTotalHeight(), 100); + assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(1), 50); + assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(2), 50); + assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(3), 50); + assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(4), 80); + assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(5), 100); + + // Remove whitespace before line 1 + linesLayout.removeWhitespace(b); + // whitespaces: d(3, 30), c(4, 20) + assert.equal(linesLayout.getWhitespacesCount(), 2); + assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(0), 3); + assert.equal(linesLayout.getHeightForWhitespaceIndex(0), 30); + assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(1), 4); + assert.equal(linesLayout.getHeightForWhitespaceIndex(1), 20); + assert.equal(linesLayout.getWhitespacesAccumulatedHeight(0), 30); + assert.equal(linesLayout.getWhitespacesAccumulatedHeight(1), 50); + assert.equal(linesLayout.getWhitespacesTotalHeight(), 50); + assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(1), 0); + assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(2), 0); + assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(3), 0); + assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(4), 30); + assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(5), 50); + + // Delete line 1 + linesLayout.onLinesDeleted(1, 1); + // whitespaces: d(2, 30), c(3, 20) + assert.equal(linesLayout.getWhitespacesCount(), 2); + assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(0), 2); + assert.equal(linesLayout.getHeightForWhitespaceIndex(0), 30); + assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(1), 3); + assert.equal(linesLayout.getHeightForWhitespaceIndex(1), 20); + assert.equal(linesLayout.getWhitespacesAccumulatedHeight(0), 30); + assert.equal(linesLayout.getWhitespacesAccumulatedHeight(1), 50); + assert.equal(linesLayout.getWhitespacesTotalHeight(), 50); + assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(1), 0); + assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(2), 0); + assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(3), 30); + assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(4), 50); + assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(5), 50); + + // Insert a line before line 1 + linesLayout.onLinesInserted(1, 1); + // whitespaces: d(3, 30), c(4, 20) + assert.equal(linesLayout.getWhitespacesCount(), 2); + assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(0), 3); + assert.equal(linesLayout.getHeightForWhitespaceIndex(0), 30); + assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(1), 4); + assert.equal(linesLayout.getHeightForWhitespaceIndex(1), 20); + assert.equal(linesLayout.getWhitespacesAccumulatedHeight(0), 30); + assert.equal(linesLayout.getWhitespacesAccumulatedHeight(1), 50); + assert.equal(linesLayout.getWhitespacesTotalHeight(), 50); + assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(1), 0); + assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(2), 0); + assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(3), 0); + assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(4), 30); + assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(5), 50); + + // Delete line 4 + linesLayout.onLinesDeleted(4, 4); + // whitespaces: d(3, 30), c(3, 20) + assert.equal(linesLayout.getWhitespacesCount(), 2); + assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(0), 3); + assert.equal(linesLayout.getHeightForWhitespaceIndex(0), 30); + assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(1), 3); + assert.equal(linesLayout.getHeightForWhitespaceIndex(1), 20); + assert.equal(linesLayout.getWhitespacesAccumulatedHeight(0), 30); + assert.equal(linesLayout.getWhitespacesAccumulatedHeight(1), 50); + assert.equal(linesLayout.getWhitespacesTotalHeight(), 50); + assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(1), 0); + assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(2), 0); + assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(3), 0); + assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(4), 50); + assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(5), 50); + }); + + test('LinesLayout findInsertionIndex', () => { + + const makeArray = (size: number, fillValue: number) => { + let r: number[] = []; + for (let i = 0; i < size; i++) { + r[i] = fillValue; + } + return r; + }; + + let arr: number[]; + let ordinals: number[]; + + arr = []; + ordinals = makeArray(arr.length, 0); + assert.equal(LinesLayout.findInsertionIndex(arr, 0, ordinals, 0), 0); + assert.equal(LinesLayout.findInsertionIndex(arr, 1, ordinals, 0), 0); + assert.equal(LinesLayout.findInsertionIndex(arr, 2, ordinals, 0), 0); + + arr = [1]; + ordinals = makeArray(arr.length, 0); + assert.equal(LinesLayout.findInsertionIndex(arr, 0, ordinals, 0), 0); + assert.equal(LinesLayout.findInsertionIndex(arr, 1, ordinals, 0), 1); + assert.equal(LinesLayout.findInsertionIndex(arr, 2, ordinals, 0), 1); + + arr = [1, 3]; + ordinals = makeArray(arr.length, 0); + assert.equal(LinesLayout.findInsertionIndex(arr, 0, ordinals, 0), 0); + assert.equal(LinesLayout.findInsertionIndex(arr, 1, ordinals, 0), 1); + assert.equal(LinesLayout.findInsertionIndex(arr, 2, ordinals, 0), 1); + assert.equal(LinesLayout.findInsertionIndex(arr, 3, ordinals, 0), 2); + assert.equal(LinesLayout.findInsertionIndex(arr, 4, ordinals, 0), 2); + + arr = [1, 3, 5]; + ordinals = makeArray(arr.length, 0); + assert.equal(LinesLayout.findInsertionIndex(arr, 0, ordinals, 0), 0); + assert.equal(LinesLayout.findInsertionIndex(arr, 1, ordinals, 0), 1); + assert.equal(LinesLayout.findInsertionIndex(arr, 2, ordinals, 0), 1); + assert.equal(LinesLayout.findInsertionIndex(arr, 3, ordinals, 0), 2); + assert.equal(LinesLayout.findInsertionIndex(arr, 4, ordinals, 0), 2); + assert.equal(LinesLayout.findInsertionIndex(arr, 5, ordinals, 0), 3); + assert.equal(LinesLayout.findInsertionIndex(arr, 6, ordinals, 0), 3); + + arr = [1, 3, 5]; + ordinals = makeArray(arr.length, 3); + assert.equal(LinesLayout.findInsertionIndex(arr, 0, ordinals, 0), 0); + assert.equal(LinesLayout.findInsertionIndex(arr, 1, ordinals, 0), 0); + assert.equal(LinesLayout.findInsertionIndex(arr, 2, ordinals, 0), 1); + assert.equal(LinesLayout.findInsertionIndex(arr, 3, ordinals, 0), 1); + assert.equal(LinesLayout.findInsertionIndex(arr, 4, ordinals, 0), 2); + assert.equal(LinesLayout.findInsertionIndex(arr, 5, ordinals, 0), 2); + assert.equal(LinesLayout.findInsertionIndex(arr, 6, ordinals, 0), 3); + + arr = [1, 3, 5, 7]; + ordinals = makeArray(arr.length, 0); + assert.equal(LinesLayout.findInsertionIndex(arr, 0, ordinals, 0), 0); + assert.equal(LinesLayout.findInsertionIndex(arr, 1, ordinals, 0), 1); + assert.equal(LinesLayout.findInsertionIndex(arr, 2, ordinals, 0), 1); + assert.equal(LinesLayout.findInsertionIndex(arr, 3, ordinals, 0), 2); + assert.equal(LinesLayout.findInsertionIndex(arr, 4, ordinals, 0), 2); + assert.equal(LinesLayout.findInsertionIndex(arr, 5, ordinals, 0), 3); + assert.equal(LinesLayout.findInsertionIndex(arr, 6, ordinals, 0), 3); + assert.equal(LinesLayout.findInsertionIndex(arr, 7, ordinals, 0), 4); + assert.equal(LinesLayout.findInsertionIndex(arr, 8, ordinals, 0), 4); + + arr = [1, 3, 5, 7, 9]; + ordinals = makeArray(arr.length, 0); + assert.equal(LinesLayout.findInsertionIndex(arr, 0, ordinals, 0), 0); + assert.equal(LinesLayout.findInsertionIndex(arr, 1, ordinals, 0), 1); + assert.equal(LinesLayout.findInsertionIndex(arr, 2, ordinals, 0), 1); + assert.equal(LinesLayout.findInsertionIndex(arr, 3, ordinals, 0), 2); + assert.equal(LinesLayout.findInsertionIndex(arr, 4, ordinals, 0), 2); + assert.equal(LinesLayout.findInsertionIndex(arr, 5, ordinals, 0), 3); + assert.equal(LinesLayout.findInsertionIndex(arr, 6, ordinals, 0), 3); + assert.equal(LinesLayout.findInsertionIndex(arr, 7, ordinals, 0), 4); + assert.equal(LinesLayout.findInsertionIndex(arr, 8, ordinals, 0), 4); + assert.equal(LinesLayout.findInsertionIndex(arr, 9, ordinals, 0), 5); + assert.equal(LinesLayout.findInsertionIndex(arr, 10, ordinals, 0), 5); + + arr = [1, 3, 5, 7, 9, 11]; + ordinals = makeArray(arr.length, 0); + assert.equal(LinesLayout.findInsertionIndex(arr, 0, ordinals, 0), 0); + assert.equal(LinesLayout.findInsertionIndex(arr, 1, ordinals, 0), 1); + assert.equal(LinesLayout.findInsertionIndex(arr, 2, ordinals, 0), 1); + assert.equal(LinesLayout.findInsertionIndex(arr, 3, ordinals, 0), 2); + assert.equal(LinesLayout.findInsertionIndex(arr, 4, ordinals, 0), 2); + assert.equal(LinesLayout.findInsertionIndex(arr, 5, ordinals, 0), 3); + assert.equal(LinesLayout.findInsertionIndex(arr, 6, ordinals, 0), 3); + assert.equal(LinesLayout.findInsertionIndex(arr, 7, ordinals, 0), 4); + assert.equal(LinesLayout.findInsertionIndex(arr, 8, ordinals, 0), 4); + assert.equal(LinesLayout.findInsertionIndex(arr, 9, ordinals, 0), 5); + assert.equal(LinesLayout.findInsertionIndex(arr, 10, ordinals, 0), 5); + assert.equal(LinesLayout.findInsertionIndex(arr, 11, ordinals, 0), 6); + assert.equal(LinesLayout.findInsertionIndex(arr, 12, ordinals, 0), 6); + + arr = [1, 3, 5, 7, 9, 11, 13]; + ordinals = makeArray(arr.length, 0); + assert.equal(LinesLayout.findInsertionIndex(arr, 0, ordinals, 0), 0); + assert.equal(LinesLayout.findInsertionIndex(arr, 1, ordinals, 0), 1); + assert.equal(LinesLayout.findInsertionIndex(arr, 2, ordinals, 0), 1); + assert.equal(LinesLayout.findInsertionIndex(arr, 3, ordinals, 0), 2); + assert.equal(LinesLayout.findInsertionIndex(arr, 4, ordinals, 0), 2); + assert.equal(LinesLayout.findInsertionIndex(arr, 5, ordinals, 0), 3); + assert.equal(LinesLayout.findInsertionIndex(arr, 6, ordinals, 0), 3); + assert.equal(LinesLayout.findInsertionIndex(arr, 7, ordinals, 0), 4); + assert.equal(LinesLayout.findInsertionIndex(arr, 8, ordinals, 0), 4); + assert.equal(LinesLayout.findInsertionIndex(arr, 9, ordinals, 0), 5); + assert.equal(LinesLayout.findInsertionIndex(arr, 10, ordinals, 0), 5); + assert.equal(LinesLayout.findInsertionIndex(arr, 11, ordinals, 0), 6); + assert.equal(LinesLayout.findInsertionIndex(arr, 12, ordinals, 0), 6); + assert.equal(LinesLayout.findInsertionIndex(arr, 13, ordinals, 0), 7); + assert.equal(LinesLayout.findInsertionIndex(arr, 14, ordinals, 0), 7); + + arr = [1, 3, 5, 7, 9, 11, 13, 15]; + ordinals = makeArray(arr.length, 0); + assert.equal(LinesLayout.findInsertionIndex(arr, 0, ordinals, 0), 0); + assert.equal(LinesLayout.findInsertionIndex(arr, 1, ordinals, 0), 1); + assert.equal(LinesLayout.findInsertionIndex(arr, 2, ordinals, 0), 1); + assert.equal(LinesLayout.findInsertionIndex(arr, 3, ordinals, 0), 2); + assert.equal(LinesLayout.findInsertionIndex(arr, 4, ordinals, 0), 2); + assert.equal(LinesLayout.findInsertionIndex(arr, 5, ordinals, 0), 3); + assert.equal(LinesLayout.findInsertionIndex(arr, 6, ordinals, 0), 3); + assert.equal(LinesLayout.findInsertionIndex(arr, 7, ordinals, 0), 4); + assert.equal(LinesLayout.findInsertionIndex(arr, 8, ordinals, 0), 4); + assert.equal(LinesLayout.findInsertionIndex(arr, 9, ordinals, 0), 5); + assert.equal(LinesLayout.findInsertionIndex(arr, 10, ordinals, 0), 5); + assert.equal(LinesLayout.findInsertionIndex(arr, 11, ordinals, 0), 6); + assert.equal(LinesLayout.findInsertionIndex(arr, 12, ordinals, 0), 6); + assert.equal(LinesLayout.findInsertionIndex(arr, 13, ordinals, 0), 7); + assert.equal(LinesLayout.findInsertionIndex(arr, 14, ordinals, 0), 7); + assert.equal(LinesLayout.findInsertionIndex(arr, 15, ordinals, 0), 8); + assert.equal(LinesLayout.findInsertionIndex(arr, 16, ordinals, 0), 8); + }); + + test('LinesLayout changeWhitespaceAfterLineNumber & getFirstWhitespaceIndexAfterLineNumber', () => { + const linesLayout = new LinesLayout(100, 20); + + const a = linesLayout.insertWhitespace(0, 0, 1, 0); + const b = linesLayout.insertWhitespace(7, 0, 1, 0); + const c = linesLayout.insertWhitespace(3, 0, 1, 0); + + assert.equal(linesLayout.getIdForWhitespaceIndex(0), a); // 0 + assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(0), 0); + assert.equal(linesLayout.getIdForWhitespaceIndex(1), c); // 3 + assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(1), 3); + assert.equal(linesLayout.getIdForWhitespaceIndex(2), b); // 7 + assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(2), 7); + + assert.equal(linesLayout.getFirstWhitespaceIndexAfterLineNumber(1), 1); // c + assert.equal(linesLayout.getFirstWhitespaceIndexAfterLineNumber(2), 1); // c + assert.equal(linesLayout.getFirstWhitespaceIndexAfterLineNumber(3), 1); // c + assert.equal(linesLayout.getFirstWhitespaceIndexAfterLineNumber(4), 2); // b + assert.equal(linesLayout.getFirstWhitespaceIndexAfterLineNumber(5), 2); // b + assert.equal(linesLayout.getFirstWhitespaceIndexAfterLineNumber(6), 2); // b + assert.equal(linesLayout.getFirstWhitespaceIndexAfterLineNumber(7), 2); // b + assert.equal(linesLayout.getFirstWhitespaceIndexAfterLineNumber(8), -1); // -- + + // Do not really move a + linesLayout.changeWhitespace(a, 1, 1); + + assert.equal(linesLayout.getIdForWhitespaceIndex(0), a); // 1 + assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(0), 1); + assert.equal(linesLayout.getIdForWhitespaceIndex(1), c); // 3 + assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(1), 3); + assert.equal(linesLayout.getIdForWhitespaceIndex(2), b); // 7 + assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(2), 7); + + assert.equal(linesLayout.getFirstWhitespaceIndexAfterLineNumber(1), 0); // a + assert.equal(linesLayout.getFirstWhitespaceIndexAfterLineNumber(2), 1); // c + assert.equal(linesLayout.getFirstWhitespaceIndexAfterLineNumber(3), 1); // c + assert.equal(linesLayout.getFirstWhitespaceIndexAfterLineNumber(4), 2); // b + assert.equal(linesLayout.getFirstWhitespaceIndexAfterLineNumber(5), 2); // b + assert.equal(linesLayout.getFirstWhitespaceIndexAfterLineNumber(6), 2); // b + assert.equal(linesLayout.getFirstWhitespaceIndexAfterLineNumber(7), 2); // b + assert.equal(linesLayout.getFirstWhitespaceIndexAfterLineNumber(8), -1); // -- + + + // Do not really move a + linesLayout.changeWhitespace(a, 2, 1); + + assert.equal(linesLayout.getIdForWhitespaceIndex(0), a); // 2 + assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(0), 2); + assert.equal(linesLayout.getIdForWhitespaceIndex(1), c); // 3 + assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(1), 3); + assert.equal(linesLayout.getIdForWhitespaceIndex(2), b); // 7 + assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(2), 7); + + assert.equal(linesLayout.getFirstWhitespaceIndexAfterLineNumber(1), 0); // a + assert.equal(linesLayout.getFirstWhitespaceIndexAfterLineNumber(2), 0); // a + assert.equal(linesLayout.getFirstWhitespaceIndexAfterLineNumber(3), 1); // c + assert.equal(linesLayout.getFirstWhitespaceIndexAfterLineNumber(4), 2); // b + assert.equal(linesLayout.getFirstWhitespaceIndexAfterLineNumber(5), 2); // b + assert.equal(linesLayout.getFirstWhitespaceIndexAfterLineNumber(6), 2); // b + assert.equal(linesLayout.getFirstWhitespaceIndexAfterLineNumber(7), 2); // b + assert.equal(linesLayout.getFirstWhitespaceIndexAfterLineNumber(8), -1); // -- + + + // Change a to conflict with c => a gets placed after c + linesLayout.changeWhitespace(a, 3, 1); + + assert.equal(linesLayout.getIdForWhitespaceIndex(0), c); // 3 + assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(0), 3); + assert.equal(linesLayout.getIdForWhitespaceIndex(1), a); // 3 + assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(1), 3); + assert.equal(linesLayout.getIdForWhitespaceIndex(2), b); // 7 + assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(2), 7); + + assert.equal(linesLayout.getFirstWhitespaceIndexAfterLineNumber(1), 0); // c + assert.equal(linesLayout.getFirstWhitespaceIndexAfterLineNumber(2), 0); // c + assert.equal(linesLayout.getFirstWhitespaceIndexAfterLineNumber(3), 0); // c + assert.equal(linesLayout.getFirstWhitespaceIndexAfterLineNumber(4), 2); // b + assert.equal(linesLayout.getFirstWhitespaceIndexAfterLineNumber(5), 2); // b + assert.equal(linesLayout.getFirstWhitespaceIndexAfterLineNumber(6), 2); // b + assert.equal(linesLayout.getFirstWhitespaceIndexAfterLineNumber(7), 2); // b + assert.equal(linesLayout.getFirstWhitespaceIndexAfterLineNumber(8), -1); // -- + + + // Make a no-op + linesLayout.changeWhitespace(c, 3, 1); + + assert.equal(linesLayout.getIdForWhitespaceIndex(0), c); // 3 + assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(0), 3); + assert.equal(linesLayout.getIdForWhitespaceIndex(1), a); // 3 + assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(1), 3); + assert.equal(linesLayout.getIdForWhitespaceIndex(2), b); // 7 + assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(2), 7); + + assert.equal(linesLayout.getFirstWhitespaceIndexAfterLineNumber(1), 0); // c + assert.equal(linesLayout.getFirstWhitespaceIndexAfterLineNumber(2), 0); // c + assert.equal(linesLayout.getFirstWhitespaceIndexAfterLineNumber(3), 0); // c + assert.equal(linesLayout.getFirstWhitespaceIndexAfterLineNumber(4), 2); // b + assert.equal(linesLayout.getFirstWhitespaceIndexAfterLineNumber(5), 2); // b + assert.equal(linesLayout.getFirstWhitespaceIndexAfterLineNumber(6), 2); // b + assert.equal(linesLayout.getFirstWhitespaceIndexAfterLineNumber(7), 2); // b + assert.equal(linesLayout.getFirstWhitespaceIndexAfterLineNumber(8), -1); // -- + + + + // Conflict c with b => c gets placed after b + linesLayout.changeWhitespace(c, 7, 1); + + assert.equal(linesLayout.getIdForWhitespaceIndex(0), a); // 3 + assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(0), 3); + assert.equal(linesLayout.getIdForWhitespaceIndex(1), b); // 7 + assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(1), 7); + assert.equal(linesLayout.getIdForWhitespaceIndex(2), c); // 7 + assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(2), 7); + + assert.equal(linesLayout.getFirstWhitespaceIndexAfterLineNumber(1), 0); // a + assert.equal(linesLayout.getFirstWhitespaceIndexAfterLineNumber(2), 0); // a + assert.equal(linesLayout.getFirstWhitespaceIndexAfterLineNumber(3), 0); // a + assert.equal(linesLayout.getFirstWhitespaceIndexAfterLineNumber(4), 1); // b + assert.equal(linesLayout.getFirstWhitespaceIndexAfterLineNumber(5), 1); // b + assert.equal(linesLayout.getFirstWhitespaceIndexAfterLineNumber(6), 1); // b + assert.equal(linesLayout.getFirstWhitespaceIndexAfterLineNumber(7), 1); // b + assert.equal(linesLayout.getFirstWhitespaceIndexAfterLineNumber(8), -1); // -- + }); + + test('LinesLayout Bug', () => { + const linesLayout = new LinesLayout(100, 20); + + const a = linesLayout.insertWhitespace(0, 0, 1, 0); + const b = linesLayout.insertWhitespace(7, 0, 1, 0); + + assert.equal(linesLayout.getIdForWhitespaceIndex(0), a); // 0 + assert.equal(linesLayout.getIdForWhitespaceIndex(1), b); // 7 + + const c = linesLayout.insertWhitespace(3, 0, 1, 0); + + assert.equal(linesLayout.getIdForWhitespaceIndex(0), a); // 0 + assert.equal(linesLayout.getIdForWhitespaceIndex(1), c); // 3 + assert.equal(linesLayout.getIdForWhitespaceIndex(2), b); // 7 + + const d = linesLayout.insertWhitespace(2, 0, 1, 0); + assert.equal(linesLayout.getIdForWhitespaceIndex(0), a); // 0 + assert.equal(linesLayout.getIdForWhitespaceIndex(1), d); // 2 + assert.equal(linesLayout.getIdForWhitespaceIndex(2), c); // 3 + assert.equal(linesLayout.getIdForWhitespaceIndex(3), b); // 7 + + const e = linesLayout.insertWhitespace(8, 0, 1, 0); + assert.equal(linesLayout.getIdForWhitespaceIndex(0), a); // 0 + assert.equal(linesLayout.getIdForWhitespaceIndex(1), d); // 2 + assert.equal(linesLayout.getIdForWhitespaceIndex(2), c); // 3 + assert.equal(linesLayout.getIdForWhitespaceIndex(3), b); // 7 + assert.equal(linesLayout.getIdForWhitespaceIndex(4), e); // 8 + + const f = linesLayout.insertWhitespace(11, 0, 1, 0); + assert.equal(linesLayout.getIdForWhitespaceIndex(0), a); // 0 + assert.equal(linesLayout.getIdForWhitespaceIndex(1), d); // 2 + assert.equal(linesLayout.getIdForWhitespaceIndex(2), c); // 3 + assert.equal(linesLayout.getIdForWhitespaceIndex(3), b); // 7 + assert.equal(linesLayout.getIdForWhitespaceIndex(4), e); // 8 + assert.equal(linesLayout.getIdForWhitespaceIndex(5), f); // 11 + + const g = linesLayout.insertWhitespace(10, 0, 1, 0); + assert.equal(linesLayout.getIdForWhitespaceIndex(0), a); // 0 + assert.equal(linesLayout.getIdForWhitespaceIndex(1), d); // 2 + assert.equal(linesLayout.getIdForWhitespaceIndex(2), c); // 3 + assert.equal(linesLayout.getIdForWhitespaceIndex(3), b); // 7 + assert.equal(linesLayout.getIdForWhitespaceIndex(4), e); // 8 + assert.equal(linesLayout.getIdForWhitespaceIndex(5), g); // 10 + assert.equal(linesLayout.getIdForWhitespaceIndex(6), f); // 11 + + const h = linesLayout.insertWhitespace(0, 0, 1, 0); + assert.equal(linesLayout.getIdForWhitespaceIndex(0), a); // 0 + assert.equal(linesLayout.getIdForWhitespaceIndex(1), h); // 0 + assert.equal(linesLayout.getIdForWhitespaceIndex(2), d); // 2 + assert.equal(linesLayout.getIdForWhitespaceIndex(3), c); // 3 + assert.equal(linesLayout.getIdForWhitespaceIndex(4), b); // 7 + assert.equal(linesLayout.getIdForWhitespaceIndex(5), e); // 8 + assert.equal(linesLayout.getIdForWhitespaceIndex(6), g); // 10 + assert.equal(linesLayout.getIdForWhitespaceIndex(7), f); // 11 + }); }); diff --git a/src/vs/editor/test/common/viewLayout/whitespaceComputer.test.ts b/src/vs/editor/test/common/viewLayout/whitespaceComputer.test.ts deleted file mode 100644 index df7527d6b9b72..0000000000000 --- a/src/vs/editor/test/common/viewLayout/whitespaceComputer.test.ts +++ /dev/null @@ -1,559 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ -import * as assert from 'assert'; -import { WhitespaceComputer } from 'vs/editor/common/viewLayout/whitespaceComputer'; -import { LinesLayout } from 'vs/editor/common/viewLayout/linesLayout'; - -suite('Editor ViewLayout - WhitespaceComputer', () => { - - test('WhitespaceComputer', () => { - - const linesLayout = new LinesLayout(100, 20); - - // Insert a whitespace after line number 2, of height 10 - const a = linesLayout.insertWhitespace(2, 0, 10, 0); - // whitespaces: a(2, 10) - assert.equal(linesLayout.getWhitespacesCount(), 1); - assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(0), 2); - assert.equal(linesLayout.getHeightForWhitespaceIndex(0), 10); - assert.equal(linesLayout.getWhitespacesAccumulatedHeight(0), 10); - assert.equal(linesLayout.getWhitespacesTotalHeight(), 10); - assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(1), 0); - assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(2), 0); - assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(3), 10); - assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(4), 10); - - // Insert a whitespace again after line number 2, of height 20 - let b = linesLayout.insertWhitespace(2, 0, 20, 0); - // whitespaces: a(2, 10), b(2, 20) - assert.equal(linesLayout.getWhitespacesCount(), 2); - assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(0), 2); - assert.equal(linesLayout.getHeightForWhitespaceIndex(0), 10); - assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(1), 2); - assert.equal(linesLayout.getHeightForWhitespaceIndex(1), 20); - assert.equal(linesLayout.getWhitespacesAccumulatedHeight(0), 10); - assert.equal(linesLayout.getWhitespacesAccumulatedHeight(1), 30); - assert.equal(linesLayout.getWhitespacesTotalHeight(), 30); - assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(1), 0); - assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(2), 0); - assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(3), 30); - assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(4), 30); - - // Change last inserted whitespace height to 30 - linesLayout.changeWhitespace(b, 2, 30); - // whitespaces: a(2, 10), b(2, 30) - assert.equal(linesLayout.getWhitespacesCount(), 2); - assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(0), 2); - assert.equal(linesLayout.getHeightForWhitespaceIndex(0), 10); - assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(1), 2); - assert.equal(linesLayout.getHeightForWhitespaceIndex(1), 30); - assert.equal(linesLayout.getWhitespacesAccumulatedHeight(0), 10); - assert.equal(linesLayout.getWhitespacesAccumulatedHeight(1), 40); - assert.equal(linesLayout.getWhitespacesTotalHeight(), 40); - assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(1), 0); - assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(2), 0); - assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(3), 40); - assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(4), 40); - - // Remove last inserted whitespace - linesLayout.removeWhitespace(b); - // whitespaces: a(2, 10) - assert.equal(linesLayout.getWhitespacesCount(), 1); - assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(0), 2); - assert.equal(linesLayout.getHeightForWhitespaceIndex(0), 10); - assert.equal(linesLayout.getWhitespacesAccumulatedHeight(0), 10); - assert.equal(linesLayout.getWhitespacesTotalHeight(), 10); - assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(1), 0); - assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(2), 0); - assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(3), 10); - assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(4), 10); - - // Add a whitespace before the first line of height 50 - b = linesLayout.insertWhitespace(0, 0, 50, 0); - // whitespaces: b(0, 50), a(2, 10) - assert.equal(linesLayout.getWhitespacesCount(), 2); - assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(0), 0); - assert.equal(linesLayout.getHeightForWhitespaceIndex(0), 50); - assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(1), 2); - assert.equal(linesLayout.getHeightForWhitespaceIndex(1), 10); - assert.equal(linesLayout.getWhitespacesAccumulatedHeight(0), 50); - assert.equal(linesLayout.getWhitespacesAccumulatedHeight(1), 60); - assert.equal(linesLayout.getWhitespacesTotalHeight(), 60); - assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(1), 50); - assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(2), 50); - assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(3), 60); - assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(4), 60); - - // Add a whitespace after line 4 of height 20 - linesLayout.insertWhitespace(4, 0, 20, 0); - // whitespaces: b(0, 50), a(2, 10), c(4, 20) - assert.equal(linesLayout.getWhitespacesCount(), 3); - assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(0), 0); - assert.equal(linesLayout.getHeightForWhitespaceIndex(0), 50); - assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(1), 2); - assert.equal(linesLayout.getHeightForWhitespaceIndex(1), 10); - assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(2), 4); - assert.equal(linesLayout.getHeightForWhitespaceIndex(2), 20); - assert.equal(linesLayout.getWhitespacesAccumulatedHeight(0), 50); - assert.equal(linesLayout.getWhitespacesAccumulatedHeight(1), 60); - assert.equal(linesLayout.getWhitespacesAccumulatedHeight(2), 80); - assert.equal(linesLayout.getWhitespacesTotalHeight(), 80); - assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(1), 50); - assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(2), 50); - assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(3), 60); - assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(4), 60); - assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(5), 80); - - // Add a whitespace after line 3 of height 30 - linesLayout.insertWhitespace(3, 0, 30, 0); - // whitespaces: b(0, 50), a(2, 10), d(3, 30), c(4, 20) - assert.equal(linesLayout.getWhitespacesCount(), 4); - assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(0), 0); - assert.equal(linesLayout.getHeightForWhitespaceIndex(0), 50); - assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(1), 2); - assert.equal(linesLayout.getHeightForWhitespaceIndex(1), 10); - assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(2), 3); - assert.equal(linesLayout.getHeightForWhitespaceIndex(2), 30); - assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(3), 4); - assert.equal(linesLayout.getHeightForWhitespaceIndex(3), 20); - assert.equal(linesLayout.getWhitespacesAccumulatedHeight(0), 50); - assert.equal(linesLayout.getWhitespacesAccumulatedHeight(1), 60); - assert.equal(linesLayout.getWhitespacesAccumulatedHeight(2), 90); - assert.equal(linesLayout.getWhitespacesAccumulatedHeight(3), 110); - assert.equal(linesLayout.getWhitespacesTotalHeight(), 110); - assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(1), 50); - assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(2), 50); - assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(3), 60); - assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(4), 90); - assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(5), 110); - - // Change whitespace after line 2 to height of 100 - linesLayout.changeWhitespace(a, 2, 100); - // whitespaces: b(0, 50), a(2, 100), d(3, 30), c(4, 20) - assert.equal(linesLayout.getWhitespacesCount(), 4); - assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(0), 0); - assert.equal(linesLayout.getHeightForWhitespaceIndex(0), 50); - assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(1), 2); - assert.equal(linesLayout.getHeightForWhitespaceIndex(1), 100); - assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(2), 3); - assert.equal(linesLayout.getHeightForWhitespaceIndex(2), 30); - assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(3), 4); - assert.equal(linesLayout.getHeightForWhitespaceIndex(3), 20); - assert.equal(linesLayout.getWhitespacesAccumulatedHeight(0), 50); - assert.equal(linesLayout.getWhitespacesAccumulatedHeight(1), 150); - assert.equal(linesLayout.getWhitespacesAccumulatedHeight(2), 180); - assert.equal(linesLayout.getWhitespacesAccumulatedHeight(3), 200); - assert.equal(linesLayout.getWhitespacesTotalHeight(), 200); - assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(1), 50); - assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(2), 50); - assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(3), 150); - assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(4), 180); - assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(5), 200); - - // Remove whitespace after line 2 - linesLayout.removeWhitespace(a); - // whitespaces: b(0, 50), d(3, 30), c(4, 20) - assert.equal(linesLayout.getWhitespacesCount(), 3); - assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(0), 0); - assert.equal(linesLayout.getHeightForWhitespaceIndex(0), 50); - assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(1), 3); - assert.equal(linesLayout.getHeightForWhitespaceIndex(1), 30); - assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(2), 4); - assert.equal(linesLayout.getHeightForWhitespaceIndex(2), 20); - assert.equal(linesLayout.getWhitespacesAccumulatedHeight(0), 50); - assert.equal(linesLayout.getWhitespacesAccumulatedHeight(1), 80); - assert.equal(linesLayout.getWhitespacesAccumulatedHeight(2), 100); - assert.equal(linesLayout.getWhitespacesTotalHeight(), 100); - assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(1), 50); - assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(2), 50); - assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(3), 50); - assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(4), 80); - assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(5), 100); - - // Remove whitespace before line 1 - linesLayout.removeWhitespace(b); - // whitespaces: d(3, 30), c(4, 20) - assert.equal(linesLayout.getWhitespacesCount(), 2); - assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(0), 3); - assert.equal(linesLayout.getHeightForWhitespaceIndex(0), 30); - assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(1), 4); - assert.equal(linesLayout.getHeightForWhitespaceIndex(1), 20); - assert.equal(linesLayout.getWhitespacesAccumulatedHeight(0), 30); - assert.equal(linesLayout.getWhitespacesAccumulatedHeight(1), 50); - assert.equal(linesLayout.getWhitespacesTotalHeight(), 50); - assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(1), 0); - assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(2), 0); - assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(3), 0); - assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(4), 30); - assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(5), 50); - - // Delete line 1 - linesLayout.onLinesDeleted(1, 1); - // whitespaces: d(2, 30), c(3, 20) - assert.equal(linesLayout.getWhitespacesCount(), 2); - assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(0), 2); - assert.equal(linesLayout.getHeightForWhitespaceIndex(0), 30); - assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(1), 3); - assert.equal(linesLayout.getHeightForWhitespaceIndex(1), 20); - assert.equal(linesLayout.getWhitespacesAccumulatedHeight(0), 30); - assert.equal(linesLayout.getWhitespacesAccumulatedHeight(1), 50); - assert.equal(linesLayout.getWhitespacesTotalHeight(), 50); - assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(1), 0); - assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(2), 0); - assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(3), 30); - assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(4), 50); - assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(5), 50); - - // Insert a line before line 1 - linesLayout.onLinesInserted(1, 1); - // whitespaces: d(3, 30), c(4, 20) - assert.equal(linesLayout.getWhitespacesCount(), 2); - assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(0), 3); - assert.equal(linesLayout.getHeightForWhitespaceIndex(0), 30); - assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(1), 4); - assert.equal(linesLayout.getHeightForWhitespaceIndex(1), 20); - assert.equal(linesLayout.getWhitespacesAccumulatedHeight(0), 30); - assert.equal(linesLayout.getWhitespacesAccumulatedHeight(1), 50); - assert.equal(linesLayout.getWhitespacesTotalHeight(), 50); - assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(1), 0); - assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(2), 0); - assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(3), 0); - assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(4), 30); - assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(5), 50); - - // Delete line 4 - linesLayout.onLinesDeleted(4, 4); - // whitespaces: d(3, 30), c(3, 20) - assert.equal(linesLayout.getWhitespacesCount(), 2); - assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(0), 3); - assert.equal(linesLayout.getHeightForWhitespaceIndex(0), 30); - assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(1), 3); - assert.equal(linesLayout.getHeightForWhitespaceIndex(1), 20); - assert.equal(linesLayout.getWhitespacesAccumulatedHeight(0), 30); - assert.equal(linesLayout.getWhitespacesAccumulatedHeight(1), 50); - assert.equal(linesLayout.getWhitespacesTotalHeight(), 50); - assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(1), 0); - assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(2), 0); - assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(3), 0); - assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(4), 50); - assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(5), 50); - }); - - test('WhitespaceComputer findInsertionIndex', () => { - - const makeArray = (size: number, fillValue: number) => { - let r: number[] = []; - for (let i = 0; i < size; i++) { - r[i] = fillValue; - } - return r; - }; - - let arr: number[]; - let ordinals: number[]; - - arr = []; - ordinals = makeArray(arr.length, 0); - assert.equal(WhitespaceComputer.findInsertionIndex(arr, 0, ordinals, 0), 0); - assert.equal(WhitespaceComputer.findInsertionIndex(arr, 1, ordinals, 0), 0); - assert.equal(WhitespaceComputer.findInsertionIndex(arr, 2, ordinals, 0), 0); - - arr = [1]; - ordinals = makeArray(arr.length, 0); - assert.equal(WhitespaceComputer.findInsertionIndex(arr, 0, ordinals, 0), 0); - assert.equal(WhitespaceComputer.findInsertionIndex(arr, 1, ordinals, 0), 1); - assert.equal(WhitespaceComputer.findInsertionIndex(arr, 2, ordinals, 0), 1); - - arr = [1, 3]; - ordinals = makeArray(arr.length, 0); - assert.equal(WhitespaceComputer.findInsertionIndex(arr, 0, ordinals, 0), 0); - assert.equal(WhitespaceComputer.findInsertionIndex(arr, 1, ordinals, 0), 1); - assert.equal(WhitespaceComputer.findInsertionIndex(arr, 2, ordinals, 0), 1); - assert.equal(WhitespaceComputer.findInsertionIndex(arr, 3, ordinals, 0), 2); - assert.equal(WhitespaceComputer.findInsertionIndex(arr, 4, ordinals, 0), 2); - - arr = [1, 3, 5]; - ordinals = makeArray(arr.length, 0); - assert.equal(WhitespaceComputer.findInsertionIndex(arr, 0, ordinals, 0), 0); - assert.equal(WhitespaceComputer.findInsertionIndex(arr, 1, ordinals, 0), 1); - assert.equal(WhitespaceComputer.findInsertionIndex(arr, 2, ordinals, 0), 1); - assert.equal(WhitespaceComputer.findInsertionIndex(arr, 3, ordinals, 0), 2); - assert.equal(WhitespaceComputer.findInsertionIndex(arr, 4, ordinals, 0), 2); - assert.equal(WhitespaceComputer.findInsertionIndex(arr, 5, ordinals, 0), 3); - assert.equal(WhitespaceComputer.findInsertionIndex(arr, 6, ordinals, 0), 3); - - arr = [1, 3, 5]; - ordinals = makeArray(arr.length, 3); - assert.equal(WhitespaceComputer.findInsertionIndex(arr, 0, ordinals, 0), 0); - assert.equal(WhitespaceComputer.findInsertionIndex(arr, 1, ordinals, 0), 0); - assert.equal(WhitespaceComputer.findInsertionIndex(arr, 2, ordinals, 0), 1); - assert.equal(WhitespaceComputer.findInsertionIndex(arr, 3, ordinals, 0), 1); - assert.equal(WhitespaceComputer.findInsertionIndex(arr, 4, ordinals, 0), 2); - assert.equal(WhitespaceComputer.findInsertionIndex(arr, 5, ordinals, 0), 2); - assert.equal(WhitespaceComputer.findInsertionIndex(arr, 6, ordinals, 0), 3); - - arr = [1, 3, 5, 7]; - ordinals = makeArray(arr.length, 0); - assert.equal(WhitespaceComputer.findInsertionIndex(arr, 0, ordinals, 0), 0); - assert.equal(WhitespaceComputer.findInsertionIndex(arr, 1, ordinals, 0), 1); - assert.equal(WhitespaceComputer.findInsertionIndex(arr, 2, ordinals, 0), 1); - assert.equal(WhitespaceComputer.findInsertionIndex(arr, 3, ordinals, 0), 2); - assert.equal(WhitespaceComputer.findInsertionIndex(arr, 4, ordinals, 0), 2); - assert.equal(WhitespaceComputer.findInsertionIndex(arr, 5, ordinals, 0), 3); - assert.equal(WhitespaceComputer.findInsertionIndex(arr, 6, ordinals, 0), 3); - assert.equal(WhitespaceComputer.findInsertionIndex(arr, 7, ordinals, 0), 4); - assert.equal(WhitespaceComputer.findInsertionIndex(arr, 8, ordinals, 0), 4); - - arr = [1, 3, 5, 7, 9]; - ordinals = makeArray(arr.length, 0); - assert.equal(WhitespaceComputer.findInsertionIndex(arr, 0, ordinals, 0), 0); - assert.equal(WhitespaceComputer.findInsertionIndex(arr, 1, ordinals, 0), 1); - assert.equal(WhitespaceComputer.findInsertionIndex(arr, 2, ordinals, 0), 1); - assert.equal(WhitespaceComputer.findInsertionIndex(arr, 3, ordinals, 0), 2); - assert.equal(WhitespaceComputer.findInsertionIndex(arr, 4, ordinals, 0), 2); - assert.equal(WhitespaceComputer.findInsertionIndex(arr, 5, ordinals, 0), 3); - assert.equal(WhitespaceComputer.findInsertionIndex(arr, 6, ordinals, 0), 3); - assert.equal(WhitespaceComputer.findInsertionIndex(arr, 7, ordinals, 0), 4); - assert.equal(WhitespaceComputer.findInsertionIndex(arr, 8, ordinals, 0), 4); - assert.equal(WhitespaceComputer.findInsertionIndex(arr, 9, ordinals, 0), 5); - assert.equal(WhitespaceComputer.findInsertionIndex(arr, 10, ordinals, 0), 5); - - arr = [1, 3, 5, 7, 9, 11]; - ordinals = makeArray(arr.length, 0); - assert.equal(WhitespaceComputer.findInsertionIndex(arr, 0, ordinals, 0), 0); - assert.equal(WhitespaceComputer.findInsertionIndex(arr, 1, ordinals, 0), 1); - assert.equal(WhitespaceComputer.findInsertionIndex(arr, 2, ordinals, 0), 1); - assert.equal(WhitespaceComputer.findInsertionIndex(arr, 3, ordinals, 0), 2); - assert.equal(WhitespaceComputer.findInsertionIndex(arr, 4, ordinals, 0), 2); - assert.equal(WhitespaceComputer.findInsertionIndex(arr, 5, ordinals, 0), 3); - assert.equal(WhitespaceComputer.findInsertionIndex(arr, 6, ordinals, 0), 3); - assert.equal(WhitespaceComputer.findInsertionIndex(arr, 7, ordinals, 0), 4); - assert.equal(WhitespaceComputer.findInsertionIndex(arr, 8, ordinals, 0), 4); - assert.equal(WhitespaceComputer.findInsertionIndex(arr, 9, ordinals, 0), 5); - assert.equal(WhitespaceComputer.findInsertionIndex(arr, 10, ordinals, 0), 5); - assert.equal(WhitespaceComputer.findInsertionIndex(arr, 11, ordinals, 0), 6); - assert.equal(WhitespaceComputer.findInsertionIndex(arr, 12, ordinals, 0), 6); - - arr = [1, 3, 5, 7, 9, 11, 13]; - ordinals = makeArray(arr.length, 0); - assert.equal(WhitespaceComputer.findInsertionIndex(arr, 0, ordinals, 0), 0); - assert.equal(WhitespaceComputer.findInsertionIndex(arr, 1, ordinals, 0), 1); - assert.equal(WhitespaceComputer.findInsertionIndex(arr, 2, ordinals, 0), 1); - assert.equal(WhitespaceComputer.findInsertionIndex(arr, 3, ordinals, 0), 2); - assert.equal(WhitespaceComputer.findInsertionIndex(arr, 4, ordinals, 0), 2); - assert.equal(WhitespaceComputer.findInsertionIndex(arr, 5, ordinals, 0), 3); - assert.equal(WhitespaceComputer.findInsertionIndex(arr, 6, ordinals, 0), 3); - assert.equal(WhitespaceComputer.findInsertionIndex(arr, 7, ordinals, 0), 4); - assert.equal(WhitespaceComputer.findInsertionIndex(arr, 8, ordinals, 0), 4); - assert.equal(WhitespaceComputer.findInsertionIndex(arr, 9, ordinals, 0), 5); - assert.equal(WhitespaceComputer.findInsertionIndex(arr, 10, ordinals, 0), 5); - assert.equal(WhitespaceComputer.findInsertionIndex(arr, 11, ordinals, 0), 6); - assert.equal(WhitespaceComputer.findInsertionIndex(arr, 12, ordinals, 0), 6); - assert.equal(WhitespaceComputer.findInsertionIndex(arr, 13, ordinals, 0), 7); - assert.equal(WhitespaceComputer.findInsertionIndex(arr, 14, ordinals, 0), 7); - - arr = [1, 3, 5, 7, 9, 11, 13, 15]; - ordinals = makeArray(arr.length, 0); - assert.equal(WhitespaceComputer.findInsertionIndex(arr, 0, ordinals, 0), 0); - assert.equal(WhitespaceComputer.findInsertionIndex(arr, 1, ordinals, 0), 1); - assert.equal(WhitespaceComputer.findInsertionIndex(arr, 2, ordinals, 0), 1); - assert.equal(WhitespaceComputer.findInsertionIndex(arr, 3, ordinals, 0), 2); - assert.equal(WhitespaceComputer.findInsertionIndex(arr, 4, ordinals, 0), 2); - assert.equal(WhitespaceComputer.findInsertionIndex(arr, 5, ordinals, 0), 3); - assert.equal(WhitespaceComputer.findInsertionIndex(arr, 6, ordinals, 0), 3); - assert.equal(WhitespaceComputer.findInsertionIndex(arr, 7, ordinals, 0), 4); - assert.equal(WhitespaceComputer.findInsertionIndex(arr, 8, ordinals, 0), 4); - assert.equal(WhitespaceComputer.findInsertionIndex(arr, 9, ordinals, 0), 5); - assert.equal(WhitespaceComputer.findInsertionIndex(arr, 10, ordinals, 0), 5); - assert.equal(WhitespaceComputer.findInsertionIndex(arr, 11, ordinals, 0), 6); - assert.equal(WhitespaceComputer.findInsertionIndex(arr, 12, ordinals, 0), 6); - assert.equal(WhitespaceComputer.findInsertionIndex(arr, 13, ordinals, 0), 7); - assert.equal(WhitespaceComputer.findInsertionIndex(arr, 14, ordinals, 0), 7); - assert.equal(WhitespaceComputer.findInsertionIndex(arr, 15, ordinals, 0), 8); - assert.equal(WhitespaceComputer.findInsertionIndex(arr, 16, ordinals, 0), 8); - }); - - test('WhitespaceComputer changeWhitespaceAfterLineNumber & getFirstWhitespaceIndexAfterLineNumber', () => { - const linesLayout = new LinesLayout(100, 20); - - const a = linesLayout.insertWhitespace(0, 0, 1, 0); - const b = linesLayout.insertWhitespace(7, 0, 1, 0); - const c = linesLayout.insertWhitespace(3, 0, 1, 0); - - assert.equal(linesLayout.getIdForWhitespaceIndex(0), a); // 0 - assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(0), 0); - assert.equal(linesLayout.getIdForWhitespaceIndex(1), c); // 3 - assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(1), 3); - assert.equal(linesLayout.getIdForWhitespaceIndex(2), b); // 7 - assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(2), 7); - - assert.equal(linesLayout.getFirstWhitespaceIndexAfterLineNumber(1), 1); // c - assert.equal(linesLayout.getFirstWhitespaceIndexAfterLineNumber(2), 1); // c - assert.equal(linesLayout.getFirstWhitespaceIndexAfterLineNumber(3), 1); // c - assert.equal(linesLayout.getFirstWhitespaceIndexAfterLineNumber(4), 2); // b - assert.equal(linesLayout.getFirstWhitespaceIndexAfterLineNumber(5), 2); // b - assert.equal(linesLayout.getFirstWhitespaceIndexAfterLineNumber(6), 2); // b - assert.equal(linesLayout.getFirstWhitespaceIndexAfterLineNumber(7), 2); // b - assert.equal(linesLayout.getFirstWhitespaceIndexAfterLineNumber(8), -1); // -- - - // Do not really move a - linesLayout.changeWhitespace(a, 1, 1); - - assert.equal(linesLayout.getIdForWhitespaceIndex(0), a); // 1 - assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(0), 1); - assert.equal(linesLayout.getIdForWhitespaceIndex(1), c); // 3 - assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(1), 3); - assert.equal(linesLayout.getIdForWhitespaceIndex(2), b); // 7 - assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(2), 7); - - assert.equal(linesLayout.getFirstWhitespaceIndexAfterLineNumber(1), 0); // a - assert.equal(linesLayout.getFirstWhitespaceIndexAfterLineNumber(2), 1); // c - assert.equal(linesLayout.getFirstWhitespaceIndexAfterLineNumber(3), 1); // c - assert.equal(linesLayout.getFirstWhitespaceIndexAfterLineNumber(4), 2); // b - assert.equal(linesLayout.getFirstWhitespaceIndexAfterLineNumber(5), 2); // b - assert.equal(linesLayout.getFirstWhitespaceIndexAfterLineNumber(6), 2); // b - assert.equal(linesLayout.getFirstWhitespaceIndexAfterLineNumber(7), 2); // b - assert.equal(linesLayout.getFirstWhitespaceIndexAfterLineNumber(8), -1); // -- - - - // Do not really move a - linesLayout.changeWhitespace(a, 2, 1); - - assert.equal(linesLayout.getIdForWhitespaceIndex(0), a); // 2 - assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(0), 2); - assert.equal(linesLayout.getIdForWhitespaceIndex(1), c); // 3 - assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(1), 3); - assert.equal(linesLayout.getIdForWhitespaceIndex(2), b); // 7 - assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(2), 7); - - assert.equal(linesLayout.getFirstWhitespaceIndexAfterLineNumber(1), 0); // a - assert.equal(linesLayout.getFirstWhitespaceIndexAfterLineNumber(2), 0); // a - assert.equal(linesLayout.getFirstWhitespaceIndexAfterLineNumber(3), 1); // c - assert.equal(linesLayout.getFirstWhitespaceIndexAfterLineNumber(4), 2); // b - assert.equal(linesLayout.getFirstWhitespaceIndexAfterLineNumber(5), 2); // b - assert.equal(linesLayout.getFirstWhitespaceIndexAfterLineNumber(6), 2); // b - assert.equal(linesLayout.getFirstWhitespaceIndexAfterLineNumber(7), 2); // b - assert.equal(linesLayout.getFirstWhitespaceIndexAfterLineNumber(8), -1); // -- - - - // Change a to conflict with c => a gets placed after c - linesLayout.changeWhitespace(a, 3, 1); - - assert.equal(linesLayout.getIdForWhitespaceIndex(0), c); // 3 - assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(0), 3); - assert.equal(linesLayout.getIdForWhitespaceIndex(1), a); // 3 - assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(1), 3); - assert.equal(linesLayout.getIdForWhitespaceIndex(2), b); // 7 - assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(2), 7); - - assert.equal(linesLayout.getFirstWhitespaceIndexAfterLineNumber(1), 0); // c - assert.equal(linesLayout.getFirstWhitespaceIndexAfterLineNumber(2), 0); // c - assert.equal(linesLayout.getFirstWhitespaceIndexAfterLineNumber(3), 0); // c - assert.equal(linesLayout.getFirstWhitespaceIndexAfterLineNumber(4), 2); // b - assert.equal(linesLayout.getFirstWhitespaceIndexAfterLineNumber(5), 2); // b - assert.equal(linesLayout.getFirstWhitespaceIndexAfterLineNumber(6), 2); // b - assert.equal(linesLayout.getFirstWhitespaceIndexAfterLineNumber(7), 2); // b - assert.equal(linesLayout.getFirstWhitespaceIndexAfterLineNumber(8), -1); // -- - - - // Make a no-op - linesLayout.changeWhitespace(c, 3, 1); - - assert.equal(linesLayout.getIdForWhitespaceIndex(0), c); // 3 - assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(0), 3); - assert.equal(linesLayout.getIdForWhitespaceIndex(1), a); // 3 - assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(1), 3); - assert.equal(linesLayout.getIdForWhitespaceIndex(2), b); // 7 - assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(2), 7); - - assert.equal(linesLayout.getFirstWhitespaceIndexAfterLineNumber(1), 0); // c - assert.equal(linesLayout.getFirstWhitespaceIndexAfterLineNumber(2), 0); // c - assert.equal(linesLayout.getFirstWhitespaceIndexAfterLineNumber(3), 0); // c - assert.equal(linesLayout.getFirstWhitespaceIndexAfterLineNumber(4), 2); // b - assert.equal(linesLayout.getFirstWhitespaceIndexAfterLineNumber(5), 2); // b - assert.equal(linesLayout.getFirstWhitespaceIndexAfterLineNumber(6), 2); // b - assert.equal(linesLayout.getFirstWhitespaceIndexAfterLineNumber(7), 2); // b - assert.equal(linesLayout.getFirstWhitespaceIndexAfterLineNumber(8), -1); // -- - - - - // Conflict c with b => c gets placed after b - linesLayout.changeWhitespace(c, 7, 1); - - assert.equal(linesLayout.getIdForWhitespaceIndex(0), a); // 3 - assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(0), 3); - assert.equal(linesLayout.getIdForWhitespaceIndex(1), b); // 7 - assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(1), 7); - assert.equal(linesLayout.getIdForWhitespaceIndex(2), c); // 7 - assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(2), 7); - - assert.equal(linesLayout.getFirstWhitespaceIndexAfterLineNumber(1), 0); // a - assert.equal(linesLayout.getFirstWhitespaceIndexAfterLineNumber(2), 0); // a - assert.equal(linesLayout.getFirstWhitespaceIndexAfterLineNumber(3), 0); // a - assert.equal(linesLayout.getFirstWhitespaceIndexAfterLineNumber(4), 1); // b - assert.equal(linesLayout.getFirstWhitespaceIndexAfterLineNumber(5), 1); // b - assert.equal(linesLayout.getFirstWhitespaceIndexAfterLineNumber(6), 1); // b - assert.equal(linesLayout.getFirstWhitespaceIndexAfterLineNumber(7), 1); // b - assert.equal(linesLayout.getFirstWhitespaceIndexAfterLineNumber(8), -1); // -- - }); - - - test('WhitespaceComputer Bug', () => { - const linesLayout = new LinesLayout(100, 20); - - const a = linesLayout.insertWhitespace(0, 0, 1, 0); - const b = linesLayout.insertWhitespace(7, 0, 1, 0); - - assert.equal(linesLayout.getIdForWhitespaceIndex(0), a); // 0 - assert.equal(linesLayout.getIdForWhitespaceIndex(1), b); // 7 - - const c = linesLayout.insertWhitespace(3, 0, 1, 0); - - assert.equal(linesLayout.getIdForWhitespaceIndex(0), a); // 0 - assert.equal(linesLayout.getIdForWhitespaceIndex(1), c); // 3 - assert.equal(linesLayout.getIdForWhitespaceIndex(2), b); // 7 - - const d = linesLayout.insertWhitespace(2, 0, 1, 0); - assert.equal(linesLayout.getIdForWhitespaceIndex(0), a); // 0 - assert.equal(linesLayout.getIdForWhitespaceIndex(1), d); // 2 - assert.equal(linesLayout.getIdForWhitespaceIndex(2), c); // 3 - assert.equal(linesLayout.getIdForWhitespaceIndex(3), b); // 7 - - const e = linesLayout.insertWhitespace(8, 0, 1, 0); - assert.equal(linesLayout.getIdForWhitespaceIndex(0), a); // 0 - assert.equal(linesLayout.getIdForWhitespaceIndex(1), d); // 2 - assert.equal(linesLayout.getIdForWhitespaceIndex(2), c); // 3 - assert.equal(linesLayout.getIdForWhitespaceIndex(3), b); // 7 - assert.equal(linesLayout.getIdForWhitespaceIndex(4), e); // 8 - - const f = linesLayout.insertWhitespace(11, 0, 1, 0); - assert.equal(linesLayout.getIdForWhitespaceIndex(0), a); // 0 - assert.equal(linesLayout.getIdForWhitespaceIndex(1), d); // 2 - assert.equal(linesLayout.getIdForWhitespaceIndex(2), c); // 3 - assert.equal(linesLayout.getIdForWhitespaceIndex(3), b); // 7 - assert.equal(linesLayout.getIdForWhitespaceIndex(4), e); // 8 - assert.equal(linesLayout.getIdForWhitespaceIndex(5), f); // 11 - - const g = linesLayout.insertWhitespace(10, 0, 1, 0); - assert.equal(linesLayout.getIdForWhitespaceIndex(0), a); // 0 - assert.equal(linesLayout.getIdForWhitespaceIndex(1), d); // 2 - assert.equal(linesLayout.getIdForWhitespaceIndex(2), c); // 3 - assert.equal(linesLayout.getIdForWhitespaceIndex(3), b); // 7 - assert.equal(linesLayout.getIdForWhitespaceIndex(4), e); // 8 - assert.equal(linesLayout.getIdForWhitespaceIndex(5), g); // 10 - assert.equal(linesLayout.getIdForWhitespaceIndex(6), f); // 11 - - const h = linesLayout.insertWhitespace(0, 0, 1, 0); - assert.equal(linesLayout.getIdForWhitespaceIndex(0), a); // 0 - assert.equal(linesLayout.getIdForWhitespaceIndex(1), h); // 0 - assert.equal(linesLayout.getIdForWhitespaceIndex(2), d); // 2 - assert.equal(linesLayout.getIdForWhitespaceIndex(3), c); // 3 - assert.equal(linesLayout.getIdForWhitespaceIndex(4), b); // 7 - assert.equal(linesLayout.getIdForWhitespaceIndex(5), e); // 8 - assert.equal(linesLayout.getIdForWhitespaceIndex(6), g); // 10 - assert.equal(linesLayout.getIdForWhitespaceIndex(7), f); // 11 - }); -}); - From e80c62bdcb0a1d7ce0d3d826241df0ef20162417 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Fri, 15 Nov 2019 10:53:04 +0100 Subject: [PATCH 319/352] allow $openUri to accept URI and string --- src/vs/workbench/api/browser/mainThreadWindow.ts | 12 ++++++++++-- src/vs/workbench/api/common/extHost.protocol.ts | 2 +- .../api/common/extHostRequireInterceptor.ts | 4 ++-- src/vs/workbench/api/common/extHostWindow.ts | 4 +++- 4 files changed, 16 insertions(+), 6 deletions(-) diff --git a/src/vs/workbench/api/browser/mainThreadWindow.ts b/src/vs/workbench/api/browser/mainThreadWindow.ts index bbce19a33881d..2a431111e936d 100644 --- a/src/vs/workbench/api/browser/mainThreadWindow.ts +++ b/src/vs/workbench/api/browser/mainThreadWindow.ts @@ -42,9 +42,17 @@ export class MainThreadWindow implements MainThreadWindowShape { return Promise.resolve(this.hostService.hasFocus); } - async $openUri(uriComponents: UriComponents, options: IOpenUriOptions): Promise { + async $openUri(uriComponents: UriComponents, uriString: string | undefined, options: IOpenUriOptions): Promise { const uri = URI.from(uriComponents); - return this.openerService.open(uri, { openExternal: true, allowTunneling: options.allowTunneling }); + let target: URI | string; + if (uriString && URI.parse(uriString).toString() === uri.toString()) { + // called with string and no transformation happened -> keep string + target = uriString; + } else { + // called with URI or transformed -> use uri + target = uri; + } + return this.openerService.open(target, { openExternal: true, allowTunneling: options.allowTunneling }); } async $asExternalUri(uriComponents: UriComponents, options: IOpenUriOptions): Promise { diff --git a/src/vs/workbench/api/common/extHost.protocol.ts b/src/vs/workbench/api/common/extHost.protocol.ts index 9bc433a17277d..5df456ab6c7e1 100644 --- a/src/vs/workbench/api/common/extHost.protocol.ts +++ b/src/vs/workbench/api/common/extHost.protocol.ts @@ -759,7 +759,7 @@ export interface IOpenUriOptions { export interface MainThreadWindowShape extends IDisposable { $getWindowVisibility(): Promise; - $openUri(uri: UriComponents, options: IOpenUriOptions): Promise; + $openUri(uri: UriComponents, uriString: string | undefined, options: IOpenUriOptions): Promise; $asExternalUri(uri: UriComponents, options: IOpenUriOptions): Promise; } diff --git a/src/vs/workbench/api/common/extHostRequireInterceptor.ts b/src/vs/workbench/api/common/extHostRequireInterceptor.ts index b6f94048fbd3b..c06e86c83051c 100644 --- a/src/vs/workbench/api/common/extHostRequireInterceptor.ts +++ b/src/vs/workbench/api/common/extHostRequireInterceptor.ts @@ -245,9 +245,9 @@ class OpenNodeModuleFactory implements INodeModuleFactory { return this.callOriginal(target, options); } if (uri.scheme === 'http' || uri.scheme === 'https') { - return mainThreadWindow.$openUri(uri, { allowTunneling: true }); + return mainThreadWindow.$openUri(uri, target, { allowTunneling: true }); } else if (uri.scheme === 'mailto' || uri.scheme === this._appUriScheme) { - return mainThreadWindow.$openUri(uri, {}); + return mainThreadWindow.$openUri(uri, target, {}); } return this.callOriginal(target, options); }; diff --git a/src/vs/workbench/api/common/extHostWindow.ts b/src/vs/workbench/api/common/extHostWindow.ts index 8ce82ac8b2dcb..f8c5d5fa3d782 100644 --- a/src/vs/workbench/api/common/extHostWindow.ts +++ b/src/vs/workbench/api/common/extHostWindow.ts @@ -39,7 +39,9 @@ export class ExtHostWindow implements ExtHostWindowShape { } openUri(stringOrUri: string | URI, options: IOpenUriOptions): Promise { + let uriAsString: string | undefined; if (typeof stringOrUri === 'string') { + uriAsString = stringOrUri; try { stringOrUri = URI.parse(stringOrUri); } catch (e) { @@ -51,7 +53,7 @@ export class ExtHostWindow implements ExtHostWindowShape { } else if (stringOrUri.scheme === Schemas.command) { return Promise.reject(`Invalid scheme '${stringOrUri.scheme}'`); } - return this._proxy.$openUri(stringOrUri, options); + return this._proxy.$openUri(stringOrUri, uriAsString, options); } async asExternalUri(uri: URI, options: IOpenUriOptions): Promise { From 6b41d230d0a90596ba2a85f5d636fab890cff32f Mon Sep 17 00:00:00 2001 From: Alexandru Dima Date: Fri, 15 Nov 2019 10:57:11 +0100 Subject: [PATCH 320/352] :lipstick: --- src/vs/editor/browser/editorBrowser.ts | 4 +- .../editor/browser/widget/codeEditorWidget.ts | 4 +- .../editor/browser/widget/diffEditorWidget.ts | 30 ++-- .../editor/common/viewLayout/linesLayout.ts | 131 +++++++++--------- src/vs/editor/common/viewLayout/viewLayout.ts | 4 +- src/vs/editor/common/viewModel/viewModel.ts | 4 +- 6 files changed, 87 insertions(+), 90 deletions(-) diff --git a/src/vs/editor/browser/editorBrowser.ts b/src/vs/editor/browser/editorBrowser.ts index bcd0995f8430c..26b562f400fe4 100644 --- a/src/vs/editor/browser/editorBrowser.ts +++ b/src/vs/editor/browser/editorBrowser.ts @@ -16,7 +16,7 @@ import * as editorCommon from 'vs/editor/common/editorCommon'; import { IIdentifiedSingleEditOperation, IModelDecoration, IModelDeltaDecoration, ITextModel, ICursorStateComputer } from 'vs/editor/common/model'; import { IModelContentChangedEvent, IModelDecorationsChangedEvent, IModelLanguageChangedEvent, IModelLanguageConfigurationChangedEvent, IModelOptionsChangedEvent } from 'vs/editor/common/model/textModelEvents'; import { OverviewRulerZone } from 'vs/editor/common/view/overviewZoneManager'; -import { IEditorWhitespace } from 'vs/editor/common/viewLayout/linesLayout'; +import { EditorWhitespace } from 'vs/editor/common/viewLayout/linesLayout'; import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { IDiffComputationResult } from 'vs/editor/common/services/editorWorkerService'; @@ -672,7 +672,7 @@ export interface ICodeEditor extends editorCommon.IEditor { * Get the view zones. * @internal */ - getWhitespaces(): IEditorWhitespace[]; + getWhitespaces(): EditorWhitespace[]; /** * Get the vertical position (top offset) for the line w.r.t. to the first line. diff --git a/src/vs/editor/browser/widget/codeEditorWidget.ts b/src/vs/editor/browser/widget/codeEditorWidget.ts index 357eeab2a9f22..348487009ef2a 100644 --- a/src/vs/editor/browser/widget/codeEditorWidget.ts +++ b/src/vs/editor/browser/widget/codeEditorWidget.ts @@ -40,7 +40,7 @@ import * as modes from 'vs/editor/common/modes'; import { editorUnnecessaryCodeBorder, editorUnnecessaryCodeOpacity } from 'vs/editor/common/view/editorColorRegistry'; import { editorErrorBorder, editorErrorForeground, editorHintBorder, editorHintForeground, editorInfoBorder, editorInfoForeground, editorWarningBorder, editorWarningForeground, editorForeground } from 'vs/platform/theme/common/colorRegistry'; import { VerticalRevealType } from 'vs/editor/common/view/viewEvents'; -import { IEditorWhitespace } from 'vs/editor/common/viewLayout/linesLayout'; +import { EditorWhitespace } from 'vs/editor/common/viewLayout/linesLayout'; import { ViewModel } from 'vs/editor/common/viewModel/viewModelImpl'; import { ICommandService } from 'vs/platform/commands/common/commands'; import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; @@ -451,7 +451,7 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE return this._modelData.viewModel.getVisibleRanges(); } - public getWhitespaces(): IEditorWhitespace[] { + public getWhitespaces(): EditorWhitespace[] { if (!this._modelData) { return []; } diff --git a/src/vs/editor/browser/widget/diffEditorWidget.ts b/src/vs/editor/browser/widget/diffEditorWidget.ts index e03249c867a6c..d97ef2e6f1945 100644 --- a/src/vs/editor/browser/widget/diffEditorWidget.ts +++ b/src/vs/editor/browser/widget/diffEditorWidget.ts @@ -32,7 +32,7 @@ import { IDiffComputationResult, IEditorWorkerService } from 'vs/editor/common/s import { OverviewRulerZone } from 'vs/editor/common/view/overviewZoneManager'; import { LineDecoration } from 'vs/editor/common/viewLayout/lineDecorations'; import { RenderLineInput, renderViewLine } from 'vs/editor/common/viewLayout/viewLineRenderer'; -import { IEditorWhitespace } from 'vs/editor/common/viewLayout/linesLayout'; +import { EditorWhitespace } from 'vs/editor/common/viewLayout/linesLayout'; import { InlineDecoration, InlineDecorationType, ViewLineRenderingData } from 'vs/editor/common/viewModel/viewModel'; import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; @@ -68,7 +68,7 @@ interface IEditorsZones { } interface IDiffEditorWidgetStyle { - getEditorsDiffDecorations(lineChanges: editorCommon.ILineChange[], ignoreTrimWhitespace: boolean, renderIndicators: boolean, originalWhitespaces: IEditorWhitespace[], modifiedWhitespaces: IEditorWhitespace[], originalEditor: editorBrowser.ICodeEditor, modifiedEditor: editorBrowser.ICodeEditor): IEditorsDiffDecorationsWithZones; + getEditorsDiffDecorations(lineChanges: editorCommon.ILineChange[], ignoreTrimWhitespace: boolean, renderIndicators: boolean, originalWhitespaces: EditorWhitespace[], modifiedWhitespaces: EditorWhitespace[], originalEditor: editorBrowser.ICodeEditor, modifiedEditor: editorBrowser.ICodeEditor): IEditorsDiffDecorationsWithZones; setEnableSplitViewResizing(enableSplitViewResizing: boolean): void; applyColors(theme: ITheme): boolean; layout(): number; @@ -91,7 +91,7 @@ class VisualEditorState { this._decorations = []; } - public getForeignViewZones(allViewZones: IEditorWhitespace[]): IEditorWhitespace[] { + public getForeignViewZones(allViewZones: EditorWhitespace[]): EditorWhitespace[] { return allViewZones.filter((z) => !this._zonesMap[String(z.id)]); } @@ -1303,7 +1303,7 @@ abstract class DiffEditorWidgetStyle extends Disposable implements IDiffEditorWi return hasChanges; } - public getEditorsDiffDecorations(lineChanges: editorCommon.ILineChange[], ignoreTrimWhitespace: boolean, renderIndicators: boolean, originalWhitespaces: IEditorWhitespace[], modifiedWhitespaces: IEditorWhitespace[], originalEditor: editorBrowser.ICodeEditor, modifiedEditor: editorBrowser.ICodeEditor): IEditorsDiffDecorationsWithZones { + public getEditorsDiffDecorations(lineChanges: editorCommon.ILineChange[], ignoreTrimWhitespace: boolean, renderIndicators: boolean, originalWhitespaces: EditorWhitespace[], modifiedWhitespaces: EditorWhitespace[], originalEditor: editorBrowser.ICodeEditor, modifiedEditor: editorBrowser.ICodeEditor): IEditorsDiffDecorationsWithZones { // Get view zones modifiedWhitespaces = modifiedWhitespaces.sort((a, b) => { return a.afterLineNumber - b.afterLineNumber; @@ -1331,7 +1331,7 @@ abstract class DiffEditorWidgetStyle extends Disposable implements IDiffEditorWi }; } - protected abstract _getViewZones(lineChanges: editorCommon.ILineChange[], originalForeignVZ: IEditorWhitespace[], modifiedForeignVZ: IEditorWhitespace[], originalEditor: editorBrowser.ICodeEditor, modifiedEditor: editorBrowser.ICodeEditor, renderIndicators: boolean): IEditorsZones; + protected abstract _getViewZones(lineChanges: editorCommon.ILineChange[], originalForeignVZ: EditorWhitespace[], modifiedForeignVZ: EditorWhitespace[], originalEditor: editorBrowser.ICodeEditor, modifiedEditor: editorBrowser.ICodeEditor, renderIndicators: boolean): IEditorsZones; protected abstract _getOriginalEditorDecorations(lineChanges: editorCommon.ILineChange[], ignoreTrimWhitespace: boolean, renderIndicators: boolean, originalEditor: editorBrowser.ICodeEditor, modifiedEditor: editorBrowser.ICodeEditor): IEditorDiffDecorations; protected abstract _getModifiedEditorDecorations(lineChanges: editorCommon.ILineChange[], ignoreTrimWhitespace: boolean, renderIndicators: boolean, originalEditor: editorBrowser.ICodeEditor, modifiedEditor: editorBrowser.ICodeEditor): IEditorDiffDecorations; @@ -1352,10 +1352,10 @@ interface IMyViewZone { class ForeignViewZonesIterator { private _index: number; - private readonly _source: IEditorWhitespace[]; - public current: IEditorWhitespace | null; + private readonly _source: EditorWhitespace[]; + public current: EditorWhitespace | null; - constructor(source: IEditorWhitespace[]) { + constructor(source: EditorWhitespace[]) { this._source = source; this._index = -1; this.current = null; @@ -1375,10 +1375,10 @@ class ForeignViewZonesIterator { abstract class ViewZonesComputer { private readonly lineChanges: editorCommon.ILineChange[]; - private readonly originalForeignVZ: IEditorWhitespace[]; - private readonly modifiedForeignVZ: IEditorWhitespace[]; + private readonly originalForeignVZ: EditorWhitespace[]; + private readonly modifiedForeignVZ: EditorWhitespace[]; - constructor(lineChanges: editorCommon.ILineChange[], originalForeignVZ: IEditorWhitespace[], modifiedForeignVZ: IEditorWhitespace[]) { + constructor(lineChanges: editorCommon.ILineChange[], originalForeignVZ: EditorWhitespace[], modifiedForeignVZ: EditorWhitespace[]) { this.lineChanges = lineChanges; this.originalForeignVZ = originalForeignVZ; this.modifiedForeignVZ = modifiedForeignVZ; @@ -1731,7 +1731,7 @@ class DiffEditorWidgetSideBySide extends DiffEditorWidgetStyle implements IDiffE return this._dataSource.getHeight(); } - protected _getViewZones(lineChanges: editorCommon.ILineChange[], originalForeignVZ: IEditorWhitespace[], modifiedForeignVZ: IEditorWhitespace[], originalEditor: editorBrowser.ICodeEditor, modifiedEditor: editorBrowser.ICodeEditor): IEditorsZones { + protected _getViewZones(lineChanges: editorCommon.ILineChange[], originalForeignVZ: EditorWhitespace[], modifiedForeignVZ: EditorWhitespace[], originalEditor: editorBrowser.ICodeEditor, modifiedEditor: editorBrowser.ICodeEditor): IEditorsZones { let c = new SideBySideViewZonesComputer(lineChanges, originalForeignVZ, modifiedForeignVZ); return c.getViewZones(); } @@ -1859,7 +1859,7 @@ class DiffEditorWidgetSideBySide extends DiffEditorWidgetStyle implements IDiffE class SideBySideViewZonesComputer extends ViewZonesComputer { - constructor(lineChanges: editorCommon.ILineChange[], originalForeignVZ: IEditorWhitespace[], modifiedForeignVZ: IEditorWhitespace[]) { + constructor(lineChanges: editorCommon.ILineChange[], originalForeignVZ: EditorWhitespace[], modifiedForeignVZ: EditorWhitespace[]) { super(lineChanges, originalForeignVZ, modifiedForeignVZ); } @@ -1911,7 +1911,7 @@ class DiffEditorWidgetInline extends DiffEditorWidgetStyle implements IDiffEdito // Nothing to do.. } - protected _getViewZones(lineChanges: editorCommon.ILineChange[], originalForeignVZ: IEditorWhitespace[], modifiedForeignVZ: IEditorWhitespace[], originalEditor: editorBrowser.ICodeEditor, modifiedEditor: editorBrowser.ICodeEditor, renderIndicators: boolean): IEditorsZones { + protected _getViewZones(lineChanges: editorCommon.ILineChange[], originalForeignVZ: EditorWhitespace[], modifiedForeignVZ: EditorWhitespace[], originalEditor: editorBrowser.ICodeEditor, modifiedEditor: editorBrowser.ICodeEditor, renderIndicators: boolean): IEditorsZones { let computer = new InlineViewZonesComputer(lineChanges, originalForeignVZ, modifiedForeignVZ, originalEditor, modifiedEditor, renderIndicators); return computer.getViewZones(); } @@ -2019,7 +2019,7 @@ class InlineViewZonesComputer extends ViewZonesComputer { private readonly modifiedEditorTabSize: number; private readonly renderIndicators: boolean; - constructor(lineChanges: editorCommon.ILineChange[], originalForeignVZ: IEditorWhitespace[], modifiedForeignVZ: IEditorWhitespace[], originalEditor: editorBrowser.ICodeEditor, modifiedEditor: editorBrowser.ICodeEditor, renderIndicators: boolean) { + constructor(lineChanges: editorCommon.ILineChange[], originalForeignVZ: EditorWhitespace[], modifiedForeignVZ: EditorWhitespace[], originalEditor: editorBrowser.ICodeEditor, modifiedEditor: editorBrowser.ICodeEditor, renderIndicators: boolean) { super(lineChanges, originalForeignVZ, modifiedForeignVZ); this.originalModel = originalEditor.getModel()!; this.modifiedEditorOptions = modifiedEditor.getOptions(); diff --git a/src/vs/editor/common/viewLayout/linesLayout.ts b/src/vs/editor/common/viewLayout/linesLayout.ts index e18482b2ef4a2..d3f4d35943192 100644 --- a/src/vs/editor/common/viewLayout/linesLayout.ts +++ b/src/vs/editor/common/viewLayout/linesLayout.ts @@ -7,10 +7,12 @@ import { IPartialViewLinesViewportData } from 'vs/editor/common/viewLayout/viewL import { IViewWhitespaceViewportData } from 'vs/editor/common/viewModel/viewModel'; import * as strings from 'vs/base/common/strings'; -export interface IEditorWhitespace { - readonly id: string; - readonly afterLineNumber: number; - readonly heightInLines: number; +export class EditorWhitespace { + constructor( + public readonly id: string, + public readonly afterLineNumber: number, + public readonly heightInLines: number, + ) { } } /** @@ -110,7 +112,7 @@ export class LinesLayout { let high = sortedArray.length; while (low < high) { - let mid = ((low + high) >>> 1); + const mid = ((low + high) >>> 1); if (value === sortedArray[mid]) { if (valueOrdinal < ordinals[mid]) { @@ -159,8 +161,8 @@ export class LinesLayout { heightInPx = heightInPx | 0; minWidth = minWidth | 0; - let id = this._instanceId + (++this._lastWhitespaceId); - let insertionIndex = LinesLayout.findInsertionIndex(this._afterLineNumbers, afterLineNumber, this._ordinals, ordinal); + const id = this._instanceId + (++this._lastWhitespaceId); + const insertionIndex = LinesLayout.findInsertionIndex(this._afterLineNumbers, afterLineNumber, this._ordinals, ordinal); this._insertWhitespaceAtIndex(id, insertionIndex, afterLineNumber, ordinal, heightInPx, minWidth); this._minWidth = -1; /* marker for not being computed */ return id; @@ -180,10 +182,9 @@ export class LinesLayout { this._ordinals.splice(insertIndex, 0, ordinal); this._prefixSum.splice(insertIndex, 0, 0); - let keys = Object.keys(this._whitespaceId2Index); - for (let i = 0, len = keys.length; i < len; i++) { - let sid = keys[i]; - let oldIndex = this._whitespaceId2Index[sid]; + const keys = Object.keys(this._whitespaceId2Index); + for (const sid of keys) { + const oldIndex = this._whitespaceId2Index[sid]; if (oldIndex >= insertIndex) { this._whitespaceId2Index[sid] = oldIndex + 1; } @@ -217,7 +218,7 @@ export class LinesLayout { newHeightInPx = newHeightInPx | 0; if (this._whitespaceId2Index.hasOwnProperty(id)) { - let index = this._whitespaceId2Index[id]; + const index = this._whitespaceId2Index[id]; if (this._heights[index] !== newHeightInPx) { this._heights[index] = newHeightInPx; this._prefixSumValidIndex = Math.min(this._prefixSumValidIndex, index - 1); @@ -238,24 +239,24 @@ export class LinesLayout { newAfterLineNumber = newAfterLineNumber | 0; if (this._whitespaceId2Index.hasOwnProperty(id)) { - let index = this._whitespaceId2Index[id]; + const index = this._whitespaceId2Index[id]; if (this._afterLineNumbers[index] !== newAfterLineNumber) { // `afterLineNumber` changed for this whitespace // Record old ordinal - let ordinal = this._ordinals[index]; + const ordinal = this._ordinals[index]; // Record old height - let heightInPx = this._heights[index]; + const heightInPx = this._heights[index]; // Record old min width - let minWidth = this._minWidths[index]; + const minWidth = this._minWidths[index]; // Since changing `afterLineNumber` can trigger a reordering, we're gonna remove this whitespace this.removeWhitespace(id); // And add it again - let insertionIndex = LinesLayout.findInsertionIndex(this._afterLineNumbers, newAfterLineNumber, this._ordinals, ordinal); + const insertionIndex = LinesLayout.findInsertionIndex(this._afterLineNumbers, newAfterLineNumber, this._ordinals, ordinal); this._insertWhitespaceAtIndex(id, insertionIndex, newAfterLineNumber, ordinal, heightInPx, minWidth); return true; @@ -272,7 +273,7 @@ export class LinesLayout { */ public removeWhitespace(id: string): boolean { if (this._whitespaceId2Index.hasOwnProperty(id)) { - let index = this._whitespaceId2Index[id]; + const index = this._whitespaceId2Index[id]; delete this._whitespaceId2Index[id]; this._removeWhitespaceAtIndex(index); this._minWidth = -1; /* marker for not being computed */ @@ -293,10 +294,9 @@ export class LinesLayout { this._prefixSum.splice(removeIndex, 1); this._prefixSumValidIndex = Math.min(this._prefixSumValidIndex, removeIndex - 1); - let keys = Object.keys(this._whitespaceId2Index); - for (let i = 0, len = keys.length; i < len; i++) { - let sid = keys[i]; - let oldIndex = this._whitespaceId2Index[sid]; + const keys = Object.keys(this._whitespaceId2Index); + for (const sid of keys) { + const oldIndex = this._whitespaceId2Index[sid]; if (oldIndex >= removeIndex) { this._whitespaceId2Index[sid] = oldIndex - 1; } @@ -315,7 +315,7 @@ export class LinesLayout { this._lineCount -= (toLineNumber - fromLineNumber + 1); for (let i = 0, len = this._afterLineNumbers.length; i < len; i++) { - let afterLineNumber = this._afterLineNumbers[i]; + const afterLineNumber = this._afterLineNumbers[i]; if (fromLineNumber <= afterLineNumber && afterLineNumber <= toLineNumber) { // The line this whitespace was after has been deleted @@ -341,7 +341,7 @@ export class LinesLayout { this._lineCount += (toLineNumber - fromLineNumber + 1); for (let i = 0, len = this._afterLineNumbers.length; i < len; i++) { - let afterLineNumber = this._afterLineNumbers[i]; + const afterLineNumber = this._afterLineNumbers[i]; if (fromLineNumber <= afterLineNumber) { this._afterLineNumbers[i] += (toLineNumber - fromLineNumber + 1); @@ -388,8 +388,8 @@ export class LinesLayout { * @return The sum of heights for all objects. */ public getLinesTotalHeight(): number { - let linesHeight = this._lineHeight * this._lineCount; - let whitespacesHeight = this.getWhitespacesTotalHeight(); + const linesHeight = this._lineHeight * this._lineCount; + const whitespacesHeight = this.getWhitespacesTotalHeight(); return linesHeight + whitespacesHeight; } @@ -401,7 +401,7 @@ export class LinesLayout { public getWhitespaceAccumulatedHeightBeforeLineNumber(lineNumber: number): number { lineNumber = lineNumber | 0; - let lastWhitespaceBeforeLineNumber = this._findLastWhitespaceBeforeLineNumber(lineNumber); + const lastWhitespaceBeforeLineNumber = this._findLastWhitespaceBeforeLineNumber(lineNumber); if (lastWhitespaceBeforeLineNumber === -1) { return 0; @@ -414,14 +414,14 @@ export class LinesLayout { lineNumber = lineNumber | 0; // Find the whitespace before line number - let afterLineNumbers = this._afterLineNumbers; + const afterLineNumbers = this._afterLineNumbers; let low = 0; let high = afterLineNumbers.length - 1; while (low <= high) { - let delta = (high - low) | 0; - let halfDelta = (delta / 2) | 0; - let mid = (low + halfDelta) | 0; + const delta = (high - low) | 0; + const halfDelta = (delta / 2) | 0; + const mid = (low + halfDelta) | 0; if (afterLineNumbers[mid] < lineNumber) { if (mid + 1 >= afterLineNumbers.length || afterLineNumbers[mid + 1] >= lineNumber) { @@ -440,8 +440,8 @@ export class LinesLayout { private _findFirstWhitespaceAfterLineNumber(lineNumber: number): number { lineNumber = lineNumber | 0; - let lastWhitespaceBeforeLineNumber = this._findLastWhitespaceBeforeLineNumber(lineNumber); - let firstWhitespaceAfterLineNumber = lastWhitespaceBeforeLineNumber + 1; + const lastWhitespaceBeforeLineNumber = this._findLastWhitespaceBeforeLineNumber(lineNumber); + const firstWhitespaceAfterLineNumber = lastWhitespaceBeforeLineNumber + 1; if (firstWhitespaceAfterLineNumber < this._heights.length) { return firstWhitespaceAfterLineNumber; @@ -476,7 +476,7 @@ export class LinesLayout { previousLinesHeight = 0; } - let previousWhitespacesHeight = this.getWhitespaceAccumulatedHeightBeforeLineNumber(lineNumber); + const previousWhitespacesHeight = this.getWhitespaceAccumulatedHeightBeforeLineNumber(lineNumber); return previousLinesHeight + previousWhitespacesHeight; } @@ -506,7 +506,7 @@ export class LinesLayout { * Check if `verticalOffset` is below all lines. */ public isAfterLines(verticalOffset: number): boolean { - let totalHeight = this.getLinesTotalHeight(); + const totalHeight = this.getLinesTotalHeight(); return verticalOffset > totalHeight; } @@ -531,9 +531,9 @@ export class LinesLayout { let maxLineNumber = linesCount; while (minLineNumber < maxLineNumber) { - let midLineNumber = ((minLineNumber + maxLineNumber) / 2) | 0; + const midLineNumber = ((minLineNumber + maxLineNumber) / 2) | 0; - let midLineNumberVerticalOffset = this.getVerticalOffsetForLineNumber(midLineNumber) | 0; + const midLineNumberVerticalOffset = this.getVerticalOffsetForLineNumber(midLineNumber) | 0; if (verticalOffset >= midLineNumberVerticalOffset + lineHeight) { // vertical offset is after mid line number @@ -602,7 +602,7 @@ export class LinesLayout { currentLineRelativeOffset -= bigNumbersDelta; } - let linesOffsets: number[] = []; + const linesOffsets: number[] = []; const verticalCenter = verticalOffset1 + (verticalOffset2 - verticalOffset1) / 2; let centeredLineNumber = -1; @@ -611,8 +611,8 @@ export class LinesLayout { for (let lineNumber = startLineNumber; lineNumber <= endLineNumber; lineNumber++) { if (centeredLineNumber === -1) { - let currentLineTop = currentVerticalOffset; - let currentLineBottom = currentVerticalOffset + lineHeight; + const currentLineTop = currentVerticalOffset; + const currentLineBottom = currentVerticalOffset + lineHeight; if ((currentLineTop <= verticalCenter && verticalCenter < currentLineBottom) || currentLineTop > verticalCenter) { centeredLineNumber = lineNumber; } @@ -681,7 +681,7 @@ export class LinesLayout { public getVerticalOffsetForWhitespaceIndex(whitespaceIndex: number): number { whitespaceIndex = whitespaceIndex | 0; - let afterLineNumber = this.getAfterLineNumberForWhitespaceIndex(whitespaceIndex); + const afterLineNumber = this.getAfterLineNumberForWhitespaceIndex(whitespaceIndex); let previousLinesHeight: number; if (afterLineNumber >= 1) { @@ -702,28 +702,25 @@ export class LinesLayout { public getWhitespaceIndexAtOrAfterVerticallOffset(verticalOffset: number): number { verticalOffset = verticalOffset | 0; - let midWhitespaceIndex: number, - minWhitespaceIndex = 0, - maxWhitespaceIndex = this.getWhitespacesCount() - 1, - midWhitespaceVerticalOffset: number, - midWhitespaceHeight: number; + let minWhitespaceIndex = 0; + let maxWhitespaceIndex = this.getWhitespacesCount() - 1; if (maxWhitespaceIndex < 0) { return -1; } // Special case: nothing to be found - let maxWhitespaceVerticalOffset = this.getVerticalOffsetForWhitespaceIndex(maxWhitespaceIndex); - let maxWhitespaceHeight = this.getHeightForWhitespaceIndex(maxWhitespaceIndex); + const maxWhitespaceVerticalOffset = this.getVerticalOffsetForWhitespaceIndex(maxWhitespaceIndex); + const maxWhitespaceHeight = this.getHeightForWhitespaceIndex(maxWhitespaceIndex); if (verticalOffset >= maxWhitespaceVerticalOffset + maxWhitespaceHeight) { return -1; } while (minWhitespaceIndex < maxWhitespaceIndex) { - midWhitespaceIndex = Math.floor((minWhitespaceIndex + maxWhitespaceIndex) / 2); + const midWhitespaceIndex = Math.floor((minWhitespaceIndex + maxWhitespaceIndex) / 2); - midWhitespaceVerticalOffset = this.getVerticalOffsetForWhitespaceIndex(midWhitespaceIndex); - midWhitespaceHeight = this.getHeightForWhitespaceIndex(midWhitespaceIndex); + const midWhitespaceVerticalOffset = this.getVerticalOffsetForWhitespaceIndex(midWhitespaceIndex); + const midWhitespaceHeight = this.getHeightForWhitespaceIndex(midWhitespaceIndex); if (verticalOffset >= midWhitespaceVerticalOffset + midWhitespaceHeight) { // vertical offset is after whitespace @@ -748,7 +745,7 @@ export class LinesLayout { public getWhitespaceAtVerticalOffset(verticalOffset: number): IViewWhitespaceViewportData | null { verticalOffset = verticalOffset | 0; - let candidateIndex = this.getWhitespaceIndexAtOrAfterVerticallOffset(verticalOffset); + const candidateIndex = this.getWhitespaceIndexAtOrAfterVerticallOffset(verticalOffset); if (candidateIndex < 0) { return null; @@ -758,15 +755,15 @@ export class LinesLayout { return null; } - let candidateTop = this.getVerticalOffsetForWhitespaceIndex(candidateIndex); + const candidateTop = this.getVerticalOffsetForWhitespaceIndex(candidateIndex); if (candidateTop > verticalOffset) { return null; } - let candidateHeight = this.getHeightForWhitespaceIndex(candidateIndex); - let candidateId = this.getIdForWhitespaceIndex(candidateIndex); - let candidateAfterLineNumber = this.getAfterLineNumberForWhitespaceIndex(candidateIndex); + const candidateHeight = this.getHeightForWhitespaceIndex(candidateIndex); + const candidateId = this.getIdForWhitespaceIndex(candidateIndex); + const candidateAfterLineNumber = this.getAfterLineNumberForWhitespaceIndex(candidateIndex); return { id: candidateId, @@ -787,8 +784,8 @@ export class LinesLayout { verticalOffset1 = verticalOffset1 | 0; verticalOffset2 = verticalOffset2 | 0; - let startIndex = this.getWhitespaceIndexAtOrAfterVerticallOffset(verticalOffset1); - let endIndex = this.getWhitespacesCount() - 1; + const startIndex = this.getWhitespaceIndexAtOrAfterVerticallOffset(verticalOffset1); + const endIndex = this.getWhitespacesCount() - 1; if (startIndex < 0) { return []; @@ -796,8 +793,8 @@ export class LinesLayout { let result: IViewWhitespaceViewportData[] = []; for (let i = startIndex; i <= endIndex; i++) { - let top = this.getVerticalOffsetForWhitespaceIndex(i); - let height = this.getHeightForWhitespaceIndex(i); + const top = this.getVerticalOffsetForWhitespaceIndex(i); + const height = this.getHeightForWhitespaceIndex(i); if (top >= verticalOffset2) { break; } @@ -816,14 +813,14 @@ export class LinesLayout { /** * Get all whitespaces. */ - public getWhitespaces(): IEditorWhitespace[] { - let result: IEditorWhitespace[] = []; + public getWhitespaces(): EditorWhitespace[] { + let result: EditorWhitespace[] = []; for (let i = 0; i < this._heights.length; i++) { - result.push({ - id: this._ids[i], - afterLineNumber: this._afterLineNumbers[i], - heightInLines: this._heights[i] / this._lineHeight - }); + result.push(new EditorWhitespace( + this._ids[i], + this._afterLineNumbers[i], + this._heights[i] / this._lineHeight + )); } return result; } diff --git a/src/vs/editor/common/viewLayout/viewLayout.ts b/src/vs/editor/common/viewLayout/viewLayout.ts index cab08b23f440f..6fd8a951a577c 100644 --- a/src/vs/editor/common/viewLayout/viewLayout.ts +++ b/src/vs/editor/common/viewLayout/viewLayout.ts @@ -8,7 +8,7 @@ import { Disposable, IDisposable } from 'vs/base/common/lifecycle'; import { IScrollPosition, ScrollEvent, Scrollable, ScrollbarVisibility } from 'vs/base/common/scrollable'; import { ConfigurationChangedEvent, EditorOption } from 'vs/editor/common/config/editorOptions'; import * as editorCommon from 'vs/editor/common/editorCommon'; -import { LinesLayout, IEditorWhitespace } from 'vs/editor/common/viewLayout/linesLayout'; +import { LinesLayout, EditorWhitespace } from 'vs/editor/common/viewLayout/linesLayout'; import { IPartialViewLinesViewportData } from 'vs/editor/common/viewLayout/viewLinesViewportData'; import { IViewLayout, IViewWhitespaceViewportData, Viewport } from 'vs/editor/common/viewModel/viewModel'; @@ -235,7 +235,7 @@ export class ViewLayout extends Disposable implements IViewLayout { const visibleBox = this.getCurrentViewport(); return this._linesLayout.getWhitespaceViewportData(visibleBox.top, visibleBox.top + visibleBox.height); } - public getWhitespaces(): IEditorWhitespace[] { + public getWhitespaces(): EditorWhitespace[] { return this._linesLayout.getWhitespaces(); } diff --git a/src/vs/editor/common/viewModel/viewModel.ts b/src/vs/editor/common/viewModel/viewModel.ts index 3dd75a94d4ba6..777195ac72906 100644 --- a/src/vs/editor/common/viewModel/viewModel.ts +++ b/src/vs/editor/common/viewModel/viewModel.ts @@ -13,7 +13,7 @@ import { INewScrollPosition } from 'vs/editor/common/editorCommon'; import { EndOfLinePreference, IActiveIndentGuideInfo, IModelDecorationOptions, TextModelResolvedOptions } from 'vs/editor/common/model'; import { IViewEventListener } from 'vs/editor/common/view/viewEvents'; import { IPartialViewLinesViewportData } from 'vs/editor/common/viewLayout/viewLinesViewportData'; -import { IEditorWhitespace } from 'vs/editor/common/viewLayout/linesLayout'; +import { EditorWhitespace } from 'vs/editor/common/viewLayout/linesLayout'; import { ITheme } from 'vs/platform/theme/common/themeService'; export interface IViewWhitespaceViewportData { @@ -61,7 +61,7 @@ export interface IViewLayout { getLinesViewportData(): IPartialViewLinesViewportData; getLinesViewportDataAtScrollTop(scrollTop: number): IPartialViewLinesViewportData; - getWhitespaces(): IEditorWhitespace[]; + getWhitespaces(): EditorWhitespace[]; isAfterLines(verticalOffset: number): boolean; getLineNumberAtVerticalOffset(verticalOffset: number): number; From efe0e246b7ebe9eedfaf3ac01ee349712daba528 Mon Sep 17 00:00:00 2001 From: Martin Aeschlimann Date: Fri, 15 Nov 2019 10:58:50 +0100 Subject: [PATCH 321/352] enable strictFunctionTypes in VS Code codebase #81574 --- src/vs/base/common/path.ts | 4 ++-- src/vs/editor/contrib/folding/folding.ts | 2 +- src/vs/editor/contrib/folding/foldingModel.ts | 8 ++++++-- .../contrib/extensions/browser/extensionTipsService.ts | 2 +- 4 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/vs/base/common/path.ts b/src/vs/base/common/path.ts index 28b7d5e61cc49..5f1739053bbdd 100644 --- a/src/vs/base/common/path.ts +++ b/src/vs/base/common/path.ts @@ -69,11 +69,11 @@ function validateString(value: string, name: string) { } } -function isPathSeparator(code: number) { +function isPathSeparator(code: number | undefined) { return code === CHAR_FORWARD_SLASH || code === CHAR_BACKWARD_SLASH; } -function isPosixPathSeparator(code: number) { +function isPosixPathSeparator(code: number | undefined) { return code === CHAR_FORWARD_SLASH; } diff --git a/src/vs/editor/contrib/folding/folding.ts b/src/vs/editor/contrib/folding/folding.ts index d000560f648ab..86f04e0db86a9 100644 --- a/src/vs/editor/contrib/folding/folding.ts +++ b/src/vs/editor/contrib/folding/folding.ts @@ -423,7 +423,7 @@ export class FoldingController extends Disposable implements IEditorContribution if (iconClicked || isCollapsed) { let toToggle = [region]; if (e.event.middleButton || e.event.shiftKey) { - toToggle.push(...foldingModel.getRegionsInside(region, r => r.isCollapsed === isCollapsed)); + toToggle.push(...foldingModel.getRegionsInside(region, (r: FoldingRegion) => r.isCollapsed === isCollapsed)); } foldingModel.toggleCollapseState(toToggle); this.reveal({ lineNumber, column: 1 }); diff --git a/src/vs/editor/contrib/folding/foldingModel.ts b/src/vs/editor/contrib/folding/foldingModel.ts index 44feb79cdf23a..93a52a1472870 100644 --- a/src/vs/editor/contrib/folding/foldingModel.ts +++ b/src/vs/editor/contrib/folding/foldingModel.ts @@ -204,7 +204,7 @@ export class FoldingModel { return null; } - getRegionsInside(region: FoldingRegion | null, filter?: (r: FoldingRegion, level?: number) => boolean): FoldingRegion[] { + getRegionsInside(region: FoldingRegion | null, filter?: RegionFilter | RegionFilterWithLevel): FoldingRegion[] { let result: FoldingRegion[] = []; let index = region ? region.regionIndex + 1 : 0; let endLineNumber = region ? region.endLineNumber : Number.MAX_VALUE; @@ -229,7 +229,7 @@ export class FoldingModel { for (let i = index, len = this._regions.length; i < len; i++) { let current = this._regions.toRegion(i); if (this._regions.getStartLineNumber(i) < endLineNumber) { - if (!filter || filter(current)) { + if (!filter || (filter as RegionFilter)(current)) { result.push(current); } } else { @@ -242,6 +242,10 @@ export class FoldingModel { } +type RegionFilter = (r: FoldingRegion) => boolean; +type RegionFilterWithLevel = (r: FoldingRegion, level: number) => boolean; + + /** * Collapse or expand the regions at the given locations * @param levels The number of levels. Use 1 to only impact the regions at the location, use Number.MAX_VALUE for all levels. diff --git a/src/vs/workbench/contrib/extensions/browser/extensionTipsService.ts b/src/vs/workbench/contrib/extensions/browser/extensionTipsService.ts index f3cde426dd0e8..3d934b3d584a6 100644 --- a/src/vs/workbench/contrib/extensions/browser/extensionTipsService.ts +++ b/src/vs/workbench/contrib/extensions/browser/extensionTipsService.ts @@ -1124,7 +1124,7 @@ export class ExtensionTipsService extends Disposable implements IExtensionTipsSe if (context.res.statusCode !== 200) { return Promise.resolve(undefined); } - return asJson(context).then((result: { [key: string]: any }) => { + return asJson(context).then((result: { [key: string]: any } | null) => { if (!result) { return; } From 9b61e277c22ad861a5c13869927d11f290a41fb2 Mon Sep 17 00:00:00 2001 From: Martin Aeschlimann Date: Fri, 15 Nov 2019 11:03:30 +0100 Subject: [PATCH 322/352] Support for `--force-renderer-accessibility` Electron argument, needed for Linux accessibility. For #84833 --- src/vs/platform/environment/common/environment.ts | 1 + src/vs/platform/environment/node/argv.ts | 1 + 2 files changed, 2 insertions(+) diff --git a/src/vs/platform/environment/common/environment.ts b/src/vs/platform/environment/common/environment.ts index 945da64223269..96031eb4ec7c7 100644 --- a/src/vs/platform/environment/common/environment.ts +++ b/src/vs/platform/environment/common/environment.ts @@ -86,6 +86,7 @@ export interface ParsedArgs { 'disable-gpu'?: boolean; 'nolazy'?: boolean; 'force-device-scale-factor'?: string; + 'force-renderer-accessibility'?: boolean; } export const IEnvironmentService = createDecorator('environmentService'); diff --git a/src/vs/platform/environment/node/argv.ts b/src/vs/platform/environment/node/argv.ts index b97cc4b20b147..6832b93c5cb86 100644 --- a/src/vs/platform/environment/node/argv.ts +++ b/src/vs/platform/environment/node/argv.ts @@ -118,6 +118,7 @@ export const OPTIONS: OptionDescriptions> = { 'inspect-brk': { type: 'string' }, 'nolazy': { type: 'boolean' }, // node inspect 'force-device-scale-factor': { type: 'string' }, + 'force-renderer-accessibility': { type: 'boolean' }, '_urls': { type: 'string[]' }, _: { type: 'string[]' } // main arguments From 0b33f025db1f5e189d42ed92b1608fcf48ea9293 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Fri, 15 Nov 2019 11:05:35 +0100 Subject: [PATCH 323/352] editors - more explicit editor view model for diff editors --- .../browser/parts/editor/editorGroupView.ts | 20 ++- src/vs/workbench/common/editor.ts | 23 +-- src/vs/workbench/common/editor/editorGroup.ts | 138 +++++++++++------- .../test/common/editor/editorGroups.test.ts | 47 ++++-- 4 files changed, 142 insertions(+), 86 deletions(-) diff --git a/src/vs/workbench/browser/parts/editor/editorGroupView.ts b/src/vs/workbench/browser/parts/editor/editorGroupView.ts index 01eab7e685699..ba94efe8d292e 100644 --- a/src/vs/workbench/browser/parts/editor/editorGroupView.ts +++ b/src/vs/workbench/browser/parts/editor/editorGroupView.ts @@ -514,15 +514,21 @@ export class EditorGroupView extends Themable implements IEditorGroupView { const editorsToClose = [editor]; // Include both sides of side by side editors when being closed and not opened multiple times - if (editor instanceof SideBySideEditorInput && !this.accessor.groups.some(groupView => groupView.group.contains(editor))) { + if (editor instanceof SideBySideEditorInput && !this.accessor.groups.some(groupView => groupView.group.containsEditorByInstance(editor))) { editorsToClose.push(editor.master, editor.details); } - // Close the editor when it is no longer open in any group including diff editors + // Dispose the editor when it is no longer open in any group including diff editors editorsToClose.forEach(editorToClose => { const resource = editorToClose ? editorToClose.getResource() : undefined; // prefer resource to not close right-hand side editors of a diff editor - if (!this.accessor.groups.some(groupView => groupView.group.contains(resource || editorToClose))) { - editorToClose.close(); + if (!this.accessor.groups.some(groupView => { + if (resource) { + return groupView.group.containsEditorByResource(resource, SideBySideEditor.MASTER); + } + + return groupView.group.containsEditorByInstance(editorToClose); + })) { + editorToClose.dispose(); } }); @@ -578,7 +584,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView { editors.forEach(editor => { if (this._group.isActive(editor)) { activeEditor = editor; - } else if (this._group.contains(editor)) { + } else if (this._group.containsEditorByInstance(editor)) { inactiveEditors.push(editor); } }); @@ -770,7 +776,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView { } isOpened(editor: EditorInput): boolean { - return this._group.contains(editor); + return this._group.containsEditorByInstance(editor); } focus(): void { @@ -1264,7 +1270,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView { private async doHandleDirty(editor: EditorInput): Promise { if ( !editor.isDirty() || // editor must be dirty - this.accessor.groups.some(groupView => groupView !== this && groupView.group.contains(editor, true /* support side by side */)) || // editor is opened in other group + this.accessor.groups.some(groupView => groupView !== this && groupView.group.containsEditorByInstance(editor, SideBySideEditor.MASTER /* support side by side */)) || // editor is opened in other group editor instanceof SideBySideEditorInput && this.isOpened(editor.master) // side by side editor master is still opened ) { return false; diff --git a/src/vs/workbench/common/editor.ts b/src/vs/workbench/common/editor.ts index 1764e7ed83280..e6a70ab470275 100644 --- a/src/vs/workbench/common/editor.ts +++ b/src/vs/workbench/common/editor.ts @@ -333,14 +333,14 @@ export interface IEditorInput extends IDisposable { */ export abstract class EditorInput extends Disposable implements IEditorInput { - protected readonly _onDidChangeDirty: Emitter = this._register(new Emitter()); - readonly onDidChangeDirty: Event = this._onDidChangeDirty.event; + protected readonly _onDidChangeDirty = this._register(new Emitter()); + readonly onDidChangeDirty = this._onDidChangeDirty.event; - protected readonly _onDidChangeLabel: Emitter = this._register(new Emitter()); - readonly onDidChangeLabel: Event = this._onDidChangeLabel.event; + protected readonly _onDidChangeLabel = this._register(new Emitter()); + readonly onDidChangeLabel = this._onDidChangeLabel.event; - private readonly _onDispose: Emitter = this._register(new Emitter()); - readonly onDispose: Event = this._onDispose.event; + private readonly _onDispose = this._register(new Emitter()); + readonly onDispose = this._onDispose.event; private disposed: boolean = false; @@ -429,13 +429,6 @@ export abstract class EditorInput extends Disposable implements IEditorInput { return Promise.resolve(true); } - /** - * Called when this input is no longer opened in any editor. Subclasses can free resources as needed. - */ - close(): void { - this.dispose(); - } - /** * Subclasses can set this to false if it does not make sense to split the editor input. */ @@ -640,8 +633,8 @@ export interface ITextEditorModel extends IEditorModel { */ export class EditorModel extends Disposable implements IEditorModel { - private readonly _onDispose: Emitter = this._register(new Emitter()); - readonly onDispose: Event = this._onDispose.event; + private readonly _onDispose = this._register(new Emitter()); + readonly onDispose = this._onDispose.event; /** * Causes this model to load returning a promise when loading is completed. diff --git a/src/vs/workbench/common/editor/editorGroup.ts b/src/vs/workbench/common/editor/editorGroup.ts index 72f1223b558fd..13df58c3ac587 100644 --- a/src/vs/workbench/common/editor/editorGroup.ts +++ b/src/vs/workbench/common/editor/editorGroup.ts @@ -60,31 +60,31 @@ export class EditorGroup extends Disposable { //#region events private readonly _onDidEditorActivate = this._register(new Emitter()); - readonly onDidEditorActivate: Event = this._onDidEditorActivate.event; + readonly onDidEditorActivate = this._onDidEditorActivate.event; private readonly _onDidEditorOpen = this._register(new Emitter()); - readonly onDidEditorOpen: Event = this._onDidEditorOpen.event; + readonly onDidEditorOpen = this._onDidEditorOpen.event; private readonly _onDidEditorClose = this._register(new Emitter()); - readonly onDidEditorClose: Event = this._onDidEditorClose.event; + readonly onDidEditorClose = this._onDidEditorClose.event; private readonly _onDidEditorDispose = this._register(new Emitter()); - readonly onDidEditorDispose: Event = this._onDidEditorDispose.event; + readonly onDidEditorDispose = this._onDidEditorDispose.event; private readonly _onDidEditorBecomeDirty = this._register(new Emitter()); - readonly onDidEditorBecomeDirty: Event = this._onDidEditorBecomeDirty.event; + readonly onDidEditorBecomeDirty = this._onDidEditorBecomeDirty.event; private readonly _onDidEditorLabelChange = this._register(new Emitter()); - readonly onDidEditorLabelChange: Event = this._onDidEditorLabelChange.event; + readonly onDidEditorLabelChange = this._onDidEditorLabelChange.event; private readonly _onDidEditorMove = this._register(new Emitter()); - readonly onDidEditorMove: Event = this._onDidEditorMove.event; + readonly onDidEditorMove = this._onDidEditorMove.event; private readonly _onDidEditorPin = this._register(new Emitter()); - readonly onDidEditorPin: Event = this._onDidEditorPin.event; + readonly onDidEditorPin = this._onDidEditorPin.event; private readonly _onDidEditorUnpin = this._register(new Emitter()); - readonly onDidEditorUnpin: Event = this._onDidEditorUnpin.event; + readonly onDidEditorUnpin = this._onDidEditorUnpin.event; //#endregion @@ -93,7 +93,10 @@ export class EditorGroup extends Disposable { private editors: EditorInput[] = []; private mru: EditorInput[] = []; - private mapResourceToEditorCount: ResourceMap = new ResourceMap(); + + private mapResourceToEditorCount = new ResourceMap(); + private mapResourceToMasterEditorCount = new ResourceMap(); + private mapResourceToDetailsEditorCount = new ResourceMap(); private preview: EditorInput | null = null; // editor in preview state private active: EditorInput | null = null; // editor in active state @@ -143,7 +146,7 @@ export class EditorGroup extends Disposable { } const resource: URI = arg1; - if (!this.contains(resource)) { + if (!this.containsEditorByResource(resource, SideBySideEditor.MASTER)) { return undefined; // fast check for resource opened or not } @@ -509,7 +512,7 @@ export class EditorGroup extends Disposable { // Add if (!del && editor) { this.mru.push(editor); // make it LRU editor - this.updateResourceMap(editor, false /* add */); // add new to resource map + this.updateResourceCounterMap(editor, false /* add */); // add new to resource map } // Remove / Replace @@ -519,42 +522,63 @@ export class EditorGroup extends Disposable { // Remove if (del && !editor) { this.mru.splice(indexInMRU, 1); // remove from MRU - this.updateResourceMap(editorToDeleteOrReplace, true /* delete */); // remove from resource map + this.updateResourceCounterMap(editorToDeleteOrReplace, true /* delete */); // remove from resource map } // Replace else if (del && editor) { this.mru.splice(indexInMRU, 1, editor); // replace MRU at location - this.updateResourceMap(editor, false /* add */); // add new to resource map - this.updateResourceMap(editorToDeleteOrReplace, true /* delete */); // remove replaced from resource map + this.updateResourceCounterMap(editor, false /* add */); // add new to resource map + this.updateResourceCounterMap(editorToDeleteOrReplace, true /* delete */); // remove replaced from resource map } } } - private updateResourceMap(editor: EditorInput, remove: boolean): void { - const resource = toResource(editor, { supportSideBySide: SideBySideEditor.MASTER }); - if (resource) { + private updateResourceCounterMap(editor: EditorInput, remove: boolean): void { - // It is possible to have the same resource opened twice (once as normal input and once as diff input) - // So we need to do ref counting on the resource to provide the correct picture - const counter = this.mapResourceToEditorCount.get(resource) || 0; + // Remember editor resource in map for fast lookup + const resource = toResource(editor); + if (resource) { + this.doUpdateResourceCounterMap(resource, this.mapResourceToEditorCount, remove); + } - // Add - let newCounter: number; - if (!remove) { - newCounter = counter + 1; + // Side by Side editor: store resource information + // for master and details side in separate maps + // to be able to lookup properly. + if (editor instanceof SideBySideEditorInput) { + const masterResource = toResource(editor.master); + if (masterResource) { + this.doUpdateResourceCounterMap(masterResource, this.mapResourceToMasterEditorCount, remove); } - // Delete - else { - newCounter = counter - 1; + const detailsResource = toResource(editor.details); + if (detailsResource) { + this.doUpdateResourceCounterMap(detailsResource, this.mapResourceToDetailsEditorCount, remove); } + } + } - if (newCounter > 0) { - this.mapResourceToEditorCount.set(resource, newCounter); - } else { - this.mapResourceToEditorCount.delete(resource); - } + private doUpdateResourceCounterMap(resource: URI, map: ResourceMap, remove: boolean): void { + + // It is possible to have the same resource opened twice (once as normal input and once as diff input) + // So we need to do ref counting on the resource to provide the correct picture + const counter = map.get(resource) || 0; + + // Add + let newCounter: number; + if (!remove) { + newCounter = counter + 1; + } + + // Delete + else { + newCounter = counter - 1; + } + + if (newCounter > 0) { + map.set(resource, newCounter); + } else { + map.delete(resource); } } @@ -572,30 +596,40 @@ export class EditorGroup extends Disposable { return -1; } - contains(editorOrResource: EditorInput | URI): boolean; - contains(editor: EditorInput, supportSideBySide?: boolean): boolean; - contains(editorOrResource: EditorInput | URI, supportSideBySide?: boolean): boolean { - if (editorOrResource instanceof EditorInput) { - const index = this.indexOf(editorOrResource); - if (index >= 0) { - return true; - } + containsEditorByResource(resource: URI, supportSideBySide?: SideBySideEditor): boolean { - if (supportSideBySide && editorOrResource instanceof SideBySideEditorInput) { - const index = this.indexOf(editorOrResource.master); - if (index >= 0) { - return true; - } - } + // Check if exact editor match is contained + let counter = this.mapResourceToEditorCount.get(resource); - return false; + // Optionally search by master/detail resource if instructed + if (supportSideBySide === SideBySideEditor.MASTER) { + counter = counter || this.mapResourceToMasterEditorCount.get(resource); + } else if (supportSideBySide === SideBySideEditor.DETAILS) { + counter = counter || this.mapResourceToDetailsEditorCount.get(resource); } - const counter = this.mapResourceToEditorCount.get(editorOrResource); - return typeof counter === 'number' && counter > 0; } + containsEditorByInstance(editor: EditorInput, supportSideBySide?: SideBySideEditor): boolean { + + // Check if exact editor match is contained + const index = this.indexOf(editor); + if (index >= 0) { + return true; + } + + // Optionally search by master/detail input if instructed + if (supportSideBySide && editor instanceof SideBySideEditorInput) { + const index = this.indexOf(supportSideBySide === SideBySideEditor.MASTER ? editor.master : editor.details); + if (index >= 0) { + return true; + } + } + + return false; + } + private setMostRecentlyUsed(editor: EditorInput): void { const index = this.indexOf(editor); if (index === -1) { @@ -620,6 +654,8 @@ export class EditorGroup extends Disposable { group.editors = this.editors.slice(0); group.mru = this.mru.slice(0); group.mapResourceToEditorCount = this.mapResourceToEditorCount.clone(); + group.mapResourceToMasterEditorCount = this.mapResourceToMasterEditorCount.clone(); + group.mapResourceToDetailsEditorCount = this.mapResourceToDetailsEditorCount.clone(); group.preview = this.preview; group.active = this.active; group.editorOpenPositioning = this.editorOpenPositioning; @@ -678,7 +714,7 @@ export class EditorGroup extends Disposable { const editor = factory.deserialize(this.instantiationService, e.value); if (editor) { this.registerEditorListeners(editor); - this.updateResourceMap(editor, false /* add */); + this.updateResourceCounterMap(editor, false /* add */); } return editor; diff --git a/src/vs/workbench/test/common/editor/editorGroups.test.ts b/src/vs/workbench/test/common/editor/editorGroups.test.ts index 46805b2c9dac1..9f8721b7a6811 100644 --- a/src/vs/workbench/test/common/editor/editorGroups.test.ts +++ b/src/vs/workbench/test/common/editor/editorGroups.test.ts @@ -5,7 +5,7 @@ import * as assert from 'assert'; import { EditorGroup, ISerializedEditorGroup, EditorCloseEvent } from 'vs/workbench/common/editor/editorGroup'; -import { Extensions as EditorExtensions, IEditorInputFactoryRegistry, EditorInput, IFileEditorInput, IEditorInputFactory, CloseDirection } from 'vs/workbench/common/editor'; +import { Extensions as EditorExtensions, IEditorInputFactoryRegistry, EditorInput, IFileEditorInput, IEditorInputFactory, CloseDirection, SideBySideEditor } from 'vs/workbench/common/editor'; import { URI } from 'vs/base/common/uri'; import { TestLifecycleService, TestContextService, TestStorageService } from 'vs/workbench/test/workbenchTestServices'; import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService'; @@ -193,13 +193,17 @@ suite('Workbench editor groups', () => { const input1 = input(); const input2 = input(); - const diffInput = new DiffEditorInput('name', 'description', input1, input2); + const diffInput1 = new DiffEditorInput('name', 'description', input1, input2); + const diffInput2 = new DiffEditorInput('name', 'description', input2, input1); group.openEditor(input2, { pinned: true, active: true }); - assert.equal(group.contains(input2), true); - assert.equal(group.contains(diffInput), false); - assert.equal(group.contains(diffInput, true), true); + assert.equal(group.containsEditorByInstance(input2, SideBySideEditor.MASTER), true); + assert.equal(group.containsEditorByInstance(diffInput1), false); + assert.equal(group.containsEditorByInstance(diffInput1, SideBySideEditor.MASTER), true); + assert.equal(group.containsEditorByInstance(diffInput1, SideBySideEditor.DETAILS), false); + assert.equal(group.containsEditorByInstance(diffInput2, SideBySideEditor.MASTER), false); + assert.equal(group.containsEditorByInstance(diffInput2, SideBySideEditor.DETAILS), true); }); test('group serialization', function () { @@ -1171,36 +1175,53 @@ suite('Workbench editor groups', () => { const input1 = input(undefined, false, input1Resource); group1.openEditor(input1); - assert.ok(group1.contains(input1Resource)); + assert.ok(group1.containsEditorByResource(input1Resource)); assert.equal(group1.getEditor(input1Resource), input1); assert.ok(!group1.getEditor(input1ResourceUpper)); - assert.ok(!group1.contains(input1ResourceUpper)); + assert.ok(!group1.containsEditorByResource(input1ResourceUpper)); group2.openEditor(input1); group1.closeEditor(input1); - assert.ok(!group1.contains(input1Resource)); + assert.ok(!group1.containsEditorByResource(input1Resource)); assert.ok(!group1.getEditor(input1Resource)); assert.ok(!group1.getEditor(input1ResourceUpper)); - assert.ok(group2.contains(input1Resource)); + assert.ok(group2.containsEditorByResource(input1Resource)); assert.equal(group2.getEditor(input1Resource), input1); const input1ResourceClone = URI.file('/hello/world.txt'); const input1Clone = input(undefined, false, input1ResourceClone); group1.openEditor(input1Clone); - assert.ok(group1.contains(input1Resource)); + assert.ok(group1.containsEditorByResource(input1Resource)); group2.closeEditor(input1); - assert.ok(group1.contains(input1Resource)); + assert.ok(group1.containsEditorByResource(input1Resource)); assert.equal(group1.getEditor(input1Resource), input1Clone); - assert.ok(!group2.contains(input1Resource)); + assert.ok(!group2.containsEditorByResource(input1Resource)); group1.closeEditor(input1Clone); - assert.ok(!group1.contains(input1Resource)); + assert.ok(!group1.containsEditorByResource(input1Resource)); + + const masterResource = URI.file('/hello/world2.txt'); + const masterInput = input(undefined, false, masterResource); + + const detailsResource = URI.file('/hello/world3.txt'); + const detailsInput = input(undefined, false, detailsResource); + + const diffEditorInput = new DiffEditorInput('name', 'description', detailsInput, masterInput); + group1.openEditor(diffEditorInput); + + assert.equal(group1.containsEditorByResource(masterResource), false); + assert.equal(group1.containsEditorByResource(masterResource, SideBySideEditor.MASTER), true); + assert.equal(group1.containsEditorByResource(masterResource, SideBySideEditor.DETAILS), false); + + assert.equal(group1.containsEditorByResource(detailsResource), false); + assert.equal(group1.containsEditorByResource(detailsResource, SideBySideEditor.MASTER), false); + assert.equal(group1.containsEditorByResource(detailsResource, SideBySideEditor.DETAILS), true); }); test('Multiple Editors - Editor Dispose', function () { From 742bb9e51f5605d2e00041e57f95f6fe54cf915a Mon Sep 17 00:00:00 2001 From: Alexandru Dima Date: Fri, 15 Nov 2019 11:08:23 +0100 Subject: [PATCH 324/352] Move ViewZoneChangeAccessor to ViewZones --- src/vs/editor/browser/view/viewImpl.ts | 58 ++++--------------- .../browser/viewParts/viewZones/viewZones.ts | 47 ++++++++++++++- 2 files changed, 55 insertions(+), 50 deletions(-) diff --git a/src/vs/editor/browser/view/viewImpl.ts b/src/vs/editor/browser/view/viewImpl.ts index 42ef1f6f5425c..02b337315c885 100644 --- a/src/vs/editor/browser/view/viewImpl.ts +++ b/src/vs/editor/browser/view/viewImpl.ts @@ -11,7 +11,7 @@ import { IDisposable } from 'vs/base/common/lifecycle'; import { IPointerHandlerHelper } from 'vs/editor/browser/controller/mouseHandler'; import { PointerHandler } from 'vs/editor/browser/controller/pointerHandler'; import { ITextAreaHandlerHelper, TextAreaHandler } from 'vs/editor/browser/controller/textAreaHandler'; -import * as editorBrowser from 'vs/editor/browser/editorBrowser'; +import { IContentWidget, IContentWidgetPosition, IOverlayWidget, IOverlayWidgetPosition, IMouseTarget, IViewZoneChangeAccessor } from 'vs/editor/browser/editorBrowser'; import { ICommandDelegate, ViewController } from 'vs/editor/browser/view/viewController'; import { ViewOutgoingEvents } from 'vs/editor/browser/view/viewOutgoingEvents'; import { ContentViewOverlays, MarginViewOverlays } from 'vs/editor/browser/view/viewOverlays'; @@ -51,17 +51,15 @@ import { EditorOption } from 'vs/editor/common/config/editorOptions'; export interface IContentWidgetData { - widget: editorBrowser.IContentWidget; - position: editorBrowser.IContentWidgetPosition | null; + widget: IContentWidget; + position: IContentWidgetPosition | null; } export interface IOverlayWidgetData { - widget: editorBrowser.IOverlayWidget; - position: editorBrowser.IOverlayWidgetPosition | null; + widget: IOverlayWidget; + position: IOverlayWidgetPosition | null; } -const invalidFunc = () => { throw new Error(`Invalid change accessor`); }; - export class View extends ViewEventHandler { private readonly eventDispatcher: ViewEventDispatcher; @@ -348,7 +346,7 @@ export class View extends ViewEventHandler { super.dispose(); } - private _renderOnce(callback: () => any): any { + private _renderOnce(callback: () => T): T { const r = safeInvokeNoArg(callback); this._scheduleRender(); return r; @@ -458,7 +456,7 @@ export class View extends ViewEventHandler { return visibleRange.left; } - public getTargetAtClientPoint(clientX: number, clientY: number): editorBrowser.IMouseTarget | null { + public getTargetAtClientPoint(clientX: number, clientY: number): IMouseTarget | null { return this.pointerHandler.getTargetAtClientPoint(clientX, clientY); } @@ -466,42 +464,15 @@ export class View extends ViewEventHandler { return new OverviewRuler(this._context, cssClassName); } - public change(callback: (changeAccessor: editorBrowser.IViewZoneChangeAccessor) => any): boolean { - let zonesHaveChanged = false; - - this._renderOnce(() => { - const changeAccessor: editorBrowser.IViewZoneChangeAccessor = { - addZone: (zone: editorBrowser.IViewZone): string => { - zonesHaveChanged = true; - return this.viewZones.addZone(zone); - }, - removeZone: (id: string): void => { - if (!id) { - return; - } - zonesHaveChanged = this.viewZones.removeZone(id) || zonesHaveChanged; - }, - layoutZone: (id: string): void => { - if (!id) { - return; - } - zonesHaveChanged = this.viewZones.layoutZone(id) || zonesHaveChanged; - } - }; - - safeInvoke1Arg(callback, changeAccessor); - - // Invalidate changeAccessor - changeAccessor.addZone = invalidFunc; - changeAccessor.removeZone = invalidFunc; - changeAccessor.layoutZone = invalidFunc; - + public change(callback: (changeAccessor: IViewZoneChangeAccessor) => any): boolean { + return this._renderOnce(() => { + const zonesHaveChanged = this.viewZones.changeViewZones(callback); if (zonesHaveChanged) { this._context.viewLayout.onHeightMaybeChanged(); this._context.privateViewEventBus.emit(new viewEvents.ViewZonesChangedEvent()); } + return zonesHaveChanged; }); - return zonesHaveChanged; } public render(now: boolean, everything: boolean): void { @@ -582,10 +553,3 @@ function safeInvokeNoArg(func: Function): any { } } -function safeInvoke1Arg(func: Function, arg1: any): any { - try { - return func(arg1); - } catch (e) { - onUnexpectedError(e); - } -} diff --git a/src/vs/editor/browser/viewParts/viewZones/viewZones.ts b/src/vs/editor/browser/viewParts/viewZones/viewZones.ts index 6d7e14730894b..c82db418cee65 100644 --- a/src/vs/editor/browser/viewParts/viewZones/viewZones.ts +++ b/src/vs/editor/browser/viewParts/viewZones/viewZones.ts @@ -5,7 +5,7 @@ import { FastDomNode, createFastDomNode } from 'vs/base/browser/fastDomNode'; import { onUnexpectedError } from 'vs/base/common/errors'; -import { IViewZone } from 'vs/editor/browser/editorBrowser'; +import { IViewZone, IViewZoneChangeAccessor } from 'vs/editor/browser/editorBrowser'; import { ViewPart } from 'vs/editor/browser/view/viewPart'; import { Position } from 'vs/editor/common/core/position'; import { RenderingContext, RestrictedRenderingContext } from 'vs/editor/common/view/renderingContext'; @@ -14,7 +14,6 @@ import * as viewEvents from 'vs/editor/common/view/viewEvents'; import { IViewWhitespaceViewportData } from 'vs/editor/common/viewModel/viewModel'; import { EditorOption } from 'vs/editor/common/config/editorOptions'; - export interface IMyViewZone { whitespaceId: string; delegate: IViewZone; @@ -29,6 +28,8 @@ interface IComputedViewZoneProps { minWidthInPx: number; } +const invalidFunc = () => { throw new Error(`Invalid change accessor`); }; + export class ViewZones extends ViewPart { private _zones: { [id: string]: IMyViewZone; }; @@ -138,7 +139,6 @@ export class ViewZones extends ViewPart { return 10000; } - private _computeWhitespaceProps(zone: IViewZone): IComputedViewZoneProps { if (zone.afterLineNumber === 0) { return { @@ -188,6 +188,39 @@ export class ViewZones extends ViewPart { }; } + public changeViewZones(callback: (changeAccessor: IViewZoneChangeAccessor) => any): boolean { + + let zonesHaveChanged = false; + + const changeAccessor: IViewZoneChangeAccessor = { + addZone: (zone: IViewZone): string => { + zonesHaveChanged = true; + return this.addZone(zone); + }, + removeZone: (id: string): void => { + if (!id) { + return; + } + zonesHaveChanged = this.removeZone(id) || zonesHaveChanged; + }, + layoutZone: (id: string): void => { + if (!id) { + return; + } + zonesHaveChanged = this.layoutZone(id) || zonesHaveChanged; + } + }; + + safeInvoke1Arg(callback, changeAccessor); + + // Invalidate changeAccessor + changeAccessor.addZone = invalidFunc; + changeAccessor.removeZone = invalidFunc; + changeAccessor.layoutZone = invalidFunc; + + return zonesHaveChanged; + } + public addZone(zone: IViewZone): string { const props = this._computeWhitespaceProps(zone); const whitespaceId = this._context.viewLayout.addWhitespace(props.afterViewLineNumber, this._getZoneOrdinal(zone), props.heightInPx, props.minWidthInPx); @@ -365,3 +398,11 @@ export class ViewZones extends ViewPart { } } } + +function safeInvoke1Arg(func: Function, arg1: any): any { + try { + return func(arg1); + } catch (e) { + onUnexpectedError(e); + } +} From 61c3f82c6519ae9fcf3e1599984d6d63db703b35 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Fri, 15 Nov 2019 11:13:00 +0100 Subject: [PATCH 325/352] Fix #83227 --- .../node/extensionManagementService.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/vs/platform/extensionManagement/node/extensionManagementService.ts b/src/vs/platform/extensionManagement/node/extensionManagementService.ts index a36425204f7c6..5bfc2bb66c110 100644 --- a/src/vs/platform/extensionManagement/node/extensionManagementService.ts +++ b/src/vs/platform/extensionManagement/node/extensionManagementService.ts @@ -217,6 +217,16 @@ export class ExtensionManagementService extends Disposable implements IExtension } else if (semver.gt(existing.manifest.version, manifest.version)) { return this.uninstall(existing, true); } + } else { + // Remove the extension with same version if it is already uninstalled. + // Installing a VSIX extension shall replace the existing extension always. + return this.unsetUninstalledAndGetLocal(identifierWithVersion) + .then(existing => { + if (existing) { + return this.removeExtension(existing, 'existing').then(null, e => Promise.reject(new Error(nls.localize('restartCode', "Please restart VS Code before reinstalling {0}.", manifest.displayName || manifest.name)))); + } + return undefined; + }); } return undefined; }) From c54ed5925dadc71f47295257a60bc4d7ef0a2cfa Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Fri, 15 Nov 2019 11:13:33 +0100 Subject: [PATCH 326/352] editors - :polish: methods --- .../browser/parts/editor/editorActions.ts | 2 +- .../browser/parts/editor/editorCommands.ts | 10 +-- .../browser/parts/editor/editorGroupView.ts | 4 +- .../browser/parts/editor/tabsTitleControl.ts | 18 ++--- src/vs/workbench/common/editor/editorGroup.ts | 22 +----- .../editor/common/editorGroupsService.ts | 10 +-- .../test/browser/editorGroupsService.test.ts | 76 +++++++++---------- .../test/common/editor/editorGroups.test.ts | 29 +++++-- .../workbench/test/workbenchTestServices.ts | 2 +- 9 files changed, 85 insertions(+), 88 deletions(-) diff --git a/src/vs/workbench/browser/parts/editor/editorActions.ts b/src/vs/workbench/browser/parts/editor/editorActions.ts index 0c2e015645589..92fd5dd5f94c4 100644 --- a/src/vs/workbench/browser/parts/editor/editorActions.ts +++ b/src/vs/workbench/browser/parts/editor/editorActions.ts @@ -507,7 +507,7 @@ export class CloseOneEditorAction extends Action { // Close specific editor in group if (typeof editorIndex === 'number') { - const editorAtIndex = group.getEditor(editorIndex); + const editorAtIndex = group.getEditorByIndex(editorIndex); if (editorAtIndex) { return group.closeEditor(editorAtIndex); } diff --git a/src/vs/workbench/browser/parts/editor/editorCommands.ts b/src/vs/workbench/browser/parts/editor/editorCommands.ts index 38bdcd700ceb1..682dbaedff1ce 100644 --- a/src/vs/workbench/browser/parts/editor/editorCommands.ts +++ b/src/vs/workbench/browser/parts/editor/editorCommands.ts @@ -318,7 +318,7 @@ function registerOpenEditorAtIndexCommands(): void { const editorService = accessor.get(IEditorService); const activeControl = editorService.activeControl; if (activeControl) { - const editor = activeControl.group.getEditor(editorIndex); + const editor = activeControl.group.getEditorByIndex(editorIndex); if (editor) { editorService.openEditor(editor); } @@ -448,7 +448,7 @@ export function splitEditor(editorGroupService: IEditorGroupsService, direction: // Split editor (if it can be split) let editorToCopy: IEditorInput | undefined; if (context && typeof context.editorIndex === 'number') { - editorToCopy = sourceGroup.getEditor(context.editorIndex); + editorToCopy = sourceGroup.getEditorByIndex(context.editorIndex); } else { editorToCopy = types.withNullAsUndefined(sourceGroup.activeEditor); } @@ -548,7 +548,7 @@ function registerCloseEditorCommands() { if (group) { const editors = coalesce(contexts .filter(context => context.groupId === groupId) - .map(context => typeof context.editorIndex === 'number' ? group.getEditor(context.editorIndex) : group.activeEditor)); + .map(context => typeof context.editorIndex === 'number' ? group.getEditorByIndex(context.editorIndex) : group.activeEditor)); return group.closeEditors(editors); } @@ -603,7 +603,7 @@ function registerCloseEditorCommands() { if (group) { const editors = contexts .filter(context => context.groupId === groupId) - .map(context => typeof context.editorIndex === 'number' ? group.getEditor(context.editorIndex) : group.activeEditor); + .map(context => typeof context.editorIndex === 'number' ? group.getEditorByIndex(context.editorIndex) : group.activeEditor); const editorsToClose = group.editors.filter(e => editors.indexOf(e) === -1); if (group.activeEditor) { @@ -715,7 +715,7 @@ function resolveCommandsContext(editorGroupService: IEditorGroupsService, contex // Resolve from context let group = context && typeof context.groupId === 'number' ? editorGroupService.getGroup(context.groupId) : undefined; - let editor = group && context && typeof context.editorIndex === 'number' ? types.withNullAsUndefined(group.getEditor(context.editorIndex)) : undefined; + let editor = group && context && typeof context.editorIndex === 'number' ? types.withNullAsUndefined(group.getEditorByIndex(context.editorIndex)) : undefined; let control = group ? group.activeControl : undefined; // Fallback to active group as needed diff --git a/src/vs/workbench/browser/parts/editor/editorGroupView.ts b/src/vs/workbench/browser/parts/editor/editorGroupView.ts index ba94efe8d292e..3bcbf85e0f772 100644 --- a/src/vs/workbench/browser/parts/editor/editorGroupView.ts +++ b/src/vs/workbench/browser/parts/editor/editorGroupView.ts @@ -767,8 +767,8 @@ export class EditorGroupView extends Themable implements IEditorGroupView { return this.editors; } - getEditor(index: number): EditorInput | undefined { - return this._group.getEditor(index); + getEditorByIndex(index: number): EditorInput | undefined { + return this._group.getEditorByIndex(index); } getIndexOfEditor(editor: EditorInput): number { diff --git a/src/vs/workbench/browser/parts/editor/tabsTitleControl.ts b/src/vs/workbench/browser/parts/editor/tabsTitleControl.ts index d22c4b9ec41dc..d42242fe11289 100644 --- a/src/vs/workbench/browser/parts/editor/tabsTitleControl.ts +++ b/src/vs/workbench/browser/parts/editor/tabsTitleControl.ts @@ -501,7 +501,7 @@ export class TabsTitleControl extends TitleControl { } // Open tabs editor - const input = this.group.getEditor(index); + const input = this.group.getEditorByIndex(index); if (input) { this.group.openEditor(input); } @@ -512,7 +512,7 @@ export class TabsTitleControl extends TitleControl { const showContextMenu = (e: Event) => { EventHelper.stop(e); - const input = this.group.getEditor(index); + const input = this.group.getEditorByIndex(index); if (input) { this.onContextMenu(input, e, tab); } @@ -562,7 +562,7 @@ export class TabsTitleControl extends TitleControl { // Run action on Enter/Space if (event.equals(KeyCode.Enter) || event.equals(KeyCode.Space)) { handled = true; - const input = this.group.getEditor(index); + const input = this.group.getEditorByIndex(index); if (input) { this.group.openEditor(input); } @@ -581,7 +581,7 @@ export class TabsTitleControl extends TitleControl { targetIndex = this.group.count - 1; } - const target = this.group.getEditor(targetIndex); + const target = this.group.getEditorByIndex(targetIndex); if (target) { handled = true; this.group.openEditor(target, { preserveFocus: true }); @@ -603,7 +603,7 @@ export class TabsTitleControl extends TitleControl { disposables.add(addDisposableListener(tab, EventType.DBLCLICK, (e: MouseEvent) => { EventHelper.stop(e); - const editor = this.group.getEditor(index); + const editor = this.group.getEditorByIndex(index); if (editor && this.group.isPinned(editor)) { this.accessor.arrangeGroups(GroupsArrangement.TOGGLE, this.group); } else { @@ -615,7 +615,7 @@ export class TabsTitleControl extends TitleControl { disposables.add(addDisposableListener(tab, EventType.CONTEXT_MENU, (e: Event) => { EventHelper.stop(e, true); - const input = this.group.getEditor(index); + const input = this.group.getEditorByIndex(index); if (input) { this.onContextMenu(input, e, tab); } @@ -623,7 +623,7 @@ export class TabsTitleControl extends TitleControl { // Drag support disposables.add(addDisposableListener(tab, EventType.DRAG_START, (e: DragEvent) => { - const editor = this.group.getEditor(index); + const editor = this.group.getEditorByIndex(index); if (!editor) { return; } @@ -669,7 +669,7 @@ export class TabsTitleControl extends TitleControl { const data = this.editorTransfer.getData(DraggedEditorIdentifier.prototype); if (Array.isArray(data)) { const localDraggedEditor = data[0].identifier; - if (localDraggedEditor.editor === this.group.getEditor(index) && localDraggedEditor.groupId === this.group.id) { + if (localDraggedEditor.editor === this.group.getEditorByIndex(index) && localDraggedEditor.groupId === this.group.id) { if (e.dataTransfer) { e.dataTransfer.dropEffect = 'none'; } @@ -739,7 +739,7 @@ export class TabsTitleControl extends TitleControl { private updateDropFeedback(element: HTMLElement, isDND: boolean, index?: number): void { const isTab = (typeof index === 'number'); - const editor = typeof index === 'number' ? this.group.getEditor(index) : undefined; + const editor = typeof index === 'number' ? this.group.getEditorByIndex(index) : undefined; const isActiveTab = isTab && !!editor && this.group.isActive(editor); // Background diff --git a/src/vs/workbench/common/editor/editorGroup.ts b/src/vs/workbench/common/editor/editorGroup.ts index 13df58c3ac587..c1c3c36f108be 100644 --- a/src/vs/workbench/common/editor/editorGroup.ts +++ b/src/vs/workbench/common/editor/editorGroup.ts @@ -138,26 +138,8 @@ export class EditorGroup extends Disposable { return mru ? this.mru.slice(0) : this.editors.slice(0); } - getEditor(index: number): EditorInput | undefined; - getEditor(resource: URI): EditorInput | undefined; - getEditor(arg1: number | URI): EditorInput | undefined { - if (typeof arg1 === 'number') { - return this.editors[arg1]; - } - - const resource: URI = arg1; - if (!this.containsEditorByResource(resource, SideBySideEditor.MASTER)) { - return undefined; // fast check for resource opened or not - } - - for (const editor of this.editors) { - const editorResource = toResource(editor, { supportSideBySide: SideBySideEditor.MASTER }); - if (editorResource?.toString() === resource.toString()) { - return editor; - } - } - - return undefined; + getEditorByIndex(index: number): EditorInput | undefined { + return this.editors[index]; } get activeEditor(): EditorInput | null { diff --git a/src/vs/workbench/services/editor/common/editorGroupsService.ts b/src/vs/workbench/services/editor/common/editorGroupsService.ts index f7708c300e8e3..3f814693d4a6e 100644 --- a/src/vs/workbench/services/editor/common/editorGroupsService.ts +++ b/src/vs/workbench/services/editor/common/editorGroupsService.ts @@ -427,11 +427,6 @@ export interface IEditorGroup { */ readonly editors: ReadonlyArray; - /** - * Returns the editor at a specific index of the group. - */ - getEditor(index: number): IEditorInput | undefined; - /** * Get all editors that are currently opened in the group optionally * sorted by being most recent active. Will sort by sequential appearance @@ -439,6 +434,11 @@ export interface IEditorGroup { */ getEditors(order?: EditorsOrder): ReadonlyArray; + /** + * Returns the editor at a specific index of the group. + */ + getEditorByIndex(index: number): IEditorInput | undefined; + /** * Returns the index of the editor in the group or -1 if not opened. */ diff --git a/src/vs/workbench/services/editor/test/browser/editorGroupsService.test.ts b/src/vs/workbench/services/editor/test/browser/editorGroupsService.test.ts index ca86ecb8744fc..05efe8dad59fe 100644 --- a/src/vs/workbench/services/editor/test/browser/editorGroupsService.test.ts +++ b/src/vs/workbench/services/editor/test/browser/editorGroupsService.test.ts @@ -440,8 +440,8 @@ suite('EditorGroupsService', () => { assert.equal(editorWillOpenCounter, 2); assert.equal(editorDidOpenCounter, 2); assert.equal(activeEditorChangeCounter, 1); - assert.equal(group.getEditor(0), input); - assert.equal(group.getEditor(1), inputInactive); + assert.equal(group.getEditorByIndex(0), input); + assert.equal(group.getEditorByIndex(1), inputInactive); assert.equal(group.getIndexOfEditor(input), 0); assert.equal(group.getIndexOfEditor(inputInactive), 1); @@ -491,8 +491,8 @@ suite('EditorGroupsService', () => { await group.openEditors([{ editor: input, options: { pinned: true } }, { editor: inputInactive }]); assert.equal(group.count, 2); - assert.equal(group.getEditor(0), input); - assert.equal(group.getEditor(1), inputInactive); + assert.equal(group.getEditorByIndex(0), input); + assert.equal(group.getEditorByIndex(1), inputInactive); await group.closeEditors([input, inputInactive]); assert.equal(group.isEmpty, true); @@ -510,13 +510,13 @@ suite('EditorGroupsService', () => { await group.openEditors([{ editor: input1, options: { pinned: true } }, { editor: input2, options: { pinned: true } }, { editor: input3 }]); assert.equal(group.count, 3); - assert.equal(group.getEditor(0), input1); - assert.equal(group.getEditor(1), input2); - assert.equal(group.getEditor(2), input3); + assert.equal(group.getEditorByIndex(0), input1); + assert.equal(group.getEditorByIndex(1), input2); + assert.equal(group.getEditorByIndex(2), input3); await group.closeEditors({ except: input2 }); assert.equal(group.count, 1); - assert.equal(group.getEditor(0), input2); + assert.equal(group.getEditorByIndex(0), input2); part.dispose(); }); @@ -531,9 +531,9 @@ suite('EditorGroupsService', () => { await group.openEditors([{ editor: input1, options: { pinned: true } }, { editor: input2, options: { pinned: true } }, { editor: input3 }]); assert.equal(group.count, 3); - assert.equal(group.getEditor(0), input1); - assert.equal(group.getEditor(1), input2); - assert.equal(group.getEditor(2), input3); + assert.equal(group.getEditorByIndex(0), input1); + assert.equal(group.getEditorByIndex(1), input2); + assert.equal(group.getEditorByIndex(2), input3); await group.closeEditors({ savedOnly: true }); assert.equal(group.count, 0); @@ -551,14 +551,14 @@ suite('EditorGroupsService', () => { await group.openEditors([{ editor: input1, options: { pinned: true } }, { editor: input2, options: { pinned: true } }, { editor: input3 }]); assert.equal(group.count, 3); - assert.equal(group.getEditor(0), input1); - assert.equal(group.getEditor(1), input2); - assert.equal(group.getEditor(2), input3); + assert.equal(group.getEditorByIndex(0), input1); + assert.equal(group.getEditorByIndex(1), input2); + assert.equal(group.getEditorByIndex(2), input3); await group.closeEditors({ direction: CloseDirection.RIGHT, except: input2 }); assert.equal(group.count, 2); - assert.equal(group.getEditor(0), input1); - assert.equal(group.getEditor(1), input2); + assert.equal(group.getEditorByIndex(0), input1); + assert.equal(group.getEditorByIndex(1), input2); part.dispose(); }); @@ -573,14 +573,14 @@ suite('EditorGroupsService', () => { await group.openEditors([{ editor: input1, options: { pinned: true } }, { editor: input2, options: { pinned: true } }, { editor: input3 }]); assert.equal(group.count, 3); - assert.equal(group.getEditor(0), input1); - assert.equal(group.getEditor(1), input2); - assert.equal(group.getEditor(2), input3); + assert.equal(group.getEditorByIndex(0), input1); + assert.equal(group.getEditorByIndex(1), input2); + assert.equal(group.getEditorByIndex(2), input3); await group.closeEditors({ direction: CloseDirection.LEFT, except: input2 }); assert.equal(group.count, 2); - assert.equal(group.getEditor(0), input2); - assert.equal(group.getEditor(1), input3); + assert.equal(group.getEditorByIndex(0), input2); + assert.equal(group.getEditorByIndex(1), input3); part.dispose(); }); @@ -594,8 +594,8 @@ suite('EditorGroupsService', () => { await group.openEditors([{ editor: input, options: { pinned: true } }, { editor: inputInactive }]); assert.equal(group.count, 2); - assert.equal(group.getEditor(0), input); - assert.equal(group.getEditor(1), inputInactive); + assert.equal(group.getEditorByIndex(0), input); + assert.equal(group.getEditorByIndex(1), inputInactive); await group.closeAllEditors(); assert.equal(group.isEmpty, true); @@ -620,12 +620,12 @@ suite('EditorGroupsService', () => { await group.openEditors([{ editor: input, options: { pinned: true } }, { editor: inputInactive }]); assert.equal(group.count, 2); - assert.equal(group.getEditor(0), input); - assert.equal(group.getEditor(1), inputInactive); + assert.equal(group.getEditorByIndex(0), input); + assert.equal(group.getEditorByIndex(1), inputInactive); group.moveEditor(inputInactive, group, { index: 0 }); assert.equal(editorMoveCounter, 1); - assert.equal(group.getEditor(0), inputInactive); - assert.equal(group.getEditor(1), input); + assert.equal(group.getEditorByIndex(0), inputInactive); + assert.equal(group.getEditorByIndex(1), input); editorGroupChangeListener.dispose(); part.dispose(); }); @@ -642,13 +642,13 @@ suite('EditorGroupsService', () => { await group.openEditors([{ editor: input, options: { pinned: true } }, { editor: inputInactive }]); assert.equal(group.count, 2); - assert.equal(group.getEditor(0), input); - assert.equal(group.getEditor(1), inputInactive); + assert.equal(group.getEditorByIndex(0), input); + assert.equal(group.getEditorByIndex(1), inputInactive); group.moveEditor(inputInactive, rightGroup, { index: 0 }); assert.equal(group.count, 1); - assert.equal(group.getEditor(0), input); + assert.equal(group.getEditorByIndex(0), input); assert.equal(rightGroup.count, 1); - assert.equal(rightGroup.getEditor(0), inputInactive); + assert.equal(rightGroup.getEditorByIndex(0), inputInactive); part.dispose(); }); @@ -664,14 +664,14 @@ suite('EditorGroupsService', () => { await group.openEditors([{ editor: input, options: { pinned: true } }, { editor: inputInactive }]); assert.equal(group.count, 2); - assert.equal(group.getEditor(0), input); - assert.equal(group.getEditor(1), inputInactive); + assert.equal(group.getEditorByIndex(0), input); + assert.equal(group.getEditorByIndex(1), inputInactive); group.copyEditor(inputInactive, rightGroup, { index: 0 }); assert.equal(group.count, 2); - assert.equal(group.getEditor(0), input); - assert.equal(group.getEditor(1), inputInactive); + assert.equal(group.getEditorByIndex(0), input); + assert.equal(group.getEditorByIndex(1), inputInactive); assert.equal(rightGroup.count, 1); - assert.equal(rightGroup.getEditor(0), inputInactive); + assert.equal(rightGroup.getEditorByIndex(0), inputInactive); part.dispose(); }); @@ -685,11 +685,11 @@ suite('EditorGroupsService', () => { await group.openEditor(input); assert.equal(group.count, 1); - assert.equal(group.getEditor(0), input); + assert.equal(group.getEditorByIndex(0), input); await group.replaceEditors([{ editor: input, replacement: inputInactive }]); assert.equal(group.count, 1); - assert.equal(group.getEditor(0), inputInactive); + assert.equal(group.getEditorByIndex(0), inputInactive); part.dispose(); }); diff --git a/src/vs/workbench/test/common/editor/editorGroups.test.ts b/src/vs/workbench/test/common/editor/editorGroups.test.ts index 9f8721b7a6811..987feb85fbad1 100644 --- a/src/vs/workbench/test/common/editor/editorGroups.test.ts +++ b/src/vs/workbench/test/common/editor/editorGroups.test.ts @@ -5,7 +5,7 @@ import * as assert from 'assert'; import { EditorGroup, ISerializedEditorGroup, EditorCloseEvent } from 'vs/workbench/common/editor/editorGroup'; -import { Extensions as EditorExtensions, IEditorInputFactoryRegistry, EditorInput, IFileEditorInput, IEditorInputFactory, CloseDirection, SideBySideEditor } from 'vs/workbench/common/editor'; +import { Extensions as EditorExtensions, IEditorInputFactoryRegistry, EditorInput, IFileEditorInput, IEditorInputFactory, CloseDirection, SideBySideEditor, toResource } from 'vs/workbench/common/editor'; import { URI } from 'vs/base/common/uri'; import { TestLifecycleService, TestContextService, TestStorageService } from 'vs/workbench/test/workbenchTestServices'; import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService'; @@ -1170,25 +1170,40 @@ suite('Workbench editor groups', () => { const group1 = createGroup(); const group2 = createGroup(); + function getEditorByResource(group: EditorGroup, resource: URI): EditorInput | undefined { + if (!group.containsEditorByResource(resource)) { + return undefined; // fast check for resource opened or not + } + + for (const editor of group.getEditors()) { + const editorResource = toResource(editor); + if (editorResource?.toString() === resource.toString()) { + return editor; + } + } + + return undefined; + } + const input1Resource = URI.file('/hello/world.txt'); const input1ResourceUpper = URI.file('/hello/WORLD.txt'); const input1 = input(undefined, false, input1Resource); group1.openEditor(input1); assert.ok(group1.containsEditorByResource(input1Resource)); - assert.equal(group1.getEditor(input1Resource), input1); + assert.equal(getEditorByResource(group1, input1Resource), input1); - assert.ok(!group1.getEditor(input1ResourceUpper)); + assert.ok(!getEditorByResource(group1, input1ResourceUpper)); assert.ok(!group1.containsEditorByResource(input1ResourceUpper)); group2.openEditor(input1); group1.closeEditor(input1); assert.ok(!group1.containsEditorByResource(input1Resource)); - assert.ok(!group1.getEditor(input1Resource)); - assert.ok(!group1.getEditor(input1ResourceUpper)); + assert.ok(!getEditorByResource(group1, input1Resource)); + assert.ok(!getEditorByResource(group1, input1ResourceUpper)); assert.ok(group2.containsEditorByResource(input1Resource)); - assert.equal(group2.getEditor(input1Resource), input1); + assert.equal(getEditorByResource(group2, input1Resource), input1); const input1ResourceClone = URI.file('/hello/world.txt'); const input1Clone = input(undefined, false, input1ResourceClone); @@ -1199,7 +1214,7 @@ suite('Workbench editor groups', () => { group2.closeEditor(input1); assert.ok(group1.containsEditorByResource(input1Resource)); - assert.equal(group1.getEditor(input1Resource), input1Clone); + assert.equal(getEditorByResource(group1, input1Resource), input1Clone); assert.ok(!group2.containsEditorByResource(input1Resource)); group1.closeEditor(input1Clone); diff --git a/src/vs/workbench/test/workbenchTestServices.ts b/src/vs/workbench/test/workbenchTestServices.ts index 1e87e03eeaa09..37cd450349d7c 100644 --- a/src/vs/workbench/test/workbenchTestServices.ts +++ b/src/vs/workbench/test/workbenchTestServices.ts @@ -809,7 +809,7 @@ export class TestEditorGroup implements IEditorGroupView { return []; } - getEditor(_index: number): IEditorInput { + getEditorByIndex(_index: number): IEditorInput { throw new Error('not implemented'); } From 7ab5bca205ef3c7c1c1fd3f0dd931464ae91aaff Mon Sep 17 00:00:00 2001 From: isidor Date: Fri, 15 Nov 2019 11:13:30 +0100 Subject: [PATCH 327/352] CallStack: keep showing the session if we were in a multi session view fixes #84601 --- src/vs/workbench/contrib/debug/browser/callStackView.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/vs/workbench/contrib/debug/browser/callStackView.ts b/src/vs/workbench/contrib/debug/browser/callStackView.ts index df3cc5348631b..528bffc3b13af 100644 --- a/src/vs/workbench/contrib/debug/browser/callStackView.ts +++ b/src/vs/workbench/contrib/debug/browser/callStackView.ts @@ -25,7 +25,6 @@ import { createAndFillInContextMenuActions } from 'vs/platform/actions/browser/m import { IListVirtualDelegate } from 'vs/base/browser/ui/list/list'; import { ITreeRenderer, ITreeNode, ITreeContextMenuEvent, IAsyncDataSource } from 'vs/base/browser/ui/tree/tree'; import { TreeResourceNavigator2, WorkbenchAsyncDataTree } from 'vs/platform/list/browser/listService'; -import { onUnexpectedError } from 'vs/base/common/errors'; import { HighlightedLabel } from 'vs/base/browser/ui/highlightedlabel/highlightedLabel'; import { createMatches, FuzzyScore } from 'vs/base/common/filters'; import { Event } from 'vs/base/common/event'; @@ -165,7 +164,7 @@ export class CallStackView extends ViewletPanel { expandOnlyOnTwistieClick: true }); - this.tree.setInput(this.debugService.getModel()).then(undefined, onUnexpectedError); + this.tree.setInput(this.debugService.getModel()); const callstackNavigator = new TreeResourceNavigator2(this.tree); this._register(callstackNavigator); @@ -644,7 +643,7 @@ class CallStackDataSource implements IAsyncDataSource 1) { + if (sessions.length > 1 || this.debugService.getViewModel().isMultiSessionView()) { return Promise.resolve(sessions.filter(s => !s.parentSession)); } From 156b4c92dfc123e30d99b76218e1e13368b6f9a8 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Fri, 15 Nov 2019 11:34:35 +0100 Subject: [PATCH 328/352] editors - cleanup dirty handling on close --- .../browser/parts/editor/editorGroupView.ts | 56 +++++++++++++----- src/vs/workbench/common/editor/editorGroup.ts | 12 +--- .../test/common/editor/editorGroups.test.ts | 59 +++++++++++++++++-- 3 files changed, 94 insertions(+), 33 deletions(-) diff --git a/src/vs/workbench/browser/parts/editor/editorGroupView.ts b/src/vs/workbench/browser/parts/editor/editorGroupView.ts index 3bcbf85e0f772..f42aac0dca0b9 100644 --- a/src/vs/workbench/browser/parts/editor/editorGroupView.ts +++ b/src/vs/workbench/browser/parts/editor/editorGroupView.ts @@ -1127,7 +1127,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView { } // Check for dirty and veto - const veto = await this.handleDirty([editor]); + const veto = await this.handleDirtyClosing([editor]); if (veto) { return; } @@ -1238,7 +1238,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView { this._group.closeEditor(editor); } - private async handleDirty(editors: EditorInput[]): Promise { + private async handleDirtyClosing(editors: EditorInput[]): Promise { if (!editors.length) { return false; // no veto } @@ -1247,13 +1247,13 @@ export class EditorGroupView extends Themable implements IEditorGroupView { // To prevent multiple confirmation dialogs from showing up one after the other // we check if a pending confirmation is currently showing and if so, join that - let handleDirtyPromise = this.mapEditorToPendingConfirmation.get(editor); - if (!handleDirtyPromise) { - handleDirtyPromise = this.doHandleDirty(editor); - this.mapEditorToPendingConfirmation.set(editor, handleDirtyPromise); + let handleDirtyClosingPromise = this.mapEditorToPendingConfirmation.get(editor); + if (!handleDirtyClosingPromise) { + handleDirtyClosingPromise = this.doHandleDirtyClosing(editor); + this.mapEditorToPendingConfirmation.set(editor, handleDirtyClosingPromise); } - const veto = await handleDirtyPromise; + const veto = await handleDirtyClosingPromise; // Make sure to remove from our map of cached pending confirmations this.mapEditorToPendingConfirmation.delete(editor); @@ -1264,16 +1264,40 @@ export class EditorGroupView extends Themable implements IEditorGroupView { } // Otherwise continue with the remainders - return this.handleDirty(editors); + return this.handleDirtyClosing(editors); } - private async doHandleDirty(editor: EditorInput): Promise { - if ( - !editor.isDirty() || // editor must be dirty - this.accessor.groups.some(groupView => groupView !== this && groupView.group.containsEditorByInstance(editor, SideBySideEditor.MASTER /* support side by side */)) || // editor is opened in other group - editor instanceof SideBySideEditorInput && this.isOpened(editor.master) // side by side editor master is still opened - ) { + private async doHandleDirtyClosing(editor: EditorInput): Promise { + if (!editor.isDirty()) { + return false; // editor must be dirty + } + + if (editor instanceof SideBySideEditorInput && this.isOpened(editor.master)) { + return false; // master-side of editor is still opened somewhere else + } + + // Note: we explicitly decide to ask for confirm if closing a normal editor even + // if it is opened in a side-by-side editor in the group. This decision is made + // because it may be less obvious that one side of a side by side editor is dirty + // and can still be changed. + + if (this.accessor.groups.some(groupView => { + if (groupView === this) { + return false; // skip this group to avoid false assumptions about the editor being opened still + } + + const otherGroup = groupView.group; + if (otherGroup.containsEditorByInstance(editor)) { + return true; // exact editor still opened + } + + if (editor instanceof SideBySideEditorInput && otherGroup.containsEditorByInstance(editor.master)) { + return true; // master side of side by side editor still opened + } + return false; + })) { + return false; // editor is still editable somewhere else } // Switch to editor that we want to handle and confirm to save/revert @@ -1330,7 +1354,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView { const editors = this.getEditorsToClose(args); // Check for dirty and veto - const veto = await this.handleDirty(editors.slice(0)); + const veto = await this.handleDirtyClosing(editors.slice(0)); if (veto) { return; } @@ -1409,7 +1433,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView { // Check for dirty and veto const editors = this._group.getEditors(true); - const veto = await this.handleDirty(editors.slice(0)); + const veto = await this.handleDirtyClosing(editors.slice(0)); if (veto) { return; } diff --git a/src/vs/workbench/common/editor/editorGroup.ts b/src/vs/workbench/common/editor/editorGroup.ts index c1c3c36f108be..bb36fca7e2418 100644 --- a/src/vs/workbench/common/editor/editorGroup.ts +++ b/src/vs/workbench/common/editor/editorGroup.ts @@ -593,22 +593,12 @@ export class EditorGroup extends Disposable { return typeof counter === 'number' && counter > 0; } - containsEditorByInstance(editor: EditorInput, supportSideBySide?: SideBySideEditor): boolean { - - // Check if exact editor match is contained + containsEditorByInstance(editor: EditorInput): boolean { const index = this.indexOf(editor); if (index >= 0) { return true; } - // Optionally search by master/detail input if instructed - if (supportSideBySide && editor instanceof SideBySideEditorInput) { - const index = this.indexOf(supportSideBySide === SideBySideEditor.MASTER ? editor.master : editor.details); - if (index >= 0) { - return true; - } - } - return false; } diff --git a/src/vs/workbench/test/common/editor/editorGroups.test.ts b/src/vs/workbench/test/common/editor/editorGroups.test.ts index 987feb85fbad1..87564524de4b2 100644 --- a/src/vs/workbench/test/common/editor/editorGroups.test.ts +++ b/src/vs/workbench/test/common/editor/editorGroups.test.ts @@ -187,7 +187,7 @@ suite('Workbench editor groups', () => { assert.equal(clone.isActive(input3), true); }); - test('contains() with diff editor support', function () { + test('containsEditorByInstance()', function () { const group = createGroup(); const input1 = input(); @@ -196,14 +196,61 @@ suite('Workbench editor groups', () => { const diffInput1 = new DiffEditorInput('name', 'description', input1, input2); const diffInput2 = new DiffEditorInput('name', 'description', input2, input1); + group.openEditor(input1, { pinned: true, active: true }); + + assert.equal(group.containsEditorByInstance(input1), true); + assert.equal(group.containsEditorByInstance(input2), false); + assert.equal(group.containsEditorByInstance(diffInput1), false); + assert.equal(group.containsEditorByInstance(diffInput2), false); + group.openEditor(input2, { pinned: true, active: true }); - assert.equal(group.containsEditorByInstance(input2, SideBySideEditor.MASTER), true); + assert.equal(group.containsEditorByInstance(input1), true); + assert.equal(group.containsEditorByInstance(input2), true); + assert.equal(group.containsEditorByInstance(diffInput1), false); + assert.equal(group.containsEditorByInstance(diffInput2), false); + + group.openEditor(diffInput1, { pinned: true, active: true }); + + assert.equal(group.containsEditorByInstance(input1), true); + assert.equal(group.containsEditorByInstance(input2), true); + assert.equal(group.containsEditorByInstance(diffInput1), true); + assert.equal(group.containsEditorByInstance(diffInput2), false); + + group.openEditor(diffInput2, { pinned: true, active: true }); + + assert.equal(group.containsEditorByInstance(input1), true); + assert.equal(group.containsEditorByInstance(input2), true); + assert.equal(group.containsEditorByInstance(diffInput1), true); + assert.equal(group.containsEditorByInstance(diffInput2), true); + + group.closeEditor(input1); + + assert.equal(group.containsEditorByInstance(input1), false); + assert.equal(group.containsEditorByInstance(input2), true); + assert.equal(group.containsEditorByInstance(diffInput1), true); + assert.equal(group.containsEditorByInstance(diffInput2), true); + + group.closeEditor(input2); + + assert.equal(group.containsEditorByInstance(input1), false); + assert.equal(group.containsEditorByInstance(input2), false); + assert.equal(group.containsEditorByInstance(diffInput1), true); + assert.equal(group.containsEditorByInstance(diffInput2), true); + + group.closeEditor(diffInput1); + + assert.equal(group.containsEditorByInstance(input1), false); + assert.equal(group.containsEditorByInstance(input2), false); + assert.equal(group.containsEditorByInstance(diffInput1), false); + assert.equal(group.containsEditorByInstance(diffInput2), true); + + group.closeEditor(diffInput2); + + assert.equal(group.containsEditorByInstance(input1), false); + assert.equal(group.containsEditorByInstance(input2), false); assert.equal(group.containsEditorByInstance(diffInput1), false); - assert.equal(group.containsEditorByInstance(diffInput1, SideBySideEditor.MASTER), true); - assert.equal(group.containsEditorByInstance(diffInput1, SideBySideEditor.DETAILS), false); - assert.equal(group.containsEditorByInstance(diffInput2, SideBySideEditor.MASTER), false); - assert.equal(group.containsEditorByInstance(diffInput2, SideBySideEditor.DETAILS), true); + assert.equal(group.containsEditorByInstance(diffInput2), false); }); test('group serialization', function () { From 0c2f93d927fde50a6e6f8a1ef3411369862be950 Mon Sep 17 00:00:00 2001 From: isidor Date: Fri, 15 Nov 2019 11:37:28 +0100 Subject: [PATCH 329/352] Some strict property init #81574 --- src/vs/workbench/api/node/extHostDebugService.ts | 9 +++++---- .../debug/browser/breakpointEditorContribution.ts | 2 +- .../contrib/debug/browser/debugEditorContribution.ts | 4 ++-- .../contrib/debug/common/abstractDebugAdapter.ts | 6 ++---- src/vs/workbench/contrib/debug/common/debugModel.ts | 9 +++------ src/vs/workbench/contrib/debug/common/debugViewModel.ts | 9 +++------ 6 files changed, 16 insertions(+), 23 deletions(-) diff --git a/src/vs/workbench/api/node/extHostDebugService.ts b/src/vs/workbench/api/node/extHostDebugService.ts index bffcbcddd2b36..81e40b7f89305 100644 --- a/src/vs/workbench/api/node/extHostDebugService.ts +++ b/src/vs/workbench/api/node/extHostDebugService.ts @@ -38,6 +38,7 @@ import { ISignService } from 'vs/platform/sign/common/sign'; import { IExtHostTerminalService } from 'vs/workbench/api/common/extHostTerminalService'; import { IExtHostRpcService } from 'vs/workbench/api/common/extHostRpcService'; import { IExtHostDebugService } from 'vs/workbench/api/common/extHostDebugService'; +import { withNullAsUndefined } from 'vs/base/common/types'; export class ExtHostDebugService implements IExtHostDebugService, ExtHostDebugServiceShape { @@ -114,7 +115,7 @@ export class ExtHostDebugService implements IExtHostDebugService, ExtHostDebugSe this._onDidStartDebugSession = new Emitter(); this._onDidTerminateDebugSession = new Emitter(); - this._onDidChangeActiveDebugSession = new Emitter(); + this._onDidChangeActiveDebugSession = new Emitter(); this._onDidReceiveDebugSessionCustomEvent = new Emitter(); this._debugServiceProxy = extHostRpcService.getProxy(MainContext.MainThreadDebugService); @@ -511,11 +512,11 @@ export class ExtHostDebugService implements IExtHostDebugService, ExtHostDebugSe } this._debugServiceProxy.$acceptDAError(debugAdapterHandle, err.name, err.message, err.stack); }); - debugAdapter.onExit((code: number) => { + debugAdapter.onExit((code: number | null) => { if (tracker && tracker.onExit) { - tracker.onExit(code, undefined); + tracker.onExit(withNullAsUndefined(code), undefined); } - this._debugServiceProxy.$acceptDAExit(debugAdapterHandle, code, undefined); + this._debugServiceProxy.$acceptDAExit(debugAdapterHandle, withNullAsUndefined(code), undefined); }); if (tracker && tracker.onWillStartSession) { diff --git a/src/vs/workbench/contrib/debug/browser/breakpointEditorContribution.ts b/src/vs/workbench/contrib/debug/browser/breakpointEditorContribution.ts index f5e1e7b7a1b10..e0a2e8c8c1d47 100644 --- a/src/vs/workbench/contrib/debug/browser/breakpointEditorContribution.ts +++ b/src/vs/workbench/contrib/debug/browser/breakpointEditorContribution.ts @@ -239,7 +239,7 @@ class BreakpointEditorContribution implements IBreakpointEditorContribution { } this.ensureBreakpointHintDecoration(showBreakpointHintAtLineNumber); })); - this.toDispose.push(this.editor.onMouseLeave((e: IEditorMouseEvent) => { + this.toDispose.push(this.editor.onMouseLeave(() => { this.ensureBreakpointHintDecoration(-1); })); diff --git a/src/vs/workbench/contrib/debug/browser/debugEditorContribution.ts b/src/vs/workbench/contrib/debug/browser/debugEditorContribution.ts index 28fad67b4396a..b68c4991ebbfb 100644 --- a/src/vs/workbench/contrib/debug/browser/debugEditorContribution.ts +++ b/src/vs/workbench/contrib/debug/browser/debugEditorContribution.ts @@ -12,7 +12,7 @@ import { KeyCode } from 'vs/base/common/keyCodes'; import { IKeyboardEvent } from 'vs/base/browser/keyboardEvent'; import { StandardTokenType } from 'vs/editor/common/modes'; import { DEFAULT_WORD_REGEXP } from 'vs/editor/common/model/wordHelper'; -import { ICodeEditor, IEditorMouseEvent, MouseTargetType } from 'vs/editor/browser/editorBrowser'; +import { ICodeEditor, IEditorMouseEvent, MouseTargetType, IPartialEditorMouseEvent } from 'vs/editor/browser/editorBrowser'; import { registerEditorContribution } from 'vs/editor/browser/editorExtensions'; import { IDecorationOptions } from 'vs/editor/common/editorCommon'; import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService'; @@ -80,7 +80,7 @@ class DebugEditorContribution implements IDebugEditorContribution { this.toDispose.push(this.editor.onMouseDown((e: IEditorMouseEvent) => this.onEditorMouseDown(e))); this.toDispose.push(this.editor.onMouseUp(() => this.mouseDown = false)); this.toDispose.push(this.editor.onMouseMove((e: IEditorMouseEvent) => this.onEditorMouseMove(e))); - this.toDispose.push(this.editor.onMouseLeave((e: IEditorMouseEvent) => { + this.toDispose.push(this.editor.onMouseLeave((e: IPartialEditorMouseEvent) => { this.provideNonDebugHoverScheduler.cancel(); const hoverDomNode = this.hoverWidget.getDomNode(); if (!hoverDomNode) { diff --git a/src/vs/workbench/contrib/debug/common/abstractDebugAdapter.ts b/src/vs/workbench/contrib/debug/common/abstractDebugAdapter.ts index 56a9de64e264d..9cbc4234d6575 100644 --- a/src/vs/workbench/contrib/debug/common/abstractDebugAdapter.ts +++ b/src/vs/workbench/contrib/debug/common/abstractDebugAdapter.ts @@ -18,13 +18,11 @@ export abstract class AbstractDebugAdapter implements IDebugAdapter { private requestCallback: ((request: DebugProtocol.Request) => void) | undefined; private eventCallback: ((request: DebugProtocol.Event) => void) | undefined; private messageCallback: ((message: DebugProtocol.ProtocolMessage) => void) | undefined; - protected readonly _onError: Emitter; - protected readonly _onExit: Emitter; + protected readonly _onError = new Emitter(); + protected readonly _onExit = new Emitter(); constructor() { this.sequence = 1; - this._onError = new Emitter(); - this._onExit = new Emitter(); } abstract startSession(): Promise; diff --git a/src/vs/workbench/contrib/debug/common/debugModel.ts b/src/vs/workbench/contrib/debug/common/debugModel.ts index 0e647c09b2338..62586d2f4ce36 100644 --- a/src/vs/workbench/contrib/debug/common/debugModel.ts +++ b/src/vs/workbench/contrib/debug/common/debugModel.ts @@ -810,9 +810,9 @@ export class DebugModel implements IDebugModel { private toDispose: lifecycle.IDisposable[]; private schedulers = new Map(); private breakpointsActivated = true; - private readonly _onDidChangeBreakpoints: Emitter; - private readonly _onDidChangeCallStack: Emitter; - private readonly _onDidChangeWatchExpressions: Emitter; + private readonly _onDidChangeBreakpoints = new Emitter(); + private readonly _onDidChangeCallStack = new Emitter(); + private readonly _onDidChangeWatchExpressions = new Emitter(); constructor( private breakpoints: Breakpoint[], @@ -824,9 +824,6 @@ export class DebugModel implements IDebugModel { ) { this.sessions = []; this.toDispose = []; - this._onDidChangeBreakpoints = new Emitter(); - this._onDidChangeCallStack = new Emitter(); - this._onDidChangeWatchExpressions = new Emitter(); } getId(): string { diff --git a/src/vs/workbench/contrib/debug/common/debugViewModel.ts b/src/vs/workbench/contrib/debug/common/debugViewModel.ts index f261025e49dc6..7d0889b5c2660 100644 --- a/src/vs/workbench/contrib/debug/common/debugViewModel.ts +++ b/src/vs/workbench/contrib/debug/common/debugViewModel.ts @@ -17,9 +17,9 @@ export class ViewModel implements IViewModel { private _focusedThread: IThread | undefined; private selectedExpression: IExpression | undefined; private selectedFunctionBreakpoint: IFunctionBreakpoint | undefined; - private readonly _onDidFocusSession: Emitter; - private readonly _onDidFocusStackFrame: Emitter<{ stackFrame: IStackFrame | undefined, explicit: boolean }>; - private readonly _onDidSelectExpression: Emitter; + private readonly _onDidFocusSession = new Emitter(); + private readonly _onDidFocusStackFrame = new Emitter<{ stackFrame: IStackFrame | undefined, explicit: boolean }>(); + private readonly _onDidSelectExpression = new Emitter(); private multiSessionView: boolean; private expressionSelectedContextKey: IContextKey; private breakpointSelectedContextKey: IContextKey; @@ -30,9 +30,6 @@ export class ViewModel implements IViewModel { private jumpToCursorSupported: IContextKey; constructor(contextKeyService: IContextKeyService) { - this._onDidFocusSession = new Emitter(); - this._onDidFocusStackFrame = new Emitter<{ stackFrame: IStackFrame, explicit: boolean }>(); - this._onDidSelectExpression = new Emitter(); this.multiSessionView = false; this.expressionSelectedContextKey = CONTEXT_EXPRESSION_SELECTED.bindTo(contextKeyService); this.breakpointSelectedContextKey = CONTEXT_BREAKPOINT_SELECTED.bindTo(contextKeyService); From d189af8dd703ae07ab5e21d353ec4470727278bc Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Fri, 15 Nov 2019 11:57:39 +0100 Subject: [PATCH 330/352] Diff editor closes when closing left hand side editor in other tab (fixes #51039) --- .../browser/parts/editor/editorGroupView.ts | 19 +-- src/vs/workbench/common/editor/editorGroup.ts | 92 ++--------- .../test/common/editor/editorGroups.test.ts | 150 +++++------------- 3 files changed, 60 insertions(+), 201 deletions(-) diff --git a/src/vs/workbench/browser/parts/editor/editorGroupView.ts b/src/vs/workbench/browser/parts/editor/editorGroupView.ts index f42aac0dca0b9..87fdf2a8415b0 100644 --- a/src/vs/workbench/browser/parts/editor/editorGroupView.ts +++ b/src/vs/workbench/browser/parts/editor/editorGroupView.ts @@ -514,20 +514,13 @@ export class EditorGroupView extends Themable implements IEditorGroupView { const editorsToClose = [editor]; // Include both sides of side by side editors when being closed and not opened multiple times - if (editor instanceof SideBySideEditorInput && !this.accessor.groups.some(groupView => groupView.group.containsEditorByInstance(editor))) { + if (editor instanceof SideBySideEditorInput && !this.accessor.groups.some(groupView => groupView.group.contains(editor))) { editorsToClose.push(editor.master, editor.details); } // Dispose the editor when it is no longer open in any group including diff editors editorsToClose.forEach(editorToClose => { - const resource = editorToClose ? editorToClose.getResource() : undefined; // prefer resource to not close right-hand side editors of a diff editor - if (!this.accessor.groups.some(groupView => { - if (resource) { - return groupView.group.containsEditorByResource(resource, SideBySideEditor.MASTER); - } - - return groupView.group.containsEditorByInstance(editorToClose); - })) { + if (!this.accessor.groups.some(groupView => groupView.group.contains(editorToClose, true /* include side by side editor master & details */))) { editorToClose.dispose(); } }); @@ -584,7 +577,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView { editors.forEach(editor => { if (this._group.isActive(editor)) { activeEditor = editor; - } else if (this._group.containsEditorByInstance(editor)) { + } else if (this._group.contains(editor)) { inactiveEditors.push(editor); } }); @@ -776,7 +769,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView { } isOpened(editor: EditorInput): boolean { - return this._group.containsEditorByInstance(editor); + return this._group.contains(editor); } focus(): void { @@ -1287,11 +1280,11 @@ export class EditorGroupView extends Themable implements IEditorGroupView { } const otherGroup = groupView.group; - if (otherGroup.containsEditorByInstance(editor)) { + if (otherGroup.contains(editor)) { return true; // exact editor still opened } - if (editor instanceof SideBySideEditorInput && otherGroup.containsEditorByInstance(editor.master)) { + if (editor instanceof SideBySideEditorInput && otherGroup.contains(editor.master)) { return true; // master side of side by side editor still opened } diff --git a/src/vs/workbench/common/editor/editorGroup.ts b/src/vs/workbench/common/editor/editorGroup.ts index bb36fca7e2418..c8de4f913176e 100644 --- a/src/vs/workbench/common/editor/editorGroup.ts +++ b/src/vs/workbench/common/editor/editorGroup.ts @@ -4,13 +4,11 @@ *--------------------------------------------------------------------------------------------*/ import { Event, Emitter } from 'vs/base/common/event'; -import { Extensions, IEditorInputFactoryRegistry, EditorInput, toResource, IEditorIdentifier, IEditorCloseEvent, GroupIdentifier, SideBySideEditorInput, CloseDirection, IEditorInput, SideBySideEditor } from 'vs/workbench/common/editor'; -import { URI } from 'vs/base/common/uri'; +import { Extensions, IEditorInputFactoryRegistry, EditorInput, IEditorIdentifier, IEditorCloseEvent, GroupIdentifier, CloseDirection, IEditorInput, SideBySideEditorInput } from 'vs/workbench/common/editor'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IConfigurationService, IConfigurationChangeEvent } from 'vs/platform/configuration/common/configuration'; import { dispose, Disposable, DisposableStore } from 'vs/base/common/lifecycle'; import { Registry } from 'vs/platform/registry/common/platform'; -import { ResourceMap } from 'vs/base/common/map'; import { coalesce } from 'vs/base/common/arrays'; const EditorOpenPositioning = { @@ -94,10 +92,6 @@ export class EditorGroup extends Disposable { private editors: EditorInput[] = []; private mru: EditorInput[] = []; - private mapResourceToEditorCount = new ResourceMap(); - private mapResourceToMasterEditorCount = new ResourceMap(); - private mapResourceToDetailsEditorCount = new ResourceMap(); - private preview: EditorInput | null = null; // editor in preview state private active: EditorInput | null = null; // editor in active state @@ -494,7 +488,6 @@ export class EditorGroup extends Disposable { // Add if (!del && editor) { this.mru.push(editor); // make it LRU editor - this.updateResourceCounterMap(editor, false /* add */); // add new to resource map } // Remove / Replace @@ -504,66 +497,15 @@ export class EditorGroup extends Disposable { // Remove if (del && !editor) { this.mru.splice(indexInMRU, 1); // remove from MRU - this.updateResourceCounterMap(editorToDeleteOrReplace, true /* delete */); // remove from resource map } // Replace else if (del && editor) { this.mru.splice(indexInMRU, 1, editor); // replace MRU at location - this.updateResourceCounterMap(editor, false /* add */); // add new to resource map - this.updateResourceCounterMap(editorToDeleteOrReplace, true /* delete */); // remove replaced from resource map - } - } - } - - private updateResourceCounterMap(editor: EditorInput, remove: boolean): void { - - // Remember editor resource in map for fast lookup - const resource = toResource(editor); - if (resource) { - this.doUpdateResourceCounterMap(resource, this.mapResourceToEditorCount, remove); - } - - // Side by Side editor: store resource information - // for master and details side in separate maps - // to be able to lookup properly. - if (editor instanceof SideBySideEditorInput) { - const masterResource = toResource(editor.master); - if (masterResource) { - this.doUpdateResourceCounterMap(masterResource, this.mapResourceToMasterEditorCount, remove); - } - - const detailsResource = toResource(editor.details); - if (detailsResource) { - this.doUpdateResourceCounterMap(detailsResource, this.mapResourceToDetailsEditorCount, remove); } } } - private doUpdateResourceCounterMap(resource: URI, map: ResourceMap, remove: boolean): void { - - // It is possible to have the same resource opened twice (once as normal input and once as diff input) - // So we need to do ref counting on the resource to provide the correct picture - const counter = map.get(resource) || 0; - - // Add - let newCounter: number; - if (!remove) { - newCounter = counter + 1; - } - - // Delete - else { - newCounter = counter - 1; - } - - if (newCounter > 0) { - map.set(resource, newCounter); - } else { - map.delete(resource); - } - } - indexOf(candidate: IEditorInput | null, editors = this.editors): number { if (!candidate) { return -1; @@ -578,25 +520,17 @@ export class EditorGroup extends Disposable { return -1; } - containsEditorByResource(resource: URI, supportSideBySide?: SideBySideEditor): boolean { - - // Check if exact editor match is contained - let counter = this.mapResourceToEditorCount.get(resource); - - // Optionally search by master/detail resource if instructed - if (supportSideBySide === SideBySideEditor.MASTER) { - counter = counter || this.mapResourceToMasterEditorCount.get(resource); - } else if (supportSideBySide === SideBySideEditor.DETAILS) { - counter = counter || this.mapResourceToDetailsEditorCount.get(resource); - } - - return typeof counter === 'number' && counter > 0; - } + contains(candidate: EditorInput, searchInSideBySideEditors?: boolean): boolean { + for (const editor of this.editors) { + if (this.matches(editor, candidate)) { + return true; + } - containsEditorByInstance(editor: EditorInput): boolean { - const index = this.indexOf(editor); - if (index >= 0) { - return true; + if (searchInSideBySideEditors && editor instanceof SideBySideEditorInput) { + if (this.matches(editor.master, candidate) || this.matches(editor.details, candidate)) { + return true; + } + } } return false; @@ -625,9 +559,6 @@ export class EditorGroup extends Disposable { const group = this.instantiationService.createInstance(EditorGroup, undefined); group.editors = this.editors.slice(0); group.mru = this.mru.slice(0); - group.mapResourceToEditorCount = this.mapResourceToEditorCount.clone(); - group.mapResourceToMasterEditorCount = this.mapResourceToMasterEditorCount.clone(); - group.mapResourceToDetailsEditorCount = this.mapResourceToDetailsEditorCount.clone(); group.preview = this.preview; group.active = this.active; group.editorOpenPositioning = this.editorOpenPositioning; @@ -686,7 +617,6 @@ export class EditorGroup extends Disposable { const editor = factory.deserialize(this.instantiationService, e.value); if (editor) { this.registerEditorListeners(editor); - this.updateResourceCounterMap(editor, false /* add */); } return editor; diff --git a/src/vs/workbench/test/common/editor/editorGroups.test.ts b/src/vs/workbench/test/common/editor/editorGroups.test.ts index 87564524de4b2..6cacfb907465e 100644 --- a/src/vs/workbench/test/common/editor/editorGroups.test.ts +++ b/src/vs/workbench/test/common/editor/editorGroups.test.ts @@ -5,7 +5,7 @@ import * as assert from 'assert'; import { EditorGroup, ISerializedEditorGroup, EditorCloseEvent } from 'vs/workbench/common/editor/editorGroup'; -import { Extensions as EditorExtensions, IEditorInputFactoryRegistry, EditorInput, IFileEditorInput, IEditorInputFactory, CloseDirection, SideBySideEditor, toResource } from 'vs/workbench/common/editor'; +import { Extensions as EditorExtensions, IEditorInputFactoryRegistry, EditorInput, IFileEditorInput, IEditorInputFactory, CloseDirection } from 'vs/workbench/common/editor'; import { URI } from 'vs/base/common/uri'; import { TestLifecycleService, TestContextService, TestStorageService } from 'vs/workbench/test/workbenchTestServices'; import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService'; @@ -187,7 +187,7 @@ suite('Workbench editor groups', () => { assert.equal(clone.isActive(input3), true); }); - test('containsEditorByInstance()', function () { + test('contains()', function () { const group = createGroup(); const input1 = input(); @@ -198,59 +198,68 @@ suite('Workbench editor groups', () => { group.openEditor(input1, { pinned: true, active: true }); - assert.equal(group.containsEditorByInstance(input1), true); - assert.equal(group.containsEditorByInstance(input2), false); - assert.equal(group.containsEditorByInstance(diffInput1), false); - assert.equal(group.containsEditorByInstance(diffInput2), false); + assert.equal(group.contains(input1), true); + assert.equal(group.contains(input1, true), true); + assert.equal(group.contains(input2), false); + assert.equal(group.contains(input2, true), false); + assert.equal(group.contains(diffInput1), false); + assert.equal(group.contains(diffInput2), false); group.openEditor(input2, { pinned: true, active: true }); - assert.equal(group.containsEditorByInstance(input1), true); - assert.equal(group.containsEditorByInstance(input2), true); - assert.equal(group.containsEditorByInstance(diffInput1), false); - assert.equal(group.containsEditorByInstance(diffInput2), false); + assert.equal(group.contains(input1), true); + assert.equal(group.contains(input2), true); + assert.equal(group.contains(diffInput1), false); + assert.equal(group.contains(diffInput2), false); group.openEditor(diffInput1, { pinned: true, active: true }); - assert.equal(group.containsEditorByInstance(input1), true); - assert.equal(group.containsEditorByInstance(input2), true); - assert.equal(group.containsEditorByInstance(diffInput1), true); - assert.equal(group.containsEditorByInstance(diffInput2), false); + assert.equal(group.contains(input1), true); + assert.equal(group.contains(input2), true); + assert.equal(group.contains(diffInput1), true); + assert.equal(group.contains(diffInput2), false); group.openEditor(diffInput2, { pinned: true, active: true }); - assert.equal(group.containsEditorByInstance(input1), true); - assert.equal(group.containsEditorByInstance(input2), true); - assert.equal(group.containsEditorByInstance(diffInput1), true); - assert.equal(group.containsEditorByInstance(diffInput2), true); + assert.equal(group.contains(input1), true); + assert.equal(group.contains(input2), true); + assert.equal(group.contains(diffInput1), true); + assert.equal(group.contains(diffInput2), true); group.closeEditor(input1); - assert.equal(group.containsEditorByInstance(input1), false); - assert.equal(group.containsEditorByInstance(input2), true); - assert.equal(group.containsEditorByInstance(diffInput1), true); - assert.equal(group.containsEditorByInstance(diffInput2), true); + assert.equal(group.contains(input1), false); + assert.equal(group.contains(input1, true), true); + assert.equal(group.contains(input2), true); + assert.equal(group.contains(diffInput1), true); + assert.equal(group.contains(diffInput2), true); group.closeEditor(input2); - assert.equal(group.containsEditorByInstance(input1), false); - assert.equal(group.containsEditorByInstance(input2), false); - assert.equal(group.containsEditorByInstance(diffInput1), true); - assert.equal(group.containsEditorByInstance(diffInput2), true); + assert.equal(group.contains(input1), false); + assert.equal(group.contains(input1, true), true); + assert.equal(group.contains(input2), false); + assert.equal(group.contains(input2, true), true); + assert.equal(group.contains(diffInput1), true); + assert.equal(group.contains(diffInput2), true); group.closeEditor(diffInput1); - assert.equal(group.containsEditorByInstance(input1), false); - assert.equal(group.containsEditorByInstance(input2), false); - assert.equal(group.containsEditorByInstance(diffInput1), false); - assert.equal(group.containsEditorByInstance(diffInput2), true); + assert.equal(group.contains(input1), false); + assert.equal(group.contains(input1, true), true); + assert.equal(group.contains(input2), false); + assert.equal(group.contains(input2, true), true); + assert.equal(group.contains(diffInput1), false); + assert.equal(group.contains(diffInput2), true); group.closeEditor(diffInput2); - assert.equal(group.containsEditorByInstance(input1), false); - assert.equal(group.containsEditorByInstance(input2), false); - assert.equal(group.containsEditorByInstance(diffInput1), false); - assert.equal(group.containsEditorByInstance(diffInput2), false); + assert.equal(group.contains(input1), false); + assert.equal(group.contains(input1, true), false); + assert.equal(group.contains(input2), false); + assert.equal(group.contains(input2, true), false); + assert.equal(group.contains(diffInput1), false); + assert.equal(group.contains(diffInput2), false); }); test('group serialization', function () { @@ -1213,79 +1222,6 @@ suite('Workbench editor groups', () => { assert.equal(group1.getEditors()[1].matches(serializableInput2), true); }); - test('Multiple Editors - Resources', function () { - const group1 = createGroup(); - const group2 = createGroup(); - - function getEditorByResource(group: EditorGroup, resource: URI): EditorInput | undefined { - if (!group.containsEditorByResource(resource)) { - return undefined; // fast check for resource opened or not - } - - for (const editor of group.getEditors()) { - const editorResource = toResource(editor); - if (editorResource?.toString() === resource.toString()) { - return editor; - } - } - - return undefined; - } - - const input1Resource = URI.file('/hello/world.txt'); - const input1ResourceUpper = URI.file('/hello/WORLD.txt'); - const input1 = input(undefined, false, input1Resource); - group1.openEditor(input1); - - assert.ok(group1.containsEditorByResource(input1Resource)); - assert.equal(getEditorByResource(group1, input1Resource), input1); - - assert.ok(!getEditorByResource(group1, input1ResourceUpper)); - assert.ok(!group1.containsEditorByResource(input1ResourceUpper)); - - group2.openEditor(input1); - group1.closeEditor(input1); - - assert.ok(!group1.containsEditorByResource(input1Resource)); - assert.ok(!getEditorByResource(group1, input1Resource)); - assert.ok(!getEditorByResource(group1, input1ResourceUpper)); - assert.ok(group2.containsEditorByResource(input1Resource)); - assert.equal(getEditorByResource(group2, input1Resource), input1); - - const input1ResourceClone = URI.file('/hello/world.txt'); - const input1Clone = input(undefined, false, input1ResourceClone); - group1.openEditor(input1Clone); - - assert.ok(group1.containsEditorByResource(input1Resource)); - - group2.closeEditor(input1); - - assert.ok(group1.containsEditorByResource(input1Resource)); - assert.equal(getEditorByResource(group1, input1Resource), input1Clone); - assert.ok(!group2.containsEditorByResource(input1Resource)); - - group1.closeEditor(input1Clone); - - assert.ok(!group1.containsEditorByResource(input1Resource)); - - const masterResource = URI.file('/hello/world2.txt'); - const masterInput = input(undefined, false, masterResource); - - const detailsResource = URI.file('/hello/world3.txt'); - const detailsInput = input(undefined, false, detailsResource); - - const diffEditorInput = new DiffEditorInput('name', 'description', detailsInput, masterInput); - group1.openEditor(diffEditorInput); - - assert.equal(group1.containsEditorByResource(masterResource), false); - assert.equal(group1.containsEditorByResource(masterResource, SideBySideEditor.MASTER), true); - assert.equal(group1.containsEditorByResource(masterResource, SideBySideEditor.DETAILS), false); - - assert.equal(group1.containsEditorByResource(detailsResource), false); - assert.equal(group1.containsEditorByResource(detailsResource, SideBySideEditor.MASTER), false); - assert.equal(group1.containsEditorByResource(detailsResource, SideBySideEditor.DETAILS), true); - }); - test('Multiple Editors - Editor Dispose', function () { const group1 = createGroup(); const group2 = createGroup(); From f9a52f260a11afb455d79ad4684cfcd730bbe206 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Fri, 15 Nov 2019 11:21:06 +0100 Subject: [PATCH 331/352] remove the marketplace azure search cache as it is enabled by default --- src/vs/code/electron-main/window.ts | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/src/vs/code/electron-main/window.ts b/src/vs/code/electron-main/window.ts index b55f4095e3b82..5eb01d0c5d7f7 100644 --- a/src/vs/code/electron-main/window.ts +++ b/src/vs/code/electron-main/window.ts @@ -438,15 +438,8 @@ export class CodeWindow extends Disposable implements ICodeWindow { // Inject headers when requests are incoming const urls = ['https://marketplace.visualstudio.com/*', 'https://*.vsassets.io/*']; - this._win.webContents.session.webRequest.onBeforeSendHeaders({ urls }, (details, cb) => { - this.marketplaceHeadersPromise.then(headers => { - const requestHeaders = objects.assign(details.requestHeaders, headers) as { [key: string]: string | undefined }; - if (!this.configurationService.getValue('extensions.disableExperimentalAzureSearch')) { - requestHeaders['Cookie'] = `${requestHeaders['Cookie'] ? requestHeaders['Cookie'] + ';' : ''}EnableExternalSearchForVSCode=true`; - } - cb({ cancel: false, requestHeaders }); - }); - }); + this._win.webContents.session.webRequest.onBeforeSendHeaders({ urls }, (details, cb) => + this.marketplaceHeadersPromise.then(headers => cb({ cancel: false, requestHeaders: objects.assign(details.requestHeaders, headers) as { [key: string]: string | undefined } }))); } private onWindowError(error: WindowError): void { From 731ebce145cd219564c8f9a4e30d72ec264596fe Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Fri, 15 Nov 2019 12:12:58 +0100 Subject: [PATCH 332/352] Fix #83135 --- src/vs/workbench/contrib/markers/browser/media/markers.css | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/vs/workbench/contrib/markers/browser/media/markers.css b/src/vs/workbench/contrib/markers/browser/media/markers.css index 963bf4a95efbc..73aab9391ecae 100644 --- a/src/vs/workbench/contrib/markers/browser/media/markers.css +++ b/src/vs/workbench/contrib/markers/browser/media/markers.css @@ -154,10 +154,6 @@ justify-content: center; } -.markers-panel .monaco-tl-contents .actions .action-item { - margin-right: 2px; -} - .markers-panel .markers-panel-container .tree-container .monaco-tl-contents .marker-source, .markers-panel .markers-panel-container .tree-container .monaco-tl-contents .related-info-resource, .markers-panel .markers-panel-container .tree-container .monaco-tl-contents .related-info-resource-separator, From c96c45dffeeb8355defd9a2fbb79722e31d3b113 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Fri, 15 Nov 2019 12:37:59 +0100 Subject: [PATCH 333/352] :lipstick --- .../contrib/markers/browser/markersPanel.ts | 45 +++++++++---------- 1 file changed, 22 insertions(+), 23 deletions(-) diff --git a/src/vs/workbench/contrib/markers/browser/markersPanel.ts b/src/vs/workbench/contrib/markers/browser/markersPanel.ts index 5b650202a9066..239f59aa6d8f8 100644 --- a/src/vs/workbench/contrib/markers/browser/markersPanel.ts +++ b/src/vs/workbench/contrib/markers/browser/markersPanel.ts @@ -482,9 +482,8 @@ export class MarkersPanel extends Panel implements IMarkerFilterController { this.setCurrentActiveEditor(); if (this.filterAction.activeFile) { this.refreshPanel(); - } else { - this.autoReveal(); } + this.autoReveal(); } private setCurrentActiveEditor(): void { @@ -547,32 +546,32 @@ export class MarkersPanel extends Panel implements IMarkerFilterController { } private autoReveal(focus: boolean = false): void { + // No need to auto reveal if active file filter is on + if (this.filterAction.activeFile) { + return; + } let autoReveal = this.configurationService.getValue('problems.autoReveal'); if (typeof autoReveal === 'boolean' && autoReveal) { - this.revealMarkersForCurrentActiveEditor(focus); - } - } - - private revealMarkersForCurrentActiveEditor(focus: boolean = false): void { - let currentActiveResource = this.getResourceForCurrentActiveResource(); - if (currentActiveResource) { - if (!this.tree.isCollapsed(currentActiveResource) && this.hasSelectedMarkerFor(currentActiveResource)) { - this.tree.reveal(this.tree.getSelection()[0], this.lastSelectedRelativeTop); - if (focus) { - this.tree.setFocus(this.tree.getSelection()); - } - } else { - this.tree.expand(currentActiveResource); - this.tree.reveal(currentActiveResource, 0); + let currentActiveResource = this.getResourceForCurrentActiveResource(); + if (currentActiveResource) { + if (!this.tree.isCollapsed(currentActiveResource) && this.hasSelectedMarkerFor(currentActiveResource)) { + this.tree.reveal(this.tree.getSelection()[0], this.lastSelectedRelativeTop); + if (focus) { + this.tree.setFocus(this.tree.getSelection()); + } + } else { + this.tree.expand(currentActiveResource); + this.tree.reveal(currentActiveResource, 0); - if (focus) { - this.tree.setFocus([currentActiveResource]); - this.tree.setSelection([currentActiveResource]); + if (focus) { + this.tree.setFocus([currentActiveResource]); + this.tree.setSelection([currentActiveResource]); + } } + } else if (focus) { + this.tree.setSelection([]); + this.tree.focusFirst(); } - } else if (focus) { - this.tree.setSelection([]); - this.tree.focusFirst(); } } From 3be1521df277ba99e8ce40e964c33a8fd83e7e7a Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Fri, 15 Nov 2019 15:19:04 +0100 Subject: [PATCH 334/352] Fix #82677 --- .../contrib/extensions/browser/extensionsActions.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/contrib/extensions/browser/extensionsActions.ts b/src/vs/workbench/contrib/extensions/browser/extensionsActions.ts index 2b847bf7ab540..d3e7af804db5e 100644 --- a/src/vs/workbench/contrib/extensions/browser/extensionsActions.ts +++ b/src/vs/workbench/contrib/extensions/browser/extensionsActions.ts @@ -59,7 +59,7 @@ import { IPreferencesService } from 'vs/workbench/services/preferences/common/pr import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; import { IProductService } from 'vs/platform/product/common/productService'; import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService'; -import { IFileDialogService } from 'vs/platform/dialogs/common/dialogs'; +import { IFileDialogService, IDialogService } from 'vs/platform/dialogs/common/dialogs'; import { IProgressService, ProgressLocation } from 'vs/platform/progress/common/progress'; export function toExtensionDescription(local: ILocalExtension): IExtensionDescription { @@ -1051,6 +1051,7 @@ export class CheckForUpdatesAction extends Action { @IExtensionsWorkbenchService private readonly extensionsWorkbenchService: IExtensionsWorkbenchService, @IExtensionEnablementService private readonly extensionEnablementService: IExtensionEnablementService, @IViewletService private readonly viewletService: IViewletService, + @IDialogService private readonly dialogService: IDialogService, @INotificationService private readonly notificationService: INotificationService ) { super(id, label, '', true); @@ -1059,7 +1060,7 @@ export class CheckForUpdatesAction extends Action { private checkUpdatesAndNotify(): void { const outdated = this.extensionsWorkbenchService.outdated; if (!outdated.length) { - this.notificationService.info(localize('noUpdatesAvailable', "All extensions are up to date.")); + this.dialogService.show(Severity.Info, localize('noUpdatesAvailable', "All extensions are up to date."), [localize('ok', "OK")]); return; } From 72c2f506de1220bf5cdd1a1a8b2868335728c090 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Fri, 15 Nov 2019 15:36:49 +0100 Subject: [PATCH 335/352] working copy - introduce first save/revert semantics (#84672) --- .../api/browser/mainThreadSaveParticipant.ts | 3 +- .../workbench/api/common/extHost.protocol.ts | 2 +- .../common/extHostDocumentSaveParticipant.ts | 2 +- .../api/common/extHostTypeConverters.ts | 3 +- .../browser/parts/editor/textEditor.ts | 3 +- src/vs/workbench/common/editor.ts | 31 ++++----- .../common/editor/untitledTextEditorInput.ts | 7 +- .../common/editor/untitledTextEditorModel.ts | 14 +++- .../customEditor/browser/customEditorModel.ts | 14 +++- .../contrib/files/browser/fileCommands.ts | 3 +- .../files/common/editors/fileEditorInput.ts | 9 +-- .../browser/testCustomEditors.ts | 12 ++-- .../dialogs/browser/simpleFileDialog.ts | 4 +- .../textfile/browser/textFileService.ts | 24 +++---- .../textfile/common/textFileEditorModel.ts | 23 ++++--- .../services/textfile/common/textfiles.ts | 20 ++---- .../textfile/test/textFileEditorModel.test.ts | 4 +- .../test/textFileEditorModelManager.test.ts | 2 +- .../workingCopy/common/workingCopyService.ts | 67 +++++++++++++++++++ .../test/common/workingCopyService.test.ts | 5 +- .../extHostDocumentSaveParticipant.test.ts | 2 +- .../api/mainThreadSaveParticipant.test.ts | 3 +- 22 files changed, 169 insertions(+), 88 deletions(-) diff --git a/src/vs/workbench/api/browser/mainThreadSaveParticipant.ts b/src/vs/workbench/api/browser/mainThreadSaveParticipant.ts index 3e79332f086b5..9d0778cfd0d1b 100644 --- a/src/vs/workbench/api/browser/mainThreadSaveParticipant.ts +++ b/src/vs/workbench/api/browser/mainThreadSaveParticipant.ts @@ -30,7 +30,8 @@ import { ILogService } from 'vs/platform/log/common/log'; import { IProgressService, ProgressLocation } from 'vs/platform/progress/common/progress'; import { extHostCustomer } from 'vs/workbench/api/common/extHostCustomers'; import { TextFileEditorModel } from 'vs/workbench/services/textfile/common/textFileEditorModel'; -import { ISaveParticipant, SaveReason, IResolvedTextFileEditorModel } from 'vs/workbench/services/textfile/common/textfiles'; +import { ISaveParticipant, IResolvedTextFileEditorModel } from 'vs/workbench/services/textfile/common/textfiles'; +import { SaveReason } from 'vs/workbench/services/workingCopy/common/workingCopyService'; import { ExtHostContext, ExtHostDocumentSaveParticipantShape, IExtHostContext } from '../common/extHost.protocol'; export interface ICodeActionsOnSaveOptions { diff --git a/src/vs/workbench/api/common/extHost.protocol.ts b/src/vs/workbench/api/common/extHost.protocol.ts index 5df456ab6c7e1..60701e91b6f4b 100644 --- a/src/vs/workbench/api/common/extHost.protocol.ts +++ b/src/vs/workbench/api/common/extHost.protocol.ts @@ -45,7 +45,7 @@ import { ITerminalDimensions, IShellLaunchConfig } from 'vs/workbench/contrib/te import { ExtensionActivationError } from 'vs/workbench/services/extensions/common/extensions'; import { createExtHostContextProxyIdentifier as createExtId, createMainContextProxyIdentifier as createMainId, IRPCProtocol } from 'vs/workbench/services/extensions/common/proxyIdentifier'; import * as search from 'vs/workbench/services/search/common/search'; -import { SaveReason } from 'vs/workbench/services/textfile/common/textfiles'; +import { SaveReason } from 'vs/workbench/services/workingCopy/common/workingCopyService'; import { ExtensionActivationReason } from 'vs/workbench/api/common/extHostExtensionActivator'; export interface IEnvironment { diff --git a/src/vs/workbench/api/common/extHostDocumentSaveParticipant.ts b/src/vs/workbench/api/common/extHostDocumentSaveParticipant.ts index f55a89b3f30ba..3b1b80c1de4f2 100644 --- a/src/vs/workbench/api/common/extHostDocumentSaveParticipant.ts +++ b/src/vs/workbench/api/common/extHostDocumentSaveParticipant.ts @@ -11,7 +11,7 @@ import { ExtHostDocumentSaveParticipantShape, MainThreadTextEditorsShape, IResou import { TextEdit } from 'vs/workbench/api/common/extHostTypes'; import { Range, TextDocumentSaveReason, EndOfLine } from 'vs/workbench/api/common/extHostTypeConverters'; import { ExtHostDocuments } from 'vs/workbench/api/common/extHostDocuments'; -import { SaveReason } from 'vs/workbench/services/textfile/common/textfiles'; +import { SaveReason } from 'vs/workbench/services/workingCopy/common/workingCopyService'; import * as vscode from 'vscode'; import { LinkedList } from 'vs/base/common/linkedList'; import { ILogService } from 'vs/platform/log/common/log'; diff --git a/src/vs/workbench/api/common/extHostTypeConverters.ts b/src/vs/workbench/api/common/extHostTypeConverters.ts index a0671a6e51ef6..3361a6e5d666b 100644 --- a/src/vs/workbench/api/common/extHostTypeConverters.ts +++ b/src/vs/workbench/api/common/extHostTypeConverters.ts @@ -13,7 +13,7 @@ import { EndOfLineSequence, TrackedRangeStickiness } from 'vs/editor/common/mode import * as vscode from 'vscode'; import { URI, UriComponents } from 'vs/base/common/uri'; import { ProgressLocation as MainProgressLocation } from 'vs/platform/progress/common/progress'; -import { SaveReason } from 'vs/workbench/services/textfile/common/textfiles'; +import { SaveReason } from 'vs/workbench/services/workingCopy/common/workingCopyService'; import { IPosition } from 'vs/editor/common/core/position'; import * as editorRange from 'vs/editor/common/core/range'; import { ISelection } from 'vs/editor/common/core/selection'; @@ -31,7 +31,6 @@ import { LogLevel as _MainLogLevel } from 'vs/platform/log/common/log'; import { coalesce, isNonEmptyArray } from 'vs/base/common/arrays'; import { RenderLineNumbersType } from 'vs/editor/common/config/editorOptions'; - export interface PositionLike { line: number; character: number; diff --git a/src/vs/workbench/browser/parts/editor/textEditor.ts b/src/vs/workbench/browser/parts/editor/textEditor.ts index cb3930fa43ad4..b9e4dcc4696da 100644 --- a/src/vs/workbench/browser/parts/editor/textEditor.ts +++ b/src/vs/workbench/browser/parts/editor/textEditor.ts @@ -16,7 +16,8 @@ import { IStorageService } from 'vs/platform/storage/common/storage'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IThemeService } from 'vs/platform/theme/common/themeService'; -import { ITextFileService, SaveReason } from 'vs/workbench/services/textfile/common/textfiles'; +import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; +import { SaveReason } from 'vs/workbench/services/workingCopy/common/workingCopyService'; import { ITextResourceConfigurationService } from 'vs/editor/common/services/resourceConfiguration'; import { IEditorOptions } from 'vs/editor/common/config/editorOptions'; import { isDiffEditor, isCodeEditor, getCodeEditor } from 'vs/editor/browser/editorBrowser'; diff --git a/src/vs/workbench/common/editor.ts b/src/vs/workbench/common/editor.ts index e6a70ab470275..aff98eee1b05c 100644 --- a/src/vs/workbench/common/editor.ts +++ b/src/vs/workbench/common/editor.ts @@ -20,6 +20,7 @@ import { ActionRunner, IAction } from 'vs/base/common/actions'; import { IFileService } from 'vs/platform/files/common/files'; import { IPathData } from 'vs/platform/windows/common/windows'; import { coalesce, firstOrDefault } from 'vs/base/common/arrays'; +import { ISaveOptions, IRevertOptions } from 'vs/workbench/services/workingCopy/common/workingCopyService'; export const ActiveEditorContext = new RawContextKey('activeEditor', null); export const ActiveEditorIsSaveableContext = new RawContextKey('activeEditorIsSaveable', false); @@ -261,25 +262,12 @@ export const enum Verbosity { LONG } -export interface IRevertOptions { - - /** - * Forces to load the contents of the editor again even if the editor is not dirty. - */ - force?: boolean; - - /** - * A soft revert will clear dirty state of an editor but will not attempt to load it. - */ - soft?: boolean; -} - export interface IEditorInput extends IDisposable { /** * Triggered when this input is disposed. */ - onDispose: Event; + readonly onDispose: Event; /** * Returns the associated resource of this input. @@ -316,6 +304,11 @@ export interface IEditorInput extends IDisposable { */ isDirty(): boolean; + /** + * Saves the editor if it is dirty. + */ + save(options?: ISaveOptions): Promise; + /** * Reverts this input. */ @@ -418,7 +411,7 @@ export abstract class EditorInput extends Disposable implements IEditorInput { /** * Saves the editor if it is dirty. Subclasses return a promise with a boolean indicating the success of the operation. */ - save(): Promise { + save(options?: ISaveOptions): Promise { return Promise.resolve(true); } @@ -553,12 +546,12 @@ export class SideBySideEditorInput extends EditorInput { return this.master.isDirty(); } - save(): Promise { - return this.master.save(); + save(options?: ISaveOptions): Promise { + return this.master.save(options); } - revert(): Promise { - return this.master.revert(); + revert(options?: IRevertOptions): Promise { + return this.master.revert(options); } getTelemetryDescriptor(): { [key: string]: unknown } { diff --git a/src/vs/workbench/common/editor/untitledTextEditorInput.ts b/src/vs/workbench/common/editor/untitledTextEditorInput.ts index 3e2998c3e2948..14c409a73eb0c 100644 --- a/src/vs/workbench/common/editor/untitledTextEditorInput.ts +++ b/src/vs/workbench/common/editor/untitledTextEditorInput.ts @@ -15,6 +15,7 @@ import { Event, Emitter } from 'vs/base/common/event'; import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; import { ILabelService } from 'vs/platform/label/common/label'; import { IResolvedTextEditorModel } from 'vs/editor/common/services/resolverService'; +import { ISaveOptions, IRevertOptions } from 'vs/workbench/services/workingCopy/common/workingCopyService'; /** * An editor input to be used for untitled text buffers. @@ -146,11 +147,11 @@ export class UntitledTextEditorInput extends EditorInput implements IEncodingSup return false; } - save(): Promise { - return this.textFileService.save(this.resource); + save(options?: ISaveOptions): Promise { + return this.textFileService.save(this.resource, options); } - revert(): Promise { + revert(options?: IRevertOptions): Promise { if (this.cachedModel) { this.cachedModel.revert(); } diff --git a/src/vs/workbench/common/editor/untitledTextEditorModel.ts b/src/vs/workbench/common/editor/untitledTextEditorModel.ts index b0d22deb9b3ad..280ad2c1068bc 100644 --- a/src/vs/workbench/common/editor/untitledTextEditorModel.ts +++ b/src/vs/workbench/common/editor/untitledTextEditorModel.ts @@ -16,7 +16,8 @@ import { ITextResourceConfigurationService } from 'vs/editor/common/services/res import { ITextBufferFactory } from 'vs/editor/common/model'; import { createTextBufferFactory } from 'vs/editor/common/model/textModel'; import { IResolvedTextEditorModel } from 'vs/editor/common/services/resolverService'; -import { IWorkingCopyService, IWorkingCopy } from 'vs/workbench/services/workingCopy/common/workingCopyService'; +import { IWorkingCopyService, IWorkingCopy, ISaveOptions } from 'vs/workbench/services/workingCopy/common/workingCopyService'; +import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; export class UntitledTextEditorModel extends BaseTextEditorModel implements IEncodingSupport, IWorkingCopy { @@ -48,7 +49,8 @@ export class UntitledTextEditorModel extends BaseTextEditorModel implements IEnc @IModelService modelService: IModelService, @IBackupFileService private readonly backupFileService: IBackupFileService, @ITextResourceConfigurationService private readonly configurationService: ITextResourceConfigurationService, - @IWorkingCopyService private readonly workingCopyService: IWorkingCopyService + @IWorkingCopyService private readonly workingCopyService: IWorkingCopyService, + @ITextFileService private readonly textFileService: ITextFileService ) { super(modelService, modeService); @@ -115,11 +117,17 @@ export class UntitledTextEditorModel extends BaseTextEditorModel implements IEnc this._onDidChangeDirty.fire(); } - revert(): void { + save(options?: ISaveOptions): Promise { + return this.textFileService.save(this.resource, options); + } + + async revert(): Promise { this.setDirty(false); // Handle content change event buffered this.contentChangeEventScheduler.schedule(); + + return true; } backup(): Promise { diff --git a/src/vs/workbench/contrib/customEditor/browser/customEditorModel.ts b/src/vs/workbench/contrib/customEditor/browser/customEditorModel.ts index 4afe96cdc35dd..255c8f09f1653 100644 --- a/src/vs/workbench/contrib/customEditor/browser/customEditorModel.ts +++ b/src/vs/workbench/contrib/customEditor/browser/customEditorModel.ts @@ -6,7 +6,7 @@ import { Emitter, Event } from 'vs/base/common/event'; import { Disposable } from 'vs/base/common/lifecycle'; import { URI } from 'vs/base/common/uri'; -import { IWorkingCopy, IWorkingCopyService, WorkingCopyCapabilities } from 'vs/workbench/services/workingCopy/common/workingCopyService'; +import { IWorkingCopy, IWorkingCopyService, WorkingCopyCapabilities, ISaveOptions, IRevertOptions } from 'vs/workbench/services/workingCopy/common/workingCopyService'; type Edit = string; @@ -56,9 +56,19 @@ export class CustomEditorModel extends Disposable implements IWorkingCopy { this._onDidChangeDirty.fire(); } - public save() { + public async save(options?: ISaveOptions) { this._savePoint = this._edits.length; this.updateDirty(); + + return true; + } + + public async revert(options?: IRevertOptions) { + while (this._currentEditIndex > 0) { + this.undo(); + } + + return true; } public undo() { diff --git a/src/vs/workbench/contrib/files/browser/fileCommands.ts b/src/vs/workbench/contrib/files/browser/fileCommands.ts index e6192c5c094f9..7fb4fcbab7ce5 100644 --- a/src/vs/workbench/contrib/files/browser/fileCommands.ts +++ b/src/vs/workbench/contrib/files/browser/fileCommands.ts @@ -14,7 +14,8 @@ import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace import { ExplorerFocusCondition, TextFileContentProvider, VIEWLET_ID, IExplorerService } from 'vs/workbench/contrib/files/common/files'; import { ExplorerViewlet } from 'vs/workbench/contrib/files/browser/explorerViewlet'; import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService'; -import { ITextFileService, ISaveOptions } from 'vs/workbench/services/textfile/common/textfiles'; +import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; +import { ISaveOptions } from 'vs/workbench/services/workingCopy/common/workingCopyService'; import { toErrorMessage } from 'vs/base/common/errorMessage'; import { IListService } from 'vs/platform/list/browser/listService'; import { CommandsRegistry } from 'vs/platform/commands/common/commands'; diff --git a/src/vs/workbench/contrib/files/common/editors/fileEditorInput.ts b/src/vs/workbench/contrib/files/common/editors/fileEditorInput.ts index 104bebe8fb3b3..b6aa3d45ac279 100644 --- a/src/vs/workbench/contrib/files/common/editors/fileEditorInput.ts +++ b/src/vs/workbench/contrib/files/common/editors/fileEditorInput.ts @@ -7,11 +7,12 @@ import { localize } from 'vs/nls'; import { createMemoizer } from 'vs/base/common/decorators'; import { dirname } from 'vs/base/common/resources'; import { URI } from 'vs/base/common/uri'; -import { EncodingMode, EditorInput, IFileEditorInput, ITextEditorModel, Verbosity, IRevertOptions } from 'vs/workbench/common/editor'; +import { EncodingMode, EditorInput, IFileEditorInput, ITextEditorModel, Verbosity } from 'vs/workbench/common/editor'; +import { IRevertOptions } from 'vs/workbench/services/workingCopy/common/workingCopyService'; import { TextFileEditorModel } from 'vs/workbench/services/textfile/common/textFileEditorModel'; import { BinaryEditorModel } from 'vs/workbench/common/editor/binaryEditorModel'; import { FileOperationError, FileOperationResult, IFileService } from 'vs/platform/files/common/files'; -import { ITextFileService, ModelState, TextFileModelChangeEvent, LoadReason, TextFileOperationError, TextFileOperationResult } from 'vs/workbench/services/textfile/common/textfiles'; +import { ITextFileService, ModelState, TextFileModelChangeEvent, LoadReason, TextFileOperationError, TextFileOperationResult, ITextFileSaveOptions } from 'vs/workbench/services/textfile/common/textfiles'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IReference } from 'vs/base/common/lifecycle'; import { ITextModelService } from 'vs/editor/common/services/resolverService'; @@ -243,8 +244,8 @@ export class FileEditorInput extends EditorInput implements IFileEditorInput { return model.isDirty(); } - save(): Promise { - return this.textFileService.save(this.resource); + save(options?: ITextFileSaveOptions): Promise { + return this.textFileService.save(this.resource, options); } revert(options?: IRevertOptions): Promise { diff --git a/src/vs/workbench/contrib/testCustomEditors/browser/testCustomEditors.ts b/src/vs/workbench/contrib/testCustomEditors/browser/testCustomEditors.ts index 1a716bb01805c..ab34523d3917d 100644 --- a/src/vs/workbench/contrib/testCustomEditors/browser/testCustomEditors.ts +++ b/src/vs/workbench/contrib/testCustomEditors/browser/testCustomEditors.ts @@ -6,7 +6,7 @@ import * as nls from 'vs/nls'; import { Action } from 'vs/base/common/actions'; import { BaseEditor } from 'vs/workbench/browser/parts/editor/baseEditor'; -import { IEditorInputFactory, EditorInput, IEditorInputFactoryRegistry, Extensions as EditorInputExtensions, EditorModel, IRevertOptions, EditorOptions } from 'vs/workbench/common/editor'; +import { IEditorInputFactory, EditorInput, IEditorInputFactoryRegistry, Extensions as EditorInputExtensions, EditorModel, EditorOptions } from 'vs/workbench/common/editor'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IEditorModel } from 'vs/platform/editor/common/editor'; import { Dimension, addDisposableListener, EventType } from 'vs/base/browser/dom'; @@ -24,7 +24,7 @@ import { isEqual } from 'vs/base/common/resources'; import { generateUuid } from 'vs/base/common/uuid'; import { CancellationToken } from 'vs/base/common/cancellation'; import { editorBackground, editorForeground } from 'vs/platform/theme/common/colorRegistry'; -import { IWorkingCopy, IWorkingCopyService } from 'vs/workbench/services/workingCopy/common/workingCopyService'; +import { IWorkingCopy, IWorkingCopyService, IRevertOptions, ISaveOptions } from 'vs/workbench/services/workingCopy/common/workingCopyService'; import { env } from 'vs/base/common/process'; const CUSTOM_SCHEME = 'testCustomEditor'; @@ -160,16 +160,16 @@ class TestCustomEditorInput extends EditorInput implements IWorkingCopy { return this.dirty; } - save(): Promise { + async save(options?: ISaveOptions): Promise { this.setDirty(false); - return Promise.resolve(true); + return true; } - revert(options?: IRevertOptions): Promise { + async revert(options?: IRevertOptions): Promise { this.setDirty(false); - return Promise.resolve(true); + return true; } async resolve(): Promise { diff --git a/src/vs/workbench/services/dialogs/browser/simpleFileDialog.ts b/src/vs/workbench/services/dialogs/browser/simpleFileDialog.ts index 4d1a4cface320..3afa7519ab93e 100644 --- a/src/vs/workbench/services/dialogs/browser/simpleFileDialog.ts +++ b/src/vs/workbench/services/dialogs/browser/simpleFileDialog.ts @@ -32,7 +32,7 @@ import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { createCancelablePromise, CancelablePromise } from 'vs/base/common/async'; import { CancellationToken } from 'vs/base/common/cancellation'; import { ICommandHandler } from 'vs/platform/commands/common/commands'; -import { ITextFileService, ISaveOptions } from 'vs/workbench/services/textfile/common/textfiles'; +import { ITextFileService, ITextFileSaveOptions } from 'vs/workbench/services/textfile/common/textfiles'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { toResource } from 'vs/workbench/common/editor'; import { normalizeDriveLetter } from 'vs/base/common/labels'; @@ -56,7 +56,7 @@ export namespace SaveLocalFileCommand { const textFileService = accessor.get(ITextFileService); const editorService = accessor.get(IEditorService); let resource: URI | undefined = toResource(editorService.activeEditor); - const options: ISaveOptions = { force: true, availableFileSystems: [Schemas.file] }; + const options: ITextFileSaveOptions = { force: true, availableFileSystems: [Schemas.file] }; if (resource) { return textFileService.saveAs(resource, undefined, options); } diff --git a/src/vs/workbench/services/textfile/browser/textFileService.ts b/src/vs/workbench/services/textfile/browser/textFileService.ts index fe4ddff014d88..4d75a95a8e40b 100644 --- a/src/vs/workbench/services/textfile/browser/textFileService.ts +++ b/src/vs/workbench/services/textfile/browser/textFileService.ts @@ -8,8 +8,8 @@ import { URI } from 'vs/base/common/uri'; import { Emitter, AsyncEmitter } from 'vs/base/common/event'; import * as platform from 'vs/base/common/platform'; import { IBackupFileService } from 'vs/workbench/services/backup/common/backup'; -import { IResult, ITextFileOperationResult, ITextFileService, ITextFileStreamContent, SaveReason, ITextFileEditorModelManager, ITextFileEditorModel, ModelState, ISaveOptions, ITextFileContent, IResourceEncodings, IReadTextFileOptions, IWriteTextFileOptions, toBufferOrReadable, TextFileOperationError, TextFileOperationResult, FileOperationWillRunEvent, FileOperationDidRunEvent } from 'vs/workbench/services/textfile/common/textfiles'; -import { IRevertOptions } from 'vs/workbench/common/editor'; +import { IResult, ITextFileOperationResult, ITextFileService, ITextFileStreamContent, ITextFileEditorModelManager, ITextFileEditorModel, ModelState, ITextFileContent, IResourceEncodings, IReadTextFileOptions, IWriteTextFileOptions, toBufferOrReadable, TextFileOperationError, TextFileOperationResult, FileOperationWillRunEvent, FileOperationDidRunEvent, ITextFileSaveOptions } from 'vs/workbench/services/textfile/common/textfiles'; +import { SaveReason, IRevertOptions } from 'vs/workbench/services/workingCopy/common/workingCopyService'; import { ILifecycleService, ShutdownReason, LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle'; import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; import { IFileService, FileOperationError, FileOperationResult, HotExitConfiguration, IFileStatWithMetadata, ICreateFileOptions, FileOperation } from 'vs/platform/files/common/files'; @@ -477,7 +477,7 @@ export abstract class AbstractTextFileService extends Disposable implements ITex //#region save/revert - async save(resource: URI, options?: ISaveOptions): Promise { + async save(resource: URI, options?: ITextFileSaveOptions): Promise { // Run a forced save if we detect the file is not dirty so that save participants can still run if (options?.force && this.fileService.canHandleResource(resource) && !this.isDirty(resource)) { @@ -496,9 +496,9 @@ export abstract class AbstractTextFileService extends Disposable implements ITex return result.results.length === 1 && !!result.results[0].success; } - saveAll(includeUntitled?: boolean, options?: ISaveOptions): Promise; - saveAll(resources: URI[], options?: ISaveOptions): Promise; - saveAll(arg1?: boolean | URI[], options?: ISaveOptions): Promise { + saveAll(includeUntitled?: boolean, options?: ITextFileSaveOptions): Promise; + saveAll(resources: URI[], options?: ITextFileSaveOptions): Promise; + saveAll(arg1?: boolean | URI[], options?: ITextFileSaveOptions): Promise { // get all dirty let toSave: URI[] = []; @@ -522,7 +522,7 @@ export abstract class AbstractTextFileService extends Disposable implements ITex return this.doSaveAll(filesToSave, untitledToSave, options); } - private async doSaveAll(fileResources: URI[], untitledResources: URI[], options?: ISaveOptions): Promise { + private async doSaveAll(fileResources: URI[], untitledResources: URI[], options?: ITextFileSaveOptions): Promise { // Handle files first that can just be saved const result = await this.doSaveAllFiles(fileResources, options); @@ -627,7 +627,7 @@ export abstract class AbstractTextFileService extends Disposable implements ITex return options; } - private async doSaveAllFiles(resources?: URI[], options: ISaveOptions = Object.create(null)): Promise { + private async doSaveAllFiles(resources?: URI[], options: ITextFileSaveOptions = Object.create(null)): Promise { const dirtyFileModels = this.getDirtyFileModels(Array.isArray(resources) ? resources : undefined /* Save All */) .filter(model => { if ((model.hasState(ModelState.CONFLICT) || model.hasState(ModelState.ERROR)) && (options.reason === SaveReason.AUTO || options.reason === SaveReason.FOCUS_CHANGE || options.reason === SaveReason.WINDOW_CHANGE)) { @@ -675,7 +675,7 @@ export abstract class AbstractTextFileService extends Disposable implements ITex return this.getFileModels(resources).filter(model => model.isDirty()); } - async saveAs(resource: URI, targetResource?: URI, options?: ISaveOptions): Promise { + async saveAs(resource: URI, targetResource?: URI, options?: ITextFileSaveOptions): Promise { // Get to target resource if (!targetResource) { @@ -702,7 +702,7 @@ export abstract class AbstractTextFileService extends Disposable implements ITex return this.doSaveAs(resource, targetResource, options); } - private async doSaveAs(resource: URI, target: URI, options?: ISaveOptions): Promise { + private async doSaveAs(resource: URI, target: URI, options?: ITextFileSaveOptions): Promise { // Retrieve text model from provided resource if any let model: ITextFileEditorModel | UntitledTextEditorModel | undefined; @@ -736,7 +736,7 @@ export abstract class AbstractTextFileService extends Disposable implements ITex return target; } - private async doSaveTextFileAs(sourceModel: ITextFileEditorModel | UntitledTextEditorModel, resource: URI, target: URI, options?: ISaveOptions): Promise { + private async doSaveTextFileAs(sourceModel: ITextFileEditorModel | UntitledTextEditorModel, resource: URI, target: URI, options?: ITextFileSaveOptions): Promise { // Prefer an existing model if it is already loaded for the given target resource let targetExists: boolean = false; @@ -866,7 +866,7 @@ export abstract class AbstractTextFileService extends Disposable implements ITex await Promise.all(fileModels.map(async model => { try { - await model.revert(options?.soft); + await model.revert(options); if (!model.isDirty()) { const result = mapResourceToResult.get(model.resource); diff --git a/src/vs/workbench/services/textfile/common/textFileEditorModel.ts b/src/vs/workbench/services/textfile/common/textFileEditorModel.ts index 7dba20135d723..f18c70d2aee23 100644 --- a/src/vs/workbench/services/textfile/common/textFileEditorModel.ts +++ b/src/vs/workbench/services/textfile/common/textFileEditorModel.ts @@ -11,7 +11,7 @@ import { URI } from 'vs/base/common/uri'; import { isUndefinedOrNull, assertIsDefined } from 'vs/base/common/types'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; -import { ITextFileService, ModelState, ITextFileEditorModel, ISaveOptions, ISaveErrorHandler, ISaveParticipant, StateChange, SaveReason, ITextFileStreamContent, ILoadOptions, LoadReason, IResolvedTextFileEditorModel } from 'vs/workbench/services/textfile/common/textfiles'; +import { ITextFileService, ModelState, ITextFileEditorModel, ISaveErrorHandler, ISaveParticipant, StateChange, ITextFileStreamContent, ILoadOptions, LoadReason, IResolvedTextFileEditorModel, ITextFileSaveOptions } from 'vs/workbench/services/textfile/common/textfiles'; import { EncodingMode } from 'vs/workbench/common/editor'; import { BaseTextEditorModel } from 'vs/workbench/common/editor/textEditorModel'; import { IBackupFileService } from 'vs/workbench/services/backup/common/backup'; @@ -29,7 +29,7 @@ import { ILogService } from 'vs/platform/log/common/log'; import { isEqual, isEqualOrParent, extname, basename, joinPath } from 'vs/base/common/resources'; import { onUnexpectedError } from 'vs/base/common/errors'; import { Schemas } from 'vs/base/common/network'; -import { IWorkingCopyService, WorkingCopyCapabilities } from 'vs/workbench/services/workingCopy/common/workingCopyService'; +import { IWorkingCopyService, WorkingCopyCapabilities, SaveReason, IRevertOptions } from 'vs/workbench/services/workingCopy/common/workingCopyService'; import { IFilesConfigurationService, IAutoSaveConfiguration } from 'vs/workbench/services/filesConfiguration/common/filesConfigurationService'; export interface IBackupMetaData { @@ -252,9 +252,9 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil return this.backupFileService.hasBackupSync(this.resource, this.versionId); } - async revert(soft?: boolean): Promise { + async revert(options?: IRevertOptions): Promise { if (!this.isResolved()) { - return; + return false; } // Cancel any running auto-save @@ -265,7 +265,8 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil const undo = this.setDirty(false); // Force read from disk unless reverting soft - if (!soft) { + const softUndo = options?.soft; + if (!softUndo) { try { await this.load({ forceReadFromDisk: true }); } catch (error) { @@ -284,6 +285,8 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil if (wasDirty) { this._onDidChangeDirty.fire(); } + + return true; } async load(options?: ILoadOptions): Promise { @@ -612,9 +615,9 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil this.autoSaveDisposable.value = toDisposable(() => clearTimeout(handle)); } - async save(options: ISaveOptions = Object.create(null)): Promise { + async save(options: ITextFileSaveOptions = Object.create(null)): Promise { if (!this.isResolved()) { - return; + return false; } this.logService.trace('save() - enter', this.resource); @@ -622,10 +625,12 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil // Cancel any currently running auto saves to make this the one that succeeds this.autoSaveDisposable.clear(); - return this.doSave(this.versionId, options); + await this.doSave(this.versionId, options); + + return true; } - private doSave(versionId: number, options: ISaveOptions): Promise { + private doSave(versionId: number, options: ITextFileSaveOptions): Promise { if (isUndefinedOrNull(options.reason)) { options.reason = SaveReason.EXPLICIT; } diff --git a/src/vs/workbench/services/textfile/common/textfiles.ts b/src/vs/workbench/services/textfile/common/textfiles.ts index d07dc93f41ee7..78c9bc6dcb887 100644 --- a/src/vs/workbench/services/textfile/common/textfiles.ts +++ b/src/vs/workbench/services/textfile/common/textfiles.ts @@ -6,7 +6,7 @@ import { URI } from 'vs/base/common/uri'; import { Event, IWaitUntil } from 'vs/base/common/event'; import { IDisposable } from 'vs/base/common/lifecycle'; -import { IEncodingSupport, IRevertOptions, IModeSupport } from 'vs/workbench/common/editor'; +import { IEncodingSupport, IModeSupport } from 'vs/workbench/common/editor'; import { IBaseStatWithMetadata, IFileStatWithMetadata, IReadFileOptions, IWriteFileOptions, FileOperationError, FileOperationResult, FileOperation } from 'vs/platform/files/common/files'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { ITextEditorModel } from 'vs/editor/common/services/resolverService'; @@ -14,7 +14,7 @@ import { ITextBufferFactory, ITextModel, ITextSnapshot } from 'vs/editor/common/ import { VSBuffer, VSBufferReadable } from 'vs/base/common/buffer'; import { isUndefinedOrNull } from 'vs/base/common/types'; import { isNative } from 'vs/base/common/platform'; -import { IWorkingCopy } from 'vs/workbench/services/workingCopy/common/workingCopyService'; +import { IWorkingCopy, ISaveOptions, SaveReason, IRevertOptions } from 'vs/workbench/services/workingCopy/common/workingCopyService'; export const ITextFileService = createDecorator('textFileService'); @@ -323,13 +323,6 @@ export interface IResult { success?: boolean; } -export const enum SaveReason { - EXPLICIT = 1, - AUTO = 2, - FOCUS_CHANGE = 3, - WINDOW_CHANGE = 4 -} - export const enum LoadReason { EDITOR = 1, REFERENCE = 2, @@ -421,12 +414,9 @@ export interface ITextFileEditorModelManager { disposeModel(model: ITextFileEditorModel): void; } -export interface ISaveOptions { - force?: boolean; - reason?: SaveReason; +export interface ITextFileSaveOptions extends ISaveOptions { overwriteReadonly?: boolean; overwriteEncoding?: boolean; - skipSaveParticipants?: boolean; writeElevated?: boolean; availableFileSystems?: readonly string[]; } @@ -458,11 +448,11 @@ export interface ITextFileEditorModel extends ITextEditorModel, IEncodingSupport updatePreferredEncoding(encoding: string | undefined): void; - save(options?: ISaveOptions): Promise; + save(options?: ITextFileSaveOptions): Promise; load(options?: ILoadOptions): Promise; - revert(soft?: boolean): Promise; + revert(options?: IRevertOptions): Promise; backup(target?: URI): Promise; diff --git a/src/vs/workbench/services/textfile/test/textFileEditorModel.test.ts b/src/vs/workbench/services/textfile/test/textFileEditorModel.test.ts index 8ccf5a25c5db6..3d8c90ba25086 100644 --- a/src/vs/workbench/services/textfile/test/textFileEditorModel.test.ts +++ b/src/vs/workbench/services/textfile/test/textFileEditorModel.test.ts @@ -263,7 +263,7 @@ suite('Files - TextFileEditorModel', () => { assert.equal(accessor.workingCopyService.dirtyCount, 1); assert.equal(accessor.workingCopyService.isDirty(model.resource), true); - await model.revert(true /* soft revert */); + await model.revert({ soft: true }); assert.ok(!model.isDirty()); assert.equal(model.textEditorModel!.getValue(), 'foo'); assert.equal(eventCounter, 1); @@ -300,7 +300,7 @@ suite('Files - TextFileEditorModel', () => { model.textEditorModel!.setValue('foo'); assert.ok(model.isDirty()); - await model.revert(true /* soft revert */); + await model.revert({ soft: true }); assert.ok(!model.isDirty()); model.onDidStateChange(e => { diff --git a/src/vs/workbench/services/textfile/test/textFileEditorModelManager.test.ts b/src/vs/workbench/services/textfile/test/textFileEditorModelManager.test.ts index 0494cbf139bb1..f4db513644fc3 100644 --- a/src/vs/workbench/services/textfile/test/textFileEditorModelManager.test.ts +++ b/src/vs/workbench/services/textfile/test/textFileEditorModelManager.test.ts @@ -286,7 +286,7 @@ suite('Files - TextFileEditorModelManager', () => { model.textEditorModel!.setValue('make dirty'); manager.disposeModel((model as TextFileEditorModel)); assert.ok(!model.isDisposed()); - model.revert(true); + model.revert({ soft: true }); manager.disposeModel((model as TextFileEditorModel)); assert.ok(model.isDisposed()); manager.dispose(); diff --git a/src/vs/workbench/services/workingCopy/common/workingCopyService.ts b/src/vs/workbench/services/workingCopy/common/workingCopyService.ts index fe2f33adfa318..d01206271bb3a 100644 --- a/src/vs/workbench/services/workingCopy/common/workingCopyService.ts +++ b/src/vs/workbench/services/workingCopy/common/workingCopyService.ts @@ -19,6 +19,63 @@ export const enum WorkingCopyCapabilities { AutoSave = 1 << 1 } +export const enum SaveReason { + + /** + * Explicit user gesture. + */ + EXPLICIT = 1, + + /** + * Auto save after a timeout. + */ + AUTO = 2, + + /** + * Auto save after editor focus change. + */ + FOCUS_CHANGE = 3, + + /** + * Auto save after window change. + */ + WINDOW_CHANGE = 4 +} + +export interface ISaveOptions { + + /** + * An indicator how the save operation was triggered. + */ + reason?: SaveReason; + + /** + * Forces to load the contents of the working copy + * again even if the working copy is not dirty. + */ + force?: boolean; + + /** + * Instructs the save operation to skip any save participants. + */ + skipSaveParticipants?: boolean; +} + +export interface IRevertOptions { + + /** + * Forces to load the contents of the working copy + * again even if the working copy is not dirty. + */ + force?: boolean; + + /** + * A soft revert will clear dirty state of a working copy + * but will not attempt to load it from its persisted state. + */ + soft?: boolean; +} + export interface IWorkingCopy { //#region Dirty Tracking @@ -29,6 +86,16 @@ export interface IWorkingCopy { //#endregion + + //#region Save/Revert + + save(options?: ISaveOptions): Promise; + + revert(options?: IRevertOptions): Promise; + + //#endregion + + readonly resource: URI; readonly capabilities: WorkingCopyCapabilities; diff --git a/src/vs/workbench/services/workingCopy/test/common/workingCopyService.test.ts b/src/vs/workbench/services/workingCopy/test/common/workingCopyService.test.ts index 7110cd285820e..f9fe16495551f 100644 --- a/src/vs/workbench/services/workingCopy/test/common/workingCopyService.test.ts +++ b/src/vs/workbench/services/workingCopy/test/common/workingCopyService.test.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import * as assert from 'assert'; -import { IWorkingCopy } from 'vs/workbench/services/workingCopy/common/workingCopyService'; +import { IWorkingCopy, ISaveOptions, IRevertOptions } from 'vs/workbench/services/workingCopy/common/workingCopyService'; import { URI } from 'vs/base/common/uri'; import { Emitter } from 'vs/base/common/event'; import { Disposable } from 'vs/base/common/lifecycle'; @@ -41,6 +41,9 @@ suite('WorkingCopyService', () => { return this.dirty; } + async save(options?: ISaveOptions): Promise { return true; } + async revert(options?: IRevertOptions): Promise { return true; } + dispose(): void { this._onDispose.fire(); diff --git a/src/vs/workbench/test/electron-browser/api/extHostDocumentSaveParticipant.test.ts b/src/vs/workbench/test/electron-browser/api/extHostDocumentSaveParticipant.test.ts index d85eae55ebf18..0e4d2acb7bd23 100644 --- a/src/vs/workbench/test/electron-browser/api/extHostDocumentSaveParticipant.test.ts +++ b/src/vs/workbench/test/electron-browser/api/extHostDocumentSaveParticipant.test.ts @@ -10,7 +10,7 @@ import { TextDocumentSaveReason, TextEdit, Position, EndOfLine } from 'vs/workbe import { MainThreadTextEditorsShape, IWorkspaceEditDto } from 'vs/workbench/api/common/extHost.protocol'; import { ExtHostDocumentSaveParticipant } from 'vs/workbench/api/common/extHostDocumentSaveParticipant'; import { SingleProxyRPCProtocol } from './testRPCProtocol'; -import { SaveReason } from 'vs/workbench/services/textfile/common/textfiles'; +import { SaveReason } from 'vs/workbench/services/workingCopy/common/workingCopyService'; import * as vscode from 'vscode'; import { mock } from 'vs/workbench/test/electron-browser/api/mock'; import { NullLogService } from 'vs/platform/log/common/log'; diff --git a/src/vs/workbench/test/electron-browser/api/mainThreadSaveParticipant.test.ts b/src/vs/workbench/test/electron-browser/api/mainThreadSaveParticipant.test.ts index 502d3fae8e908..c6122bedf48cb 100644 --- a/src/vs/workbench/test/electron-browser/api/mainThreadSaveParticipant.test.ts +++ b/src/vs/workbench/test/electron-browser/api/mainThreadSaveParticipant.test.ts @@ -13,7 +13,8 @@ import { IModelService } from 'vs/editor/common/services/modelService'; import { Range } from 'vs/editor/common/core/range'; import { Selection } from 'vs/editor/common/core/selection'; import { TextFileEditorModel } from 'vs/workbench/services/textfile/common/textFileEditorModel'; -import { ITextFileService, SaveReason, IResolvedTextFileEditorModel, snapshotToString } from 'vs/workbench/services/textfile/common/textfiles'; +import { ITextFileService, IResolvedTextFileEditorModel, snapshotToString } from 'vs/workbench/services/textfile/common/textfiles'; +import { SaveReason } from 'vs/workbench/services/workingCopy/common/workingCopyService'; import { TextFileEditorModelManager } from 'vs/workbench/services/textfile/common/textFileEditorModelManager'; class ServiceAccessor { From acb8bd592df141d11ad586d34a49ab880e3287fb Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Fri, 15 Nov 2019 15:40:58 +0100 Subject: [PATCH 336/352] custom editor - wire save/revert into custom editor input --- .../contrib/customEditor/browser/customEditorInput.ts | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/vs/workbench/contrib/customEditor/browser/customEditorInput.ts b/src/vs/workbench/contrib/customEditor/browser/customEditorInput.ts index d89fcb9b26f03..d100c41d38e23 100644 --- a/src/vs/workbench/contrib/customEditor/browser/customEditorInput.ts +++ b/src/vs/workbench/contrib/customEditor/browser/customEditorInput.ts @@ -16,6 +16,7 @@ import { IEditorInput, Verbosity } from 'vs/workbench/common/editor'; import { WebviewEditorOverlay } from 'vs/workbench/contrib/webview/browser/webview'; import { IWebviewWorkbenchService, LazilyResolvedWebviewEditorInput } from 'vs/workbench/contrib/webview/browser/webviewWorkbenchService'; import { CustomEditorModel } from './customEditorModel'; +import { ISaveOptions, IRevertOptions } from 'vs/workbench/services/workingCopy/common/workingCopyService'; export class CustomFileEditorInput extends LazilyResolvedWebviewEditorInput { @@ -119,4 +120,12 @@ export class CustomFileEditorInput extends LazilyResolvedWebviewEditorInput { public isDirty(): boolean { return this._model ? this._model.isDirty() : false; } + + public save(options?: ISaveOptions): Promise { + return this._model ? this._model.save(options) : Promise.resolve(false); + } + + public revert(options?: IRevertOptions): Promise { + return this._model ? this._model.revert(options) : Promise.resolve(false); + } } From 40d5fd27f6e0fb579eef00c73ecdc8d01afa0a97 Mon Sep 17 00:00:00 2001 From: isidor Date: Fri, 15 Nov 2019 15:41:03 +0100 Subject: [PATCH 337/352] fixes #84810 --- src/vs/workbench/contrib/debug/browser/debugToolBar.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/debug/browser/debugToolBar.ts b/src/vs/workbench/contrib/debug/browser/debugToolBar.ts index 781ac16a5dea2..76e38f1bab209 100644 --- a/src/vs/workbench/contrib/debug/browser/debugToolBar.ts +++ b/src/vs/workbench/contrib/debug/browser/debugToolBar.ts @@ -111,6 +111,7 @@ export class DebugToolBar extends Themable implements IWorkbenchContribution { private updateScheduler: RunOnceScheduler; private debugToolBarMenu: IMenu; private disposeOnUpdate: IDisposable | undefined; + private yCoordinate = 0; private isVisible = false; private isBuilt = false; @@ -264,9 +265,10 @@ export class DebugToolBar extends Themable implements IWorkbenchContribution { } } - private setYCoordinate(y = 0): void { + private setYCoordinate(y = this.yCoordinate): void { const titlebarOffset = this.layoutService.getTitleBarOffset(); this.$el.style.top = `${titlebarOffset + y}px`; + this.yCoordinate = y; } private setCoordinates(x?: number, y?: number): void { From c96aaab661a78cecf226343511e894eae3132dba Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Fri, 15 Nov 2019 15:54:07 +0100 Subject: [PATCH 338/352] workspace - do not allow workspace files without .code-workspace suffix (#84818) --- src/vs/workbench/browser/actions/workspaceActions.ts | 4 ++-- .../workspaces/electron-browser/workspaceEditingService.ts | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/vs/workbench/browser/actions/workspaceActions.ts b/src/vs/workbench/browser/actions/workspaceActions.ts index b129dc792f8c8..c8941a826a1ff 100644 --- a/src/vs/workbench/browser/actions/workspaceActions.ts +++ b/src/vs/workbench/browser/actions/workspaceActions.ts @@ -22,7 +22,7 @@ import { IHostService } from 'vs/workbench/services/host/browser/host'; import { KeyChord, KeyCode, KeyMod } from 'vs/base/common/keyCodes'; import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; -import { IWorkspacesService } from 'vs/platform/workspaces/common/workspaces'; +import { IWorkspacesService, hasWorkspaceFileExtension } from 'vs/platform/workspaces/common/workspaces'; export class OpenFileAction extends Action { @@ -213,7 +213,7 @@ export class SaveWorkspaceAsAction extends Action { async run(): Promise { const configPathUri = await this.workspaceEditingService.pickNewWorkspacePath(); - if (configPathUri) { + if (configPathUri && hasWorkspaceFileExtension(configPathUri)) { switch (this.contextService.getWorkbenchState()) { case WorkbenchState.EMPTY: case WorkbenchState.FOLDER: diff --git a/src/vs/workbench/services/workspaces/electron-browser/workspaceEditingService.ts b/src/vs/workbench/services/workspaces/electron-browser/workspaceEditingService.ts index 63e66f3a6b545..eae32007ddcd3 100644 --- a/src/vs/workbench/services/workspaces/electron-browser/workspaceEditingService.ts +++ b/src/vs/workbench/services/workspaces/electron-browser/workspaceEditingService.ts @@ -8,7 +8,7 @@ import { URI } from 'vs/base/common/uri'; import * as nls from 'vs/nls'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; import { IJSONEditingService } from 'vs/workbench/services/configuration/common/jsonEditing'; -import { IWorkspacesService, isUntitledWorkspace, IWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; +import { IWorkspacesService, isUntitledWorkspace, IWorkspaceIdentifier, hasWorkspaceFileExtension } from 'vs/platform/workspaces/common/workspaces'; import { WorkspaceService } from 'vs/workbench/services/configuration/browser/configurationService'; import { IStorageService } from 'vs/platform/storage/common/storage'; import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; @@ -124,7 +124,7 @@ export class NativeWorkspaceEditingService extends AbstractWorkspaceEditingServi // Save: save workspace, but do not veto unload if path provided case ConfirmResult.SAVE: { const newWorkspacePath = await this.pickNewWorkspacePath(); - if (!newWorkspacePath) { + if (!newWorkspacePath || !hasWorkspaceFileExtension(newWorkspacePath)) { return true; // keep veto if no target was provided } From c1b6edad134d1d5cc794f3905566413191d7c2cb Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Fri, 15 Nov 2019 15:56:13 +0100 Subject: [PATCH 339/352] experiment with showing a highlight when going to a definition, #84553 --- .../editor/contrib/gotoSymbol/goToCommands.ts | 25 ++++++++++++++++--- .../outline/browser/outlineNavigation.ts | 2 +- 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/src/vs/editor/contrib/gotoSymbol/goToCommands.ts b/src/vs/editor/contrib/gotoSymbol/goToCommands.ts index 5ec0555a5efbe..b9fbc7182ce98 100644 --- a/src/vs/editor/contrib/gotoSymbol/goToCommands.ts +++ b/src/vs/editor/contrib/gotoSymbol/goToCommands.ts @@ -119,8 +119,9 @@ abstract class SymbolNavigationAction extends EditorAction { } else { const next = model.firstReference()!; - const targetEditor = await this._openReference(editor, editorService, next, this._configuration.openToSide); - if (targetEditor && model.references.length > 1 && gotoLocation === 'gotoAndPeek') { + const peek = model.references.length > 1 && gotoLocation === 'gotoAndPeek'; + const targetEditor = await this._openReference(editor, editorService, next, this._configuration.openToSide, !peek); + if (peek && targetEditor) { this._openInPeek(targetEditor, model); } else { model.dispose(); @@ -134,7 +135,7 @@ abstract class SymbolNavigationAction extends EditorAction { } } - private _openReference(editor: ICodeEditor, editorService: ICodeEditorService, reference: Location | LocationLink, sideBySide: boolean): Promise { + private async _openReference(editor: ICodeEditor, editorService: ICodeEditorService, reference: Location | LocationLink, sideBySide: boolean, highlight: boolean): Promise { // range is the target-selection-range when we have one // and the the fallback is the 'full' range let range: IRange | undefined = undefined; @@ -145,13 +146,29 @@ abstract class SymbolNavigationAction extends EditorAction { range = reference.range; } - return editorService.openCodeEditor({ + const targetEditor = await editorService.openCodeEditor({ resource: reference.uri, options: { selection: Range.collapseToStart(range), revealInCenterIfOutsideViewport: true } }, editor, sideBySide); + + if (!targetEditor) { + return undefined; + } + + if (highlight) { + const modelNow = targetEditor.getModel(); + const ids = targetEditor.deltaDecorations([], [{ range, options: { className: 'rangeHighlight' } }]); + setTimeout(() => { + if (targetEditor.getModel() === modelNow) { + targetEditor.deltaDecorations(ids, []); + } + }, 350); + } + + return targetEditor; } private _openInPeek(target: ICodeEditor, model: ReferencesModel) { diff --git a/src/vs/workbench/contrib/outline/browser/outlineNavigation.ts b/src/vs/workbench/contrib/outline/browser/outlineNavigation.ts index 7d22b68aa6999..d7023790f9348 100644 --- a/src/vs/workbench/contrib/outline/browser/outlineNavigation.ts +++ b/src/vs/workbench/contrib/outline/browser/outlineNavigation.ts @@ -147,7 +147,7 @@ export class OutlineNavigation implements IEditorContribution { if (modelNow === this._editor.getModel()) { this._editor.deltaDecorations(ids, []); } - }, 250); + }, 350); } } From 1624087eea278a8daa8d98e13d58bc690ae70a9e Mon Sep 17 00:00:00 2001 From: isidor Date: Fri, 15 Nov 2019 16:05:00 +0100 Subject: [PATCH 340/352] fixes #83387 --- src/vs/workbench/contrib/debug/browser/repl.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/debug/browser/repl.ts b/src/vs/workbench/contrib/debug/browser/repl.ts index 37ed56928be43..88b1a92027211 100644 --- a/src/vs/workbench/contrib/debug/browser/repl.ts +++ b/src/vs/workbench/contrib/debug/browser/repl.ts @@ -344,7 +344,7 @@ export class Repl extends Panel implements IPrivateReplService, IHistoryNavigati } focus(): void { - this.replInput.focus(); + setTimeout(() => this.replInput.focus(), 0); } getActionViewItem(action: IAction): IActionViewItem | undefined { From b066bb2c50c17e7845bebf34ad4d39c73f5b4fd0 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Fri, 15 Nov 2019 16:44:27 +0100 Subject: [PATCH 341/352] custom editors - wire in "Revert" --- .../contrib/files/browser/fileCommands.ts | 68 ++++++++----------- .../workbench/contrib/files/browser/files.ts | 65 ++++++++++++++---- .../browser/testCustomEditors.ts | 4 ++ 3 files changed, 83 insertions(+), 54 deletions(-) diff --git a/src/vs/workbench/contrib/files/browser/fileCommands.ts b/src/vs/workbench/contrib/files/browser/fileCommands.ts index 7fb4fcbab7ce5..1cc2e85ae1d50 100644 --- a/src/vs/workbench/contrib/files/browser/fileCommands.ts +++ b/src/vs/workbench/contrib/files/browser/fileCommands.ts @@ -29,7 +29,7 @@ import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/co import { KeyMod, KeyCode, KeyChord } from 'vs/base/common/keyCodes'; import { isWindows } from 'vs/base/common/platform'; import { ITextModelService } from 'vs/editor/common/services/resolverService'; -import { getResourceForCommand, getMultiSelectedResources } from 'vs/workbench/contrib/files/browser/files'; +import { getResourceForCommand, getMultiSelectedResources, getMultiSelectedEditors } from 'vs/workbench/contrib/files/browser/files'; import { IWorkspaceEditingService } from 'vs/workbench/services/workspaces/common/workspaceEditing'; import { getMultiSelectedEditorContexts } from 'vs/workbench/browser/parts/editor/editorCommands'; import { Schemas } from 'vs/base/common/network'; @@ -44,6 +44,7 @@ import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/ import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { UNTITLED_WORKSPACE_NAME } from 'vs/platform/workspaces/common/workspaces'; import { withUndefinedAsNull, withNullAsUndefined } from 'vs/base/common/types'; +import { assign } from 'vs/base/common/objects'; // Commands @@ -124,8 +125,17 @@ async function save( return doSaveAs(resource, isSaveAs, options, editorService, fileService, untitledTextEditorService, textFileService, editorGroupService, environmentService); } - // Save - return doSave(resource, options, editorService, textFileService); + // Pin the active editor if we are saving it + const activeControl = editorService.activeControl; + const activeEditorResource = activeControl?.input?.getResource(); + if (activeControl && activeEditorResource && isEqual(activeEditorResource, resource)) { + activeControl.group.pinEditor(activeControl.input); + } + + // Just save (force a change to the file to trigger external watchers if any) + options = assign({ force: true }, options || Object.create(null)); + + return textFileService.save(resource, options); } async function doSaveAs( @@ -162,7 +172,7 @@ async function doSaveAs( // Force a change to the file to trigger external watchers if any // fixes https://github.com/Microsoft/vscode/issues/59655 - options = ensureForcedSave(options); + options = assign({ force: true }, options || Object.create(null)); target = await textFileService.saveAs(resource, undefined, options); } @@ -188,36 +198,6 @@ async function doSaveAs( return true; } -async function doSave( - resource: URI, - options: ISaveOptions | undefined, - editorService: IEditorService, - textFileService: ITextFileService -): Promise { - - // Pin the active editor if we are saving it - const activeControl = editorService.activeControl; - const activeEditorResource = activeControl?.input?.getResource(); - if (activeControl && activeEditorResource && isEqual(activeEditorResource, resource)) { - activeControl.group.pinEditor(activeControl.input); - } - - // Just save (force a change to the file to trigger external watchers if any) - options = ensureForcedSave(options); - - return textFileService.save(resource, options); -} - -function ensureForcedSave(options?: ISaveOptions): ISaveOptions { - if (!options) { - options = { force: true }; - } else { - options.force = true; - } - - return options; -} - async function saveAll(saveAllArguments: any, editorService: IEditorService, untitledTextEditorService: IUntitledTextEditorService, textFileService: ITextFileService, editorGroupService: IEditorGroupsService): Promise { @@ -268,17 +248,23 @@ async function saveAll(saveAllArguments: any, editorService: IEditorService, unt CommandsRegistry.registerCommand({ id: REVERT_FILE_COMMAND_ID, handler: async (accessor, resource: URI | object) => { - const editorService = accessor.get(IEditorService); - const textFileService = accessor.get(ITextFileService); const notificationService = accessor.get(INotificationService); - const resources = getMultiSelectedResources(resource, accessor.get(IListService), editorService) - .filter(resource => resource.scheme !== Schemas.untitled); + const listService = accessor.get(IListService); + const editorService = accessor.get(IEditorService); - if (resources.length) { + const editors = getMultiSelectedEditors(listService, editorService); + if (editors.length) { try { - await textFileService.revertAll(resources, { force: true }); + await Promise.all(editors.map(async editor => { + const resource = editor.getResource(); + if (resource && resource.scheme === Schemas.untitled) { + return; // we do not allow to revert untitled files + } + + return editor.revert({ force: true }); + })); } catch (error) { - notificationService.error(nls.localize('genericRevertError', "Failed to revert '{0}': {1}", resources.map(r => basename(r)).join(', '), toErrorMessage(error, false))); + notificationService.error(nls.localize('genericRevertResourcesError', "Failed to revert '{0}': {1}", editors.map(e => e.getName()).join(', '), toErrorMessage(error, false))); } } } diff --git a/src/vs/workbench/contrib/files/browser/files.ts b/src/vs/workbench/contrib/files/browser/files.ts index d492c77b3b057..534b0283a6cc0 100644 --- a/src/vs/workbench/contrib/files/browser/files.ts +++ b/src/vs/workbench/contrib/files/browser/files.ts @@ -6,20 +6,14 @@ import { URI } from 'vs/base/common/uri'; import { IListService } from 'vs/platform/list/browser/listService'; import { OpenEditor } from 'vs/workbench/contrib/files/common/files'; -import { toResource, SideBySideEditor } from 'vs/workbench/common/editor'; +import { toResource, SideBySideEditor, IEditorInput } from 'vs/workbench/common/editor'; import { List } from 'vs/base/browser/ui/list/listWidget'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { ExplorerItem } from 'vs/workbench/contrib/files/common/explorerModel'; import { coalesce } from 'vs/base/common/arrays'; import { AsyncDataTree } from 'vs/base/browser/ui/tree/asyncDataTree'; -// Commands can get exeucted from a command pallete, from a context menu or from some list using a keybinding -// To cover all these cases we need to properly compute the resource on which the command is being executed -export function getResourceForCommand(resource: URI | object | undefined, listService: IListService, editorService: IEditorService): URI | undefined { - if (URI.isUri(resource)) { - return resource; - } - +function getFocus(listService: IListService): unknown | undefined { let list = listService.lastFocusedList; if (list?.getHTMLElement() === document.activeElement) { let focus: unknown; @@ -35,16 +29,38 @@ export function getResourceForCommand(resource: URI | object | undefined, listSe } } - if (focus instanceof ExplorerItem) { - return focus.resource; - } else if (focus instanceof OpenEditor) { - return focus.getResource(); - } + return focus; + } + + return undefined; +} + +// Commands can get exeucted from a command pallete, from a context menu or from some list using a keybinding +// To cover all these cases we need to properly compute the resource on which the command is being executed +export function getResourceForCommand(resource: URI | object | undefined, listService: IListService, editorService: IEditorService): URI | undefined { + if (URI.isUri(resource)) { + return resource; + } + + const focus = getFocus(listService); + if (focus instanceof ExplorerItem) { + return focus.resource; + } else if (focus instanceof OpenEditor) { + return focus.getResource(); } return editorService.activeEditor ? toResource(editorService.activeEditor, { supportSideBySide: SideBySideEditor.MASTER }) : undefined; } +export function getEditorForCommand(listService: IListService, editorService: IEditorService): IEditorInput | undefined { + const focus = getFocus(listService); + if (focus instanceof OpenEditor) { + return focus.editor; + } + + return editorService.activeEditor ? editorService.activeEditor : undefined; +} + export function getMultiSelectedResources(resource: URI | object | undefined, listService: IListService, editorService: IEditorService): Array { const list = listService.lastFocusedList; if (list?.getHTMLElement() === document.activeElement) { @@ -83,3 +99,26 @@ export function getMultiSelectedResources(resource: URI | object | undefined, li const result = getResourceForCommand(resource, listService, editorService); return !!result ? [result] : []; } + +export function getMultiSelectedEditors(listService: IListService, editorService: IEditorService): Array { + const list = listService.lastFocusedList; + if (list?.getHTMLElement() === document.activeElement) { + // Open editors view + if (list instanceof List) { + const selection = coalesce(list.getSelectedElements().filter(s => s instanceof OpenEditor).map((oe: OpenEditor) => oe.editor)); + const focusedElements = list.getFocusedElements(); + const focus = focusedElements.length ? focusedElements[0] : undefined; + let mainEditor: IEditorInput | undefined = undefined; + if (focus instanceof OpenEditor) { + mainEditor = focus.editor; + } + // We only respect the selection if it contains the main element. + if (selection.some(s => s === mainEditor)) { + return selection; + } + } + } + + const result = getEditorForCommand(listService, editorService); + return !!result ? [result] : []; +} diff --git a/src/vs/workbench/contrib/testCustomEditors/browser/testCustomEditors.ts b/src/vs/workbench/contrib/testCustomEditors/browser/testCustomEditors.ts index ab34523d3917d..e2f0bfcc1f7d7 100644 --- a/src/vs/workbench/contrib/testCustomEditors/browser/testCustomEditors.ts +++ b/src/vs/workbench/contrib/testCustomEditors/browser/testCustomEditors.ts @@ -143,6 +143,10 @@ class TestCustomEditorInput extends EditorInput implements IWorkingCopy { setValue(value: string) { if (this.model) { + if (this.model.value === value) { + return; + } + this.model.value = value; } From 71c0930d3488f6d0ba78c685a483861fbdf86497 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Fri, 15 Nov 2019 17:06:15 +0100 Subject: [PATCH 342/352] revert - operate on groups and pin editor on revert --- .../contrib/files/browser/fileCommands.ts | 13 +++++++----- .../workbench/contrib/files/browser/files.ts | 21 +++++++++++-------- 2 files changed, 20 insertions(+), 14 deletions(-) diff --git a/src/vs/workbench/contrib/files/browser/fileCommands.ts b/src/vs/workbench/contrib/files/browser/fileCommands.ts index 1cc2e85ae1d50..6305930969906 100644 --- a/src/vs/workbench/contrib/files/browser/fileCommands.ts +++ b/src/vs/workbench/contrib/files/browser/fileCommands.ts @@ -247,24 +247,27 @@ async function saveAll(saveAllArguments: any, editorService: IEditorService, unt CommandsRegistry.registerCommand({ id: REVERT_FILE_COMMAND_ID, - handler: async (accessor, resource: URI | object) => { + handler: async accessor => { const notificationService = accessor.get(INotificationService); const listService = accessor.get(IListService); - const editorService = accessor.get(IEditorService); + const editorGroupsService = accessor.get(IEditorGroupsService); - const editors = getMultiSelectedEditors(listService, editorService); + const editors = getMultiSelectedEditors(listService, editorGroupsService); if (editors.length) { try { - await Promise.all(editors.map(async editor => { + await Promise.all(editors.map(async ({ groupId, editor }) => { const resource = editor.getResource(); if (resource && resource.scheme === Schemas.untitled) { return; // we do not allow to revert untitled files } + // Use revert as a hint to pin the editor + editorGroupsService.getGroup(groupId)?.pinEditor(editor); + return editor.revert({ force: true }); })); } catch (error) { - notificationService.error(nls.localize('genericRevertResourcesError', "Failed to revert '{0}': {1}", editors.map(e => e.getName()).join(', '), toErrorMessage(error, false))); + notificationService.error(nls.localize('genericRevertResourcesError', "Failed to revert '{0}': {1}", editors.map(({ editor }) => editor.getName()).join(', '), toErrorMessage(error, false))); } } } diff --git a/src/vs/workbench/contrib/files/browser/files.ts b/src/vs/workbench/contrib/files/browser/files.ts index 534b0283a6cc0..6b99f39e9228d 100644 --- a/src/vs/workbench/contrib/files/browser/files.ts +++ b/src/vs/workbench/contrib/files/browser/files.ts @@ -6,12 +6,13 @@ import { URI } from 'vs/base/common/uri'; import { IListService } from 'vs/platform/list/browser/listService'; import { OpenEditor } from 'vs/workbench/contrib/files/common/files'; -import { toResource, SideBySideEditor, IEditorInput } from 'vs/workbench/common/editor'; +import { toResource, SideBySideEditor, IEditorIdentifier } from 'vs/workbench/common/editor'; import { List } from 'vs/base/browser/ui/list/listWidget'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { ExplorerItem } from 'vs/workbench/contrib/files/common/explorerModel'; import { coalesce } from 'vs/base/common/arrays'; import { AsyncDataTree } from 'vs/base/browser/ui/tree/asyncDataTree'; +import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService'; function getFocus(listService: IListService): unknown | undefined { let list = listService.lastFocusedList; @@ -52,13 +53,15 @@ export function getResourceForCommand(resource: URI | object | undefined, listSe return editorService.activeEditor ? toResource(editorService.activeEditor, { supportSideBySide: SideBySideEditor.MASTER }) : undefined; } -export function getEditorForCommand(listService: IListService, editorService: IEditorService): IEditorInput | undefined { +export function getEditorForCommand(listService: IListService, editorGroupService: IEditorGroupsService): IEditorIdentifier | undefined { const focus = getFocus(listService); if (focus instanceof OpenEditor) { - return focus.editor; + return focus; } - return editorService.activeEditor ? editorService.activeEditor : undefined; + const activeGroup = editorGroupService.activeGroup; + + return activeGroup.activeEditor ? { groupId: activeGroup.id, editor: activeGroup.activeEditor } : undefined; } export function getMultiSelectedResources(resource: URI | object | undefined, listService: IListService, editorService: IEditorService): Array { @@ -100,17 +103,17 @@ export function getMultiSelectedResources(resource: URI | object | undefined, li return !!result ? [result] : []; } -export function getMultiSelectedEditors(listService: IListService, editorService: IEditorService): Array { +export function getMultiSelectedEditors(listService: IListService, editorGroupsService: IEditorGroupsService): Array { const list = listService.lastFocusedList; if (list?.getHTMLElement() === document.activeElement) { // Open editors view if (list instanceof List) { - const selection = coalesce(list.getSelectedElements().filter(s => s instanceof OpenEditor).map((oe: OpenEditor) => oe.editor)); + const selection = coalesce(list.getSelectedElements().filter(s => s instanceof OpenEditor)); const focusedElements = list.getFocusedElements(); const focus = focusedElements.length ? focusedElements[0] : undefined; - let mainEditor: IEditorInput | undefined = undefined; + let mainEditor: IEditorIdentifier | undefined = undefined; if (focus instanceof OpenEditor) { - mainEditor = focus.editor; + mainEditor = focus; } // We only respect the selection if it contains the main element. if (selection.some(s => s === mainEditor)) { @@ -119,6 +122,6 @@ export function getMultiSelectedEditors(listService: IListService, editorService } } - const result = getEditorForCommand(listService, editorService); + const result = getEditorForCommand(listService, editorGroupsService); return !!result ? [result] : []; } From 3e092938e8ba3d4331ab23c67eb0e62ee9bf3bd5 Mon Sep 17 00:00:00 2001 From: Alexandru Dima Date: Fri, 15 Nov 2019 11:25:15 +0100 Subject: [PATCH 343/352] Move the change accessor down to LinesLayout --- .../browser/viewParts/viewZones/viewZones.ts | 91 +++++++++-------- .../editor/common/viewLayout/linesLayout.ts | 33 ++++++- src/vs/editor/common/viewLayout/viewLayout.ts | 13 +-- src/vs/editor/common/viewModel/viewModel.ts | 16 +-- .../common/viewLayout/linesLayout.test.ts | 98 +++++++++++-------- 5 files changed, 140 insertions(+), 111 deletions(-) diff --git a/src/vs/editor/browser/viewParts/viewZones/viewZones.ts b/src/vs/editor/browser/viewParts/viewZones/viewZones.ts index c82db418cee65..aca0e779c2f1d 100644 --- a/src/vs/editor/browser/viewParts/viewZones/viewZones.ts +++ b/src/vs/editor/browser/viewParts/viewZones/viewZones.ts @@ -13,6 +13,7 @@ import { ViewContext } from 'vs/editor/common/view/viewContext'; import * as viewEvents from 'vs/editor/common/view/viewEvents'; import { IViewWhitespaceViewportData } from 'vs/editor/common/viewModel/viewModel'; import { EditorOption } from 'vs/editor/common/config/editorOptions'; +import { IWhitespaceChangeAccessor } from 'vs/editor/common/viewLayout/linesLayout'; export interface IMyViewZone { whitespaceId: string; @@ -73,20 +74,22 @@ export class ViewZones extends ViewPart { // ---- begin view event handlers private _recomputeWhitespacesProps(): boolean { - let hadAChange = false; - - const keys = Object.keys(this._zones); - for (let i = 0, len = keys.length; i < len; i++) { - const id = keys[i]; - const zone = this._zones[id]; - const props = this._computeWhitespaceProps(zone.delegate); - if (this._context.viewLayout.changeWhitespace(id, props.afterViewLineNumber, props.heightInPx)) { - this._safeCallOnComputedHeight(zone.delegate, props.heightInPx); - hadAChange = true; + return this._context.viewLayout.changeWhitespace((whitespaceAccessor: IWhitespaceChangeAccessor) => { + let hadAChange = false; + + const keys = Object.keys(this._zones); + for (let i = 0, len = keys.length; i < len; i++) { + const id = keys[i]; + const zone = this._zones[id]; + const props = this._computeWhitespaceProps(zone.delegate); + if (whitespaceAccessor.changeOneWhitespace(id, props.afterViewLineNumber, props.heightInPx)) { + this._safeCallOnComputedHeight(zone.delegate, props.heightInPx); + hadAChange = true; + } } - } - return hadAChange; + return hadAChange; + }); } public onConfigurationChanged(e: viewEvents.ViewConfigurationChangedEvent): boolean { @@ -190,40 +193,42 @@ export class ViewZones extends ViewPart { public changeViewZones(callback: (changeAccessor: IViewZoneChangeAccessor) => any): boolean { - let zonesHaveChanged = false; - - const changeAccessor: IViewZoneChangeAccessor = { - addZone: (zone: IViewZone): string => { - zonesHaveChanged = true; - return this.addZone(zone); - }, - removeZone: (id: string): void => { - if (!id) { - return; - } - zonesHaveChanged = this.removeZone(id) || zonesHaveChanged; - }, - layoutZone: (id: string): void => { - if (!id) { - return; + return this._context.viewLayout.changeWhitespace((whitespaceAccessor: IWhitespaceChangeAccessor) => { + let zonesHaveChanged = false; + + const changeAccessor: IViewZoneChangeAccessor = { + addZone: (zone: IViewZone): string => { + zonesHaveChanged = true; + return this._addZone(whitespaceAccessor, zone); + }, + removeZone: (id: string): void => { + if (!id) { + return; + } + zonesHaveChanged = this._removeZone(whitespaceAccessor, id) || zonesHaveChanged; + }, + layoutZone: (id: string): void => { + if (!id) { + return; + } + zonesHaveChanged = this._layoutZone(whitespaceAccessor, id) || zonesHaveChanged; } - zonesHaveChanged = this.layoutZone(id) || zonesHaveChanged; - } - }; + }; - safeInvoke1Arg(callback, changeAccessor); + safeInvoke1Arg(callback, changeAccessor); - // Invalidate changeAccessor - changeAccessor.addZone = invalidFunc; - changeAccessor.removeZone = invalidFunc; - changeAccessor.layoutZone = invalidFunc; + // Invalidate changeAccessor + changeAccessor.addZone = invalidFunc; + changeAccessor.removeZone = invalidFunc; + changeAccessor.layoutZone = invalidFunc; - return zonesHaveChanged; + return zonesHaveChanged; + }); } - public addZone(zone: IViewZone): string { + private _addZone(whitespaceAccessor: IWhitespaceChangeAccessor, zone: IViewZone): string { const props = this._computeWhitespaceProps(zone); - const whitespaceId = this._context.viewLayout.addWhitespace(props.afterViewLineNumber, this._getZoneOrdinal(zone), props.heightInPx, props.minWidthInPx); + const whitespaceId = whitespaceAccessor.insertWhitespace(props.afterViewLineNumber, this._getZoneOrdinal(zone), props.heightInPx, props.minWidthInPx); const myZone: IMyViewZone = { whitespaceId: whitespaceId, @@ -257,11 +262,11 @@ export class ViewZones extends ViewPart { return myZone.whitespaceId; } - public removeZone(id: string): boolean { + private _removeZone(whitespaceAccessor: IWhitespaceChangeAccessor, id: string): boolean { if (this._zones.hasOwnProperty(id)) { const zone = this._zones[id]; delete this._zones[id]; - this._context.viewLayout.removeWhitespace(zone.whitespaceId); + whitespaceAccessor.removeWhitespace(zone.whitespaceId); zone.domNode.removeAttribute('monaco-visible-view-zone'); zone.domNode.removeAttribute('monaco-view-zone'); @@ -280,13 +285,13 @@ export class ViewZones extends ViewPart { return false; } - public layoutZone(id: string): boolean { + private _layoutZone(whitespaceAccessor: IWhitespaceChangeAccessor, id: string): boolean { let changed = false; if (this._zones.hasOwnProperty(id)) { const zone = this._zones[id]; const props = this._computeWhitespaceProps(zone.delegate); // const newOrdinal = this._getZoneOrdinal(zone.delegate); - changed = this._context.viewLayout.changeWhitespace(zone.whitespaceId, props.afterViewLineNumber, props.heightInPx) || changed; + changed = whitespaceAccessor.changeOneWhitespace(zone.whitespaceId, props.afterViewLineNumber, props.heightInPx) || changed; // TODO@Alex: change `newOrdinal` too if (changed) { diff --git a/src/vs/editor/common/viewLayout/linesLayout.ts b/src/vs/editor/common/viewLayout/linesLayout.ts index d3f4d35943192..14c7dd29481bf 100644 --- a/src/vs/editor/common/viewLayout/linesLayout.ts +++ b/src/vs/editor/common/viewLayout/linesLayout.ts @@ -15,6 +15,15 @@ export class EditorWhitespace { ) { } } +/** + * An accessor that allows for whtiespace to be added, removed or changed in bulk. + */ +export interface IWhitespaceChangeAccessor { + insertWhitespace(afterLineNumber: number, ordinal: number, heightInPx: number, minWidth: number): string; + changeOneWhitespace(id: string, newAfterLineNumber: number, newHeight: number): boolean; + removeWhitespace(id: string): boolean; +} + /** * Layouting of objects that take vertical space (by having a height) and push down other objects. * @@ -146,6 +155,22 @@ export class LinesLayout { this._lineCount = lineCount; } + public changeWhitespace(callback: (accessor: IWhitespaceChangeAccessor) => T): T { + const accessor = { + insertWhitespace: (afterLineNumber: number, ordinal: number, heightInPx: number, minWidth: number): string => { + return this._insertWhitespace(afterLineNumber, ordinal, heightInPx, minWidth); + }, + changeOneWhitespace: (id: string, newAfterLineNumber: number, newHeight: number): boolean => { + return this._changeOneWhitespace(id, newAfterLineNumber, newHeight); + }, + removeWhitespace: (id: string): boolean => { + return this._removeWhitespace(id); + } + }; + const r = callback(accessor); + return r; + } + /** * Insert a new whitespace of a certain height after a line number. * The whitespace has a "sticky" characteristic. @@ -155,7 +180,7 @@ export class LinesLayout { * @param heightInPx The height of the whitespace, in pixels. * @return An id that can be used later to mutate or delete the whitespace */ - public insertWhitespace(afterLineNumber: number, ordinal: number, heightInPx: number, minWidth: number): string { + private _insertWhitespace(afterLineNumber: number, ordinal: number, heightInPx: number, minWidth: number): string { afterLineNumber = afterLineNumber | 0; ordinal = ordinal | 0; heightInPx = heightInPx | 0; @@ -197,7 +222,7 @@ export class LinesLayout { /** * Change properties associated with a certain whitespace. */ - public changeWhitespace(id: string, newAfterLineNumber: number, newHeight: number): boolean { + private _changeOneWhitespace(id: string, newAfterLineNumber: number, newHeight: number): boolean { newAfterLineNumber = newAfterLineNumber | 0; newHeight = newHeight | 0; @@ -253,7 +278,7 @@ export class LinesLayout { const minWidth = this._minWidths[index]; // Since changing `afterLineNumber` can trigger a reordering, we're gonna remove this whitespace - this.removeWhitespace(id); + this._removeWhitespace(id); // And add it again const insertionIndex = LinesLayout.findInsertionIndex(this._afterLineNumbers, newAfterLineNumber, this._ordinals, ordinal); @@ -271,7 +296,7 @@ export class LinesLayout { * @param id The whitespace to remove * @return Returns true if the whitespace is found and it is removed. */ - public removeWhitespace(id: string): boolean { + private _removeWhitespace(id: string): boolean { if (this._whitespaceId2Index.hasOwnProperty(id)) { const index = this._whitespaceId2Index[id]; delete this._whitespaceId2Index[id]; diff --git a/src/vs/editor/common/viewLayout/viewLayout.ts b/src/vs/editor/common/viewLayout/viewLayout.ts index 6fd8a951a577c..1fbc3db5462cd 100644 --- a/src/vs/editor/common/viewLayout/viewLayout.ts +++ b/src/vs/editor/common/viewLayout/viewLayout.ts @@ -8,7 +8,7 @@ import { Disposable, IDisposable } from 'vs/base/common/lifecycle'; import { IScrollPosition, ScrollEvent, Scrollable, ScrollbarVisibility } from 'vs/base/common/scrollable'; import { ConfigurationChangedEvent, EditorOption } from 'vs/editor/common/config/editorOptions'; import * as editorCommon from 'vs/editor/common/editorCommon'; -import { LinesLayout, EditorWhitespace } from 'vs/editor/common/viewLayout/linesLayout'; +import { LinesLayout, EditorWhitespace, IWhitespaceChangeAccessor } from 'vs/editor/common/viewLayout/linesLayout'; import { IPartialViewLinesViewportData } from 'vs/editor/common/viewLayout/viewLinesViewportData'; import { IViewLayout, IViewWhitespaceViewportData, Viewport } from 'vs/editor/common/viewModel/viewModel'; @@ -193,15 +193,8 @@ export class ViewLayout extends Disposable implements IViewLayout { } // ---- IVerticalLayoutProvider - - public addWhitespace(afterLineNumber: number, ordinal: number, height: number, minWidth: number): string { - return this._linesLayout.insertWhitespace(afterLineNumber, ordinal, height, minWidth); - } - public changeWhitespace(id: string, newAfterLineNumber: number, newHeight: number): boolean { - return this._linesLayout.changeWhitespace(id, newAfterLineNumber, newHeight); - } - public removeWhitespace(id: string): boolean { - return this._linesLayout.removeWhitespace(id); + public changeWhitespace(callback: (accessor: IWhitespaceChangeAccessor) => T): T { + return this._linesLayout.changeWhitespace(callback); } public getVerticalOffsetForLineNumber(lineNumber: number): number { return this._linesLayout.getVerticalOffsetForLineNumber(lineNumber); diff --git a/src/vs/editor/common/viewModel/viewModel.ts b/src/vs/editor/common/viewModel/viewModel.ts index 777195ac72906..3d23b97c93c8c 100644 --- a/src/vs/editor/common/viewModel/viewModel.ts +++ b/src/vs/editor/common/viewModel/viewModel.ts @@ -13,7 +13,7 @@ import { INewScrollPosition } from 'vs/editor/common/editorCommon'; import { EndOfLinePreference, IActiveIndentGuideInfo, IModelDecorationOptions, TextModelResolvedOptions } from 'vs/editor/common/model'; import { IViewEventListener } from 'vs/editor/common/view/viewEvents'; import { IPartialViewLinesViewportData } from 'vs/editor/common/viewLayout/viewLinesViewportData'; -import { EditorWhitespace } from 'vs/editor/common/viewLayout/linesLayout'; +import { EditorWhitespace, IWhitespaceChangeAccessor } from 'vs/editor/common/viewLayout/linesLayout'; import { ITheme } from 'vs/platform/theme/common/themeService'; export interface IViewWhitespaceViewportData { @@ -69,20 +69,8 @@ export interface IViewLayout { getWhitespaceAtVerticalOffset(verticalOffset: number): IViewWhitespaceViewportData | null; // --------------- Begin vertical whitespace management + changeWhitespace(callback: (accessor: IWhitespaceChangeAccessor) => T): T; - /** - * Reserve rendering space. - * @return an identifier that can be later used to remove or change the whitespace. - */ - addWhitespace(afterLineNumber: number, ordinal: number, height: number, minWidth: number): string; - /** - * Change the properties of a whitespace. - */ - changeWhitespace(id: string, newAfterLineNumber: number, newHeight: number): boolean; - /** - * Remove rendering space - */ - removeWhitespace(id: string): boolean; /** * Get the layout information for whitespaces currently in the viewport */ diff --git a/src/vs/editor/test/common/viewLayout/linesLayout.test.ts b/src/vs/editor/test/common/viewLayout/linesLayout.test.ts index a88c5c16c6d35..12f4693761a0e 100644 --- a/src/vs/editor/test/common/viewLayout/linesLayout.test.ts +++ b/src/vs/editor/test/common/viewLayout/linesLayout.test.ts @@ -7,6 +7,24 @@ import { LinesLayout } from 'vs/editor/common/viewLayout/linesLayout'; suite('Editor ViewLayout - LinesLayout', () => { + function insertWhitespace(linesLayout: LinesLayout, afterLineNumber: number, ordinal: number, heightInPx: number, minWidth: number): string { + return linesLayout.changeWhitespace((accessor) => { + return accessor.insertWhitespace(afterLineNumber, ordinal, heightInPx, minWidth); + }); + } + + function changeOneWhitespace(linesLayout: LinesLayout, id: string, newAfterLineNumber: number, newHeight: number): boolean { + return linesLayout.changeWhitespace((accessor) => { + return accessor.changeOneWhitespace(id, newAfterLineNumber, newHeight); + }); + } + + function removeWhitespace(linesLayout: LinesLayout, id: string): boolean { + return linesLayout.changeWhitespace((accessor) => { + return accessor.removeWhitespace(id); + }); + } + test('LinesLayout 1', () => { // Start off with 10 lines @@ -39,7 +57,7 @@ suite('Editor ViewLayout - LinesLayout', () => { assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(29), 3); // Add whitespace of height 5px after 2nd line - linesLayout.insertWhitespace(2, 0, 5, 0); + insertWhitespace(linesLayout, 2, 0, 5, 0); // lines: [0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] // whitespace: a(2,5) assert.equal(linesLayout.getLinesTotalHeight(), 105); @@ -63,8 +81,8 @@ suite('Editor ViewLayout - LinesLayout', () => { assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(105), 10); // Add two more whitespaces of height 5px - linesLayout.insertWhitespace(3, 0, 5, 0); - linesLayout.insertWhitespace(4, 0, 5, 0); + insertWhitespace(linesLayout, 3, 0, 5, 0); + insertWhitespace(linesLayout, 4, 0, 5, 0); // lines: [0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] // whitespace: a(2,5), b(3, 5), c(4, 5) assert.equal(linesLayout.getLinesTotalHeight(), 115); @@ -120,7 +138,7 @@ suite('Editor ViewLayout - LinesLayout', () => { // Start off with 10 lines and one whitespace after line 2, of height 5 let linesLayout = new LinesLayout(10, 1); - let a = linesLayout.insertWhitespace(2, 0, 5, 0); + let a = insertWhitespace(linesLayout, 2, 0, 5, 0); // 10 lines // whitespace: - a(2,5) @@ -139,7 +157,7 @@ suite('Editor ViewLayout - LinesLayout', () => { // Change whitespace height // 10 lines // whitespace: - a(2,10) - linesLayout.changeWhitespace(a, 2, 10); + changeOneWhitespace(linesLayout, a, 2, 10); assert.equal(linesLayout.getLinesTotalHeight(), 20); assert.equal(linesLayout.getVerticalOffsetForLineNumber(1), 0); assert.equal(linesLayout.getVerticalOffsetForLineNumber(2), 1); @@ -155,7 +173,7 @@ suite('Editor ViewLayout - LinesLayout', () => { // Change whitespace position // 10 lines // whitespace: - a(5,10) - linesLayout.changeWhitespace(a, 5, 10); + changeOneWhitespace(linesLayout, a, 5, 10); assert.equal(linesLayout.getLinesTotalHeight(), 20); assert.equal(linesLayout.getVerticalOffsetForLineNumber(1), 0); assert.equal(linesLayout.getVerticalOffsetForLineNumber(2), 1); @@ -200,7 +218,7 @@ suite('Editor ViewLayout - LinesLayout', () => { // Remove whitespace // 10 lines - linesLayout.removeWhitespace(a); + removeWhitespace(linesLayout, a); assert.equal(linesLayout.getLinesTotalHeight(), 10); assert.equal(linesLayout.getVerticalOffsetForLineNumber(1), 0); assert.equal(linesLayout.getVerticalOffsetForLineNumber(2), 1); @@ -216,7 +234,7 @@ suite('Editor ViewLayout - LinesLayout', () => { test('LinesLayout getLineNumberAtOrAfterVerticalOffset', () => { let linesLayout = new LinesLayout(10, 1); - linesLayout.insertWhitespace(6, 0, 10, 0); + insertWhitespace(linesLayout, 6, 0, 10, 0); // 10 lines // whitespace: - a(6,10) @@ -265,7 +283,7 @@ suite('Editor ViewLayout - LinesLayout', () => { test('LinesLayout getCenteredLineInViewport', () => { let linesLayout = new LinesLayout(10, 1); - linesLayout.insertWhitespace(6, 0, 10, 0); + insertWhitespace(linesLayout, 6, 0, 10, 0); // 10 lines // whitespace: - a(6,10) @@ -348,7 +366,7 @@ suite('Editor ViewLayout - LinesLayout', () => { test('LinesLayout getLinesViewportData 1', () => { let linesLayout = new LinesLayout(10, 10); - linesLayout.insertWhitespace(6, 0, 100, 0); + insertWhitespace(linesLayout, 6, 0, 100, 0); // 10 lines // whitespace: - a(6,100) @@ -481,8 +499,8 @@ suite('Editor ViewLayout - LinesLayout', () => { test('LinesLayout getLinesViewportData 2 & getWhitespaceViewportData', () => { let linesLayout = new LinesLayout(10, 10); - let a = linesLayout.insertWhitespace(6, 0, 100, 0); - let b = linesLayout.insertWhitespace(7, 0, 50, 0); + let a = insertWhitespace(linesLayout, 6, 0, 100, 0); + let b = insertWhitespace(linesLayout, 7, 0, 50, 0); // 10 lines // whitespace: - a(6,100), b(7, 50) @@ -552,8 +570,8 @@ suite('Editor ViewLayout - LinesLayout', () => { test('LinesLayout getWhitespaceAtVerticalOffset', () => { let linesLayout = new LinesLayout(10, 10); - let a = linesLayout.insertWhitespace(6, 0, 100, 0); - let b = linesLayout.insertWhitespace(7, 0, 50, 0); + let a = insertWhitespace(linesLayout, 6, 0, 100, 0); + let b = insertWhitespace(linesLayout, 7, 0, 50, 0); let whitespace = linesLayout.getWhitespaceAtVerticalOffset(0); assert.equal(whitespace, null); @@ -597,7 +615,7 @@ suite('Editor ViewLayout - LinesLayout', () => { const linesLayout = new LinesLayout(100, 20); // Insert a whitespace after line number 2, of height 10 - const a = linesLayout.insertWhitespace(2, 0, 10, 0); + const a = insertWhitespace(linesLayout, 2, 0, 10, 0); // whitespaces: a(2, 10) assert.equal(linesLayout.getWhitespacesCount(), 1); assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(0), 2); @@ -610,7 +628,7 @@ suite('Editor ViewLayout - LinesLayout', () => { assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(4), 10); // Insert a whitespace again after line number 2, of height 20 - let b = linesLayout.insertWhitespace(2, 0, 20, 0); + let b = insertWhitespace(linesLayout, 2, 0, 20, 0); // whitespaces: a(2, 10), b(2, 20) assert.equal(linesLayout.getWhitespacesCount(), 2); assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(0), 2); @@ -626,7 +644,7 @@ suite('Editor ViewLayout - LinesLayout', () => { assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(4), 30); // Change last inserted whitespace height to 30 - linesLayout.changeWhitespace(b, 2, 30); + changeOneWhitespace(linesLayout, b, 2, 30); // whitespaces: a(2, 10), b(2, 30) assert.equal(linesLayout.getWhitespacesCount(), 2); assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(0), 2); @@ -642,7 +660,7 @@ suite('Editor ViewLayout - LinesLayout', () => { assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(4), 40); // Remove last inserted whitespace - linesLayout.removeWhitespace(b); + removeWhitespace(linesLayout, b); // whitespaces: a(2, 10) assert.equal(linesLayout.getWhitespacesCount(), 1); assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(0), 2); @@ -655,7 +673,7 @@ suite('Editor ViewLayout - LinesLayout', () => { assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(4), 10); // Add a whitespace before the first line of height 50 - b = linesLayout.insertWhitespace(0, 0, 50, 0); + b = insertWhitespace(linesLayout, 0, 0, 50, 0); // whitespaces: b(0, 50), a(2, 10) assert.equal(linesLayout.getWhitespacesCount(), 2); assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(0), 0); @@ -671,7 +689,7 @@ suite('Editor ViewLayout - LinesLayout', () => { assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(4), 60); // Add a whitespace after line 4 of height 20 - linesLayout.insertWhitespace(4, 0, 20, 0); + insertWhitespace(linesLayout, 4, 0, 20, 0); // whitespaces: b(0, 50), a(2, 10), c(4, 20) assert.equal(linesLayout.getWhitespacesCount(), 3); assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(0), 0); @@ -691,7 +709,7 @@ suite('Editor ViewLayout - LinesLayout', () => { assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(5), 80); // Add a whitespace after line 3 of height 30 - linesLayout.insertWhitespace(3, 0, 30, 0); + insertWhitespace(linesLayout, 3, 0, 30, 0); // whitespaces: b(0, 50), a(2, 10), d(3, 30), c(4, 20) assert.equal(linesLayout.getWhitespacesCount(), 4); assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(0), 0); @@ -714,7 +732,7 @@ suite('Editor ViewLayout - LinesLayout', () => { assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(5), 110); // Change whitespace after line 2 to height of 100 - linesLayout.changeWhitespace(a, 2, 100); + changeOneWhitespace(linesLayout, a, 2, 100); // whitespaces: b(0, 50), a(2, 100), d(3, 30), c(4, 20) assert.equal(linesLayout.getWhitespacesCount(), 4); assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(0), 0); @@ -737,7 +755,7 @@ suite('Editor ViewLayout - LinesLayout', () => { assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(5), 200); // Remove whitespace after line 2 - linesLayout.removeWhitespace(a); + removeWhitespace(linesLayout, a); // whitespaces: b(0, 50), d(3, 30), c(4, 20) assert.equal(linesLayout.getWhitespacesCount(), 3); assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(0), 0); @@ -757,7 +775,7 @@ suite('Editor ViewLayout - LinesLayout', () => { assert.equal(linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(5), 100); // Remove whitespace before line 1 - linesLayout.removeWhitespace(b); + removeWhitespace(linesLayout, b); // whitespaces: d(3, 30), c(4, 20) assert.equal(linesLayout.getWhitespacesCount(), 2); assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(0), 3); @@ -962,9 +980,9 @@ suite('Editor ViewLayout - LinesLayout', () => { test('LinesLayout changeWhitespaceAfterLineNumber & getFirstWhitespaceIndexAfterLineNumber', () => { const linesLayout = new LinesLayout(100, 20); - const a = linesLayout.insertWhitespace(0, 0, 1, 0); - const b = linesLayout.insertWhitespace(7, 0, 1, 0); - const c = linesLayout.insertWhitespace(3, 0, 1, 0); + const a = insertWhitespace(linesLayout, 0, 0, 1, 0); + const b = insertWhitespace(linesLayout, 7, 0, 1, 0); + const c = insertWhitespace(linesLayout, 3, 0, 1, 0); assert.equal(linesLayout.getIdForWhitespaceIndex(0), a); // 0 assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(0), 0); @@ -983,7 +1001,7 @@ suite('Editor ViewLayout - LinesLayout', () => { assert.equal(linesLayout.getFirstWhitespaceIndexAfterLineNumber(8), -1); // -- // Do not really move a - linesLayout.changeWhitespace(a, 1, 1); + changeOneWhitespace(linesLayout, a, 1, 1); assert.equal(linesLayout.getIdForWhitespaceIndex(0), a); // 1 assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(0), 1); @@ -1003,7 +1021,7 @@ suite('Editor ViewLayout - LinesLayout', () => { // Do not really move a - linesLayout.changeWhitespace(a, 2, 1); + changeOneWhitespace(linesLayout, a, 2, 1); assert.equal(linesLayout.getIdForWhitespaceIndex(0), a); // 2 assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(0), 2); @@ -1023,7 +1041,7 @@ suite('Editor ViewLayout - LinesLayout', () => { // Change a to conflict with c => a gets placed after c - linesLayout.changeWhitespace(a, 3, 1); + changeOneWhitespace(linesLayout, a, 3, 1); assert.equal(linesLayout.getIdForWhitespaceIndex(0), c); // 3 assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(0), 3); @@ -1043,7 +1061,7 @@ suite('Editor ViewLayout - LinesLayout', () => { // Make a no-op - linesLayout.changeWhitespace(c, 3, 1); + changeOneWhitespace(linesLayout, c, 3, 1); assert.equal(linesLayout.getIdForWhitespaceIndex(0), c); // 3 assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(0), 3); @@ -1064,7 +1082,7 @@ suite('Editor ViewLayout - LinesLayout', () => { // Conflict c with b => c gets placed after b - linesLayout.changeWhitespace(c, 7, 1); + changeOneWhitespace(linesLayout, c, 7, 1); assert.equal(linesLayout.getIdForWhitespaceIndex(0), a); // 3 assert.equal(linesLayout.getAfterLineNumberForWhitespaceIndex(0), 3); @@ -1086,32 +1104,32 @@ suite('Editor ViewLayout - LinesLayout', () => { test('LinesLayout Bug', () => { const linesLayout = new LinesLayout(100, 20); - const a = linesLayout.insertWhitespace(0, 0, 1, 0); - const b = linesLayout.insertWhitespace(7, 0, 1, 0); + const a = insertWhitespace(linesLayout, 0, 0, 1, 0); + const b = insertWhitespace(linesLayout, 7, 0, 1, 0); assert.equal(linesLayout.getIdForWhitespaceIndex(0), a); // 0 assert.equal(linesLayout.getIdForWhitespaceIndex(1), b); // 7 - const c = linesLayout.insertWhitespace(3, 0, 1, 0); + const c = insertWhitespace(linesLayout, 3, 0, 1, 0); assert.equal(linesLayout.getIdForWhitespaceIndex(0), a); // 0 assert.equal(linesLayout.getIdForWhitespaceIndex(1), c); // 3 assert.equal(linesLayout.getIdForWhitespaceIndex(2), b); // 7 - const d = linesLayout.insertWhitespace(2, 0, 1, 0); + const d = insertWhitespace(linesLayout, 2, 0, 1, 0); assert.equal(linesLayout.getIdForWhitespaceIndex(0), a); // 0 assert.equal(linesLayout.getIdForWhitespaceIndex(1), d); // 2 assert.equal(linesLayout.getIdForWhitespaceIndex(2), c); // 3 assert.equal(linesLayout.getIdForWhitespaceIndex(3), b); // 7 - const e = linesLayout.insertWhitespace(8, 0, 1, 0); + const e = insertWhitespace(linesLayout, 8, 0, 1, 0); assert.equal(linesLayout.getIdForWhitespaceIndex(0), a); // 0 assert.equal(linesLayout.getIdForWhitespaceIndex(1), d); // 2 assert.equal(linesLayout.getIdForWhitespaceIndex(2), c); // 3 assert.equal(linesLayout.getIdForWhitespaceIndex(3), b); // 7 assert.equal(linesLayout.getIdForWhitespaceIndex(4), e); // 8 - const f = linesLayout.insertWhitespace(11, 0, 1, 0); + const f = insertWhitespace(linesLayout, 11, 0, 1, 0); assert.equal(linesLayout.getIdForWhitespaceIndex(0), a); // 0 assert.equal(linesLayout.getIdForWhitespaceIndex(1), d); // 2 assert.equal(linesLayout.getIdForWhitespaceIndex(2), c); // 3 @@ -1119,7 +1137,7 @@ suite('Editor ViewLayout - LinesLayout', () => { assert.equal(linesLayout.getIdForWhitespaceIndex(4), e); // 8 assert.equal(linesLayout.getIdForWhitespaceIndex(5), f); // 11 - const g = linesLayout.insertWhitespace(10, 0, 1, 0); + const g = insertWhitespace(linesLayout, 10, 0, 1, 0); assert.equal(linesLayout.getIdForWhitespaceIndex(0), a); // 0 assert.equal(linesLayout.getIdForWhitespaceIndex(1), d); // 2 assert.equal(linesLayout.getIdForWhitespaceIndex(2), c); // 3 @@ -1128,7 +1146,7 @@ suite('Editor ViewLayout - LinesLayout', () => { assert.equal(linesLayout.getIdForWhitespaceIndex(5), g); // 10 assert.equal(linesLayout.getIdForWhitespaceIndex(6), f); // 11 - const h = linesLayout.insertWhitespace(0, 0, 1, 0); + const h = insertWhitespace(linesLayout, 0, 0, 1, 0); assert.equal(linesLayout.getIdForWhitespaceIndex(0), a); // 0 assert.equal(linesLayout.getIdForWhitespaceIndex(1), h); // 0 assert.equal(linesLayout.getIdForWhitespaceIndex(2), d); // 2 From 2a49e82150196bfcc19fca3703af53d5b8ec2673 Mon Sep 17 00:00:00 2001 From: Alexandru Dima Date: Fri, 15 Nov 2019 16:15:07 +0100 Subject: [PATCH 344/352] Switch to objects in LinesLayout --- .../browser/viewParts/viewZones/viewZones.ts | 24 +- .../editor/common/viewLayout/linesLayout.ts | 375 ++++++++++-------- .../common/viewLayout/linesLayout.test.ts | 255 ++++++------ 3 files changed, 340 insertions(+), 314 deletions(-) diff --git a/src/vs/editor/browser/viewParts/viewZones/viewZones.ts b/src/vs/editor/browser/viewParts/viewZones/viewZones.ts index aca0e779c2f1d..a2160d7817397 100644 --- a/src/vs/editor/browser/viewParts/viewZones/viewZones.ts +++ b/src/vs/editor/browser/viewParts/viewZones/viewZones.ts @@ -13,7 +13,7 @@ import { ViewContext } from 'vs/editor/common/view/viewContext'; import * as viewEvents from 'vs/editor/common/view/viewEvents'; import { IViewWhitespaceViewportData } from 'vs/editor/common/viewModel/viewModel'; import { EditorOption } from 'vs/editor/common/config/editorOptions'; -import { IWhitespaceChangeAccessor } from 'vs/editor/common/viewLayout/linesLayout'; +import { IWhitespaceChangeAccessor, EditorWhitespace } from 'vs/editor/common/viewLayout/linesLayout'; export interface IMyViewZone { whitespaceId: string; @@ -74,6 +74,11 @@ export class ViewZones extends ViewPart { // ---- begin view event handlers private _recomputeWhitespacesProps(): boolean { + const whitespaces = this._context.viewLayout.getWhitespaces(); + const oldWhitespaces = new Map(); + for (const whitespace of whitespaces) { + oldWhitespaces.set(whitespace.id, whitespace); + } return this._context.viewLayout.changeWhitespace((whitespaceAccessor: IWhitespaceChangeAccessor) => { let hadAChange = false; @@ -82,7 +87,9 @@ export class ViewZones extends ViewPart { const id = keys[i]; const zone = this._zones[id]; const props = this._computeWhitespaceProps(zone.delegate); - if (whitespaceAccessor.changeOneWhitespace(id, props.afterViewLineNumber, props.heightInPx)) { + const oldWhitespace = oldWhitespaces.get(id); + if (oldWhitespace && (oldWhitespace.afterLineNumber !== props.afterViewLineNumber || oldWhitespace.heightInPx !== props.heightInPx)) { + whitespaceAccessor.changeOneWhitespace(id, props.afterViewLineNumber, props.heightInPx); this._safeCallOnComputedHeight(zone.delegate, props.heightInPx); hadAChange = true; } @@ -286,20 +293,19 @@ export class ViewZones extends ViewPart { } private _layoutZone(whitespaceAccessor: IWhitespaceChangeAccessor, id: string): boolean { - let changed = false; if (this._zones.hasOwnProperty(id)) { const zone = this._zones[id]; const props = this._computeWhitespaceProps(zone.delegate); // const newOrdinal = this._getZoneOrdinal(zone.delegate); - changed = whitespaceAccessor.changeOneWhitespace(zone.whitespaceId, props.afterViewLineNumber, props.heightInPx) || changed; + whitespaceAccessor.changeOneWhitespace(zone.whitespaceId, props.afterViewLineNumber, props.heightInPx); // TODO@Alex: change `newOrdinal` too - if (changed) { - this._safeCallOnComputedHeight(zone.delegate, props.heightInPx); - this.setShouldRender(); - } + this._safeCallOnComputedHeight(zone.delegate, props.heightInPx); + this.setShouldRender(); + + return true; } - return changed; + return false; } public shouldSuppressMouseDownOnViewZone(id: string): boolean { diff --git a/src/vs/editor/common/viewLayout/linesLayout.ts b/src/vs/editor/common/viewLayout/linesLayout.ts index 14c7dd29481bf..ca6b2fcfacf36 100644 --- a/src/vs/editor/common/viewLayout/linesLayout.ts +++ b/src/vs/editor/common/viewLayout/linesLayout.ts @@ -11,6 +11,7 @@ export class EditorWhitespace { constructor( public readonly id: string, public readonly afterLineNumber: number, + public readonly heightInPx: number, public readonly heightInLines: number, ) { } } @@ -20,8 +21,80 @@ export class EditorWhitespace { */ export interface IWhitespaceChangeAccessor { insertWhitespace(afterLineNumber: number, ordinal: number, heightInPx: number, minWidth: number): string; - changeOneWhitespace(id: string, newAfterLineNumber: number, newHeight: number): boolean; - removeWhitespace(id: string): boolean; + changeOneWhitespace(id: string, newAfterLineNumber: number, newHeight: number): void; + removeWhitespace(id: string): void; +} + +interface IPendingInsert { id: string; afterLineNumber: number; ordinal: number; heightInPx: number; minWidth: number; } +interface IPendingChange { id: string; newAfterLineNumber: number; newHeight: number; } +interface IPendingRemove { id: string; } + +class PendingChanges { + private _hasPending: boolean; + private _inserts: IPendingInsert[]; + private _changes: IPendingChange[]; + private _removes: IPendingRemove[]; + + constructor() { + this._hasPending = false; + this._inserts = []; + this._changes = []; + this._removes = []; + } + + public insert(x: IPendingInsert): void { + this._hasPending = true; + this._inserts.push(x); + } + + public change(x: IPendingChange): void { + this._hasPending = true; + this._changes.push(x); + } + + public remove(x: IPendingRemove): void { + this._hasPending = true; + this._removes.push(x); + } + + public mustCommit(): boolean { + return this._hasPending; + } + + public commit(linesLayout: LinesLayout): void { + if (!this._hasPending) { + return; + } + + const inserts = this._inserts; + const changes = this._changes; + const removes = this._removes; + + this._hasPending = false; + this._inserts = []; + this._changes = []; + this._removes = []; + + linesLayout._commitPendingChanges(inserts, changes, removes); + } +} + +export class InternalWhitespace { + public id: string; + public afterLineNumber: number; + public ordinal: number; + public height: number; + public minWidth: number; + public prefixSum: number; + + constructor(id: string, afterLineNumber: number, ordinal: number, height: number, minWidth: number) { + this.id = id; + this.afterLineNumber = afterLineNumber; + this.ordinal = ordinal; + this.height = height; + this.minWidth = minWidth; + this.prefixSum = 0; + } } /** @@ -36,41 +109,15 @@ export class LinesLayout { private readonly _instanceId: string; - /** - * heights[i] is the height in pixels for whitespace at index i - */ - private readonly _heights: number[]; - - /** - * minWidths[i] is the min width in pixels for whitespace at index i - */ - private readonly _minWidths: number[]; - - /** - * afterLineNumbers[i] is the line number whitespace at index i is after - */ - private readonly _afterLineNumbers: number[]; + private _pendingChanges: PendingChanges; - /** - * ordinals[i] is the orinal of the whitespace at index i - */ - private readonly _ordinals: number[]; + private readonly _arr: InternalWhitespace[]; /** - * prefixSum[i] = SUM(heights[j]), 1 <= j <= i - */ - private readonly _prefixSum: number[]; - - /** - * prefixSum[i], 1 <= i <= prefixSumValidIndex can be trusted + * _arr[i].prefixSum, 1 <= i <= prefixSumValidIndex can be trusted */ private _prefixSumValidIndex: number; - /** - * ids[i] is the whitespace id of whitespace at index i - */ - private readonly _ids: string[]; - /** * index at which a whitespace is positioned (inside heights, afterLineNumbers, prefixSum members) */ @@ -98,12 +145,8 @@ export class LinesLayout { constructor(lineCount: number, lineHeight: number) { this._instanceId = strings.singleLetterHash(++LinesLayout.INSTANCE_COUNT); - this._heights = []; - this._minWidths = []; - this._ids = []; - this._afterLineNumbers = []; - this._ordinals = []; - this._prefixSum = []; + this._pendingChanges = new PendingChanges(); + this._arr = []; this._prefixSumValidIndex = -1; this._whitespaceId2Index = {}; this._lastWhitespaceId = 0; @@ -116,20 +159,20 @@ export class LinesLayout { * Find the insertion index for a new value inside a sorted array of values. * If the value is already present in the sorted array, the insertion index will be after the already existing value. */ - public static findInsertionIndex(sortedArray: number[], value: number, ordinals: number[], valueOrdinal: number): number { + public static findInsertionIndex(arr: InternalWhitespace[], afterLineNumber: number, ordinal: number): number { let low = 0; - let high = sortedArray.length; + let high = arr.length; while (low < high) { const mid = ((low + high) >>> 1); - if (value === sortedArray[mid]) { - if (valueOrdinal < ordinals[mid]) { + if (afterLineNumber === arr[mid].afterLineNumber) { + if (ordinal < arr[mid].ordinal) { high = mid; } else { low = mid + 1; } - } else if (value < sortedArray[mid]) { + } else if (afterLineNumber < arr[mid].afterLineNumber) { high = mid; } else { low = mid + 1; @@ -143,6 +186,7 @@ export class LinesLayout { * Change the height of a line in pixels. */ public setLineHeight(lineHeight: number): void { + this._checkPendingChanges(); this._lineHeight = lineHeight; } @@ -152,23 +196,59 @@ export class LinesLayout { * @param lineCount New number of lines. */ public onFlushed(lineCount: number): void { + this._checkPendingChanges(); this._lineCount = lineCount; } public changeWhitespace(callback: (accessor: IWhitespaceChangeAccessor) => T): T { - const accessor = { - insertWhitespace: (afterLineNumber: number, ordinal: number, heightInPx: number, minWidth: number): string => { - return this._insertWhitespace(afterLineNumber, ordinal, heightInPx, minWidth); - }, - changeOneWhitespace: (id: string, newAfterLineNumber: number, newHeight: number): boolean => { - return this._changeOneWhitespace(id, newAfterLineNumber, newHeight); - }, - removeWhitespace: (id: string): boolean => { - return this._removeWhitespace(id); - } - }; - const r = callback(accessor); - return r; + try { + const accessor = { + insertWhitespace: (afterLineNumber: number, ordinal: number, heightInPx: number, minWidth: number): string => { + afterLineNumber = afterLineNumber | 0; + ordinal = ordinal | 0; + heightInPx = heightInPx | 0; + minWidth = minWidth | 0; + + const id = this._instanceId + (++this._lastWhitespaceId); + this._pendingChanges.insert({ id, afterLineNumber, ordinal, heightInPx, minWidth }); + return id; + // return this._insertWhitespace(afterLineNumber, ordinal, heightInPx, minWidth); + }, + changeOneWhitespace: (id: string, newAfterLineNumber: number, newHeight: number): void => { + newAfterLineNumber = newAfterLineNumber | 0; + newHeight = newHeight | 0; + + this._pendingChanges.change({ id, newAfterLineNumber, newHeight }); + // this._changeOneWhitespace(id, newAfterLineNumber, newHeight); + }, + removeWhitespace: (id: string): void => { + this._pendingChanges.remove({ id }); + // this._removeWhitespace(id); + } + }; + return callback(accessor); + } finally { + this._pendingChanges.commit(this); + } + } + + public _commitPendingChanges(inserts: IPendingInsert[], changes: IPendingChange[], removes: IPendingRemove[]): void { + for (const insert of inserts) { + this._insertWhitespace(insert.id, insert.afterLineNumber, insert.ordinal, insert.heightInPx, insert.minWidth); + } + for (const change of changes) { + this._changeOneWhitespace(change.id, change.newAfterLineNumber, change.newHeight); + } + for (const remove of removes) { + this._removeWhitespace(remove.id); + } + // console.log(`TODO: `, inserts, changes, removes); + } + + private _checkPendingChanges(): void { + if (this._pendingChanges.mustCommit()) { + console.log(`I should commit pending changes!`);//TODO + } } /** @@ -180,32 +260,16 @@ export class LinesLayout { * @param heightInPx The height of the whitespace, in pixels. * @return An id that can be used later to mutate or delete the whitespace */ - private _insertWhitespace(afterLineNumber: number, ordinal: number, heightInPx: number, minWidth: number): string { - afterLineNumber = afterLineNumber | 0; - ordinal = ordinal | 0; - heightInPx = heightInPx | 0; - minWidth = minWidth | 0; - - const id = this._instanceId + (++this._lastWhitespaceId); - const insertionIndex = LinesLayout.findInsertionIndex(this._afterLineNumbers, afterLineNumber, this._ordinals, ordinal); - this._insertWhitespaceAtIndex(id, insertionIndex, afterLineNumber, ordinal, heightInPx, minWidth); + private _insertWhitespace(id: string, afterLineNumber: number, ordinal: number, heightInPx: number, minWidth: number): string { + const whitespace = new InternalWhitespace(id, afterLineNumber, ordinal, heightInPx, minWidth); + const insertionIndex = LinesLayout.findInsertionIndex(this._arr, whitespace.afterLineNumber, whitespace.ordinal); + this._insertWhitespaceAtIndex(insertionIndex, whitespace); this._minWidth = -1; /* marker for not being computed */ return id; } - private _insertWhitespaceAtIndex(id: string, insertIndex: number, afterLineNumber: number, ordinal: number, heightInPx: number, minWidth: number): void { - insertIndex = insertIndex | 0; - afterLineNumber = afterLineNumber | 0; - ordinal = ordinal | 0; - heightInPx = heightInPx | 0; - minWidth = minWidth | 0; - - this._heights.splice(insertIndex, 0, heightInPx); - this._minWidths.splice(insertIndex, 0, minWidth); - this._ids.splice(insertIndex, 0, id); - this._afterLineNumbers.splice(insertIndex, 0, afterLineNumber); - this._ordinals.splice(insertIndex, 0, ordinal); - this._prefixSum.splice(insertIndex, 0, 0); + private _insertWhitespaceAtIndex(insertIndex: number, whitespace: InternalWhitespace): void { + this._arr.splice(insertIndex, 0, whitespace); const keys = Object.keys(this._whitespaceId2Index); for (const sid of keys) { @@ -215,79 +279,36 @@ export class LinesLayout { } } - this._whitespaceId2Index[id] = insertIndex; + this._whitespaceId2Index[whitespace.id] = insertIndex; this._prefixSumValidIndex = Math.min(this._prefixSumValidIndex, insertIndex - 1); } /** * Change properties associated with a certain whitespace. */ - private _changeOneWhitespace(id: string, newAfterLineNumber: number, newHeight: number): boolean { - newAfterLineNumber = newAfterLineNumber | 0; - newHeight = newHeight | 0; - - let hasChanges = false; - hasChanges = this.changeWhitespaceHeight(id, newHeight) || hasChanges; - hasChanges = this.changeWhitespaceAfterLineNumber(id, newAfterLineNumber) || hasChanges; - return hasChanges; - } - - /** - * Change the height of an existing whitespace - * - * @param id The whitespace to change - * @param newHeightInPx The new height of the whitespace, in pixels - * @return Returns true if the whitespace is found and if the new height is different than the old height - */ - public changeWhitespaceHeight(id: string, newHeightInPx: number): boolean { - newHeightInPx = newHeightInPx | 0; - + private _changeOneWhitespace(id: string, newAfterLineNumber: number, newHeight: number): void { if (this._whitespaceId2Index.hasOwnProperty(id)) { const index = this._whitespaceId2Index[id]; - if (this._heights[index] !== newHeightInPx) { - this._heights[index] = newHeightInPx; + if (this._arr[index].height !== newHeight) { + this._arr[index].height = newHeight; this._prefixSumValidIndex = Math.min(this._prefixSumValidIndex, index - 1); - return true; } - } - return false; - } - - /** - * Change the line number after which an existing whitespace flows. - * - * @param id The whitespace to change - * @param newAfterLineNumber The new line number the whitespace will follow - * @return Returns true if the whitespace is found and if the new line number is different than the old line number - */ - public changeWhitespaceAfterLineNumber(id: string, newAfterLineNumber: number): boolean { - newAfterLineNumber = newAfterLineNumber | 0; - - if (this._whitespaceId2Index.hasOwnProperty(id)) { - const index = this._whitespaceId2Index[id]; - if (this._afterLineNumbers[index] !== newAfterLineNumber) { + if (this._arr[index].afterLineNumber !== newAfterLineNumber) { // `afterLineNumber` changed for this whitespace - // Record old ordinal - const ordinal = this._ordinals[index]; - - // Record old height - const heightInPx = this._heights[index]; - - // Record old min width - const minWidth = this._minWidths[index]; + // Record old whitespace + const whitespace = this._arr[index]; // Since changing `afterLineNumber` can trigger a reordering, we're gonna remove this whitespace this._removeWhitespace(id); - // And add it again - const insertionIndex = LinesLayout.findInsertionIndex(this._afterLineNumbers, newAfterLineNumber, this._ordinals, ordinal); - this._insertWhitespaceAtIndex(id, insertionIndex, newAfterLineNumber, ordinal, heightInPx, minWidth); + whitespace.afterLineNumber = newAfterLineNumber; - return true; + // And add it again + const insertionIndex = LinesLayout.findInsertionIndex(this._arr, whitespace.afterLineNumber, whitespace.ordinal); + this._insertWhitespaceAtIndex(insertionIndex, whitespace); } } - return false; } /** @@ -296,27 +317,18 @@ export class LinesLayout { * @param id The whitespace to remove * @return Returns true if the whitespace is found and it is removed. */ - private _removeWhitespace(id: string): boolean { + private _removeWhitespace(id: string): void { if (this._whitespaceId2Index.hasOwnProperty(id)) { const index = this._whitespaceId2Index[id]; delete this._whitespaceId2Index[id]; this._removeWhitespaceAtIndex(index); this._minWidth = -1; /* marker for not being computed */ - return true; } - - return false; } private _removeWhitespaceAtIndex(removeIndex: number): void { - removeIndex = removeIndex | 0; - - this._heights.splice(removeIndex, 1); - this._minWidths.splice(removeIndex, 1); - this._ids.splice(removeIndex, 1); - this._afterLineNumbers.splice(removeIndex, 1); - this._ordinals.splice(removeIndex, 1); - this._prefixSum.splice(removeIndex, 1); + + this._arr.splice(removeIndex, 1); this._prefixSumValidIndex = Math.min(this._prefixSumValidIndex, removeIndex - 1); const keys = Object.keys(this._whitespaceId2Index); @@ -335,21 +347,22 @@ export class LinesLayout { * @param toLineNumber The line number at which the deletion ended, inclusive */ public onLinesDeleted(fromLineNumber: number, toLineNumber: number): void { + this._checkPendingChanges(); fromLineNumber = fromLineNumber | 0; toLineNumber = toLineNumber | 0; this._lineCount -= (toLineNumber - fromLineNumber + 1); - for (let i = 0, len = this._afterLineNumbers.length; i < len; i++) { - const afterLineNumber = this._afterLineNumbers[i]; + for (let i = 0, len = this._arr.length; i < len; i++) { + const afterLineNumber = this._arr[i].afterLineNumber; if (fromLineNumber <= afterLineNumber && afterLineNumber <= toLineNumber) { // The line this whitespace was after has been deleted // => move whitespace to before first deleted line - this._afterLineNumbers[i] = fromLineNumber - 1; + this._arr[i].afterLineNumber = fromLineNumber - 1; } else if (afterLineNumber > toLineNumber) { // The line this whitespace was after has been moved up // => move whitespace up - this._afterLineNumbers[i] -= (toLineNumber - fromLineNumber + 1); + this._arr[i].afterLineNumber -= (toLineNumber - fromLineNumber + 1); } } } @@ -361,15 +374,16 @@ export class LinesLayout { * @param toLineNumber The line number at which the insertion ended, inclusive. */ public onLinesInserted(fromLineNumber: number, toLineNumber: number): void { + this._checkPendingChanges(); fromLineNumber = fromLineNumber | 0; toLineNumber = toLineNumber | 0; this._lineCount += (toLineNumber - fromLineNumber + 1); - for (let i = 0, len = this._afterLineNumbers.length; i < len; i++) { - const afterLineNumber = this._afterLineNumbers[i]; + for (let i = 0, len = this._arr.length; i < len; i++) { + const afterLineNumber = this._arr[i].afterLineNumber; if (fromLineNumber <= afterLineNumber) { - this._afterLineNumbers[i] += (toLineNumber - fromLineNumber + 1); + this._arr[i].afterLineNumber += (toLineNumber - fromLineNumber + 1); } } } @@ -378,10 +392,11 @@ export class LinesLayout { * Get the sum of all the whitespaces. */ public getWhitespacesTotalHeight(): number { - if (this._heights.length === 0) { + this._checkPendingChanges(); + if (this._arr.length === 0) { return 0; } - return this.getWhitespacesAccumulatedHeight(this._heights.length - 1); + return this.getWhitespacesAccumulatedHeight(this._arr.length - 1); } /** @@ -392,19 +407,20 @@ export class LinesLayout { * @return The sum of the heights of all whitespaces before the one at `index`, including the one at `index`. */ public getWhitespacesAccumulatedHeight(index: number): number { + this._checkPendingChanges(); index = index | 0; let startIndex = Math.max(0, this._prefixSumValidIndex + 1); if (startIndex === 0) { - this._prefixSum[0] = this._heights[0]; + this._arr[0].prefixSum = this._arr[0].height; startIndex++; } for (let i = startIndex; i <= index; i++) { - this._prefixSum[i] = this._prefixSum[i - 1] + this._heights[i]; + this._arr[i].prefixSum = this._arr[i - 1].prefixSum + this._arr[i].height; } this._prefixSumValidIndex = Math.max(this._prefixSumValidIndex, index); - return this._prefixSum[index]; + return this._arr[index].prefixSum; } /** @@ -413,6 +429,7 @@ export class LinesLayout { * @return The sum of heights for all objects. */ public getLinesTotalHeight(): number { + this._checkPendingChanges(); const linesHeight = this._lineHeight * this._lineCount; const whitespacesHeight = this.getWhitespacesTotalHeight(); return linesHeight + whitespacesHeight; @@ -424,6 +441,7 @@ export class LinesLayout { * @param lineNumber The line number */ public getWhitespaceAccumulatedHeightBeforeLineNumber(lineNumber: number): number { + this._checkPendingChanges(); lineNumber = lineNumber | 0; const lastWhitespaceBeforeLineNumber = this._findLastWhitespaceBeforeLineNumber(lineNumber); @@ -439,17 +457,17 @@ export class LinesLayout { lineNumber = lineNumber | 0; // Find the whitespace before line number - const afterLineNumbers = this._afterLineNumbers; + const arr = this._arr; let low = 0; - let high = afterLineNumbers.length - 1; + let high = arr.length - 1; while (low <= high) { const delta = (high - low) | 0; const halfDelta = (delta / 2) | 0; const mid = (low + halfDelta) | 0; - if (afterLineNumbers[mid] < lineNumber) { - if (mid + 1 >= afterLineNumbers.length || afterLineNumbers[mid + 1] >= lineNumber) { + if (arr[mid].afterLineNumber < lineNumber) { + if (mid + 1 >= arr.length || arr[mid + 1].afterLineNumber >= lineNumber) { return mid; } else { low = (mid + 1) | 0; @@ -468,7 +486,7 @@ export class LinesLayout { const lastWhitespaceBeforeLineNumber = this._findLastWhitespaceBeforeLineNumber(lineNumber); const firstWhitespaceAfterLineNumber = lastWhitespaceBeforeLineNumber + 1; - if (firstWhitespaceAfterLineNumber < this._heights.length) { + if (firstWhitespaceAfterLineNumber < this._arr.length) { return firstWhitespaceAfterLineNumber; } @@ -480,6 +498,7 @@ export class LinesLayout { * @return The index of the first whitespace with `afterLineNumber` >= `lineNumber` or -1 if no whitespace is found. */ public getFirstWhitespaceIndexAfterLineNumber(lineNumber: number): number { + this._checkPendingChanges(); lineNumber = lineNumber | 0; return this._findFirstWhitespaceAfterLineNumber(lineNumber); @@ -492,6 +511,7 @@ export class LinesLayout { * @return The sum of heights for all objects above `lineNumber`. */ public getVerticalOffsetForLineNumber(lineNumber: number): number { + this._checkPendingChanges(); lineNumber = lineNumber | 0; let previousLinesHeight: number; @@ -510,6 +530,7 @@ export class LinesLayout { * Returns if there is any whitespace in the document. */ public hasWhitespace(): boolean { + this._checkPendingChanges(); return this.getWhitespacesCount() > 0; } @@ -517,10 +538,11 @@ export class LinesLayout { * The maximum min width for all whitespaces. */ public getWhitespaceMinWidth(): number { + this._checkPendingChanges(); if (this._minWidth === -1) { let minWidth = 0; - for (let i = 0, len = this._minWidths.length; i < len; i++) { - minWidth = Math.max(minWidth, this._minWidths[i]); + for (let i = 0, len = this._arr.length; i < len; i++) { + minWidth = Math.max(minWidth, this._arr[i].minWidth); } this._minWidth = minWidth; } @@ -531,6 +553,7 @@ export class LinesLayout { * Check if `verticalOffset` is below all lines. */ public isAfterLines(verticalOffset: number): boolean { + this._checkPendingChanges(); const totalHeight = this.getLinesTotalHeight(); return verticalOffset > totalHeight; } @@ -544,6 +567,7 @@ export class LinesLayout { * @return The line number at or after vertical offset `verticalOffset`. */ public getLineNumberAtOrAfterVerticalOffset(verticalOffset: number): number { + this._checkPendingChanges(); verticalOffset = verticalOffset | 0; if (verticalOffset < 0) { @@ -587,6 +611,7 @@ export class LinesLayout { * @return A structure describing the lines positioned between `verticalOffset1` and `verticalOffset2`. */ public getLinesViewportData(verticalOffset1: number, verticalOffset2: number): IPartialViewLinesViewportData { + this._checkPendingChanges(); verticalOffset1 = verticalOffset1 | 0; verticalOffset2 = verticalOffset2 | 0; const lineHeight = this._lineHeight; @@ -704,6 +729,7 @@ export class LinesLayout { } public getVerticalOffsetForWhitespaceIndex(whitespaceIndex: number): number { + this._checkPendingChanges(); whitespaceIndex = whitespaceIndex | 0; const afterLineNumber = this.getAfterLineNumberForWhitespaceIndex(whitespaceIndex); @@ -725,6 +751,7 @@ export class LinesLayout { } public getWhitespaceIndexAtOrAfterVerticallOffset(verticalOffset: number): number { + this._checkPendingChanges(); verticalOffset = verticalOffset | 0; let minWhitespaceIndex = 0; @@ -768,6 +795,7 @@ export class LinesLayout { * @return Precisely the whitespace that is layouted at `verticaloffset` or null. */ public getWhitespaceAtVerticalOffset(verticalOffset: number): IViewWhitespaceViewportData | null { + this._checkPendingChanges(); verticalOffset = verticalOffset | 0; const candidateIndex = this.getWhitespaceIndexAtOrAfterVerticallOffset(verticalOffset); @@ -806,6 +834,7 @@ export class LinesLayout { * @return An array with all the whitespaces in the viewport. If no whitespace is in viewport, the array is empty. */ public getWhitespaceViewportData(verticalOffset1: number, verticalOffset2: number): IViewWhitespaceViewportData[] { + this._checkPendingChanges(); verticalOffset1 = verticalOffset1 | 0; verticalOffset2 = verticalOffset2 | 0; @@ -839,12 +868,14 @@ export class LinesLayout { * Get all whitespaces. */ public getWhitespaces(): EditorWhitespace[] { + this._checkPendingChanges(); let result: EditorWhitespace[] = []; - for (let i = 0; i < this._heights.length; i++) { + for (let i = 0; i < this._arr.length; i++) { result.push(new EditorWhitespace( - this._ids[i], - this._afterLineNumbers[i], - this._heights[i] / this._lineHeight + this._arr[i].id, + this._arr[i].afterLineNumber, + this._arr[i].height, + this._arr[i].height / this._lineHeight )); } return result; @@ -854,7 +885,8 @@ export class LinesLayout { * The number of whitespaces. */ public getWhitespacesCount(): number { - return this._heights.length; + this._checkPendingChanges(); + return this._arr.length; } /** @@ -864,9 +896,10 @@ export class LinesLayout { * @return `id` of whitespace at `index`. */ public getIdForWhitespaceIndex(index: number): string { + this._checkPendingChanges(); index = index | 0; - return this._ids[index]; + return this._arr[index].id; } /** @@ -876,9 +909,10 @@ export class LinesLayout { * @return `afterLineNumber` of whitespace at `index`. */ public getAfterLineNumberForWhitespaceIndex(index: number): number { + this._checkPendingChanges(); index = index | 0; - return this._afterLineNumbers[index]; + return this._arr[index].afterLineNumber; } /** @@ -888,8 +922,9 @@ export class LinesLayout { * @return `height` of whitespace at `index`. */ public getHeightForWhitespaceIndex(index: number): number { + this._checkPendingChanges(); index = index | 0; - return this._heights[index]; + return this._arr[index].height; } } diff --git a/src/vs/editor/test/common/viewLayout/linesLayout.test.ts b/src/vs/editor/test/common/viewLayout/linesLayout.test.ts index 12f4693761a0e..57ee0db54279b 100644 --- a/src/vs/editor/test/common/viewLayout/linesLayout.test.ts +++ b/src/vs/editor/test/common/viewLayout/linesLayout.test.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ import * as assert from 'assert'; -import { LinesLayout } from 'vs/editor/common/viewLayout/linesLayout'; +import { LinesLayout, InternalWhitespace } from 'vs/editor/common/viewLayout/linesLayout'; suite('Editor ViewLayout - LinesLayout', () => { @@ -13,15 +13,15 @@ suite('Editor ViewLayout - LinesLayout', () => { }); } - function changeOneWhitespace(linesLayout: LinesLayout, id: string, newAfterLineNumber: number, newHeight: number): boolean { - return linesLayout.changeWhitespace((accessor) => { - return accessor.changeOneWhitespace(id, newAfterLineNumber, newHeight); + function changeOneWhitespace(linesLayout: LinesLayout, id: string, newAfterLineNumber: number, newHeight: number): void { + linesLayout.changeWhitespace((accessor) => { + accessor.changeOneWhitespace(id, newAfterLineNumber, newHeight); }); } - function removeWhitespace(linesLayout: LinesLayout, id: string): boolean { - return linesLayout.changeWhitespace((accessor) => { - return accessor.removeWhitespace(id); + function removeWhitespace(linesLayout: LinesLayout, id: string): void { + linesLayout.changeWhitespace((accessor) => { + accessor.removeWhitespace(id); }); } @@ -845,136 +845,121 @@ suite('Editor ViewLayout - LinesLayout', () => { test('LinesLayout findInsertionIndex', () => { - const makeArray = (size: number, fillValue: number) => { - let r: number[] = []; - for (let i = 0; i < size; i++) { - r[i] = fillValue; - } - return r; + const makeInternalWhitespace = (afterLineNumbers: number[], ordinal: number = 0) => { + return afterLineNumbers.map((afterLineNumber) => new InternalWhitespace('', afterLineNumber, ordinal, 0, 0)); }; - let arr: number[]; - let ordinals: number[]; - - arr = []; - ordinals = makeArray(arr.length, 0); - assert.equal(LinesLayout.findInsertionIndex(arr, 0, ordinals, 0), 0); - assert.equal(LinesLayout.findInsertionIndex(arr, 1, ordinals, 0), 0); - assert.equal(LinesLayout.findInsertionIndex(arr, 2, ordinals, 0), 0); - - arr = [1]; - ordinals = makeArray(arr.length, 0); - assert.equal(LinesLayout.findInsertionIndex(arr, 0, ordinals, 0), 0); - assert.equal(LinesLayout.findInsertionIndex(arr, 1, ordinals, 0), 1); - assert.equal(LinesLayout.findInsertionIndex(arr, 2, ordinals, 0), 1); - - arr = [1, 3]; - ordinals = makeArray(arr.length, 0); - assert.equal(LinesLayout.findInsertionIndex(arr, 0, ordinals, 0), 0); - assert.equal(LinesLayout.findInsertionIndex(arr, 1, ordinals, 0), 1); - assert.equal(LinesLayout.findInsertionIndex(arr, 2, ordinals, 0), 1); - assert.equal(LinesLayout.findInsertionIndex(arr, 3, ordinals, 0), 2); - assert.equal(LinesLayout.findInsertionIndex(arr, 4, ordinals, 0), 2); - - arr = [1, 3, 5]; - ordinals = makeArray(arr.length, 0); - assert.equal(LinesLayout.findInsertionIndex(arr, 0, ordinals, 0), 0); - assert.equal(LinesLayout.findInsertionIndex(arr, 1, ordinals, 0), 1); - assert.equal(LinesLayout.findInsertionIndex(arr, 2, ordinals, 0), 1); - assert.equal(LinesLayout.findInsertionIndex(arr, 3, ordinals, 0), 2); - assert.equal(LinesLayout.findInsertionIndex(arr, 4, ordinals, 0), 2); - assert.equal(LinesLayout.findInsertionIndex(arr, 5, ordinals, 0), 3); - assert.equal(LinesLayout.findInsertionIndex(arr, 6, ordinals, 0), 3); - - arr = [1, 3, 5]; - ordinals = makeArray(arr.length, 3); - assert.equal(LinesLayout.findInsertionIndex(arr, 0, ordinals, 0), 0); - assert.equal(LinesLayout.findInsertionIndex(arr, 1, ordinals, 0), 0); - assert.equal(LinesLayout.findInsertionIndex(arr, 2, ordinals, 0), 1); - assert.equal(LinesLayout.findInsertionIndex(arr, 3, ordinals, 0), 1); - assert.equal(LinesLayout.findInsertionIndex(arr, 4, ordinals, 0), 2); - assert.equal(LinesLayout.findInsertionIndex(arr, 5, ordinals, 0), 2); - assert.equal(LinesLayout.findInsertionIndex(arr, 6, ordinals, 0), 3); - - arr = [1, 3, 5, 7]; - ordinals = makeArray(arr.length, 0); - assert.equal(LinesLayout.findInsertionIndex(arr, 0, ordinals, 0), 0); - assert.equal(LinesLayout.findInsertionIndex(arr, 1, ordinals, 0), 1); - assert.equal(LinesLayout.findInsertionIndex(arr, 2, ordinals, 0), 1); - assert.equal(LinesLayout.findInsertionIndex(arr, 3, ordinals, 0), 2); - assert.equal(LinesLayout.findInsertionIndex(arr, 4, ordinals, 0), 2); - assert.equal(LinesLayout.findInsertionIndex(arr, 5, ordinals, 0), 3); - assert.equal(LinesLayout.findInsertionIndex(arr, 6, ordinals, 0), 3); - assert.equal(LinesLayout.findInsertionIndex(arr, 7, ordinals, 0), 4); - assert.equal(LinesLayout.findInsertionIndex(arr, 8, ordinals, 0), 4); - - arr = [1, 3, 5, 7, 9]; - ordinals = makeArray(arr.length, 0); - assert.equal(LinesLayout.findInsertionIndex(arr, 0, ordinals, 0), 0); - assert.equal(LinesLayout.findInsertionIndex(arr, 1, ordinals, 0), 1); - assert.equal(LinesLayout.findInsertionIndex(arr, 2, ordinals, 0), 1); - assert.equal(LinesLayout.findInsertionIndex(arr, 3, ordinals, 0), 2); - assert.equal(LinesLayout.findInsertionIndex(arr, 4, ordinals, 0), 2); - assert.equal(LinesLayout.findInsertionIndex(arr, 5, ordinals, 0), 3); - assert.equal(LinesLayout.findInsertionIndex(arr, 6, ordinals, 0), 3); - assert.equal(LinesLayout.findInsertionIndex(arr, 7, ordinals, 0), 4); - assert.equal(LinesLayout.findInsertionIndex(arr, 8, ordinals, 0), 4); - assert.equal(LinesLayout.findInsertionIndex(arr, 9, ordinals, 0), 5); - assert.equal(LinesLayout.findInsertionIndex(arr, 10, ordinals, 0), 5); - - arr = [1, 3, 5, 7, 9, 11]; - ordinals = makeArray(arr.length, 0); - assert.equal(LinesLayout.findInsertionIndex(arr, 0, ordinals, 0), 0); - assert.equal(LinesLayout.findInsertionIndex(arr, 1, ordinals, 0), 1); - assert.equal(LinesLayout.findInsertionIndex(arr, 2, ordinals, 0), 1); - assert.equal(LinesLayout.findInsertionIndex(arr, 3, ordinals, 0), 2); - assert.equal(LinesLayout.findInsertionIndex(arr, 4, ordinals, 0), 2); - assert.equal(LinesLayout.findInsertionIndex(arr, 5, ordinals, 0), 3); - assert.equal(LinesLayout.findInsertionIndex(arr, 6, ordinals, 0), 3); - assert.equal(LinesLayout.findInsertionIndex(arr, 7, ordinals, 0), 4); - assert.equal(LinesLayout.findInsertionIndex(arr, 8, ordinals, 0), 4); - assert.equal(LinesLayout.findInsertionIndex(arr, 9, ordinals, 0), 5); - assert.equal(LinesLayout.findInsertionIndex(arr, 10, ordinals, 0), 5); - assert.equal(LinesLayout.findInsertionIndex(arr, 11, ordinals, 0), 6); - assert.equal(LinesLayout.findInsertionIndex(arr, 12, ordinals, 0), 6); - - arr = [1, 3, 5, 7, 9, 11, 13]; - ordinals = makeArray(arr.length, 0); - assert.equal(LinesLayout.findInsertionIndex(arr, 0, ordinals, 0), 0); - assert.equal(LinesLayout.findInsertionIndex(arr, 1, ordinals, 0), 1); - assert.equal(LinesLayout.findInsertionIndex(arr, 2, ordinals, 0), 1); - assert.equal(LinesLayout.findInsertionIndex(arr, 3, ordinals, 0), 2); - assert.equal(LinesLayout.findInsertionIndex(arr, 4, ordinals, 0), 2); - assert.equal(LinesLayout.findInsertionIndex(arr, 5, ordinals, 0), 3); - assert.equal(LinesLayout.findInsertionIndex(arr, 6, ordinals, 0), 3); - assert.equal(LinesLayout.findInsertionIndex(arr, 7, ordinals, 0), 4); - assert.equal(LinesLayout.findInsertionIndex(arr, 8, ordinals, 0), 4); - assert.equal(LinesLayout.findInsertionIndex(arr, 9, ordinals, 0), 5); - assert.equal(LinesLayout.findInsertionIndex(arr, 10, ordinals, 0), 5); - assert.equal(LinesLayout.findInsertionIndex(arr, 11, ordinals, 0), 6); - assert.equal(LinesLayout.findInsertionIndex(arr, 12, ordinals, 0), 6); - assert.equal(LinesLayout.findInsertionIndex(arr, 13, ordinals, 0), 7); - assert.equal(LinesLayout.findInsertionIndex(arr, 14, ordinals, 0), 7); - - arr = [1, 3, 5, 7, 9, 11, 13, 15]; - ordinals = makeArray(arr.length, 0); - assert.equal(LinesLayout.findInsertionIndex(arr, 0, ordinals, 0), 0); - assert.equal(LinesLayout.findInsertionIndex(arr, 1, ordinals, 0), 1); - assert.equal(LinesLayout.findInsertionIndex(arr, 2, ordinals, 0), 1); - assert.equal(LinesLayout.findInsertionIndex(arr, 3, ordinals, 0), 2); - assert.equal(LinesLayout.findInsertionIndex(arr, 4, ordinals, 0), 2); - assert.equal(LinesLayout.findInsertionIndex(arr, 5, ordinals, 0), 3); - assert.equal(LinesLayout.findInsertionIndex(arr, 6, ordinals, 0), 3); - assert.equal(LinesLayout.findInsertionIndex(arr, 7, ordinals, 0), 4); - assert.equal(LinesLayout.findInsertionIndex(arr, 8, ordinals, 0), 4); - assert.equal(LinesLayout.findInsertionIndex(arr, 9, ordinals, 0), 5); - assert.equal(LinesLayout.findInsertionIndex(arr, 10, ordinals, 0), 5); - assert.equal(LinesLayout.findInsertionIndex(arr, 11, ordinals, 0), 6); - assert.equal(LinesLayout.findInsertionIndex(arr, 12, ordinals, 0), 6); - assert.equal(LinesLayout.findInsertionIndex(arr, 13, ordinals, 0), 7); - assert.equal(LinesLayout.findInsertionIndex(arr, 14, ordinals, 0), 7); - assert.equal(LinesLayout.findInsertionIndex(arr, 15, ordinals, 0), 8); - assert.equal(LinesLayout.findInsertionIndex(arr, 16, ordinals, 0), 8); + let arr: InternalWhitespace[]; + + arr = makeInternalWhitespace([]); + assert.equal(LinesLayout.findInsertionIndex(arr, 0, 0), 0); + assert.equal(LinesLayout.findInsertionIndex(arr, 1, 0), 0); + assert.equal(LinesLayout.findInsertionIndex(arr, 2, 0), 0); + + arr = makeInternalWhitespace([1]); + assert.equal(LinesLayout.findInsertionIndex(arr, 0, 0), 0); + assert.equal(LinesLayout.findInsertionIndex(arr, 1, 0), 1); + assert.equal(LinesLayout.findInsertionIndex(arr, 2, 0), 1); + + arr = makeInternalWhitespace([1, 3]); + assert.equal(LinesLayout.findInsertionIndex(arr, 0, 0), 0); + assert.equal(LinesLayout.findInsertionIndex(arr, 1, 0), 1); + assert.equal(LinesLayout.findInsertionIndex(arr, 2, 0), 1); + assert.equal(LinesLayout.findInsertionIndex(arr, 3, 0), 2); + assert.equal(LinesLayout.findInsertionIndex(arr, 4, 0), 2); + + arr = makeInternalWhitespace([1, 3, 5]); + assert.equal(LinesLayout.findInsertionIndex(arr, 0, 0), 0); + assert.equal(LinesLayout.findInsertionIndex(arr, 1, 0), 1); + assert.equal(LinesLayout.findInsertionIndex(arr, 2, 0), 1); + assert.equal(LinesLayout.findInsertionIndex(arr, 3, 0), 2); + assert.equal(LinesLayout.findInsertionIndex(arr, 4, 0), 2); + assert.equal(LinesLayout.findInsertionIndex(arr, 5, 0), 3); + assert.equal(LinesLayout.findInsertionIndex(arr, 6, 0), 3); + + arr = makeInternalWhitespace([1, 3, 5], 3); + assert.equal(LinesLayout.findInsertionIndex(arr, 0, 0), 0); + assert.equal(LinesLayout.findInsertionIndex(arr, 1, 0), 0); + assert.equal(LinesLayout.findInsertionIndex(arr, 2, 0), 1); + assert.equal(LinesLayout.findInsertionIndex(arr, 3, 0), 1); + assert.equal(LinesLayout.findInsertionIndex(arr, 4, 0), 2); + assert.equal(LinesLayout.findInsertionIndex(arr, 5, 0), 2); + assert.equal(LinesLayout.findInsertionIndex(arr, 6, 0), 3); + + arr = makeInternalWhitespace([1, 3, 5, 7]); + assert.equal(LinesLayout.findInsertionIndex(arr, 0, 0), 0); + assert.equal(LinesLayout.findInsertionIndex(arr, 1, 0), 1); + assert.equal(LinesLayout.findInsertionIndex(arr, 2, 0), 1); + assert.equal(LinesLayout.findInsertionIndex(arr, 3, 0), 2); + assert.equal(LinesLayout.findInsertionIndex(arr, 4, 0), 2); + assert.equal(LinesLayout.findInsertionIndex(arr, 5, 0), 3); + assert.equal(LinesLayout.findInsertionIndex(arr, 6, 0), 3); + assert.equal(LinesLayout.findInsertionIndex(arr, 7, 0), 4); + assert.equal(LinesLayout.findInsertionIndex(arr, 8, 0), 4); + + arr = makeInternalWhitespace([1, 3, 5, 7, 9]); + assert.equal(LinesLayout.findInsertionIndex(arr, 0, 0), 0); + assert.equal(LinesLayout.findInsertionIndex(arr, 1, 0), 1); + assert.equal(LinesLayout.findInsertionIndex(arr, 2, 0), 1); + assert.equal(LinesLayout.findInsertionIndex(arr, 3, 0), 2); + assert.equal(LinesLayout.findInsertionIndex(arr, 4, 0), 2); + assert.equal(LinesLayout.findInsertionIndex(arr, 5, 0), 3); + assert.equal(LinesLayout.findInsertionIndex(arr, 6, 0), 3); + assert.equal(LinesLayout.findInsertionIndex(arr, 7, 0), 4); + assert.equal(LinesLayout.findInsertionIndex(arr, 8, 0), 4); + assert.equal(LinesLayout.findInsertionIndex(arr, 9, 0), 5); + assert.equal(LinesLayout.findInsertionIndex(arr, 10, 0), 5); + + arr = makeInternalWhitespace([1, 3, 5, 7, 9, 11]); + assert.equal(LinesLayout.findInsertionIndex(arr, 0, 0), 0); + assert.equal(LinesLayout.findInsertionIndex(arr, 1, 0), 1); + assert.equal(LinesLayout.findInsertionIndex(arr, 2, 0), 1); + assert.equal(LinesLayout.findInsertionIndex(arr, 3, 0), 2); + assert.equal(LinesLayout.findInsertionIndex(arr, 4, 0), 2); + assert.equal(LinesLayout.findInsertionIndex(arr, 5, 0), 3); + assert.equal(LinesLayout.findInsertionIndex(arr, 6, 0), 3); + assert.equal(LinesLayout.findInsertionIndex(arr, 7, 0), 4); + assert.equal(LinesLayout.findInsertionIndex(arr, 8, 0), 4); + assert.equal(LinesLayout.findInsertionIndex(arr, 9, 0), 5); + assert.equal(LinesLayout.findInsertionIndex(arr, 10, 0), 5); + assert.equal(LinesLayout.findInsertionIndex(arr, 11, 0), 6); + assert.equal(LinesLayout.findInsertionIndex(arr, 12, 0), 6); + + arr = makeInternalWhitespace([1, 3, 5, 7, 9, 11, 13]); + assert.equal(LinesLayout.findInsertionIndex(arr, 0, 0), 0); + assert.equal(LinesLayout.findInsertionIndex(arr, 1, 0), 1); + assert.equal(LinesLayout.findInsertionIndex(arr, 2, 0), 1); + assert.equal(LinesLayout.findInsertionIndex(arr, 3, 0), 2); + assert.equal(LinesLayout.findInsertionIndex(arr, 4, 0), 2); + assert.equal(LinesLayout.findInsertionIndex(arr, 5, 0), 3); + assert.equal(LinesLayout.findInsertionIndex(arr, 6, 0), 3); + assert.equal(LinesLayout.findInsertionIndex(arr, 7, 0), 4); + assert.equal(LinesLayout.findInsertionIndex(arr, 8, 0), 4); + assert.equal(LinesLayout.findInsertionIndex(arr, 9, 0), 5); + assert.equal(LinesLayout.findInsertionIndex(arr, 10, 0), 5); + assert.equal(LinesLayout.findInsertionIndex(arr, 11, 0), 6); + assert.equal(LinesLayout.findInsertionIndex(arr, 12, 0), 6); + assert.equal(LinesLayout.findInsertionIndex(arr, 13, 0), 7); + assert.equal(LinesLayout.findInsertionIndex(arr, 14, 0), 7); + + arr = makeInternalWhitespace([1, 3, 5, 7, 9, 11, 13, 15]); + assert.equal(LinesLayout.findInsertionIndex(arr, 0, 0), 0); + assert.equal(LinesLayout.findInsertionIndex(arr, 1, 0), 1); + assert.equal(LinesLayout.findInsertionIndex(arr, 2, 0), 1); + assert.equal(LinesLayout.findInsertionIndex(arr, 3, 0), 2); + assert.equal(LinesLayout.findInsertionIndex(arr, 4, 0), 2); + assert.equal(LinesLayout.findInsertionIndex(arr, 5, 0), 3); + assert.equal(LinesLayout.findInsertionIndex(arr, 6, 0), 3); + assert.equal(LinesLayout.findInsertionIndex(arr, 7, 0), 4); + assert.equal(LinesLayout.findInsertionIndex(arr, 8, 0), 4); + assert.equal(LinesLayout.findInsertionIndex(arr, 9, 0), 5); + assert.equal(LinesLayout.findInsertionIndex(arr, 10, 0), 5); + assert.equal(LinesLayout.findInsertionIndex(arr, 11, 0), 6); + assert.equal(LinesLayout.findInsertionIndex(arr, 12, 0), 6); + assert.equal(LinesLayout.findInsertionIndex(arr, 13, 0), 7); + assert.equal(LinesLayout.findInsertionIndex(arr, 14, 0), 7); + assert.equal(LinesLayout.findInsertionIndex(arr, 15, 0), 8); + assert.equal(LinesLayout.findInsertionIndex(arr, 16, 0), 8); }); test('LinesLayout changeWhitespaceAfterLineNumber & getFirstWhitespaceIndexAfterLineNumber', () => { From 4e8f42499d72c7ce1afa97d2ddfbe2ec5f6779d8 Mon Sep 17 00:00:00 2001 From: Alexandru Dima Date: Fri, 15 Nov 2019 16:22:40 +0100 Subject: [PATCH 345/352] More type reuse --- .../editor/common/viewLayout/linesLayout.ts | 40 ++++++------------- 1 file changed, 13 insertions(+), 27 deletions(-) diff --git a/src/vs/editor/common/viewLayout/linesLayout.ts b/src/vs/editor/common/viewLayout/linesLayout.ts index ca6b2fcfacf36..496c48d32aef6 100644 --- a/src/vs/editor/common/viewLayout/linesLayout.ts +++ b/src/vs/editor/common/viewLayout/linesLayout.ts @@ -25,13 +25,12 @@ export interface IWhitespaceChangeAccessor { removeWhitespace(id: string): void; } -interface IPendingInsert { id: string; afterLineNumber: number; ordinal: number; heightInPx: number; minWidth: number; } interface IPendingChange { id: string; newAfterLineNumber: number; newHeight: number; } interface IPendingRemove { id: string; } class PendingChanges { private _hasPending: boolean; - private _inserts: IPendingInsert[]; + private _inserts: InternalWhitespace[]; private _changes: IPendingChange[]; private _removes: IPendingRemove[]; @@ -42,7 +41,7 @@ class PendingChanges { this._removes = []; } - public insert(x: IPendingInsert): void { + public insert(x: InternalWhitespace): void { this._hasPending = true; this._inserts.push(x); } @@ -210,7 +209,7 @@ export class LinesLayout { minWidth = minWidth | 0; const id = this._instanceId + (++this._lastWhitespaceId); - this._pendingChanges.insert({ id, afterLineNumber, ordinal, heightInPx, minWidth }); + this._pendingChanges.insert(new InternalWhitespace(id, afterLineNumber, ordinal, heightInPx, minWidth)); return id; // return this._insertWhitespace(afterLineNumber, ordinal, heightInPx, minWidth); }, @@ -232,9 +231,12 @@ export class LinesLayout { } } - public _commitPendingChanges(inserts: IPendingInsert[], changes: IPendingChange[], removes: IPendingRemove[]): void { + public _commitPendingChanges(inserts: InternalWhitespace[], changes: IPendingChange[], removes: IPendingRemove[]): void { + // const magnitude = inserts.length + changes.length + removes.length; + // if (magnitude === 1) { + // // when only one thing for (const insert of inserts) { - this._insertWhitespace(insert.id, insert.afterLineNumber, insert.ordinal, insert.heightInPx, insert.minWidth); + this._insertWhitespace(insert); } for (const change of changes) { this._changeOneWhitespace(change.id, change.newAfterLineNumber, change.newHeight); @@ -242,6 +244,10 @@ export class LinesLayout { for (const remove of removes) { this._removeWhitespace(remove.id); } + return; + // } + + // console.log(`magnitude: ${magnitude} -- inserts: ${inserts.length}, changes: ${changes.length}, removes: ${removes.length}`); // console.log(`TODO: `, inserts, changes, removes); } @@ -251,21 +257,10 @@ export class LinesLayout { } } - /** - * Insert a new whitespace of a certain height after a line number. - * The whitespace has a "sticky" characteristic. - * Irrespective of edits above or below `afterLineNumber`, the whitespace will follow the initial line. - * - * @param afterLineNumber The conceptual position of this whitespace. The whitespace will follow this line as best as possible even when deleting/inserting lines above/below. - * @param heightInPx The height of the whitespace, in pixels. - * @return An id that can be used later to mutate or delete the whitespace - */ - private _insertWhitespace(id: string, afterLineNumber: number, ordinal: number, heightInPx: number, minWidth: number): string { - const whitespace = new InternalWhitespace(id, afterLineNumber, ordinal, heightInPx, minWidth); + private _insertWhitespace(whitespace: InternalWhitespace): void { const insertionIndex = LinesLayout.findInsertionIndex(this._arr, whitespace.afterLineNumber, whitespace.ordinal); this._insertWhitespaceAtIndex(insertionIndex, whitespace); this._minWidth = -1; /* marker for not being computed */ - return id; } private _insertWhitespaceAtIndex(insertIndex: number, whitespace: InternalWhitespace): void { @@ -283,9 +278,6 @@ export class LinesLayout { this._prefixSumValidIndex = Math.min(this._prefixSumValidIndex, insertIndex - 1); } - /** - * Change properties associated with a certain whitespace. - */ private _changeOneWhitespace(id: string, newAfterLineNumber: number, newHeight: number): void { if (this._whitespaceId2Index.hasOwnProperty(id)) { const index = this._whitespaceId2Index[id]; @@ -311,12 +303,6 @@ export class LinesLayout { } } - /** - * Remove an existing whitespace. - * - * @param id The whitespace to remove - * @return Returns true if the whitespace is found and it is removed. - */ private _removeWhitespace(id: string): void { if (this._whitespaceId2Index.hasOwnProperty(id)) { const index = this._whitespaceId2Index[id]; From 9c0ac421fc6c2b0df8a5b980e42b7d2943822d4a Mon Sep 17 00:00:00 2001 From: Alexandru Dima Date: Fri, 15 Nov 2019 16:45:48 +0100 Subject: [PATCH 346/352] Avoid allocating for getWhitespaces() call --- src/vs/editor/browser/editorBrowser.ts | 4 +- .../browser/viewParts/viewZones/viewZones.ts | 6 +-- .../editor/browser/widget/codeEditorWidget.ts | 4 +- .../editor/browser/widget/diffEditorWidget.ts | 44 ++++++++++--------- .../editor/common/viewLayout/linesLayout.ts | 42 +++++++----------- src/vs/editor/common/viewLayout/viewLayout.ts | 4 +- src/vs/editor/common/viewModel/viewModel.ts | 4 +- .../common/viewLayout/linesLayout.test.ts | 6 +-- 8 files changed, 53 insertions(+), 61 deletions(-) diff --git a/src/vs/editor/browser/editorBrowser.ts b/src/vs/editor/browser/editorBrowser.ts index 26b562f400fe4..bcd0995f8430c 100644 --- a/src/vs/editor/browser/editorBrowser.ts +++ b/src/vs/editor/browser/editorBrowser.ts @@ -16,7 +16,7 @@ import * as editorCommon from 'vs/editor/common/editorCommon'; import { IIdentifiedSingleEditOperation, IModelDecoration, IModelDeltaDecoration, ITextModel, ICursorStateComputer } from 'vs/editor/common/model'; import { IModelContentChangedEvent, IModelDecorationsChangedEvent, IModelLanguageChangedEvent, IModelLanguageConfigurationChangedEvent, IModelOptionsChangedEvent } from 'vs/editor/common/model/textModelEvents'; import { OverviewRulerZone } from 'vs/editor/common/view/overviewZoneManager'; -import { EditorWhitespace } from 'vs/editor/common/viewLayout/linesLayout'; +import { IEditorWhitespace } from 'vs/editor/common/viewLayout/linesLayout'; import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { IDiffComputationResult } from 'vs/editor/common/services/editorWorkerService'; @@ -672,7 +672,7 @@ export interface ICodeEditor extends editorCommon.IEditor { * Get the view zones. * @internal */ - getWhitespaces(): EditorWhitespace[]; + getWhitespaces(): IEditorWhitespace[]; /** * Get the vertical position (top offset) for the line w.r.t. to the first line. diff --git a/src/vs/editor/browser/viewParts/viewZones/viewZones.ts b/src/vs/editor/browser/viewParts/viewZones/viewZones.ts index a2160d7817397..5e28b7785ecfc 100644 --- a/src/vs/editor/browser/viewParts/viewZones/viewZones.ts +++ b/src/vs/editor/browser/viewParts/viewZones/viewZones.ts @@ -13,7 +13,7 @@ import { ViewContext } from 'vs/editor/common/view/viewContext'; import * as viewEvents from 'vs/editor/common/view/viewEvents'; import { IViewWhitespaceViewportData } from 'vs/editor/common/viewModel/viewModel'; import { EditorOption } from 'vs/editor/common/config/editorOptions'; -import { IWhitespaceChangeAccessor, EditorWhitespace } from 'vs/editor/common/viewLayout/linesLayout'; +import { IWhitespaceChangeAccessor, IEditorWhitespace } from 'vs/editor/common/viewLayout/linesLayout'; export interface IMyViewZone { whitespaceId: string; @@ -75,7 +75,7 @@ export class ViewZones extends ViewPart { private _recomputeWhitespacesProps(): boolean { const whitespaces = this._context.viewLayout.getWhitespaces(); - const oldWhitespaces = new Map(); + const oldWhitespaces = new Map(); for (const whitespace of whitespaces) { oldWhitespaces.set(whitespace.id, whitespace); } @@ -88,7 +88,7 @@ export class ViewZones extends ViewPart { const zone = this._zones[id]; const props = this._computeWhitespaceProps(zone.delegate); const oldWhitespace = oldWhitespaces.get(id); - if (oldWhitespace && (oldWhitespace.afterLineNumber !== props.afterViewLineNumber || oldWhitespace.heightInPx !== props.heightInPx)) { + if (oldWhitespace && (oldWhitespace.afterLineNumber !== props.afterViewLineNumber || oldWhitespace.height !== props.heightInPx)) { whitespaceAccessor.changeOneWhitespace(id, props.afterViewLineNumber, props.heightInPx); this._safeCallOnComputedHeight(zone.delegate, props.heightInPx); hadAChange = true; diff --git a/src/vs/editor/browser/widget/codeEditorWidget.ts b/src/vs/editor/browser/widget/codeEditorWidget.ts index 348487009ef2a..357eeab2a9f22 100644 --- a/src/vs/editor/browser/widget/codeEditorWidget.ts +++ b/src/vs/editor/browser/widget/codeEditorWidget.ts @@ -40,7 +40,7 @@ import * as modes from 'vs/editor/common/modes'; import { editorUnnecessaryCodeBorder, editorUnnecessaryCodeOpacity } from 'vs/editor/common/view/editorColorRegistry'; import { editorErrorBorder, editorErrorForeground, editorHintBorder, editorHintForeground, editorInfoBorder, editorInfoForeground, editorWarningBorder, editorWarningForeground, editorForeground } from 'vs/platform/theme/common/colorRegistry'; import { VerticalRevealType } from 'vs/editor/common/view/viewEvents'; -import { EditorWhitespace } from 'vs/editor/common/viewLayout/linesLayout'; +import { IEditorWhitespace } from 'vs/editor/common/viewLayout/linesLayout'; import { ViewModel } from 'vs/editor/common/viewModel/viewModelImpl'; import { ICommandService } from 'vs/platform/commands/common/commands'; import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; @@ -451,7 +451,7 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE return this._modelData.viewModel.getVisibleRanges(); } - public getWhitespaces(): EditorWhitespace[] { + public getWhitespaces(): IEditorWhitespace[] { if (!this._modelData) { return []; } diff --git a/src/vs/editor/browser/widget/diffEditorWidget.ts b/src/vs/editor/browser/widget/diffEditorWidget.ts index d97ef2e6f1945..9dbc302244ed0 100644 --- a/src/vs/editor/browser/widget/diffEditorWidget.ts +++ b/src/vs/editor/browser/widget/diffEditorWidget.ts @@ -32,7 +32,7 @@ import { IDiffComputationResult, IEditorWorkerService } from 'vs/editor/common/s import { OverviewRulerZone } from 'vs/editor/common/view/overviewZoneManager'; import { LineDecoration } from 'vs/editor/common/viewLayout/lineDecorations'; import { RenderLineInput, renderViewLine } from 'vs/editor/common/viewLayout/viewLineRenderer'; -import { EditorWhitespace } from 'vs/editor/common/viewLayout/linesLayout'; +import { IEditorWhitespace } from 'vs/editor/common/viewLayout/linesLayout'; import { InlineDecoration, InlineDecorationType, ViewLineRenderingData } from 'vs/editor/common/viewModel/viewModel'; import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; @@ -68,7 +68,7 @@ interface IEditorsZones { } interface IDiffEditorWidgetStyle { - getEditorsDiffDecorations(lineChanges: editorCommon.ILineChange[], ignoreTrimWhitespace: boolean, renderIndicators: boolean, originalWhitespaces: EditorWhitespace[], modifiedWhitespaces: EditorWhitespace[], originalEditor: editorBrowser.ICodeEditor, modifiedEditor: editorBrowser.ICodeEditor): IEditorsDiffDecorationsWithZones; + getEditorsDiffDecorations(lineChanges: editorCommon.ILineChange[], ignoreTrimWhitespace: boolean, renderIndicators: boolean, originalWhitespaces: IEditorWhitespace[], modifiedWhitespaces: IEditorWhitespace[], originalEditor: editorBrowser.ICodeEditor, modifiedEditor: editorBrowser.ICodeEditor): IEditorsDiffDecorationsWithZones; setEnableSplitViewResizing(enableSplitViewResizing: boolean): void; applyColors(theme: ITheme): boolean; layout(): number; @@ -91,7 +91,7 @@ class VisualEditorState { this._decorations = []; } - public getForeignViewZones(allViewZones: EditorWhitespace[]): EditorWhitespace[] { + public getForeignViewZones(allViewZones: IEditorWhitespace[]): IEditorWhitespace[] { return allViewZones.filter((z) => !this._zonesMap[String(z.id)]); } @@ -1303,7 +1303,7 @@ abstract class DiffEditorWidgetStyle extends Disposable implements IDiffEditorWi return hasChanges; } - public getEditorsDiffDecorations(lineChanges: editorCommon.ILineChange[], ignoreTrimWhitespace: boolean, renderIndicators: boolean, originalWhitespaces: EditorWhitespace[], modifiedWhitespaces: EditorWhitespace[], originalEditor: editorBrowser.ICodeEditor, modifiedEditor: editorBrowser.ICodeEditor): IEditorsDiffDecorationsWithZones { + public getEditorsDiffDecorations(lineChanges: editorCommon.ILineChange[], ignoreTrimWhitespace: boolean, renderIndicators: boolean, originalWhitespaces: IEditorWhitespace[], modifiedWhitespaces: IEditorWhitespace[], originalEditor: editorBrowser.ICodeEditor, modifiedEditor: editorBrowser.ICodeEditor): IEditorsDiffDecorationsWithZones { // Get view zones modifiedWhitespaces = modifiedWhitespaces.sort((a, b) => { return a.afterLineNumber - b.afterLineNumber; @@ -1331,7 +1331,7 @@ abstract class DiffEditorWidgetStyle extends Disposable implements IDiffEditorWi }; } - protected abstract _getViewZones(lineChanges: editorCommon.ILineChange[], originalForeignVZ: EditorWhitespace[], modifiedForeignVZ: EditorWhitespace[], originalEditor: editorBrowser.ICodeEditor, modifiedEditor: editorBrowser.ICodeEditor, renderIndicators: boolean): IEditorsZones; + protected abstract _getViewZones(lineChanges: editorCommon.ILineChange[], originalForeignVZ: IEditorWhitespace[], modifiedForeignVZ: IEditorWhitespace[], originalEditor: editorBrowser.ICodeEditor, modifiedEditor: editorBrowser.ICodeEditor, renderIndicators: boolean): IEditorsZones; protected abstract _getOriginalEditorDecorations(lineChanges: editorCommon.ILineChange[], ignoreTrimWhitespace: boolean, renderIndicators: boolean, originalEditor: editorBrowser.ICodeEditor, modifiedEditor: editorBrowser.ICodeEditor): IEditorDiffDecorations; protected abstract _getModifiedEditorDecorations(lineChanges: editorCommon.ILineChange[], ignoreTrimWhitespace: boolean, renderIndicators: boolean, originalEditor: editorBrowser.ICodeEditor, modifiedEditor: editorBrowser.ICodeEditor): IEditorDiffDecorations; @@ -1352,10 +1352,10 @@ interface IMyViewZone { class ForeignViewZonesIterator { private _index: number; - private readonly _source: EditorWhitespace[]; - public current: EditorWhitespace | null; + private readonly _source: IEditorWhitespace[]; + public current: IEditorWhitespace | null; - constructor(source: EditorWhitespace[]) { + constructor(source: IEditorWhitespace[]) { this._source = source; this._index = -1; this.current = null; @@ -1375,13 +1375,17 @@ class ForeignViewZonesIterator { abstract class ViewZonesComputer { private readonly lineChanges: editorCommon.ILineChange[]; - private readonly originalForeignVZ: EditorWhitespace[]; - private readonly modifiedForeignVZ: EditorWhitespace[]; + private readonly originalForeignVZ: IEditorWhitespace[]; + private readonly originalLineHeight: number; + private readonly modifiedForeignVZ: IEditorWhitespace[]; + private readonly modifiedLineHeight: number; - constructor(lineChanges: editorCommon.ILineChange[], originalForeignVZ: EditorWhitespace[], modifiedForeignVZ: EditorWhitespace[]) { + constructor(lineChanges: editorCommon.ILineChange[], originalForeignVZ: IEditorWhitespace[], originalLineHeight: number, modifiedForeignVZ: IEditorWhitespace[], modifiedLineHeight: number) { this.lineChanges = lineChanges; this.originalForeignVZ = originalForeignVZ; + this.originalLineHeight = originalLineHeight; this.modifiedForeignVZ = modifiedForeignVZ; + this.modifiedLineHeight = modifiedLineHeight; } public getViewZones(): IEditorsZones { @@ -1456,7 +1460,7 @@ abstract class ViewZonesComputer { stepOriginal.push({ afterLineNumber: viewZoneLineNumber, - heightInLines: modifiedForeignVZ.current.heightInLines, + heightInLines: modifiedForeignVZ.current.height / this.modifiedLineHeight, domNode: null, marginDomNode: marginDomNode }); @@ -1473,7 +1477,7 @@ abstract class ViewZonesComputer { } stepModified.push({ afterLineNumber: viewZoneLineNumber, - heightInLines: originalForeignVZ.current.heightInLines, + heightInLines: originalForeignVZ.current.height / this.originalLineHeight, domNode: null }); originalForeignVZ.advance(); @@ -1731,8 +1735,8 @@ class DiffEditorWidgetSideBySide extends DiffEditorWidgetStyle implements IDiffE return this._dataSource.getHeight(); } - protected _getViewZones(lineChanges: editorCommon.ILineChange[], originalForeignVZ: EditorWhitespace[], modifiedForeignVZ: EditorWhitespace[], originalEditor: editorBrowser.ICodeEditor, modifiedEditor: editorBrowser.ICodeEditor): IEditorsZones { - let c = new SideBySideViewZonesComputer(lineChanges, originalForeignVZ, modifiedForeignVZ); + protected _getViewZones(lineChanges: editorCommon.ILineChange[], originalForeignVZ: IEditorWhitespace[], modifiedForeignVZ: IEditorWhitespace[], originalEditor: editorBrowser.ICodeEditor, modifiedEditor: editorBrowser.ICodeEditor): IEditorsZones { + let c = new SideBySideViewZonesComputer(lineChanges, originalForeignVZ, originalEditor.getOption(EditorOption.lineHeight), modifiedForeignVZ, modifiedEditor.getOption(EditorOption.lineHeight)); return c.getViewZones(); } @@ -1859,8 +1863,8 @@ class DiffEditorWidgetSideBySide extends DiffEditorWidgetStyle implements IDiffE class SideBySideViewZonesComputer extends ViewZonesComputer { - constructor(lineChanges: editorCommon.ILineChange[], originalForeignVZ: EditorWhitespace[], modifiedForeignVZ: EditorWhitespace[]) { - super(lineChanges, originalForeignVZ, modifiedForeignVZ); + constructor(lineChanges: editorCommon.ILineChange[], originalForeignVZ: IEditorWhitespace[], originalLineHeight: number, modifiedForeignVZ: IEditorWhitespace[], modifiedLineHeight: number) { + super(lineChanges, originalForeignVZ, originalLineHeight, modifiedForeignVZ, modifiedLineHeight); } protected _createOriginalMarginDomNodeForModifiedForeignViewZoneInAddedRegion(): HTMLDivElement | null { @@ -1911,7 +1915,7 @@ class DiffEditorWidgetInline extends DiffEditorWidgetStyle implements IDiffEdito // Nothing to do.. } - protected _getViewZones(lineChanges: editorCommon.ILineChange[], originalForeignVZ: EditorWhitespace[], modifiedForeignVZ: EditorWhitespace[], originalEditor: editorBrowser.ICodeEditor, modifiedEditor: editorBrowser.ICodeEditor, renderIndicators: boolean): IEditorsZones { + protected _getViewZones(lineChanges: editorCommon.ILineChange[], originalForeignVZ: IEditorWhitespace[], modifiedForeignVZ: IEditorWhitespace[], originalEditor: editorBrowser.ICodeEditor, modifiedEditor: editorBrowser.ICodeEditor, renderIndicators: boolean): IEditorsZones { let computer = new InlineViewZonesComputer(lineChanges, originalForeignVZ, modifiedForeignVZ, originalEditor, modifiedEditor, renderIndicators); return computer.getViewZones(); } @@ -2019,8 +2023,8 @@ class InlineViewZonesComputer extends ViewZonesComputer { private readonly modifiedEditorTabSize: number; private readonly renderIndicators: boolean; - constructor(lineChanges: editorCommon.ILineChange[], originalForeignVZ: EditorWhitespace[], modifiedForeignVZ: EditorWhitespace[], originalEditor: editorBrowser.ICodeEditor, modifiedEditor: editorBrowser.ICodeEditor, renderIndicators: boolean) { - super(lineChanges, originalForeignVZ, modifiedForeignVZ); + constructor(lineChanges: editorCommon.ILineChange[], originalForeignVZ: IEditorWhitespace[], modifiedForeignVZ: IEditorWhitespace[], originalEditor: editorBrowser.ICodeEditor, modifiedEditor: editorBrowser.ICodeEditor, renderIndicators: boolean) { + super(lineChanges, originalForeignVZ, originalEditor.getOption(EditorOption.lineHeight), modifiedForeignVZ, modifiedEditor.getOption(EditorOption.lineHeight)); this.originalModel = originalEditor.getModel()!; this.modifiedEditorOptions = modifiedEditor.getOptions(); this.modifiedEditorTabSize = modifiedEditor.getModel()!.getOptions().tabSize; diff --git a/src/vs/editor/common/viewLayout/linesLayout.ts b/src/vs/editor/common/viewLayout/linesLayout.ts index 496c48d32aef6..8aab4c60d90b9 100644 --- a/src/vs/editor/common/viewLayout/linesLayout.ts +++ b/src/vs/editor/common/viewLayout/linesLayout.ts @@ -7,13 +7,10 @@ import { IPartialViewLinesViewportData } from 'vs/editor/common/viewLayout/viewL import { IViewWhitespaceViewportData } from 'vs/editor/common/viewModel/viewModel'; import * as strings from 'vs/base/common/strings'; -export class EditorWhitespace { - constructor( - public readonly id: string, - public readonly afterLineNumber: number, - public readonly heightInPx: number, - public readonly heightInLines: number, - ) { } +export interface IEditorWhitespace { + readonly id: string; + readonly afterLineNumber: number; + readonly height: number; } /** @@ -30,7 +27,7 @@ interface IPendingRemove { id: string; } class PendingChanges { private _hasPending: boolean; - private _inserts: InternalWhitespace[]; + private _inserts: EditorWhitespace[]; private _changes: IPendingChange[]; private _removes: IPendingRemove[]; @@ -41,7 +38,7 @@ class PendingChanges { this._removes = []; } - public insert(x: InternalWhitespace): void { + public insert(x: EditorWhitespace): void { this._hasPending = true; this._inserts.push(x); } @@ -78,7 +75,7 @@ class PendingChanges { } } -export class InternalWhitespace { +export class EditorWhitespace implements IEditorWhitespace { public id: string; public afterLineNumber: number; public ordinal: number; @@ -110,7 +107,7 @@ export class LinesLayout { private _pendingChanges: PendingChanges; - private readonly _arr: InternalWhitespace[]; + private readonly _arr: EditorWhitespace[]; /** * _arr[i].prefixSum, 1 <= i <= prefixSumValidIndex can be trusted @@ -158,7 +155,7 @@ export class LinesLayout { * Find the insertion index for a new value inside a sorted array of values. * If the value is already present in the sorted array, the insertion index will be after the already existing value. */ - public static findInsertionIndex(arr: InternalWhitespace[], afterLineNumber: number, ordinal: number): number { + public static findInsertionIndex(arr: EditorWhitespace[], afterLineNumber: number, ordinal: number): number { let low = 0; let high = arr.length; @@ -209,7 +206,7 @@ export class LinesLayout { minWidth = minWidth | 0; const id = this._instanceId + (++this._lastWhitespaceId); - this._pendingChanges.insert(new InternalWhitespace(id, afterLineNumber, ordinal, heightInPx, minWidth)); + this._pendingChanges.insert(new EditorWhitespace(id, afterLineNumber, ordinal, heightInPx, minWidth)); return id; // return this._insertWhitespace(afterLineNumber, ordinal, heightInPx, minWidth); }, @@ -231,7 +228,7 @@ export class LinesLayout { } } - public _commitPendingChanges(inserts: InternalWhitespace[], changes: IPendingChange[], removes: IPendingRemove[]): void { + public _commitPendingChanges(inserts: EditorWhitespace[], changes: IPendingChange[], removes: IPendingRemove[]): void { // const magnitude = inserts.length + changes.length + removes.length; // if (magnitude === 1) { // // when only one thing @@ -257,13 +254,13 @@ export class LinesLayout { } } - private _insertWhitespace(whitespace: InternalWhitespace): void { + private _insertWhitespace(whitespace: EditorWhitespace): void { const insertionIndex = LinesLayout.findInsertionIndex(this._arr, whitespace.afterLineNumber, whitespace.ordinal); this._insertWhitespaceAtIndex(insertionIndex, whitespace); this._minWidth = -1; /* marker for not being computed */ } - private _insertWhitespaceAtIndex(insertIndex: number, whitespace: InternalWhitespace): void { + private _insertWhitespaceAtIndex(insertIndex: number, whitespace: EditorWhitespace): void { this._arr.splice(insertIndex, 0, whitespace); const keys = Object.keys(this._whitespaceId2Index); @@ -853,18 +850,9 @@ export class LinesLayout { /** * Get all whitespaces. */ - public getWhitespaces(): EditorWhitespace[] { + public getWhitespaces(): IEditorWhitespace[] { this._checkPendingChanges(); - let result: EditorWhitespace[] = []; - for (let i = 0; i < this._arr.length; i++) { - result.push(new EditorWhitespace( - this._arr[i].id, - this._arr[i].afterLineNumber, - this._arr[i].height, - this._arr[i].height / this._lineHeight - )); - } - return result; + return this._arr.slice(0); } /** diff --git a/src/vs/editor/common/viewLayout/viewLayout.ts b/src/vs/editor/common/viewLayout/viewLayout.ts index 1fbc3db5462cd..115e4a1c85b50 100644 --- a/src/vs/editor/common/viewLayout/viewLayout.ts +++ b/src/vs/editor/common/viewLayout/viewLayout.ts @@ -8,7 +8,7 @@ import { Disposable, IDisposable } from 'vs/base/common/lifecycle'; import { IScrollPosition, ScrollEvent, Scrollable, ScrollbarVisibility } from 'vs/base/common/scrollable'; import { ConfigurationChangedEvent, EditorOption } from 'vs/editor/common/config/editorOptions'; import * as editorCommon from 'vs/editor/common/editorCommon'; -import { LinesLayout, EditorWhitespace, IWhitespaceChangeAccessor } from 'vs/editor/common/viewLayout/linesLayout'; +import { LinesLayout, IEditorWhitespace, IWhitespaceChangeAccessor } from 'vs/editor/common/viewLayout/linesLayout'; import { IPartialViewLinesViewportData } from 'vs/editor/common/viewLayout/viewLinesViewportData'; import { IViewLayout, IViewWhitespaceViewportData, Viewport } from 'vs/editor/common/viewModel/viewModel'; @@ -228,7 +228,7 @@ export class ViewLayout extends Disposable implements IViewLayout { const visibleBox = this.getCurrentViewport(); return this._linesLayout.getWhitespaceViewportData(visibleBox.top, visibleBox.top + visibleBox.height); } - public getWhitespaces(): EditorWhitespace[] { + public getWhitespaces(): IEditorWhitespace[] { return this._linesLayout.getWhitespaces(); } diff --git a/src/vs/editor/common/viewModel/viewModel.ts b/src/vs/editor/common/viewModel/viewModel.ts index 3d23b97c93c8c..a3abd74ee4ebc 100644 --- a/src/vs/editor/common/viewModel/viewModel.ts +++ b/src/vs/editor/common/viewModel/viewModel.ts @@ -13,7 +13,7 @@ import { INewScrollPosition } from 'vs/editor/common/editorCommon'; import { EndOfLinePreference, IActiveIndentGuideInfo, IModelDecorationOptions, TextModelResolvedOptions } from 'vs/editor/common/model'; import { IViewEventListener } from 'vs/editor/common/view/viewEvents'; import { IPartialViewLinesViewportData } from 'vs/editor/common/viewLayout/viewLinesViewportData'; -import { EditorWhitespace, IWhitespaceChangeAccessor } from 'vs/editor/common/viewLayout/linesLayout'; +import { IEditorWhitespace, IWhitespaceChangeAccessor } from 'vs/editor/common/viewLayout/linesLayout'; import { ITheme } from 'vs/platform/theme/common/themeService'; export interface IViewWhitespaceViewportData { @@ -61,7 +61,7 @@ export interface IViewLayout { getLinesViewportData(): IPartialViewLinesViewportData; getLinesViewportDataAtScrollTop(scrollTop: number): IPartialViewLinesViewportData; - getWhitespaces(): EditorWhitespace[]; + getWhitespaces(): IEditorWhitespace[]; isAfterLines(verticalOffset: number): boolean; getLineNumberAtVerticalOffset(verticalOffset: number): number; diff --git a/src/vs/editor/test/common/viewLayout/linesLayout.test.ts b/src/vs/editor/test/common/viewLayout/linesLayout.test.ts index 57ee0db54279b..b6b26b7f35ae3 100644 --- a/src/vs/editor/test/common/viewLayout/linesLayout.test.ts +++ b/src/vs/editor/test/common/viewLayout/linesLayout.test.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ import * as assert from 'assert'; -import { LinesLayout, InternalWhitespace } from 'vs/editor/common/viewLayout/linesLayout'; +import { LinesLayout, EditorWhitespace } from 'vs/editor/common/viewLayout/linesLayout'; suite('Editor ViewLayout - LinesLayout', () => { @@ -846,10 +846,10 @@ suite('Editor ViewLayout - LinesLayout', () => { test('LinesLayout findInsertionIndex', () => { const makeInternalWhitespace = (afterLineNumbers: number[], ordinal: number = 0) => { - return afterLineNumbers.map((afterLineNumber) => new InternalWhitespace('', afterLineNumber, ordinal, 0, 0)); + return afterLineNumbers.map((afterLineNumber) => new EditorWhitespace('', afterLineNumber, ordinal, 0, 0)); }; - let arr: InternalWhitespace[]; + let arr: EditorWhitespace[]; arr = makeInternalWhitespace([]); assert.equal(LinesLayout.findInsertionIndex(arr, 0, 0), 0); From c0032079593cf751b318a589214037a9cd9d5085 Mon Sep 17 00:00:00 2001 From: Alexandru Dima Date: Fri, 15 Nov 2019 16:57:21 +0100 Subject: [PATCH 347/352] Remove _whitespaceId2Index --- .../editor/common/viewLayout/linesLayout.ts | 123 ++++++++---------- 1 file changed, 56 insertions(+), 67 deletions(-) diff --git a/src/vs/editor/common/viewLayout/linesLayout.ts b/src/vs/editor/common/viewLayout/linesLayout.ts index 8aab4c60d90b9..1e60452a56005 100644 --- a/src/vs/editor/common/viewLayout/linesLayout.ts +++ b/src/vs/editor/common/viewLayout/linesLayout.ts @@ -105,7 +105,7 @@ export class LinesLayout { private readonly _instanceId: string; - private _pendingChanges: PendingChanges; + private readonly _pendingChanges: PendingChanges; private readonly _arr: EditorWhitespace[]; @@ -114,13 +114,6 @@ export class LinesLayout { */ private _prefixSumValidIndex: number; - /** - * index at which a whitespace is positioned (inside heights, afterLineNumbers, prefixSum members) - */ - private readonly _whitespaceId2Index: { - [id: string]: number; - }; - /** * last whitespace id issued */ @@ -144,7 +137,6 @@ export class LinesLayout { this._pendingChanges = new PendingChanges(); this._arr = []; this._prefixSumValidIndex = -1; - this._whitespaceId2Index = {}; this._lastWhitespaceId = 0; this._minWidth = -1; /* marker for not being computed */ this._lineCount = lineCount; @@ -229,23 +221,34 @@ export class LinesLayout { } public _commitPendingChanges(inserts: EditorWhitespace[], changes: IPendingChange[], removes: IPendingRemove[]): void { - // const magnitude = inserts.length + changes.length + removes.length; - // if (magnitude === 1) { - // // when only one thing - for (const insert of inserts) { - this._insertWhitespace(insert); - } - for (const change of changes) { - this._changeOneWhitespace(change.id, change.newAfterLineNumber, change.newHeight); + if (!false || inserts.length + changes.length + removes.length <= 1) { + // when only one thing happened, handle it "delicately" + for (const insert of inserts) { + this._insertWhitespace(insert); + this._minWidth = -1; /* marker for not being computed */ + } + for (const change of changes) { + this._changeOneWhitespace(change.id, change.newAfterLineNumber, change.newHeight); + } + for (const remove of removes) { + this._removeWhitespace(remove.id); + } + return; } + + // simply rebuild the entire datastructure + + const toRemove = new Set(); for (const remove of removes) { - this._removeWhitespace(remove.id); + toRemove.add(remove.id); } - return; - // } - // console.log(`magnitude: ${magnitude} -- inserts: ${inserts.length}, changes: ${changes.length}, removes: ${removes.length}`); - // console.log(`TODO: `, inserts, changes, removes); + const toChange = new Map(); + for (const change of changes) { + toChange.set(change.id, change); + } + + this._minWidth = -1; /* marker for not being computed */ } private _checkPendingChanges(): void { @@ -255,72 +258,58 @@ export class LinesLayout { } private _insertWhitespace(whitespace: EditorWhitespace): void { - const insertionIndex = LinesLayout.findInsertionIndex(this._arr, whitespace.afterLineNumber, whitespace.ordinal); - this._insertWhitespaceAtIndex(insertionIndex, whitespace); - this._minWidth = -1; /* marker for not being computed */ - } - - private _insertWhitespaceAtIndex(insertIndex: number, whitespace: EditorWhitespace): void { + const insertIndex = LinesLayout.findInsertionIndex(this._arr, whitespace.afterLineNumber, whitespace.ordinal); this._arr.splice(insertIndex, 0, whitespace); + this._prefixSumValidIndex = Math.min(this._prefixSumValidIndex, insertIndex - 1); + } - const keys = Object.keys(this._whitespaceId2Index); - for (const sid of keys) { - const oldIndex = this._whitespaceId2Index[sid]; - if (oldIndex >= insertIndex) { - this._whitespaceId2Index[sid] = oldIndex + 1; + private _findWhitespaceIndex(id: string): number { + const arr = this._arr; + for (let i = 0, len = arr.length; i < len; i++) { + if (arr[i].id === id) { + return i; } } - - this._whitespaceId2Index[whitespace.id] = insertIndex; - this._prefixSumValidIndex = Math.min(this._prefixSumValidIndex, insertIndex - 1); + return -1; } private _changeOneWhitespace(id: string, newAfterLineNumber: number, newHeight: number): void { - if (this._whitespaceId2Index.hasOwnProperty(id)) { - const index = this._whitespaceId2Index[id]; - if (this._arr[index].height !== newHeight) { - this._arr[index].height = newHeight; - this._prefixSumValidIndex = Math.min(this._prefixSumValidIndex, index - 1); - } - if (this._arr[index].afterLineNumber !== newAfterLineNumber) { - // `afterLineNumber` changed for this whitespace + const index = this._findWhitespaceIndex(id); + if (index === -1) { + return; + } + if (this._arr[index].height !== newHeight) { + this._arr[index].height = newHeight; + this._prefixSumValidIndex = Math.min(this._prefixSumValidIndex, index - 1); + } + if (this._arr[index].afterLineNumber !== newAfterLineNumber) { + // `afterLineNumber` changed for this whitespace - // Record old whitespace - const whitespace = this._arr[index]; + // Record old whitespace + const whitespace = this._arr[index]; - // Since changing `afterLineNumber` can trigger a reordering, we're gonna remove this whitespace - this._removeWhitespace(id); + // Since changing `afterLineNumber` can trigger a reordering, we're gonna remove this whitespace + this._removeWhitespaceAtIndex(index); - whitespace.afterLineNumber = newAfterLineNumber; + whitespace.afterLineNumber = newAfterLineNumber; - // And add it again - const insertionIndex = LinesLayout.findInsertionIndex(this._arr, whitespace.afterLineNumber, whitespace.ordinal); - this._insertWhitespaceAtIndex(insertionIndex, whitespace); - } + // And add it again + this._insertWhitespace(whitespace); } } private _removeWhitespace(id: string): void { - if (this._whitespaceId2Index.hasOwnProperty(id)) { - const index = this._whitespaceId2Index[id]; - delete this._whitespaceId2Index[id]; - this._removeWhitespaceAtIndex(index); - this._minWidth = -1; /* marker for not being computed */ + const index = this._findWhitespaceIndex(id); + if (index === -1) { + return; } + this._removeWhitespaceAtIndex(index); + this._minWidth = -1; /* marker for not being computed */ } private _removeWhitespaceAtIndex(removeIndex: number): void { - this._arr.splice(removeIndex, 1); this._prefixSumValidIndex = Math.min(this._prefixSumValidIndex, removeIndex - 1); - - const keys = Object.keys(this._whitespaceId2Index); - for (const sid of keys) { - const oldIndex = this._whitespaceId2Index[sid]; - if (oldIndex >= removeIndex) { - this._whitespaceId2Index[sid] = oldIndex - 1; - } - } } /** From f0ec8373f329cc96e5d90ebffa6046089598ba4d Mon Sep 17 00:00:00 2001 From: Alexandru Dima Date: Fri, 15 Nov 2019 17:14:19 +0100 Subject: [PATCH 348/352] Recompute whitespace entirely in case of larger changes (#84726) --- .../editor/common/viewLayout/linesLayout.ts | 85 ++++++++++--------- 1 file changed, 43 insertions(+), 42 deletions(-) diff --git a/src/vs/editor/common/viewLayout/linesLayout.ts b/src/vs/editor/common/viewLayout/linesLayout.ts index 1e60452a56005..90f7335de7a32 100644 --- a/src/vs/editor/common/viewLayout/linesLayout.ts +++ b/src/vs/editor/common/viewLayout/linesLayout.ts @@ -104,40 +104,20 @@ export class LinesLayout { private static INSTANCE_COUNT = 0; private readonly _instanceId: string; - private readonly _pendingChanges: PendingChanges; - - private readonly _arr: EditorWhitespace[]; - - /** - * _arr[i].prefixSum, 1 <= i <= prefixSumValidIndex can be trusted - */ - private _prefixSumValidIndex: number; - - /** - * last whitespace id issued - */ private _lastWhitespaceId: number; - + private _arr: EditorWhitespace[]; + private _prefixSumValidIndex: number; private _minWidth: number; - - /** - * Keep track of the total number of lines. - * This is useful for doing binary searches or for doing hit-testing. - */ private _lineCount: number; - - /** - * The height of a line in pixels. - */ private _lineHeight: number; constructor(lineCount: number, lineHeight: number) { this._instanceId = strings.singleLetterHash(++LinesLayout.INSTANCE_COUNT); this._pendingChanges = new PendingChanges(); + this._lastWhitespaceId = 0; this._arr = []; this._prefixSumValidIndex = -1; - this._lastWhitespaceId = 0; this._minWidth = -1; /* marker for not being computed */ this._lineCount = lineCount; this._lineHeight = lineHeight; @@ -200,18 +180,15 @@ export class LinesLayout { const id = this._instanceId + (++this._lastWhitespaceId); this._pendingChanges.insert(new EditorWhitespace(id, afterLineNumber, ordinal, heightInPx, minWidth)); return id; - // return this._insertWhitespace(afterLineNumber, ordinal, heightInPx, minWidth); }, changeOneWhitespace: (id: string, newAfterLineNumber: number, newHeight: number): void => { newAfterLineNumber = newAfterLineNumber | 0; newHeight = newHeight | 0; this._pendingChanges.change({ id, newAfterLineNumber, newHeight }); - // this._changeOneWhitespace(id, newAfterLineNumber, newHeight); }, removeWhitespace: (id: string): void => { this._pendingChanges.remove({ id }); - // this._removeWhitespace(id); } }; return callback(accessor); @@ -221,17 +198,24 @@ export class LinesLayout { } public _commitPendingChanges(inserts: EditorWhitespace[], changes: IPendingChange[], removes: IPendingRemove[]): void { - if (!false || inserts.length + changes.length + removes.length <= 1) { + if (inserts.length > 0 || removes.length > 0) { + this._minWidth = -1; /* marker for not being computed */ + } + + if (inserts.length + changes.length + removes.length <= 1) { // when only one thing happened, handle it "delicately" for (const insert of inserts) { this._insertWhitespace(insert); - this._minWidth = -1; /* marker for not being computed */ } for (const change of changes) { this._changeOneWhitespace(change.id, change.newAfterLineNumber, change.newHeight); } for (const remove of removes) { - this._removeWhitespace(remove.id); + const index = this._findWhitespaceIndex(remove.id); + if (index === -1) { + continue; + } + this._removeWhitespace(index); } return; } @@ -248,12 +232,38 @@ export class LinesLayout { toChange.set(change.id, change); } - this._minWidth = -1; /* marker for not being computed */ + const applyRemoveAndChange = (whitespaces: EditorWhitespace[]): EditorWhitespace[] => { + let result: EditorWhitespace[] = []; + for (const whitespace of whitespaces) { + if (toRemove.has(whitespace.id)) { + continue; + } + if (toChange.has(whitespace.id)) { + const change = toChange.get(whitespace.id)!; + whitespace.afterLineNumber = change.newAfterLineNumber; + whitespace.height = change.newHeight; + } + result.push(whitespace); + } + return result; + }; + + const result = applyRemoveAndChange(this._arr).concat(applyRemoveAndChange(inserts)); + result.sort((a, b) => { + if (a.afterLineNumber === b.afterLineNumber) { + return a.ordinal - b.ordinal; + } + return a.afterLineNumber - b.afterLineNumber; + }); + + this._arr = result; + this._prefixSumValidIndex = -1; } private _checkPendingChanges(): void { if (this._pendingChanges.mustCommit()) { - console.log(`I should commit pending changes!`);//TODO + console.warn(`Commiting pending changes before change accessor leaves due to read access.`); + this._pendingChanges.commit(this); } } @@ -289,7 +299,7 @@ export class LinesLayout { const whitespace = this._arr[index]; // Since changing `afterLineNumber` can trigger a reordering, we're gonna remove this whitespace - this._removeWhitespaceAtIndex(index); + this._removeWhitespace(index); whitespace.afterLineNumber = newAfterLineNumber; @@ -298,16 +308,7 @@ export class LinesLayout { } } - private _removeWhitespace(id: string): void { - const index = this._findWhitespaceIndex(id); - if (index === -1) { - return; - } - this._removeWhitespaceAtIndex(index); - this._minWidth = -1; /* marker for not being computed */ - } - - private _removeWhitespaceAtIndex(removeIndex: number): void { + private _removeWhitespace(removeIndex: number): void { this._arr.splice(removeIndex, 1); this._prefixSumValidIndex = Math.min(this._prefixSumValidIndex, removeIndex - 1); } From da112cdb5a1c74fa8355f63cb28d077a272fe56c Mon Sep 17 00:00:00 2001 From: Alex Dima Date: Fri, 15 Nov 2019 17:27:08 +0100 Subject: [PATCH 349/352] changes for #81574 --- src/vs/base/browser/dom.ts | 2 +- src/vs/base/browser/globalMouseMoveMonitor.ts | 4 +- .../editor/browser/controller/mouseHandler.ts | 2 +- .../browser/controller/pointerHandler.ts | 10 ++-- src/vs/editor/browser/editorDom.ts | 8 +-- .../browser/viewParts/lines/viewLine.ts | 54 ++++++++++--------- src/vs/editor/contrib/dnd/dnd.ts | 6 +-- .../standalone/browser/standaloneServices.ts | 2 +- 8 files changed, 47 insertions(+), 41 deletions(-) diff --git a/src/vs/base/browser/dom.ts b/src/vs/base/browser/dom.ts index cbdf3775398e9..6a912ed755952 100644 --- a/src/vs/base/browser/dom.ts +++ b/src/vs/base/browser/dom.ts @@ -443,7 +443,7 @@ export interface DOMEvent { } const MINIMUM_TIME_MS = 16; -const DEFAULT_EVENT_MERGER: IEventMerger = function (lastEvent: DOMEvent, currentEvent: DOMEvent) { +const DEFAULT_EVENT_MERGER: IEventMerger = function (lastEvent: DOMEvent | null, currentEvent: DOMEvent) { return currentEvent; }; diff --git a/src/vs/base/browser/globalMouseMoveMonitor.ts b/src/vs/base/browser/globalMouseMoveMonitor.ts index b24a3db0e504e..4ab9a6c2d335e 100644 --- a/src/vs/base/browser/globalMouseMoveMonitor.ts +++ b/src/vs/base/browser/globalMouseMoveMonitor.ts @@ -16,7 +16,7 @@ export interface IStandardMouseMoveEventData { } export interface IEventMerger { - (lastEvent: R, currentEvent: MouseEvent): R; + (lastEvent: R | null, currentEvent: MouseEvent): R; } export interface IMouseMoveCallback { @@ -90,7 +90,7 @@ export class GlobalMouseMoveMonitor implements IDisposable { for (const element of windowChain) { this.hooks.add(dom.addDisposableThrottledListener(element.window.document, mouseMove, (data: R) => this.mouseMoveCallback!(data), - (lastEvent: R, currentEvent) => this.mouseMoveEventMerger!(lastEvent, currentEvent as MouseEvent) + (lastEvent: R | null, currentEvent) => this.mouseMoveEventMerger!(lastEvent, currentEvent as MouseEvent) )); this.hooks.add(dom.addDisposableListener(element.window.document, mouseUp, (e: MouseEvent) => this.stopMonitoring(true))); } diff --git a/src/vs/editor/browser/controller/mouseHandler.ts b/src/vs/editor/browser/controller/mouseHandler.ts index 8c8bb7434624e..d235e6ba79177 100644 --- a/src/vs/editor/browser/controller/mouseHandler.ts +++ b/src/vs/editor/browser/controller/mouseHandler.ts @@ -27,7 +27,7 @@ import { EditorOption } from 'vs/editor/common/config/editorOptions'; * Merges mouse events when mouse move events are throttled */ export function createMouseMoveEventMerger(mouseTargetFactory: MouseTargetFactory | null) { - return function (lastEvent: EditorMouseEvent, currentEvent: EditorMouseEvent): EditorMouseEvent { + return function (lastEvent: EditorMouseEvent | null, currentEvent: EditorMouseEvent): EditorMouseEvent { let targetIsWidget = false; if (mouseTargetFactory) { targetIsWidget = mouseTargetFactory.mouseTargetIsWidget(currentEvent); diff --git a/src/vs/editor/browser/controller/pointerHandler.ts b/src/vs/editor/browser/controller/pointerHandler.ts index 28ebcf990affb..8818742feff9a 100644 --- a/src/vs/editor/browser/controller/pointerHandler.ts +++ b/src/vs/editor/browser/controller/pointerHandler.ts @@ -18,7 +18,7 @@ interface IThrottledGestureEvent { translationY: number; } -function gestureChangeEventMerger(lastEvent: IThrottledGestureEvent, currentEvent: MSGestureEvent): IThrottledGestureEvent { +function gestureChangeEventMerger(lastEvent: IThrottledGestureEvent | null, currentEvent: MSGestureEvent): IThrottledGestureEvent { const r = { translationY: currentEvent.translationY, translationX: currentEvent.translationX @@ -53,7 +53,7 @@ class MsPointerHandler extends MouseHandler implements IDisposable { const penGesture = new MSGesture(); touchGesture.target = this.viewHelper.linesContentDomNode; penGesture.target = this.viewHelper.linesContentDomNode; - this.viewHelper.linesContentDomNode.addEventListener('MSPointerDown', (e: MSPointerEvent) => { + this.viewHelper.linesContentDomNode.addEventListener('MSPointerDown', (e: MSPointerEvent) => { // Circumvent IE11 breaking change in e.pointerType & TypeScript's stale definitions const pointerType = e.pointerType; if (pointerType === ((e).MSPOINTER_TYPE_MOUSE || 'mouse')) { @@ -67,7 +67,7 @@ class MsPointerHandler extends MouseHandler implements IDisposable { penGesture.addPointer(e.pointerId); } }); - this._register(dom.addDisposableThrottledListener(this.viewHelper.linesContentDomNode, 'MSGestureChange', (e) => this._onGestureChange(e), gestureChangeEventMerger)); + this._register(dom.addDisposableThrottledListener(this.viewHelper.linesContentDomNode, 'MSGestureChange', (e) => this._onGestureChange(e), gestureChangeEventMerger)); this._register(dom.addDisposableListener(this.viewHelper.linesContentDomNode, 'MSGestureTap', (e) => this._onCaptureGestureTap(e), true)); } }, 100); @@ -132,7 +132,7 @@ class StandardPointerHandler extends MouseHandler implements IDisposable { const penGesture = new MSGesture(); touchGesture.target = this.viewHelper.linesContentDomNode; penGesture.target = this.viewHelper.linesContentDomNode; - this.viewHelper.linesContentDomNode.addEventListener('pointerdown', (e: MSPointerEvent) => { + this.viewHelper.linesContentDomNode.addEventListener('pointerdown', (e: PointerEvent) => { const pointerType = e.pointerType; if (pointerType === 'mouse') { this._lastPointerType = 'mouse'; @@ -145,7 +145,7 @@ class StandardPointerHandler extends MouseHandler implements IDisposable { penGesture.addPointer(e.pointerId); } }); - this._register(dom.addDisposableThrottledListener(this.viewHelper.linesContentDomNode, 'MSGestureChange', (e) => this._onGestureChange(e), gestureChangeEventMerger)); + this._register(dom.addDisposableThrottledListener(this.viewHelper.linesContentDomNode, 'MSGestureChange', (e) => this._onGestureChange(e), gestureChangeEventMerger)); this._register(dom.addDisposableListener(this.viewHelper.linesContentDomNode, 'MSGestureTap', (e) => this._onCaptureGestureTap(e), true)); } }, 100); diff --git a/src/vs/editor/browser/editorDom.ts b/src/vs/editor/browser/editorDom.ts index 60df7e8f1b893..9401fdd259e69 100644 --- a/src/vs/editor/browser/editorDom.ts +++ b/src/vs/editor/browser/editorDom.ts @@ -84,7 +84,7 @@ export class EditorMouseEvent extends StandardMouseEvent { } export interface EditorMouseEventMerger { - (lastEvent: EditorMouseEvent, currentEvent: EditorMouseEvent): EditorMouseEvent; + (lastEvent: EditorMouseEvent | null, currentEvent: EditorMouseEvent): EditorMouseEvent; } export class EditorMouseEventFactory { @@ -124,7 +124,7 @@ export class EditorMouseEventFactory { } public onMouseMoveThrottled(target: HTMLElement, callback: (e: EditorMouseEvent) => void, merger: EditorMouseEventMerger, minimumTimeMs: number): IDisposable { - const myMerger: dom.IEventMerger = (lastEvent: EditorMouseEvent, currentEvent: MouseEvent): EditorMouseEvent => { + const myMerger: dom.IEventMerger = (lastEvent: EditorMouseEvent | null, currentEvent: MouseEvent): EditorMouseEvent => { return merger(lastEvent, this._create(currentEvent)); }; return dom.addDisposableThrottledListener(target, 'mousemove', callback, myMerger, minimumTimeMs); @@ -162,7 +162,7 @@ export class EditorPointerEventFactory { } public onPointerMoveThrottled(target: HTMLElement, callback: (e: EditorMouseEvent) => void, merger: EditorMouseEventMerger, minimumTimeMs: number): IDisposable { - const myMerger: dom.IEventMerger = (lastEvent: EditorMouseEvent, currentEvent: MouseEvent): EditorMouseEvent => { + const myMerger: dom.IEventMerger = (lastEvent: EditorMouseEvent | null, currentEvent: MouseEvent): EditorMouseEvent => { return merger(lastEvent, this._create(currentEvent)); }; return dom.addDisposableThrottledListener(target, 'pointermove', callback, myMerger, minimumTimeMs); @@ -195,7 +195,7 @@ export class GlobalEditorMouseMoveMonitor extends Disposable { this._globalMouseMoveMonitor.stopMonitoring(true); }, true); - const myMerger: dom.IEventMerger = (lastEvent: EditorMouseEvent, currentEvent: MouseEvent): EditorMouseEvent => { + const myMerger: dom.IEventMerger = (lastEvent: EditorMouseEvent | null, currentEvent: MouseEvent): EditorMouseEvent => { return merger(lastEvent, new EditorMouseEvent(currentEvent, this._editorViewDomNode)); }; diff --git a/src/vs/editor/browser/viewParts/lines/viewLine.ts b/src/vs/editor/browser/viewParts/lines/viewLine.ts index 655b93462d31c..8840a0140322e 100644 --- a/src/vs/editor/browser/viewParts/lines/viewLine.ts +++ b/src/vs/editor/browser/viewParts/lines/viewLine.ts @@ -407,7 +407,7 @@ class FastRenderedViewLine implements IRenderedViewLine { */ class RenderedViewLine implements IRenderedViewLine { - public domNode: FastDomNode; + public domNode: FastDomNode | null; public readonly input: RenderLineInput; protected readonly _characterMapping: CharacterMapping; @@ -420,7 +420,7 @@ class RenderedViewLine implements IRenderedViewLine { */ private readonly _pixelOffsetCache: Int32Array | null; - constructor(domNode: FastDomNode, renderLineInput: RenderLineInput, characterMapping: CharacterMapping, containsRTL: boolean, containsForeignElements: ForeignElementType) { + constructor(domNode: FastDomNode | null, renderLineInput: RenderLineInput, characterMapping: CharacterMapping, containsRTL: boolean, containsForeignElements: ForeignElementType) { this.domNode = domNode; this.input = renderLineInput; this._characterMapping = characterMapping; @@ -439,16 +439,19 @@ class RenderedViewLine implements IRenderedViewLine { // --- Reading from the DOM methods - protected _getReadingTarget(): HTMLElement { - return this.domNode.domNode.firstChild; + protected _getReadingTarget(myDomNode: FastDomNode): HTMLElement { + return myDomNode.domNode.firstChild; } /** * Width of the line in pixels */ public getWidth(): number { + if (!this.domNode) { + return 0; + } if (this._cachedWidth === -1) { - this._cachedWidth = this._getReadingTarget().offsetWidth; + this._cachedWidth = this._getReadingTarget(this.domNode).offsetWidth; } return this._cachedWidth; } @@ -464,14 +467,17 @@ class RenderedViewLine implements IRenderedViewLine { * Visible ranges for a model range */ public getVisibleRangesForRange(startColumn: number, endColumn: number, context: DomReadingContext): HorizontalRange[] | null { + if (!this.domNode) { + return null; + } if (this._pixelOffsetCache !== null) { // the text is LTR - const startOffset = this._readPixelOffset(startColumn, context); + const startOffset = this._readPixelOffset(this.domNode, startColumn, context); if (startOffset === -1) { return null; } - const endOffset = this._readPixelOffset(endColumn, context); + const endOffset = this._readPixelOffset(this.domNode, endColumn, context); if (endOffset === -1) { return null; } @@ -479,23 +485,23 @@ class RenderedViewLine implements IRenderedViewLine { return [new HorizontalRange(startOffset, endOffset - startOffset)]; } - return this._readVisibleRangesForRange(startColumn, endColumn, context); + return this._readVisibleRangesForRange(this.domNode, startColumn, endColumn, context); } - protected _readVisibleRangesForRange(startColumn: number, endColumn: number, context: DomReadingContext): HorizontalRange[] | null { + protected _readVisibleRangesForRange(domNode: FastDomNode, startColumn: number, endColumn: number, context: DomReadingContext): HorizontalRange[] | null { if (startColumn === endColumn) { - const pixelOffset = this._readPixelOffset(startColumn, context); + const pixelOffset = this._readPixelOffset(domNode, startColumn, context); if (pixelOffset === -1) { return null; } else { return [new HorizontalRange(pixelOffset, 0)]; } } else { - return this._readRawVisibleRangesForRange(startColumn, endColumn, context); + return this._readRawVisibleRangesForRange(domNode, startColumn, endColumn, context); } } - protected _readPixelOffset(column: number, context: DomReadingContext): number { + protected _readPixelOffset(domNode: FastDomNode, column: number, context: DomReadingContext): number { if (this._characterMapping.length === 0) { // This line has no content if (this._containsForeignElements === ForeignElementType.None) { @@ -520,18 +526,18 @@ class RenderedViewLine implements IRenderedViewLine { return cachedPixelOffset; } - const result = this._actualReadPixelOffset(column, context); + const result = this._actualReadPixelOffset(domNode, column, context); this._pixelOffsetCache[column] = result; return result; } - return this._actualReadPixelOffset(column, context); + return this._actualReadPixelOffset(domNode, column, context); } - private _actualReadPixelOffset(column: number, context: DomReadingContext): number { + private _actualReadPixelOffset(domNode: FastDomNode, column: number, context: DomReadingContext): number { if (this._characterMapping.length === 0) { // This line has no content - const r = RangeUtil.readHorizontalRanges(this._getReadingTarget(), 0, 0, 0, 0, context.clientRectDeltaLeft, context.endNode); + const r = RangeUtil.readHorizontalRanges(this._getReadingTarget(domNode), 0, 0, 0, 0, context.clientRectDeltaLeft, context.endNode); if (!r || r.length === 0) { return -1; } @@ -547,14 +553,14 @@ class RenderedViewLine implements IRenderedViewLine { const partIndex = CharacterMapping.getPartIndex(partData); const charOffsetInPart = CharacterMapping.getCharIndex(partData); - const r = RangeUtil.readHorizontalRanges(this._getReadingTarget(), partIndex, charOffsetInPart, partIndex, charOffsetInPart, context.clientRectDeltaLeft, context.endNode); + const r = RangeUtil.readHorizontalRanges(this._getReadingTarget(domNode), partIndex, charOffsetInPart, partIndex, charOffsetInPart, context.clientRectDeltaLeft, context.endNode); if (!r || r.length === 0) { return -1; } return r[0].left; } - private _readRawVisibleRangesForRange(startColumn: number, endColumn: number, context: DomReadingContext): HorizontalRange[] | null { + private _readRawVisibleRangesForRange(domNode: FastDomNode, startColumn: number, endColumn: number, context: DomReadingContext): HorizontalRange[] | null { if (startColumn === 1 && endColumn === this._characterMapping.length) { // This branch helps IE with bidi text & gives a performance boost to other browsers when reading visible ranges for an entire line @@ -570,7 +576,7 @@ class RenderedViewLine implements IRenderedViewLine { const endPartIndex = CharacterMapping.getPartIndex(endPartData); const endCharOffsetInPart = CharacterMapping.getCharIndex(endPartData); - return RangeUtil.readHorizontalRanges(this._getReadingTarget(), startPartIndex, startCharOffsetInPart, endPartIndex, endCharOffsetInPart, context.clientRectDeltaLeft, context.endNode); + return RangeUtil.readHorizontalRanges(this._getReadingTarget(domNode), startPartIndex, startCharOffsetInPart, endPartIndex, endCharOffsetInPart, context.clientRectDeltaLeft, context.endNode); } /** @@ -591,8 +597,8 @@ class RenderedViewLine implements IRenderedViewLine { } class WebKitRenderedViewLine extends RenderedViewLine { - protected _readVisibleRangesForRange(startColumn: number, endColumn: number, context: DomReadingContext): HorizontalRange[] | null { - const output = super._readVisibleRangesForRange(startColumn, endColumn, context); + protected _readVisibleRangesForRange(domNode: FastDomNode, startColumn: number, endColumn: number, context: DomReadingContext): HorizontalRange[] | null { + const output = super._readVisibleRangesForRange(domNode, startColumn, endColumn, context); if (!output || output.length === 0 || startColumn === endColumn || (startColumn === 1 && endColumn === this._characterMapping.length)) { return output; @@ -603,7 +609,7 @@ class WebKitRenderedViewLine extends RenderedViewLine { if (!this.input.containsRTL) { // This is an attempt to patch things up // Find position of last column - const endPixelOffset = this._readPixelOffset(endColumn, context); + const endPixelOffset = this._readPixelOffset(domNode, endColumn, context); if (endPixelOffset !== -1) { const lastRange = output[output.length - 1]; if (lastRange.left < endPixelOffset) { @@ -624,10 +630,10 @@ const createRenderedLine: (domNode: FastDomNode | null, renderLineI return createNormalRenderedLine; })(); -function createWebKitRenderedLine(domNode: FastDomNode, renderLineInput: RenderLineInput, characterMapping: CharacterMapping, containsRTL: boolean, containsForeignElements: ForeignElementType): RenderedViewLine { +function createWebKitRenderedLine(domNode: FastDomNode | null, renderLineInput: RenderLineInput, characterMapping: CharacterMapping, containsRTL: boolean, containsForeignElements: ForeignElementType): RenderedViewLine { return new WebKitRenderedViewLine(domNode, renderLineInput, characterMapping, containsRTL, containsForeignElements); } -function createNormalRenderedLine(domNode: FastDomNode, renderLineInput: RenderLineInput, characterMapping: CharacterMapping, containsRTL: boolean, containsForeignElements: ForeignElementType): RenderedViewLine { +function createNormalRenderedLine(domNode: FastDomNode | null, renderLineInput: RenderLineInput, characterMapping: CharacterMapping, containsRTL: boolean, containsForeignElements: ForeignElementType): RenderedViewLine { return new RenderedViewLine(domNode, renderLineInput, characterMapping, containsRTL, containsForeignElements); } diff --git a/src/vs/editor/contrib/dnd/dnd.ts b/src/vs/editor/contrib/dnd/dnd.ts index f9c0cd0090276..6d4226cbe5ea5 100644 --- a/src/vs/editor/contrib/dnd/dnd.ts +++ b/src/vs/editor/contrib/dnd/dnd.ts @@ -8,7 +8,7 @@ import { IKeyboardEvent } from 'vs/base/browser/keyboardEvent'; import { Disposable } from 'vs/base/common/lifecycle'; import { isMacintosh } from 'vs/base/common/platform'; import { KeyCode } from 'vs/base/common/keyCodes'; -import { ICodeEditor, IEditorMouseEvent, IMouseTarget, MouseTargetType } from 'vs/editor/browser/editorBrowser'; +import { ICodeEditor, IEditorMouseEvent, IMouseTarget, MouseTargetType, IPartialEditorMouseEvent } from 'vs/editor/browser/editorBrowser'; import { registerEditorContribution } from 'vs/editor/browser/editorExtensions'; import * as editorCommon from 'vs/editor/common/editorCommon'; import { Position } from 'vs/editor/common/core/position'; @@ -50,7 +50,7 @@ export class DragAndDropController extends Disposable implements editorCommon.IE this._register(this._editor.onMouseDown((e: IEditorMouseEvent) => this._onEditorMouseDown(e))); this._register(this._editor.onMouseUp((e: IEditorMouseEvent) => this._onEditorMouseUp(e))); this._register(this._editor.onMouseDrag((e: IEditorMouseEvent) => this._onEditorMouseDrag(e))); - this._register(this._editor.onMouseDrop((e: IEditorMouseEvent) => this._onEditorMouseDrop(e))); + this._register(this._editor.onMouseDrop((e: IPartialEditorMouseEvent) => this._onEditorMouseDrop(e))); this._register(this._editor.onKeyDown((e: IKeyboardEvent) => this.onEditorKeyDown(e))); this._register(this._editor.onKeyUp((e: IKeyboardEvent) => this.onEditorKeyUp(e))); this._register(this._editor.onDidBlurEditorWidget(() => this.onEditorBlur())); @@ -143,7 +143,7 @@ export class DragAndDropController extends Disposable implements editorCommon.IE } } - private _onEditorMouseDrop(mouseEvent: IEditorMouseEvent): void { + private _onEditorMouseDrop(mouseEvent: IPartialEditorMouseEvent): void { if (mouseEvent.target && (this._hitContent(mouseEvent.target) || this._hitMargin(mouseEvent.target)) && mouseEvent.target.position) { let newCursorPosition = new Position(mouseEvent.target.position.lineNumber, mouseEvent.target.position.column); diff --git a/src/vs/editor/standalone/browser/standaloneServices.ts b/src/vs/editor/standalone/browser/standaloneServices.ts index 1777683f5ccba..b9abf518d3393 100644 --- a/src/vs/editor/standalone/browser/standaloneServices.ts +++ b/src/vs/editor/standalone/browser/standaloneServices.ts @@ -89,7 +89,7 @@ export module StaticServices { let _all: LazyStaticService[] = []; - function define(serviceId: ServiceIdentifier, factory: (overrides: IEditorOverrideServices) => T): LazyStaticService { + function define(serviceId: ServiceIdentifier, factory: (overrides: IEditorOverrideServices | undefined) => T): LazyStaticService { let r = new LazyStaticService(serviceId, factory); _all.push(r); return r; From 44e755ba4b0dbd11d2910311dafc355a8b1430cd Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Fri, 15 Nov 2019 17:34:24 +0100 Subject: [PATCH 350/352] custom editors - support simple save() --- .../contrib/files/browser/fileCommands.ts | 25 +++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/contrib/files/browser/fileCommands.ts b/src/vs/workbench/contrib/files/browser/fileCommands.ts index 6305930969906..1a4031d384949 100644 --- a/src/vs/workbench/contrib/files/browser/fileCommands.ts +++ b/src/vs/workbench/contrib/files/browser/fileCommands.ts @@ -496,9 +496,30 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({ weight: KeybindingWeight.WorkbenchContrib, primary: KeyMod.CtrlCmd | KeyCode.KEY_S, id: SAVE_FILE_COMMAND_ID, - handler: (accessor, resource: URI | object) => { + handler: async (accessor, resource: URI | object) => { + const listService = accessor.get(IListService); + const editorGroupsService = accessor.get(IEditorGroupsService); + const notificationService = accessor.get(INotificationService); + + const editors = getMultiSelectedEditors(listService, editorGroupsService); + if (editors.length && !editors.some(({ editor }) => editor.getResource()?.scheme === Schemas.untitled)) { + try { + await Promise.all(editors.map(async ({ groupId, editor }) => { + + // Use save as a hint to pin the editor + editorGroupsService.getGroup(groupId)?.pinEditor(editor); + + return editor.save({ force: true }); + })); + } catch (error) { + notificationService.error(nls.localize('genericRevertResourcesError', "Failed to revert '{0}': {1}", editors.map(({ editor }) => editor.getName()).join(', '), toErrorMessage(error, false))); + } + + return; + } + const editorService = accessor.get(IEditorService); - const resources = getMultiSelectedResources(resource, accessor.get(IListService), editorService); + const resources = getMultiSelectedResources(resource, listService, editorService); if (resources.length === 1) { // If only one resource is selected explictly call save since the behavior is a bit different than save all #41841 From ca81ca47db3ff6e7f39fb514b52797937266bc22 Mon Sep 17 00:00:00 2001 From: Alexandru Dima Date: Fri, 15 Nov 2019 18:02:15 +0100 Subject: [PATCH 351/352] More changes for #81574 --- src/vs/base/browser/globalMouseMoveMonitor.ts | 2 +- src/vs/editor/browser/editorExtensions.ts | 4 ++-- src/vs/platform/remote/common/remoteAgentConnection.ts | 4 ++-- src/vs/workbench/api/common/extHost.api.impl.ts | 3 +-- .../browser/suggestEnabledInput/suggestEnabledInput.ts | 2 +- .../extensions/common/extensionHostProcessManager.ts | 5 ++++- .../workbench/services/mode/common/workbenchModeService.ts | 2 +- 7 files changed, 12 insertions(+), 10 deletions(-) diff --git a/src/vs/base/browser/globalMouseMoveMonitor.ts b/src/vs/base/browser/globalMouseMoveMonitor.ts index 4ab9a6c2d335e..cc8474f39ee63 100644 --- a/src/vs/base/browser/globalMouseMoveMonitor.ts +++ b/src/vs/base/browser/globalMouseMoveMonitor.ts @@ -27,7 +27,7 @@ export interface IOnStopCallback { (): void; } -export function standardMouseMoveMerger(lastEvent: IStandardMouseMoveEventData, currentEvent: MouseEvent): IStandardMouseMoveEventData { +export function standardMouseMoveMerger(lastEvent: IStandardMouseMoveEventData | null, currentEvent: MouseEvent): IStandardMouseMoveEventData { let ev = new StandardMouseEvent(currentEvent); ev.preventDefault(); return { diff --git a/src/vs/editor/browser/editorExtensions.ts b/src/vs/editor/browser/editorExtensions.ts index 1b81608b01366..2a12d008b5c32 100644 --- a/src/vs/editor/browser/editorExtensions.ts +++ b/src/vs/editor/browser/editorExtensions.ts @@ -307,7 +307,7 @@ export function registerEditorContribution(id EditorContributionRegistry.INSTANCE.registerEditorContribution(id, ctor); } -export function registerDiffEditorContribution(id: string, ctor: IDiffEditorContributionCtor): void { +export function registerDiffEditorContribution(id: string, ctor: { new(editor: IDiffEditor, ...services: Services): IEditorContribution }): void { EditorContributionRegistry.INSTANCE.registerDiffEditorContribution(id, ctor); } @@ -363,7 +363,7 @@ class EditorContributionRegistry { return this.editorContributions.slice(0); } - public registerDiffEditorContribution(id: string, ctor: IDiffEditorContributionCtor): void { + public registerDiffEditorContribution(id: string, ctor: { new(editor: IDiffEditor, ...services: Services): IEditorContribution }): void { this.diffEditorContributions.push({ id, ctor }); } diff --git a/src/vs/platform/remote/common/remoteAgentConnection.ts b/src/vs/platform/remote/common/remoteAgentConnection.ts index b526d149fa3af..eab8591492166 100644 --- a/src/vs/platform/remote/common/remoteAgentConnection.ts +++ b/src/vs/platform/remote/common/remoteAgentConnection.ts @@ -89,8 +89,8 @@ async function connectToRemoteExtensionHostAgent(options: ISimpleConnectionOptio options.host, options.port, `reconnectionToken=${options.reconnectionToken}&reconnection=${options.reconnectionProtocol ? 'true' : 'false'}`, - (err: any, socket: ISocket) => { - if (err) { + (err: any, socket: ISocket | undefined) => { + if (err || !socket) { options.logService.error(`${logPrefix} socketFactory.connect() failed. Error:`); options.logService.error(err); e(err); diff --git a/src/vs/workbench/api/common/extHost.api.impl.ts b/src/vs/workbench/api/common/extHost.api.impl.ts index 448923b104465..e71a93d69e4d5 100644 --- a/src/vs/workbench/api/common/extHost.api.impl.ts +++ b/src/vs/workbench/api/common/extHost.api.impl.ts @@ -185,8 +185,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I } return activeTextEditor.edit((edit: vscode.TextEditorEdit) => { - args.unshift(activeTextEditor, edit); - callback.apply(thisArg, args); + callback.apply(thisArg, [activeTextEditor, edit, ...args]); }).then((result) => { if (!result) { diff --git a/src/vs/workbench/contrib/codeEditor/browser/suggestEnabledInput/suggestEnabledInput.ts b/src/vs/workbench/contrib/codeEditor/browser/suggestEnabledInput/suggestEnabledInput.ts index 223949c9ac683..b7f1355fdad3e 100644 --- a/src/vs/workbench/contrib/codeEditor/browser/suggestEnabledInput/suggestEnabledInput.ts +++ b/src/vs/workbench/contrib/codeEditor/browser/suggestEnabledInput/suggestEnabledInput.ts @@ -82,7 +82,7 @@ export interface ISuggestEnabledInputStyleOverrides extends IStyleOverrides { } type ISuggestEnabledInputStyles = { - [P in keyof ISuggestEnabledInputStyleOverrides]: Color; + [P in keyof ISuggestEnabledInputStyleOverrides]: Color | undefined; }; export function attachSuggestEnabledInputBoxStyler(widget: IThemable, themeService: IThemeService, style?: ISuggestEnabledInputStyleOverrides): IDisposable { diff --git a/src/vs/workbench/services/extensions/common/extensionHostProcessManager.ts b/src/vs/workbench/services/extensions/common/extensionHostProcessManager.ts index cb638f64361c1..f3b6c2bf21d5c 100644 --- a/src/vs/workbench/services/extensions/common/extensionHostProcessManager.ts +++ b/src/vs/workbench/services/extensions/common/extensionHostProcessManager.ts @@ -406,7 +406,10 @@ export class MeasureExtHostLatencyAction extends Action { this._editorService.openEditor({ contents: measurements.map(MeasureExtHostLatencyAction._print).join('\n\n'), options: { pinned: true } } as IUntitledTextResourceInput); } - private static _print(m: ExtHostLatencyResult): string { + private static _print(m: ExtHostLatencyResult | null): string { + if (!m) { + return ''; + } return `${m.remoteAuthority ? `Authority: ${m.remoteAuthority}\n` : ``}Roundtrip latency: ${m.latency.toFixed(3)}ms\nUp: ${MeasureExtHostLatencyAction._printSpeed(m.up)}\nDown: ${MeasureExtHostLatencyAction._printSpeed(m.down)}\n`; } diff --git a/src/vs/workbench/services/mode/common/workbenchModeService.ts b/src/vs/workbench/services/mode/common/workbenchModeService.ts index f097879bc0de4..c6033d4ef9851 100644 --- a/src/vs/workbench/services/mode/common/workbenchModeService.ts +++ b/src/vs/workbench/services/mode/common/workbenchModeService.ts @@ -105,7 +105,7 @@ export class WorkbenchModeServiceImpl extends ModeServiceImpl { this._configurationService = configurationService; this._extensionService = extensionService; - languagesExtPoint.setHandler((extensions: IExtensionPointUser[]) => { + languagesExtPoint.setHandler((extensions: readonly IExtensionPointUser[]) => { let allValidLanguages: ILanguageExtensionPoint[] = []; for (let i = 0, len = extensions.length; i < len; i++) { From cfeeb1a6c2e9f9be0ff84c059e4bf3e6bf6550b1 Mon Sep 17 00:00:00 2001 From: Miguel Solorio Date: Fri, 15 Nov 2019 10:32:40 -0800 Subject: [PATCH 352/352] Simplify color tokens for breakpoints --- .../browser/debugCallStackContribution.ts | 55 ++----------------- 1 file changed, 5 insertions(+), 50 deletions(-) diff --git a/src/vs/workbench/contrib/debug/browser/debugCallStackContribution.ts b/src/vs/workbench/contrib/debug/browser/debugCallStackContribution.ts index 687eb51cd2d10..ee78a18990e3f 100644 --- a/src/vs/workbench/contrib/debug/browser/debugCallStackContribution.ts +++ b/src/vs/workbench/contrib/debug/browser/debugCallStackContribution.ts @@ -181,6 +181,11 @@ registerThemingParticipant((theme, collector) => { if (debugIconBreakpointColor) { collector.addRule(` .monaco-workbench .codicon-debug-breakpoint, + .monaco-workbench .codicon-debug-breakpoint-conditional, + .monaco-workbench .codicon-debug-breakpoint-log, + .monaco-workbench .codicon-debug-breakpoint-function, + .monaco-workbench .codicon-debug-breakpoint-data, + .monaco-workbench .codicon-debug-breakpoint-unsupported, .monaco-workbench .codicon-debug-hint:not(*[class*='codicon-debug-breakpoint']) , .monaco-workbench .codicon-debug-breakpoint-stackframe-dot, .monaco-workbench .codicon-debug-breakpoint.codicon-debug-breakpoint-stackframe-focused::after { @@ -207,51 +212,6 @@ registerThemingParticipant((theme, collector) => { `); } - const debugIconBreakpointConditionalColor = theme.getColor(debugIconBreakpointConditionalForeground); - if (debugIconBreakpointConditionalColor) { - collector.addRule(` - .monaco-workbench .codicon-debug-breakpoint-conditional { - color: ${debugIconBreakpointConditionalColor} !important; - } - `); - } - - const debugIconBreakpointLogColor = theme.getColor(debugIconBreakpointLogForeground); - if (debugIconBreakpointLogColor) { - collector.addRule(` - .monaco-workbench .codicon-debug-breakpoint-log { - color: ${debugIconBreakpointLogColor} !important; - } - `); - } - - const debugIconBreakpointFunctionColor = theme.getColor(debugIconBreakpointFunctionForeground); - if (debugIconBreakpointFunctionColor) { - collector.addRule(` - .monaco-workbench .codicon-debug-breakpoint-function { - color: ${debugIconBreakpointFunctionColor} !important; - } - `); - } - - const debugIconBreakpointDataColor = theme.getColor(debugIconBreakpointDataForeground); - if (debugIconBreakpointDataColor) { - collector.addRule(` - .monaco-workbench .codicon-debug-breakpoint-data { - color: ${debugIconBreakpointDataColor} !important; - } - `); - } - - const debugIconBreakpointUnsupportedColor = theme.getColor(debugIconBreakpointUnsupportedForeground); - if (debugIconBreakpointUnsupportedColor) { - collector.addRule(` - .monaco-workbench .codicon-debug-breakpoint-unsupported { - color: ${debugIconBreakpointUnsupportedColor} !important; - } - `); - } - const debugIconBreakpointStackframeColor = theme.getColor(debugIconBreakpointStackframeForeground); if (debugIconBreakpointStackframeColor) { collector.addRule(` @@ -279,10 +239,5 @@ const focusedStackFrameColor = registerColor('editor.focusedStackFrameHighlightB const debugIconBreakpointForeground = registerColor('debugIcon.breakpointForeground', { dark: '#E51400', light: '#E51400', hc: '#E51400' }, localize('debugIcon.breakpointForeground', 'Icon color for breakpoints.')); const debugIconBreakpointDisabledForeground = registerColor('debugIcon.breakpointDisabledForeground', { dark: '#848484', light: '#848484', hc: '#848484' }, localize('debugIcon.breakpointDisabledForeground', 'Icon color for disabled breakpoints.')); const debugIconBreakpointUnverifiedForeground = registerColor('debugIcon.breakpointUnverifiedForeground', { dark: '#848484', light: '#848484', hc: '#848484' }, localize('debugIcon.breakpointUnverifiedForeground', 'Icon color for unverified breakpoints.')); -const debugIconBreakpointConditionalForeground = registerColor('debugIcon.breakpointConditionalForeground', { dark: debugIconBreakpointForeground, light: debugIconBreakpointForeground, hc: debugIconBreakpointForeground }, localize('debugIcon.breakpointConditionalForeground', 'Icon color for conditional breakpoints.')); -const debugIconBreakpointLogForeground = registerColor('debugIcon.breakpointLogForeground', { dark: debugIconBreakpointForeground, light: debugIconBreakpointForeground, hc: debugIconBreakpointForeground }, localize('debugIcon.breakpointLogForeground', 'Icon color for log breakpoints.')); -const debugIconBreakpointFunctionForeground = registerColor('debugIcon.breakpointFunctionForeground', { dark: debugIconBreakpointForeground, light: debugIconBreakpointForeground, hc: debugIconBreakpointForeground }, localize('debugIcon.breakpointFunctionForeground', 'Icon color for function breakpoints.')); -const debugIconBreakpointDataForeground = registerColor('debugIcon.breakpointDataForeground', { dark: debugIconBreakpointForeground, light: debugIconBreakpointForeground, hc: debugIconBreakpointForeground }, localize('debugIcon.breakpointDataForeground', 'Icon color for data breakpoints.')); -const debugIconBreakpointUnsupportedForeground = registerColor('debugIcon.breakpointUnsupportedForeground', { dark: debugIconBreakpointForeground, light: debugIconBreakpointForeground, hc: debugIconBreakpointForeground }, localize('debugIcon.breakpointUnsupportedForeground', 'Icon color for unsupported breakpoints.')); const debugIconBreakpointStackframeForeground = registerColor('debugIcon.breakpointStackframeForeground', { dark: '#FFCC00', light: '#FFCC00', hc: '#FFCC00' }, localize('debugIcon.breakpointStackframeForeground', 'Icon color for breakpoints.')); const debugIconBreakpointStackframeFocusedForeground = registerColor('debugIcon.breakpointStackframeFocusedForeground', { dark: '#89D185', light: '#89D185', hc: '#89D185' }, localize('debugIcon.breakpointStackframeFocusedForeground', 'Icon color for breakpoints.'));