} }); } <ins> public getLenses(): CodeLensWidget[] { return this._lenses; } } export class ShowLensesInCurrentLineCommand extends EditorCommand { public runEditorCommand(accessor: ServicesAccessor, editor: ICodeEditor, args: any): void | Promise<void> { const quickInputService = accessor.get(IQuickInputService); const commandService = accessor.get(ICommandService); const notificationService = accessor.get(INotificationService); const lineNumber = editor.getSelection()?.positionLineNumber; const codelensController = editor.getContribution(CodeLensContribution.ID) as CodeLensContribution; const activeLensesWidgets = codelensController.getLenses().filter(lens => lens.getLineNumber() === lineNumber); const commandArguments: Map<string, any[] | undefined> = new Map(); const items: (IQuickPickItem | IQuickPickSeparator)[] = []; activeLensesWidgets.forEach(widget => { widget.getItems().forEach(codelens => { const command = codelens.symbol.command; if (!command) { return; } items.push({ id: command.id, label: command.title }); commandArguments.set(command.id, command.arguments); }); }); // We dont want an empty picker if (!items.length) { return; } quickInputService.pick(items, { canPickMany: false }).then(item => { const id = item.id!; commandService.executeCommand(id, ...(commandArguments.get(id) || [])).catch(err => notificationService.error(err)); }); } </ins> } registerEditorContribution(CodeLensContribution.ID, CodeLensContribution); <ins> const showLensesInCurrentLineCommand = new ShowLensesInCurrentLineCommand({ id: 'codelens.showLensesInCurrentLine', precondition: undefined }); showLensesInCurrentLineCommand.register(); </ins>


} } } <ins> getItems(): CodeLensItem[] { return this._data; } </ins> } registerThemingParticipant((theme, collector) => {


import { CancellationToken } from 'vs/base/common/cancellation'; import { IQuickPickItem, IPickOptions, IInputOptions, IQuickNavigateConfiguration, IQuickPick, IQuickInputButton, IInputBox, QuickPickInput } from 'vs/base/parts/quickinput/common/quickInput'; <del> export { IQuickPickItem, IPickOptions, IInputOptions, IQuickNavigateConfiguration, IQuickPick, IQuickInput, IQuickInputButton, IInputBox, IQuickPickItemButtonEvent, QuickPickInput, IQuickPickSeparator, IKeyMods } from 'vs/base/parts/quickinput/common/quickInput'; </del> <ins> export * from 'vs/base/parts/quickinput/common/quickInput'; </ins> export const IQuickInputService = createDecorator<IQuickInputService>('quickInputService');


import { IPartService, Position } from 'vs/workbench/services/part/common/partService'; const SPLIT_PANE_MIN_SIZE = 120; <ins> const TERMINAL_MIN_USEFUL_SIZE = 250; </ins> class SplitPaneContainer { private _height: number;


configHelper: ITerminalConfigHelper, shellLaunchConfig: IShellLaunchConfig ): ITerminalInstance { <ins> const newTerminalSize = ((this._panelPosition === Position.BOTTOM ? this._container.clientWidth : this._container.clientHeight) / (this._terminalInstances.length + 1)); if (newTerminalSize < TERMINAL_MIN_USEFUL_SIZE) { return undefined; } </ins> const instance = this._terminalService.createInstance( terminalFocusContextKey, configHelper,


} protected abstract _showTerminalCloseConfirmation(): TPromise<boolean>; <ins> protected abstract _showNotEnoughSpaceToast(): void; </ins> public abstract createTerminal(shell?: IShellLaunchConfig, wasNewTerminalAction?: boolean): ITerminalInstance; public abstract createTerminalRenderer(name: string): ITerminalInstance; public abstract createInstance(terminalFocusContextKey: IContextKey<boolean>, configHelper: ITerminalConfigHelper, container: HTMLElement, shellLaunchConfig: IShellLaunchConfig, doCreateProcess: boolean): ITerminalInstance;


} const instance = tab.split(this._terminalFocusContextKey, this.configHelper, shellLaunchConfig); <del> this._initInstanceListeners(instance); this._onInstancesChanged.fire(); </del> <ins> if (instance) { this._initInstanceListeners(instance); this._onInstancesChanged.fire(); </ins> <del> this._terminalTabs.forEach((t, i) => t.setVisible(i === this._activeTabIndex)); </del> <ins> this._terminalTabs.forEach((t, i) => t.setVisible(i === this._activeTabIndex)); } else { this._showNotEnoughSpaceToast(); } </ins> } protected _initInstanceListeners(instance: ITerminalInstance): void {


this._terminalTabs = []; this._configHelper = this._instantiationService.createInstance(TerminalConfigHelper); ipc.on('vscode:openFiles', (_event: any, request: IOpenFileRequest) => { // if the request to open files is coming in from the integrated terminal (identified though // the termProgram variable) and we are instructed to wait for editors close, wait for the


}).then(res => !res.confirmed); } <ins> protected _showNotEnoughSpaceToast(): void { this._notificationService.warn(nls.localize('terminal.minWidth', "Not enough space to split terminal.")); } </ins> public setContainers(panelContainer: HTMLElement, terminalContainer: HTMLElement): void { this._configHelper.panelContainer = panelContainer; this._terminalContainer = terminalContainer;


import { ModelDecorationMinimapOptions } from 'vs/editor/common/model/textModel'; import { Selection } from 'vs/editor/common/core/selection'; import { Color } from 'vs/base/common/color'; <ins> import { GestureEvent, EventType, Gesture } from 'vs/base/browser/touch'; </ins> function getMinimapLineHeight(renderMinimap: RenderMinimap): number { if (renderMinimap === RenderMinimap.Large) {


return Math.round(desiredSliderPosition / this._computedSliderRatio); } <ins> public getDesiredScrollTopFromTouchLocation(pageY: number): number { return Math.round((pageY - this.sliderHeight / 2) / this._computedSliderRatio); } </ins> public static create( options: MinimapOptions, viewportStartLineNumber: number,


private readonly _mouseDownListener: IDisposable; private readonly _sliderMouseMoveMonitor: GlobalMouseMoveMonitor<IStandardMouseMoveEventData>; private readonly _sliderMouseDownListener: IDisposable; <ins> private readonly _sliderTouchStartListener: IDisposable; private readonly _sliderTouchMoveListener: IDisposable; private readonly _sliderTouchEndListener: IDisposable; </ins> private _options: MinimapOptions; private _lastRenderData: RenderData | null; private _selections: Selection[] = []; private _selectionColor: Color | undefined; private _renderDecorations: boolean = false; <ins> private _gestureInProgress: boolean = false; </ins> private _buffers: MinimapBuffers | null; constructor(context: ViewContext) {


); } }); <ins> Gesture.addTarget(this._domNode.domNode); this._sliderTouchStartListener = dom.addDisposableListener(this._domNode.domNode, EventType.Start, (e: GestureEvent) => { e.preventDefault(); e.stopPropagation(); if (this._lastRenderData) { this._slider.toggleClassName('active', true); this._gestureInProgress = true; this.scrollDueToTouchEvent(e); } }); this._sliderTouchMoveListener = dom.addStandardDisposableListener(this._domNode.domNode, EventType.Change, (e: GestureEvent) => { e.preventDefault(); e.stopPropagation(); if (this._lastRenderData && this._gestureInProgress) { this.scrollDueToTouchEvent(e); } }); this._sliderTouchEndListener = dom.addStandardDisposableListener(this._domNode.domNode, EventType.End, (e: GestureEvent) => { e.preventDefault(); e.stopPropagation(); this._gestureInProgress = false; this._slider.toggleClassName('active', false); }); } private scrollDueToTouchEvent(touch: GestureEvent) { const startY = this._domNode.domNode.getBoundingClientRect().top; const scrollTop = this._lastRenderData!.renderedLayout.getDesiredScrollTopFromTouchLocation(touch.pageY - startY); this._context.viewLayout.setScrollPositionNow({ scrollTop: scrollTop }); </ins> } public dispose(): void { this._mouseDownListener.dispose(); this._sliderMouseMoveMonitor.dispose(); this._sliderMouseDownListener.dispose(); <ins> this._sliderTouchStartListener.dispose(); this._sliderTouchMoveListener.dispose(); this._sliderTouchEndListener.dispose(); </ins> super.dispose(); }


"native-watchdog": "0.3.0", "node-pty": "0.7.7", "semver": "^5.5.0", <del> "spdlog": "0.7.1", </del> <ins> "spdlog": "0.7.2", </ins> "sudo-prompt": "8.2.0", "v8-inspect-profiler": "^0.0.8", "vscode-chokidar": "1.6.4",


version "1.0.0" resolved "https://registry.yarnpkg.com/sparkles/-/sparkles-1.0.0.tgz#1acbbfb592436d10bbe8f785b7cc6f82815012c3" <del> spdlog@0.7.1: version "0.7.1" resolved "https://registry.yarnpkg.com/spdlog/-/spdlog-0.7.1.tgz#960b8cdced12e8c482d1df9fa65220789f276979" </del> <ins> spdlog@0.7.2: version "0.7.2" resolved "https://registry.yarnpkg.com/spdlog/-/spdlog-0.7.2.tgz#9298753d7694b9ee9bbfd7e01ea1e4c6ace1e64d" </ins> dependencies: bindings "^1.3.0" mkdirp "^0.5.1"


return candidate; } <del> if (element === document.body) { </del> <ins> if (element === this.scrollableElement.getDomNode() || element === document.body) { </ins> return null; } } while (element = element.parentElement);


import { Schemas } from 'vs/base/common/network'; import { IDialogService, IConfirmationResult, IConfirmation, getConfirmMessage } from 'vs/platform/dialogs/common/dialogs'; import { INotificationService, Severity } from 'vs/platform/notification/common/notification'; <ins> import { Constants } from 'vs/editor/common/core/uint'; </ins> export interface IEditableData { action: IAction;


export function incrementFileName(name: string, isFolder: boolean): string { const separators = '[.-_]'; <ins> const maxNumber = Constants.MAX_SAFE_SMALL_INTEGER; </ins> // file.1.txt=>file.2.txt let suffixFileRegex = RegExp('(.*' + separators + ')(d+)(..*)$'); if (!isFolder && name.match(suffixFileRegex)) { return name.replace(suffixFileRegex, (match, g1?, g2?, g3?) => { <del> return g1 + strings.pad(parseInt(g2) + 1, g2.length) + g3; </del> <ins> let number = parseInt(g2); return number < maxNumber ? g1 + strings.pad(number + 1, g2.length) + g3 : strings.format('{0}{1}.1{2}', g1, g2, g3); </ins> }); }


let prefixFileRegex = RegExp('(d+)(' + separators + '.*)(..*)$'); if (!isFolder && name.match(prefixFileRegex)) { return name.replace(prefixFileRegex, (match, g1?, g2?, g3?) => { <del> return strings.pad(parseInt(g1) + 1, g1.length) + g2 + g3; </del> <ins> let number = parseInt(g1); return number < maxNumber ? strings.pad(number + 1, g1.length) + g2 + g3 : strings.format('{0}{1}.1{2}', g1, g2, g3); </ins> }); }


// folder.1=>folder.2 if (isFolder && name.match(/(d+)$/)) { <del> return name.replace(/(d+)$/, (match: string, ...groups: any[]) => { return strings.pad(parseInt(groups[0]) + 1, groups[0].length); }); </del> <ins> return name.replace(/(d+)$/, (match: string, ...groups: any[]) => { let number = parseInt(groups[0]); return number < maxNumber ? strings.pad(number + 1, groups[0].length) : strings.format('{0}.1', groups[0]); }); </ins> } // 1.folder=>2.folder if (isFolder && name.match(/^(d+)/)) { <del> return name.replace(/^(d+)/, (match: string, ...groups: any[]) => { return strings.pad(parseInt(groups[0]) + 1, groups[0].length); }); </del> <ins> return name.replace(/^(d+)(.*)$/, (match: string, ...groups: any[]) => { let number = parseInt(groups[0]); return number < maxNumber ? strings.pad(number + 1, groups[0].length) + groups[1] : strings.format('{0}{1}.1', groups[0], groups[1]); }); </ins> } // file/folder=>file.1/folder.1


assert.strictEqual(result, 'test_2'); }); <ins> test('Increment file name with suffix version, too big number', function () { const name = 'test.9007199254740992.js'; const result = incrementFileName(name, false); assert.strictEqual(result, 'test.9007199254740992.1.js'); }); test('Increment folder name with suffix version, too big number', function () { const name = 'test.9007199254740992'; const result = incrementFileName(name, true); assert.strictEqual(result, 'test.9007199254740992.1'); }); </ins> test('Increment file name with prefix version', function () { const name = '1.test.js'; const result = incrementFileName(name, false);


assert.strictEqual(result, '2_test.js'); }); <del> test('Increment folder name with suffix version', function () { </del> <ins> test('Increment file name with prefix version, too big number', function () { const name = '9007199254740992.test.js'; const result = incrementFileName(name, false); assert.strictEqual(result, '9007199254740992.test.1.js'); }); test('Increment folder name with prefix version', function () { </ins> const name = '1.test'; const result = incrementFileName(name, true); assert.strictEqual(result, '2.test'); }); <del> test('Increment folder name with suffix version, trailing zeros', function () { </del> <ins> test('Increment folder name with prefix version, too big number', function () { const name = '9007199254740992.test'; const result = incrementFileName(name, true); assert.strictEqual(result, '9007199254740992.test.1'); }); test('Increment folder name with prefix version, trailing zeros', function () { </ins> const name = '001.test'; const result = incrementFileName(name, true); assert.strictEqual(result, '002.test'); }); <del> test('Increment folder name with suffix version  with `-` as separator', function () { </del> <ins> test('Increment folder name with prefix version  with `-` as separator', function () { </ins> const name = '1-test'; const result = incrementFileName(name, true); assert.strictEqual(result, '2-test');


import { nullTokenize2 } from 'vs/editor/common/modes/nullMode'; import { generateTokensCSSForColorMap } from 'vs/editor/common/modes/supports/tokenization'; import { Color } from 'vs/base/common/color'; <ins> import { INotificationService } from 'vs/platform/notification/common/notification'; </ins> import URI from 'vs/base/common/uri'; export class TMScopeRegistry {


private _scopeRegistry: TMScopeRegistry; private _injections: { [scopeName: string]: string[]; }; private _injectedEmbeddedLanguages: { [scopeName: string]: IEmbeddedLanguagesMap[]; }; <ins> private _notificationService: INotificationService; </ins> private _languageToScope: Map<string, string>; private _styleElement: HTMLStyleElement;


constructor( @IModeService modeService: IModeService, <del> @IWorkbenchThemeService themeService: IWorkbenchThemeService </del> <ins> @IWorkbenchThemeService themeService: IWorkbenchThemeService, @INotificationService notificationService: INotificationService </ins> ) { this._styleElement = dom.createStyleSheet(); this._styleElement.className = 'vscode-tokens-styles';


this._injections = {}; this._injectedEmbeddedLanguages = {}; this._languageToScope = new Map<string, string>(); <ins> this._notificationService = notificationService; </ins> this._grammarRegistry = null;


private registerDefinition(modeId: string): void { this._createGrammar(modeId).then((r) => { <del> TokenizationRegistry.register(modeId, new TMTokenization(this._scopeRegistry, r.languageId, r.grammar, r.initialState, r.containsEmbeddedLanguages)); </del> <ins> TokenizationRegistry.register(modeId, new TMTokenization(this._scopeRegistry, r.languageId, r.grammar, r.initialState, r.containsEmbeddedLanguages, this._notificationService)); </ins> }, onUnexpectedError); } }


private readonly _containsEmbeddedLanguages: boolean; private readonly _seenLanguages: boolean[]; private readonly _initialState: StackElement; <ins> private _tokenizationWarningAlreadyShown: boolean; </ins> <del> constructor(scopeRegistry: TMScopeRegistry, languageId: LanguageId, grammar: IGrammar, initialState: StackElement, containsEmbeddedLanguages: boolean) { </del> <ins> constructor(scopeRegistry: TMScopeRegistry, languageId: LanguageId, grammar: IGrammar, initialState: StackElement, containsEmbeddedLanguages: boolean, @INotificationService private notificationService: INotificationService) { </ins> this._scopeRegistry = scopeRegistry; this._languageId = languageId; this._grammar = grammar;


// Do not attempt to tokenize if a line has over 20k if (line.length >= 20000) { <ins> if (!this._tokenizationWarningAlreadyShown) { this._tokenizationWarningAlreadyShown = true; this.notificationService.warn(nls.localize('too many characters', "Tokenization is skipped for lines longer than 20k characters for performance reasons.")); } </ins> console.log(`Line (${line.substr(0, 15)}...): longer than 20k characters, tokenization skipped.`); return nullTokenize2(this._languageId, line, state, offsetDelta); }


'use strict'; <ins> import { localize } from 'vs/nls'; </ins> import { append, $, addClass, removeClass, toggleClass } from 'vs/base/browser/dom'; import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { Action } from 'vs/base/common/actions';


private updateRecommendationStatus(extension: IExtension, data: ITemplateData) { const extRecommendations = this.extensionTipsService.getAllRecommendationsWithReason(); <ins> let ariaLabel = extension.displayName + '. '; </ins> if (!extRecommendations[extension.id.toLowerCase()]) { <del> data.root.setAttribute('aria-label', extension.displayName); data.root.title = ''; </del> removeClass(data.root, 'recommended'); <ins> data.root.title = ''; </ins> } else { <del> data.root.setAttribute('aria-label', extension.displayName + '. ' + extRecommendations[extension.id]); data.root.title = extRecommendations[extension.id.toLowerCase()].reasonText; </del> addClass(data.root, 'recommended'); <ins> ariaLabel += extRecommendations[extension.id.toLowerCase()].reasonText + ' '; data.root.title = extRecommendations[extension.id.toLowerCase()].reasonText; </ins> } <ins> ariaLabel += localize('viewExtensionDetailsAria', "Press enter for extension details."); data.root.setAttribute('aria-label', ariaLabel); </ins> } disposeTemplate(data: ITemplateData): void {


this.disposables.push(this.list.onOpen(e => { let isSingleClick = false; let isDoubleClick = false; <ins> let isMiddleClick = false; </ins> let openToSide = false; const browserEvent = e.browserEvent; if (browserEvent instanceof MouseEvent) { isSingleClick = browserEvent.detail === 1; isDoubleClick = browserEvent.detail === 2; <ins> isMiddleClick = browserEvent.button === 1; </ins> openToSide = (browserEvent.ctrlKey || browserEvent.metaKey || browserEvent.altKey); } const focused = this.list.getFocusedElements(); const element = focused.length ? focused[0] : undefined; <ins> if (isMiddleClick) { if (element instanceof Breakpoint) { this.debugService.removeBreakpoints(element.getId()); } else if (element instanceof FunctionBreakpoint) { this.debugService.removeFunctionBreakpoints(element.getId()); } return; } </ins> if (element instanceof Breakpoint) { openBreakpointSource(element, openToSide, isSingleClick, this.debugService, this.editorService).done(undefined, onUnexpectedError); }


this.searchBox.setModel(this.modelService.createModel('', null, uri.parse('extensions:searchinput'), true)); this.disposables.push(this.searchBox.onDidPaste(() => { <del> this.searchBox.setValue(this.searchBox.getValue().replace(/s+/g, ' ')); </del> <ins> let trimmed = this.searchBox.getValue().replace(/s+/g, ' '); this.searchBox.setValue(trimmed); </ins> this.searchBox.setScrollTop(0); <ins> this.searchBox.setPosition(new Position(1, trimmed.length + 1)); </ins> })); this.disposables.push(this.searchBox.onDidFocusEditorText(() => addClass(this.monacoStyleContainer, 'synthetic-focus'))); this.disposables.push(this.searchBox.onDidBlurEditorText(() => removeClass(this.monacoStyleContainer, 'synthetic-focus')));


}, "Insert link": { "prefix": "link", <del> "body": "[${1:text}](http://${2:link})$0", </del> <ins> "body": "[${1:text}](https://${2:link})$0", </ins> "description": "Insert link" }, "Insert image": { "prefix": "image", <del> "body": "![${1:alt}](http://${2:link})$0", </del> <ins> "body": "![${1:alt}](https://${2:link})$0", </ins> "description": "Insert image" } }


this.addDisposable(this._configurationService.onDidChangeConfiguration(e => { if (e.affectsConfiguration('terminal.integrated')) { this.updateConfig(); <ins> // HACK: Trigger another async layout to ensure xterm's CharMeasure is ready to use, // this hack can be removed when https://github.com/xtermjs/xterm.js/issues/702 is // supported. this.setVisible(this._isVisible); </ins> } if (e.affectsConfiguration('editor.accessibilitySupport')) { this.updateAccessibilitySupport();


VERTICAL_REVERSE, } <ins> export interface ActionTrigger { keys: KeyCode[]; keyDown: boolean; } </ins> export interface IActionItemProvider { (action: IAction): IActionItem; }


actionRunner?: IActionRunner; ariaLabel?: string; animated?: boolean; <ins> triggerKeys?: ActionTrigger; </ins> } let defaultOptions: IActionBarOptions = { orientation: ActionsOrientation.HORIZONTAL, <del> context: null </del> <ins> context: null, triggerKeys: { keys: [KeyCode.Enter, KeyCode.Space], keyDown: false } </ins> }; export interface IActionOptions extends IActionItemOptions {


this.focusNext(); } else if (event.equals(KeyCode.Escape)) { this.cancel(); <del> } else if (event.equals(KeyCode.Enter) || event.equals(KeyCode.Space)) { // Nothing, just staying out of the else branch </del> <ins> } else if (this.isTriggerKeyEvent(event)) { // Staying out of the else branch even if not triggered if (this.options.triggerKeys && this.options.triggerKeys.keyDown) { this.doTrigger(event); } </ins> } else { eventHandled = false; }


let event = new StandardKeyboardEvent(e as KeyboardEvent); // Run action on Enter/Space <del> if (event.equals(KeyCode.Enter) || event.equals(KeyCode.Space)) { this.doTrigger(event); </del> <ins> if (this.isTriggerKeyEvent(event)) { if (!this.options.triggerKeys.keyDown) { this.doTrigger(event); } </ins> event.preventDefault(); event.stopPropagation(); }


} } <ins> private isTriggerKeyEvent(event: StandardKeyboardEvent): boolean { let ret = false; if (this.options.triggerKeys) { this.options.triggerKeys.keys.forEach(keyCode => { ret = ret || event.equals(keyCode); }); } return ret; } </ins> private updateFocusedItem(): void { for (let i = 0; i < this.actionsList.children.length; i++) { let elem = this.actionsList.children[i];


actionItemProvider: action => this.doGetActionItem(action, options, parentData), context: options.context, actionRunner: options.actionRunner, <del> ariaLabel: options.ariaLabel </del> <ins> ariaLabel: options.ariaLabel, triggerKeys: { keys: [KeyCode.Enter], keyDown: true } </ins> }); this.actionsList.setAttribute('role', 'menu');


if (defaultUri && defaultUri.scheme !== Schemas.file) { return Promise.reject(new Error('Not supported - Open-dialogs can only be opened on `file`-uris.')); } <del> const filters = []; if (options.filters) { for (let name in options.filters) { filters.push({ name, extensions: options.filters[name] }); } } </del> const newOptions: OpenDialogOptions = { title: options.title, defaultPath: defaultUri && defaultUri.fsPath, buttonLabel: options.openLabel, <del> filters, </del> <ins> filters: options.filters, </ins> properties: [] }; newOptions.properties.push('createDirectory');


resetStateMachine = true; } } else if (state === State.End) { <del> const chClass = classifier.get(chCode); </del> <ins> let chClass: CharacterClass; if (chCode === CharCode.OpenSquareBracket) { // Allow for the authority part to contain ipv6 addresses which contain [ and ] hasOpenSquareBracket = true; chClass = CharacterClass.None; } else { chClass = classifier.get(chCode); } </ins> // Check if character terminates link if (chClass === CharacterClass.ForceTermination) {


'                                                                                https://msdn.microsoft.com/en-us/library/windows/desktop/ms687414(v=vs.85).aspx                                  ' ); }); <ins> test('issue #62278: "Ctrl + click to follow link" for IPv6 URLs', () => { assertLink( 'let x = "http://[::1]:5000/connect/token"', '         http://[::1]:5000/connect/token  ' ); }); </ins> });


const position = this.getWindowPosition(this._issueParentWindow, 700, 800); this._issueWindow = new BrowserWindow({ <ins> fullscreen: false, </ins> width: position.width, height: position.height, minWidth: 300,


this._processExplorerWindow = new BrowserWindow({ skipTaskbar: true, resizable: true, <ins> fullscreen: false, </ins> width: position.width, height: position.height, minWidth: 300,


} const resultsSelectedBackground = theme.getColor(peekViewResultsSelectionBackground); if (resultsSelectedBackground) { <del> collector.addRule(`.monaco-editor .reference-zone-widget .ref-tree .monaco-tree.focused .monaco-tree-rows > .monaco-tree-row.selected:not(.highlighted) { background-color: ${resultsSelectedBackground}; }`); </del> <ins> collector.addRule(`.monaco-editor .reference-zone-widget .ref-tree .monaco-list:focus .monaco-list-rows > .monaco-list-row.selected:not(.highlighted) { background-color: ${resultsSelectedBackground}; }`); </ins> } const resultsSelectedForeground = theme.getColor(peekViewResultsSelectionForeground); if (resultsSelectedForeground) { <del> collector.addRule(`.monaco-editor .reference-zone-widget .ref-tree .monaco-tree.focused .monaco-tree-rows > .monaco-tree-row.selected:not(.highlighted) { color: ${resultsSelectedForeground} !important; }`); </del> <ins> collector.addRule(`.monaco-editor .reference-zone-widget .ref-tree .monaco-list:focus .monaco-list-rows > .monaco-list-row.selected:not(.highlighted) { color: ${resultsSelectedForeground} !important; }`); </ins> } const editorBackground = theme.getColor(peekViewEditorBackground); if (editorBackground) {


}, description: { description: nls.localize('snippetSchema.json.description', 'The snippet description.'), <del> type: 'string' </del> <ins> type: ['string', 'array'] </ins> } }, additionalProperties: false


body = body.join('n'); } <ins> if (Array.isArray(description)) { description = description.join('n'); } </ins> if ((typeof prefix !== 'string' && !Array.isArray(prefix)) || typeof body !== 'string') { return; }


return; } <del> if (this.extension.type !== ExtensionType.User) { this.enabled = false; this.class = UpdateAction.DisabledClass; this.label = this.getLabel(); return; } </del> const canInstall = await this.extensionsWorkbenchService.canInstall(this.extension); const isInstalled = this.extension.state === ExtensionState.Installed;


import { IExtensionManifestPropertiesService } from 'vs/workbench/services/extensions/common/extensionManifestPropertiesService'; import { IExtensionService, IExtensionsStatus } from 'vs/workbench/services/extensions/common/extensions'; import { ExtensionEditor } from 'vs/workbench/contrib/extensions/browser/extensionEditor'; <ins> import { isWeb } from 'vs/base/common/platform'; </ins> interface IExtensionStateProvider<T> { (extension: Extension): T;


if (!this.gallery || !this.local) { return false; } <del> if (this.type !== ExtensionType.User) { return false; } </del> if (!this.local.preRelease && this.gallery.properties.isPreReleaseVersion) { return false; }


this.queryLocal().then(() => { this.resetIgnoreAutoUpdateExtensions(); this.eventuallyCheckForUpdates(true); <del> // Always auto update builtin extensions if (!this.isAutoUpdateEnabled()) { </del> <ins> // Always auto update builtin extensions in web if (isWeb && !this.isAutoUpdateEnabled()) { </ins> this.autoUpdateBuiltinExtensions(); } });


} const infos: IExtensionInfo[] = []; for (const installed of this.local) { <del> if (installed.type === ExtensionType.User && (!onlyBuiltin || installed.isBuiltin)) { </del> <ins> if (!onlyBuiltin || installed.isBuiltin) { </ins> infos.push({ ...installed.identifier, preRelease: !!installed.local?.preRelease }); } }


assert.strictEqual(extension.outdated, true); }); <del> test('extension is not outdated when local is built in and older than gallery', () => { </del> <ins> test('extension is outdated when local is built in and older than gallery', () => { </ins> const extension = instantiationService.createInstance(Extension, () => ExtensionState.Installed, undefined, aLocalExtension('somext', { version: '1.0.0' }, { type: ExtensionType.System }), aGalleryExtension('somext', { version: '1.0.1' })); <del> assert.strictEqual(extension.outdated, false); </del> <ins> assert.strictEqual(extension.outdated, true); </ins> }); test('extension is outdated when local and gallery are on same version but on different target platforms', () => {


}); test('findFiles', () => { <del> return vscode.workspace.findFiles('*.png').then((res) => { </del> <ins> return vscode.workspace.findFiles('**/*.png').then((res) => { assert.equal(res.length, 2); assert.equal(basename(vscode.workspace.asRelativePath(res[0])), 'image.png'); }); }); test('findFiles, exclude', () => { return vscode.workspace.findFiles('**/*.png', '**/sub/**').then((res) => { </ins> assert.equal(res.length, 1); assert.equal(basename(vscode.workspace.asRelativePath(res[0])), 'image.png'); });


disregardSearchExcludeSettings: true, disregardIgnoreFiles: true, includePattern, <ins> excludePattern: typeof excludePatternOrDisregardExcludes === 'string' ? excludePatternOrDisregardExcludes : undefined, </ins> _reason: 'startFileSearch' });


const query = queryBuilder.file(folders, { _reason: 'checkExists', includePattern: includes.join(', '), <ins> expandPatterns: true, </ins> exists: true });


if (options.includePattern) { includeSearchPathsInfo = options.expandPatterns ? this.parseSearchPaths(options.includePattern) : <del> { pattern: patternListToIExpression(...splitGlobPattern(options.includePattern)) }; </del> <ins> { pattern: patternListToIExpression(options.includePattern) }; </ins> } let excludeSearchPathsInfo: ISearchPathsInfo = {}; if (options.excludePattern) { excludeSearchPathsInfo = options.expandPatterns ? this.parseSearchPaths(options.excludePattern) : <del> { pattern: patternListToIExpression(...splitGlobPattern(options.excludePattern)) }; </del> <ins> { pattern: patternListToIExpression(options.excludePattern) }; </ins> } // Build folderQueries from searchPaths, if given, otherwise folderResources


}); }); <del> test('splits glob pattern even with expandPatterns disabled', () => { </del> <ins> test('does not split glob pattern when expandPatterns disabled', () => { </ins> assertEqualQueries( queryBuilder.file([ROOT_1_URI], { includePattern: '**/foo, **/bar' }), {


}], type: QueryType.File, includePattern: { <del> '**/foo': true, '**/bar': true </del> <ins> '**/foo, **/bar': true </ins> } }); });


} // Handle empty to restore <del> if (emptyToRestore.length > 0) { emptyToRestore.forEach(emptyWindowBackupInfo => { </del> <ins> const allEmptyToRestore = arrays.distinct(emptyToRestore, info => info.backupFolder); // prevent duplicates if (allEmptyToRestore.length > 0) { allEmptyToRestore.forEach(emptyWindowBackupInfo => { </ins> const remoteAuthority = emptyWindowBackupInfo.remoteAuthority; const fileInputsForWindow = (fileInputs && fileInputs.remoteAuthority === remoteAuthority) ? fileInputs : undefined;


// Rewrite `#editor.fontSize#` to link format text = fixSettingLinks(text); <del> const renderedMarkdown = renderMarkdown({ value: text }, { </del> <ins> const renderedMarkdown = renderMarkdown({ value: text, isTrusted: true }, { </ins> actionHandler: { callback: (content: string) => { if (startsWith(content, '#')) {


// Filename not allowed this.filePickBox.validationMessage = nls.localize('remoteFileDialog.validateBadFilename', 'Please enter a valid file name.'); return Promise.resolve(false); <del> } else if (!statDirname || !statDirname.isDirectory) { </del> <ins> } else if (!statDirname) { </ins> // Folder to save in doesn't exist <ins> const message = nls.localize('remoteFileDialog.validateCreateDirectory', 'The folder {0} does not exist. Would you like to create it?', resources.basename(resources.dirname(uri))); return this.yesNoPrompt(uri, message); } else if (!statDirname.isDirectory) { </ins> this.filePickBox.validationMessage = nls.localize('remoteFileDialog.validateNonexistentDir', 'Please enter a path that exists.'); return Promise.resolve(false); }


const picks = formatter.map((formatter, index) => { return <IIndexedPick>{ index, <del> label: formatter.displayName || formatter.extensionId || '?' </del> <ins> label: formatter.displayName || formatter.extensionId || '?', description: formatter.extensionId && formatter.extensionId.value </ins> }; }); const langName = this._modeService.getLanguageName(document.getModeId()) || document.getModeId();


{ "open": "{", "close": "}" }, { "open": "(", "close": ")" }, { "open": "'", "close": "'", "notIn": ["string", "comment"] }, <del> { "open": """, "close": """, "notIn": ["string"] } </del> <ins> { "open": """, "close": """, "notIn": ["string"] }, { "open": "/*", "close": " */", "notIn": ["string", "comment"] } </ins> ], "surroundingPairs": [ ["{", "}"],


return; } <ins> this._set(nodes, false, browserEvent); } private _set(nodes: ITreeNode<T, any>[], silent: boolean, browserEvent?: UIEvent): void { </ins> this.nodes = [...nodes]; this.elements = undefined; this._nodeSet = undefined; <del> const that = this; this._onDidChange.fire({ get elements() { return that.get(); }, browserEvent }); </del> <ins> if (!silent) { const that = this; this._onDidChange.fire({ get elements() { return that.get(); }, browserEvent }); } </ins> } get(): T[] {


insertedNodes.forEach(node => dfs(node, insertedNodesVisitor)); const nodes: ITreeNode<T, any>[] = []; <ins> let silent = true; </ins> for (const node of this.nodes) { const id = this.identityProvider.getId(node.element).toString();


if (insertedNode) { nodes.push(insertedNode); <ins> } else { silent = false; </ins> } } } <del> this.set(nodes); </del> <ins> this._set(nodes, silent); </ins> } private createNodeSet(): Set<ITreeNode<T, any>> {


this.parent.removeAttribute('aria-label'); this.parent.title = this.getTooltip(); if (this.extension) { <del> this.parent.setAttribute('aria-label', localize('extension-arialabel', "{0}. {1} Press enter for extension details.", this.extension.displayName)); </del> <ins> this.parent.setAttribute('aria-label', localize('extension-arialabel', "{0}. Press enter for extension details.", this.extension.displayName)); </ins> } }


return; } <del> const extensionName = 'vscode-smoketest-check'; </del> await app.workbench.extensions.openExtensionsViewlet(); <del> await app.workbench.extensions.installExtension(extensionName); </del> <ins> await app.workbench.extensions.installExtension('michelkaporin.vscode-smoketest-check', 'vscode-smoketest-check'); </ins> await app.workbench.extensions.waitForExtensionsViewlet(); await app.workbench.quickopen.runCommand('Smoke Test Check');


await this.code.waitForElement(SEARCH_BOX); } <del> async searchForExtension(name: string): Promise<any> { </del> <ins> async searchForExtension(id: string): Promise<any> { </ins> await this.code.waitAndClick(SEARCH_BOX); await this.code.waitForActiveElement(SEARCH_BOX); <del> await this.code.waitForTypeInEditor(SEARCH_BOX, `name:"${name}"`); </del> <ins> await this.code.waitForTypeInEditor(SEARCH_BOX, `@id:${id}`); </ins> } <del> async installExtension(name: string): Promise<void> { await this.searchForExtension(name); </del> <ins> async installExtension(id: string, name: string): Promise<void> { await this.searchForExtension(id); </ins> const ariaLabel = `${name}. Press enter for extension details.`; await this.code.waitAndClick(`div.extensions-viewlet[id="workbench.view.extensions"] .monaco-list-row[aria-label="${ariaLabel}"] .extension li[class='action-item'] .extension-action.install`); await this.code.waitForElement(`.extension-editor .monaco-action-bar .action-item:not(.disabled) .extension-action.uninstall`);


return; } <del> const extensionName = 'German Language Pack for Visual Studio Code'; </del> await app.workbench.extensions.openExtensionsViewlet(); <del> await app.workbench.extensions.installExtension(extensionName); </del> <ins> await app.workbench.extensions.installExtension('ms-ceintl.vscode-language-pack-de', 'German Language Pack for Visual Studio Code'); </ins> await app.restart({ extraArgs: ['--locale=DE'] }); });


import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IWindowService } from 'vs/platform/windows/common/windows'; <del> import Severity from 'vs/base/common/severity'; </del> import { URI } from 'vs/base/common/uri'; import { IExtension, ExtensionState, IExtensionsWorkbenchService, AutoUpdateConfigurationKey, AutoCheckUpdatesConfigurationKey } from 'vs/workbench/contrib/extensions/common/extensions'; import { IEditorService, SIDE_GROUP, ACTIVE_GROUP } from 'vs/workbench/services/editor/common/editorService';


return this.windowService.focusWindow() .then(() => this.open(extension)); } return this.queryGallery({ names: [extensionId], source: 'uri' }, CancellationToken.None).then(result => { if (result.total < 1) { return Promise.resolve(null);


const extension = result.firstPage[0]; return this.windowService.focusWindow().then(() => { <del> return this.open(extension).then(() => { this.notificationService.prompt( Severity.Info, nls.localize('installConfirmation', "Would you like to install the '{0}' extension?", extension.displayName, extension.publisher), [{ label: nls.localize('install', "Install"), run: () => this.install(extension).then(undefined, error => this.onError(error)) }], { sticky: true } ); }); </del> <ins> return this.open(extension); </ins> }); }); }).then(undefined, error => this.onError(error));


import { lstat, Stats } from 'fs'; import * as os from 'os'; import * as path from 'path'; <del> import { commands, Disposable, LineChange, MessageOptions, OutputChannel, Position, ProgressLocation, QuickPickItem, Range, SourceControlResourceState, TextDocumentShowOptions, TextEditor, Uri, ViewColumn, window, workspace, WorkspaceEdit, WorkspaceFolder } from 'vscode'; </del> <ins> import { Selection, commands, Disposable, LineChange, MessageOptions, OutputChannel, Position, ProgressLocation, QuickPickItem, Range, SourceControlResourceState, TextDocumentShowOptions, TextEditor, Uri, ViewColumn, window, workspace, WorkspaceEdit, WorkspaceFolder } from 'vscode'; </ins> import TelemetryReporter from 'vscode-extension-telemetry'; import * as nls from 'vscode-nls'; import { Branch, GitErrorCodes, Ref, RefType, Status } from './api/git';


} await this._stageChanges(textEditor, [changes[index]]); <ins> const firstStagedLine = changes[index].modifiedStartLineNumber - 1; textEditor.selections = [new Selection(firstStagedLine, 0, firstStagedLine, 0)]; </ins> } @command('git.stageSelectedRanges', { diff: true })


} await this._revertChanges(textEditor, [...changes.slice(0, index), ...changes.slice(index + 1)]); <ins> const firstStagedLine = changes[index].modifiedStartLineNumber - 1; textEditor.selections = [new Selection(firstStagedLine, 0, firstStagedLine, 0)]; </ins> } @command('git.revertSelectedRanges', { diff: true })


return; } <ins> const selectionsBeforeRevert = textEditor.selections; </ins> await this._revertChanges(textEditor, selectedChanges); <ins> textEditor.selections = selectionsBeforeRevert; </ins> } private async _revertChanges(textEditor: TextEditor, changes: LineChange[]): Promise<void> {


const originalUri = toGitUri(modifiedUri, '~'); const originalDocument = await workspace.openTextDocument(originalUri); <del> const selectionsBeforeRevert = textEditor.selections; </del> const visibleRangesBeforeRevert = textEditor.visibleRanges; const result = applyLineChanges(originalDocument, modifiedDocument, changes);


await modifiedDocument.save(); <del> textEditor.selections = selectionsBeforeRevert; </del> textEditor.revealRange(visibleRangesBeforeRevert[0]); }


<key>function</key> <dict> <key>begin</key> <del> <string>((?i:function|filter|configuration|workflow))s+((?:p{L}|d|_|-|.)+)</string> </del> <ins> <string>(?<!S)(?i)(function|filter|configuration|workflow)s+(?:(global|local|script|private):)?((?:p{L}|d|_|-|.)+)</string> </ins> <key>beginCaptures</key> <dict> <key>0</key>


<key>2</key> <dict> <key>name</key> <del> <string>entity.name.function</string> </del> <ins> <string>storage.modifier.scope.powershell</string> </dict> <key>3</key> <dict> <key>name</key> <string>entity.name.function.powershell</string> </ins> </dict> </dict> <key>end</key>


<key>uuid</key> <string>f8f5ffb0-503e-11df-9879-0800200c9a66</string> </dict> <del> </plist> </del>  No newline at end of file <ins> </plist> </ins>


if (jsFlags) { app.commandLine.appendSwitch('--js-flags', jsFlags); } <del> // Disable smooth scrolling for Webviews if (cliArgs['disable-smooth-scrolling']) { app.commandLine.appendSwitch('disable-smooth-scrolling'); } </del> } /**


.then(extensions => { for (const extension of extensions) { const requireReload = !(extension.local && this.extensionService.canAddExtension(toExtensionDescription(extension.local))); <del> const message = requireReload ? localize('InstallVSIXAction.successReload', "Please reload Visual Studio Code to complete installing the extension {0}.", extension.identifier.id) : localize('InstallVSIXAction.success', "Completed installing the extension {0}.", extension.identifier.id); </del> <ins> const message = requireReload ? localize('InstallVSIXAction.successReload', "Please reload Visual Studio Code to complete installing the extension {0}.", extension.displayName || extension.name) : localize('InstallVSIXAction.success', "Completed installing the extension {0}.", extension.displayName || extension.name); </ins> const actions = requireReload ? [{ label: localize('InstallVSIXAction.reloadNow', "Reload Now"), run: () => this.windowService.reloadWindow()


export class AbstractVariableResolverService implements IConfigurationResolverService { <ins> static readonly VARIABLE_LHS = '${'; </ins> static readonly VARIABLE_REGEXP = /${(.*?)}/g; declare readonly _serviceBrand: undefined;


// loop through all variables occurrences in 'value' const replaced = value.replace(AbstractVariableResolverService.VARIABLE_REGEXP, (match: string, variable: string) => { <ins> // disallow attempted nesting, see #77289 if (variable.includes(AbstractVariableResolverService.VARIABLE_LHS)) { return match; } </ins> let resolvedValue = this.evaluateSingleVariable(match, variable, folderUri, commandValueMapping);


} }); <ins> test('disallows nested keys (#77289)', () => { assert.strictEqual(configurationResolverService!.resolve(workspace, '${env:key1} ${env:key1${env:key2}}'), 'Value for key1 ${env:key1${env:key2}}'); }); </ins> // test('substitute keys and values in object', () => { // 	const myObject = { // 		'${workspaceRootFolderName}': '${lineNumber}',


} } }); <ins> KeybindingsRegistry.registerCommandAndKeybindingRule({ id: 'list.focusParent', weight: KeybindingWeight.WorkbenchContrib, when: WorkbenchListFocusContextKey, primary: KeyCode.Shift | KeyCode.LeftArrow, handler: (accessor) => { const focused = accessor.get(IListService).lastFocusedList; // Tree only if (focused && !(focused instanceof List || focused instanceof PagedList)) { if (focused instanceof ObjectTree || focused instanceof DataTree || focused instanceof AsyncDataTree) { const tree = focused; const focusedElements = tree.getFocus(); if (focusedElements.length === 0) { return; } const focus = focusedElements[0]; const parent = tree.getParentElement(focus); if (parent) { const fakeKeyboardEvent = new KeyboardEvent('keydown'); tree.setFocus([parent], fakeKeyboardEvent); tree.reveal(parent); } } else { const tree = focused; tree.focusParent({ origin: 'keyboard' }); } } } }); </ins>  No newline at end of file


// If a single setting is being refreshed, it's ok to refresh now if that is not the focused setting if (key) { const focusedKey = focusedSetting.getAttribute(AbstractSettingRenderer.SETTING_KEY_ATTR); <del> /** * Update `list`s live if focused item is whole list or list item, * as they have a separate "submit edit" step built in before this */ if ( focusedKey === key && !DOM.hasClass(focusedSetting, 'setting-item-list') && !DOM.hasClass(focusedSetting, 'setting-item-contents') </del> <ins> if (focusedKey === key && // update `list`s live, as they have a separate "submit edit" step built in before this (focusedSetting.parentElement && !DOM.hasClass(focusedSetting.parentElement, 'setting-item-list')) </ins> ) { this.updateModifiedLabelForKey(key);


const onKeyDown = Event.chain(domEvent(this.view.getHTMLElement(), 'keydown')) .filter(e => !isInputElement(e.target as HTMLElement) || e.target === this.filterOnTypeDomNode) <del> .filter(e => e.key !== 'Dead') </del> <ins> .filter(e => e.key !== 'Dead' && !/^Media/.test(e.key)) </ins> .map(e => new StandardKeyboardEvent(e)) .filter(this.keyboardNavigationEventFilter || (() => true)) .filter(() => this.automaticKeyboardNavigation || this.triggered)


private async doRefresh(elements: ITreeItem[]): Promise<void> { if (this.tree) { this.refreshing = true; <del> await Promise.all(elements.map(element => this.tree.updateChildren(element, true))); elements.map(element => this.tree.rerender(element)); </del> <ins> const parents: Set<ITreeItem> = new Set<ITreeItem>(); elements.forEach(element => { if (element !== this.root) { const parent = this.tree.getParentElement(element); parents.add(parent); } else { parents.add(element); } }); await Promise.all(Array.from(parents.values()).map(element => this.tree.updateChildren(element, true))); </ins> this.refreshing = false; this.updateContentAreas(); if (this.focused) {


} } <del> const dataPaths: string[] = params.initializationOptions.dataPaths; </del> <ins> const dataPaths: string[] = params.initializationOptions.dataPaths || []; </ins> const customDataProviders = getDataProviders(dataPaths); function getClientCapability<T>(name: string, def: T) {


viewStates[handle] = { visible: input === group.activeEditor, active: input === activeInput, <del> position: editorGroupToViewColumn(this._editorGroupService, group.id || 0), </del> <ins> position: editorGroupToViewColumn(this._editorGroupService, group.id), </ins> }; } }


} private onDidClickLink(handle: WebviewPanelHandle, link: URI): void { <del> if (!link) { return; } </del> const webview = this.getWebviewEditorInput(handle); if (this.isSupportedLink(webview, link)) { this._openerService.open(link);


return; case 'did-click-link': <del> let [uri] = event.args; </del> <ins> const [uri] = event.args; </ins> this._onDidClickLink.fire(URI.parse(uri)); return;


clientY: rawEvent.clientY + bounds.top, })); return; <del> } catch (TypeError) { </del> <ins> } catch { </ins> // CustomEvent was treated as MouseEvent so don't do anything - https://github.com/microsoft/vscode/issues/78915 return; } } case 'did-set-content':


export function addDisposableNonBubblingMouseOutListener(node: Element, handler: (event: MouseEvent) => void): IDisposable { return addDisposableListener(node, 'mouseout', (e: MouseEvent) => { // Mouse out bubbles, so this is an attempt to ignore faux mouse outs coming from children elements <del> let toElement: Node | null = <Node>(e.relatedTarget || e.target); </del> <ins> let toElement: Node | null = <Node>(e.relatedTarget); </ins> while (toElement && toElement !== node) { toElement = toElement.parentNode; }


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 <del> let toElement: Node | null = <Node>(e.relatedTarget || e.target); </del> <ins> let toElement: Node | null = <Node>(e.relatedTarget); </ins> while (toElement && toElement !== node) { toElement = toElement.parentNode; }


export function buildReplaceStringWithCasePreserved(matches: string[] | null, pattern: string): string { if (matches && (matches[0] !== '')) { <ins> const containsHyphens = validateSpecificSpecialCharacter(matches, pattern, '-'); const containsUnderscores = validateSpecificSpecialCharacter(matches, pattern, '_'); if (containsHyphens && !containsUnderscores) { return buildReplaceStringForSpecificSpecialCharacter(matches, pattern, '-'); } else if (!containsHyphens && containsUnderscores) { return buildReplaceStringForSpecificSpecialCharacter(matches, pattern, '_'); } </ins> if (matches[0].toUpperCase() === matches[0]) { return pattern.toUpperCase(); } else if (matches[0].toLowerCase() === matches[0]) { return pattern.toLowerCase(); } else if (strings.containsUppercaseCharacter(matches[0][0])) { <del> const containsHyphens = validateSpecificSpecialCharacter(matches, pattern, '-'); const containsUnderscores = validateSpecificSpecialCharacter(matches, pattern, '_'); if (containsHyphens && !containsUnderscores) { return buildReplaceStringForSpecificSpecialCharacter(matches, pattern, '-'); } else if (!containsHyphens && containsUnderscores) { return buildReplaceStringForSpecificSpecialCharacter(matches, pattern, '_'); } else { return pattern[0].toUpperCase() + pattern.substr(1); } </del> <ins> return pattern[0].toUpperCase() + pattern.substr(1); </ins> } else { // we don't understand its pattern yet. return pattern;


assert.equal(buildReplaceStringWithCasePreserved(actual, 'newfoo-newbar-newabc'), 'Newfoo-Newbar-Newabc'); actual = ['Foo-Bar-abc']; assert.equal(buildReplaceStringWithCasePreserved(actual, 'newfoo-newbar'), 'Newfoo-newbar'); <ins> actual = ['foo-Bar']; assert.equal(buildReplaceStringWithCasePreserved(actual, 'newfoo-newbar'), 'newfoo-Newbar'); actual = ['foo-BAR']; assert.equal(buildReplaceStringWithCasePreserved(actual, 'newfoo-newbar'), 'newfoo-NEWBAR'); </ins> actual = ['Foo_Bar']; assert.equal(buildReplaceStringWithCasePreserved(actual, 'newfoo_newbar'), 'Newfoo_Newbar');


assert.equal(buildReplaceStringWithCasePreserved(actual, 'newfoo_newbar'), 'Newfoo_newbar'); actual = ['Foo_Bar-abc']; assert.equal(buildReplaceStringWithCasePreserved(actual, 'newfoo_newbar-abc'), 'Newfoo_newbar-abc'); <ins> actual = ['foo_Bar']; assert.equal(buildReplaceStringWithCasePreserved(actual, 'newfoo_newbar'), 'newfoo_Newbar'); actual = ['Foo_BAR']; assert.equal(buildReplaceStringWithCasePreserved(actual, 'newfoo_newbar'), 'Newfoo_NEWBAR'); </ins> }); test('preserve case', () => {


actual = replacePattern.buildReplaceString(['Foo-Bar-abc'], true); assert.equal(actual, 'Newfoo-newbar'); <ins> replacePattern = parseReplaceString('newfoo-newbar'); actual = replacePattern.buildReplaceString(['foo-Bar'], true); assert.equal(actual, 'newfoo-Newbar'); replacePattern = parseReplaceString('newfoo-newbar'); actual = replacePattern.buildReplaceString(['foo-BAR'], true); assert.equal(actual, 'newfoo-NEWBAR'); </ins> replacePattern = parseReplaceString('newfoo_newbar'); actual = replacePattern.buildReplaceString(['Foo_Bar'], true); assert.equal(actual, 'Newfoo_Newbar');


replacePattern = parseReplaceString('newfoo_newbar-abc'); actual = replacePattern.buildReplaceString(['Foo_Bar-abc'], true); assert.equal(actual, 'Newfoo_newbar-abc'); <ins> replacePattern = parseReplaceString('newfoo_newbar'); actual = replacePattern.buildReplaceString(['foo_Bar'], true); assert.equal(actual, 'newfoo_Newbar'); replacePattern = parseReplaceString('newfoo_newbar'); actual = replacePattern.buildReplaceString(['foo_BAR'], true); assert.equal(actual, 'newfoo_NEWBAR'); </ins> }); });


const extensionPacks: ExtensionSuggestion[] = [ { name: localize('welcomePage.javaScript', "JavaScript"), id: 'dbaeumer.vscode-eslint' }, <del> { name: localize('welcomePage.typeScript', "TypeScript"), id: 'ms-vscode.vscode-typescript-tslint-plugin' }, </del> { name: localize('welcomePage.python', "Python"), id: 'ms-python.python' }, // { name: localize('welcomePage.go', "Go"), id: 'lukehoban.go' }, { name: localize('welcomePage.php', "PHP"), id: 'felixfbecker.php-pack' },


if (item.isDisposed) { return this.onSelectResource(resource, reveal, retry + 1); } <del> this.tree.reveal(item, 0.5); </del> <ins> // Don't scroll to the item if it's already visible if (this.tree.getRelativeTop(item) === null) { this.tree.reveal(item, 0.5); } </ins> } this.tree.setFocus([item]);


"config.scanRepositories": "List of paths to search for git repositories in.", "config.showProgress": "Controls whether git actions should show progress.", "config.rebaseWhenSync": "Force git to use rebase when running the sync command.", <del> "config.confirmEmptyCommits": "Always confirm the creation of empty commits.", </del> <ins> "config.confirmEmptyCommits": "Always confirm the creation of empty commits for the 'Git: Commit Empty' command.", </ins> "config.fetchOnPull": "Fetch all branches when pulling or just the current one.", "config.pullTags": "Fetch all tags when pulling.", "config.autoStash": "Stash any changes before pulling and restore them after successful pull.",


"url": "https://schemastore.azurewebsites.net/schemas/json/babelrc.json" }, { <ins> "fileMatch": "babel.config.json", "url": "https://schemastore.azurewebsites.net/schemas/json/babelrc.json" }, { </ins> "fileMatch": "jsconfig.json", "url": "https://schemastore.azurewebsites.net/schemas/json/jsconfig.json" },


if (this._terminalService.terminalInstances.length > 0) { this._updateFont(); this._updateTheme(); <ins> this._terminalService.getActiveTab()?.setVisible(visible); </ins> } else { // Check if instances were already restored as part of workbench restore if (this._terminalService.terminalInstances.length === 0) {


return; } <del> this._currentResolveCodeLensSymbolsPromise = createCancelablePromise(token => { </del> <ins> const resolvePromise = createCancelablePromise(token => { </ins> const promises = toResolve.map((request, i) => {


return Promise.all(promises); }); <ins> this._currentResolveCodeLensSymbolsPromise = resolvePromise; </ins> this._currentResolveCodeLensSymbolsPromise.then(() => { if (this._currentCodeLensModel) { // update the cached state with new resolved items this._codeLensCache.put(model, this._currentCodeLensModel); } this._oldCodeLensModels.clear(); // dispose old models once we have updated the UI with the current model <del> this._currentResolveCodeLensSymbolsPromise = undefined; </del> <ins> if (resolvePromise === this._currentResolveCodeLensSymbolsPromise) { this._currentResolveCodeLensSymbolsPromise = undefined; } </ins> }, err => { onUnexpectedError(err); // can also be cancellation! <del> this._currentResolveCodeLensSymbolsPromise = undefined; </del> <ins> if (resolvePromise === this._currentResolveCodeLensSymbolsPromise) { this._currentResolveCodeLensSymbolsPromise = undefined; } </ins> }); } }


} <del> export function findValidPasteFileTarget(explorerService: IExplorerService, targetFolder: ExplorerItem, fileToPaste: { resource: URI; isDirectory?: boolean; allowOverwrite: boolean }, incrementalNaming: 'simple' | 'smart'): URI { </del> <ins> export function findValidPasteFileTarget(explorerService: IExplorerService, targetFolder: ExplorerItem, fileToPaste: { resource: URI; isDirectory?: boolean; allowOverwrite: boolean }, incrementalNaming: 'simple' | 'smart' | 'disabled'): URI { </ins> let name = resources.basenameOrAuthority(fileToPaste.resource); let candidate = resources.joinPath(targetFolder.resource, name);


break; } <del> name = incrementFileName(name, !!fileToPaste.isDirectory, incrementalNaming); </del> <ins> if (incrementalNaming !== 'disabled') { name = incrementFileName(name, !!fileToPaste.isDirectory, incrementalNaming); } </ins> candidate = resources.joinPath(targetFolder.resource, name); }


const context = explorerService.getContext(true); const toPaste = resources.distinctParents(await clipboardService.readResources(), r => r); const element = context.length ? context[0] : explorerService.roots[0]; <ins> const incrementalNaming = configurationService.getValue<IFilesConfiguration>().explorer.incrementalNaming; </ins> try { // Check if target is ancestor of pasted folder


target = element.isDirectory ? element : element.parent!; } <del> const incrementalNaming = configurationService.getValue<IFilesConfiguration>().explorer.incrementalNaming; const targetFile = findValidPasteFileTarget(explorerService, target, { resource: fileToPaste, isDirectory: fileToPasteStat.isDirectory, allowOverwrite: pasteShouldMove }, incrementalNaming); </del> <ins> const targetFile = findValidPasteFileTarget(explorerService, target, { resource: fileToPaste, isDirectory: fileToPasteStat.isDirectory, allowOverwrite: pasteShouldMove || incrementalNaming === 'disabled' }, incrementalNaming); </ins> return { source: fileToPaste, target: targetFile }; }));


}; await explorerService.applyBulkEdit(resourceFileEdits, options); } else { <del> const resourceFileEdits = sourceTargetPairs.map(pair => new ResourceFileEdit(pair.source, pair.target, { copy: true })); </del> <ins> const resourceFileEdits = sourceTargetPairs.map(pair => new ResourceFileEdit(pair.source, pair.target, { copy: true, overwrite: incrementalNaming === 'disabled' })); </ins> const undoLevel = configurationService.getValue<IFilesConfiguration>().explorer.confirmUndo; const options = { confirmBeforeUndo: undoLevel === UndoConfirmLevel.Default || undoLevel === UndoConfirmLevel.Verbose,


}, 'explorer.incrementalNaming': { 'type': 'string', <del> enum: ['simple', 'smart'], </del> <ins> enum: ['simple', 'smart', 'disabled'], </ins> enumDescriptions: [ nls.localize('simple', "Appends the word "copy" at the end of the duplicated name potentially followed by a number"), <del> nls.localize('smart', "Adds a number at the end of the duplicated name. If some number is already part of the name, tries to increase that number") </del> <ins> nls.localize('smart', "Adds a number at the end of the duplicated name. If some number is already part of the name, tries to increase that number"), nls.localize('disabled', "Disables incremental naming. If two files with the same name exist you will be prompted to overwrite the existing file") </ins> ], description: nls.localize('explorer.incrementalNaming', "Controls what naming strategy to use when a giving a new name to a duplicated explorer item on paste."), default: 'simple'


colors: boolean; badges: boolean; }; <del> incrementalNaming: 'simple' | 'smart'; </del> <ins> incrementalNaming: 'simple' | 'smart' | 'disabled'; </ins> excludeGitIgnore: boolean; fileNesting: { enabled: boolean;


} public disable(): void { <ins> this.blur(); </ins> this.input.disabled = true; this._hideMessage(); }


], "folding": { "markers": { <del> "start": "^=pods*$", "end": "^=cuts*$" </del> <ins> "start": "^(?:(?:=pods*$)|(?:s*#regionb))", "end": "^(?:(?:=cuts*$)|(?:s*#endregionb))" </ins> } } }  No newline at end of file


description: localize('symbolSortOrder', "Controls how symbols are sorted in the breadcrumbs outline view."), type: 'string', default: 'position', <ins> overridable: true, </ins> enum: ['position', 'name', 'type'], enumDescriptions: [ localize('symbolSortOrder.position', "Show symbol outline in file position order."),


import { URI } from 'vs/base/common/uri'; import 'vs/css!./media/breadcrumbscontrol'; import { OutlineElement, OutlineModel, TreeElement } from 'vs/editor/contrib/documentSymbols/outlineModel'; <del> import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; </del> <ins> import { IConfigurationService, IConfigurationOverrides } from 'vs/platform/configuration/common/configuration'; </ins> import { FileKind, IFileService, IFileStat } from 'vs/platform/files/common/files'; import { IConstructorSignature1, IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { WorkbenchDataTree, WorkbenchAsyncDataTree } from 'vs/platform/list/browser/listService';


export class BreadcrumbsOutlinePicker extends BreadcrumbsPicker { protected readonly _symbolSortOrder: BreadcrumbsConfig<'position' | 'name' | 'type'>; <ins> protected _outlineComparator: OutlineItemComparator; </ins> constructor( parent: HTMLElement,


) { super(parent, instantiationService, themeService, configurationService); this._symbolSortOrder = BreadcrumbsConfig.SymbolSortOrder.bindTo(this._configurationService); <ins> this._outlineComparator = new OutlineItemComparator(); </ins> } protected _createTree(container: HTMLElement) {


collapseByDefault: true, expandOnlyOnTwistieClick: true, multipleSelectionSupport: false, <del> sorter: new OutlineItemComparator(this._getOutlineItemCompareType()), </del> <ins> sorter: this._outlineComparator, </ins> identityProvider: new OutlineIdentityProvider(), keyboardNavigationLabelProvider: new OutlineNavigationLabelProvider(), filter: this._instantiationService.createInstance(OutlineFilter, 'breadcrumbs')


const tree = this._tree as WorkbenchDataTree<OutlineModel, any, FuzzyScore>; tree.setInput(model); <ins> const textModel = model.textModel; const overrideConfiguration = { resource: textModel.uri, overrideIdentifier: textModel.getLanguageIdentifier().language }; this._outlineComparator.type = this._getOutlineItemCompareType(overrideConfiguration); </ins> if (element !== model) { tree.reveal(element, 0.5); tree.setFocus([element], this._fakeEvent);


} } <del> private _getOutlineItemCompareType(): OutlineSortOrder { switch (this._symbolSortOrder.getValue()) { </del> <ins> private _getOutlineItemCompareType(overrideConfiguration?: IConfigurationOverrides): OutlineSortOrder { switch (this._symbolSortOrder.getValue(overrideConfiguration)) { </ins> case 'name': return OutlineSortOrder.ByName; case 'type':


this.focus(); } <del> getContextMenuActions(): IAction[] { </del> <ins> getContextMenuActions(viewDescriptor?: IViewDescriptor): IAction[] { </ins> const result: IAction[] = []; <ins> if (viewDescriptor) { result.push(<IAction>{ id: `${viewDescriptor.id}.removeView`, label: localize('hideView', "Hide"), enabled: viewDescriptor.canToggleVisibility, run: () => this.toggleViewVisibility(viewDescriptor.id) }); } </ins> const viewToggleActions = this.viewsModel.viewDescriptors.map(viewDescriptor => (<IAction>{ id: `${viewDescriptor.id}.toggleVisibility`, label: viewDescriptor.name,


run: () => this.toggleViewVisibility(viewDescriptor.id) })); <ins> if (result.length && viewToggleActions.length) { result.push(new Separator()); } </ins> result.push(...viewToggleActions); const parentActions = this.getViewletContextMenuActions(); <del> if (viewToggleActions.length && parentActions.length) { </del> <ins> if (result.length && parentActions.length) { </ins> result.push(new Separator()); } result.push(...parentActions); return result; }


event.stopPropagation(); event.preventDefault(); <del> const actions: IAction[] = []; actions.push(<IAction>{ id: `${viewDescriptor.id}.removeView`, label: localize('hideView', "Hide"), enabled: viewDescriptor.canToggleVisibility, run: () => this.toggleViewVisibility(viewDescriptor.id) }); const otherActions = this.getContextMenuActions(); if (otherActions.length) { actions.push(...[new Separator(), ...otherActions]); } </del> <ins> const actions: IAction[] = this.getContextMenuActions(viewDescriptor); </ins> let anchor: { x: number, y: number } = { x: event.posx, y: event.posy }; this.contextMenuService.showContextMenu({


if (contribution.scopes) { if ((!Array.isArray(contribution.scopes) || contribution.scopes.some(s => typeof s !== 'string'))) { <del> collector.error(nls.localize('invalid.scopes', "If defined, 'configuration.tokenStyleDefaults.scopes' must must be an array or strings")); </del> <ins> collector.error(nls.localize('invalid.scopes', "If defined, 'configuration.tokenStyleDefaults.scopes' must be an array or strings")); </ins> continue; } tokenStyleDefault.scopesToProbe = [contribution.scopes];


if (ranges.length > 0) { this._emitModelTokensChangedEvent({ tokenizationSupportChanged: false, <ins> semanticTokensApplied: false, </ins> ranges: ranges }); }


this._emitModelTokensChangedEvent({ tokenizationSupportChanged: false, <ins> semanticTokensApplied: tokens !== null, </ins> ranges: [{ fromLineNumber: 1, toLineNumber: this.getLineCount() }] }); }


this._tokens.flush(); this._emitModelTokensChangedEvent({ tokenizationSupportChanged: true, <ins> semanticTokensApplied: false, </ins> ranges: [{ fromLineNumber: 1, toLineNumber: this._buffer.getLineCount()


this._emitModelTokensChangedEvent({ tokenizationSupportChanged: false, <ins> semanticTokensApplied: false, </ins> ranges: [{ fromLineNumber: 1, toLineNumber: this.getLineCount() }] }); }


*/ export interface IModelTokensChangedEvent { readonly tokenizationSupportChanged: boolean; <ins> readonly semanticTokensApplied: boolean; </ins> readonly ranges: { /** * The start of the range (inclusive)


import './largeFileOptimizations'; import './inspectEditorTokens/inspectEditorTokens'; import './saveParticipants'; <ins> import './semanticTokensHelp'; </ins> import './toggleColumnSelection'; import './toggleMinimap'; import './toggleMultiCursorModifier';


<ins> /*--------------------------------------------------------------------------------------------- *  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 path from 'vs/base/common/path'; import { Disposable, DisposableStore } from 'vs/base/common/lifecycle'; import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; import { registerEditorContribution } from 'vs/editor/browser/editorExtensions'; import { IEditorContribution } from 'vs/editor/common/editorCommon'; import { INotificationService, Severity } from 'vs/platform/notification/common/notification'; import { IOpenerService } from 'vs/platform/opener/common/opener'; import { URI } from 'vs/base/common/uri'; import { ITextModel } from 'vs/editor/common/model'; import { IWorkbenchThemeService } from 'vs/workbench/services/themes/common/workbenchThemeService'; /** * Shows a message when semantic tokens are shown the first time. */ export class SemanticTokensHelp extends Disposable implements IEditorContribution { public static readonly ID = 'editor.contrib.semanticHighlightHelp'; constructor( _editor: ICodeEditor, @INotificationService _notificationService: INotificationService, @IOpenerService _openerService: IOpenerService, @IWorkbenchThemeService _themeService: IWorkbenchThemeService ) { super(); const toDispose = this._register(new DisposableStore()); const localToDispose = toDispose.add(new DisposableStore()); const installChangeTokenListener = (model: ITextModel) => { localToDispose.add(model.onDidChangeTokens((e) => { if (!e.semanticTokensApplied) { return; } toDispose.dispose(); // uninstall all listeners, makes sure the notification is only shown once per window const message = nls.localize( { key: 'semanticTokensHelp', comment: [ 'Variable 0 will be a file name.', 'Variable 1 will be a theme name.' ] }, "Semantic highlighting has been applied to '{0}' as the theme '{1}' has semantic highlighting enabled.", path.basename(model.uri.path), _themeService.getColorTheme().label ); _notificationService.prompt(Severity.Info, message, [ { label: nls.localize('learnMoreButton', "Learn More"), run: () => { const url = 'https://go.microsoft.com/fwlink/?linkid=2122588'; _openerService.open(URI.parse(url)); } } ], { neverShowAgain: { id: 'editor.contrib.semanticTokensHelp' } }); })); }; const model = _editor.getModel(); if (model !== null) { installChangeTokenListener(model); } toDispose.add(_editor.onDidChangeModel((e) => { localToDispose.clear(); const model = _editor.getModel(); if (!model) { return; } installChangeTokenListener(model); })); } } registerEditorContribution(SemanticTokensHelp.ID, SemanticTokensHelp); </ins>


import { IHoverService } from 'vs/workbench/services/hover/browser/hover'; import { IHoverDelegate, IHoverDelegateOptions } from 'vs/base/browser/ui/iconLabel/iconHoverDelegate'; import { IUriIdentityService } from 'vs/platform/uriIdentity/common/uriIdentity'; <ins> import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; </ins> const ItemHeight = 22;


@IThemeService themeService: IThemeService, @ITelemetryService telemetryService: ITelemetryService, @ILabelService private readonly labelService: ILabelService, <del> @IUriIdentityService private readonly uriIdentityService: IUriIdentityService </del> <ins> @IUriIdentityService private readonly uriIdentityService: IUriIdentityService, @IExtensionService private readonly extensionService: IExtensionService, </ins> ) { super({ ...options, titleMenuId: MenuId.TimelineTitle }, keybindingService, contextMenuService, configurationService, contextKeyService, viewDescriptorService, instantiationService, openerService, themeService, telemetryService);


override setVisible(visible: boolean): void { if (visible) { <ins> this.extensionService.activateByEvent('onView:timeline'); </ins> this.visibilityDisposables = new DisposableStore(); this.editorService.onDidActiveEditorChange(this.onActiveEditorChanged, this, this.visibilityDisposables);


const viewContainer = this.getViewContainer(panelDescriptor.id); if (viewContainer?.hideIfEmpty) { const viewDescriptors = this.viewDescriptorService.getViewDescriptors(viewContainer); <del> if (viewDescriptors.activeViewDescriptors.length === 0) { </del> <ins> if (viewDescriptors.activeViewDescriptors.length === 0 && this.compositeBar.getPinnedComposites().length > 1) { </ins> this.hideComposite(panelDescriptor.id); // Update the composite bar by hiding } }


"config.enableSmartCommit": "Commit all changes when there are no staged changes.", "config.smartCommitChanges": "Control which changes are automatically staged by Smart Commit.", "config.smartCommitChanges.all": "Automatically stage all changes.", <del> "config.smartCommitChanges.tracked": "Automatically staged tracked changes only.", </del> <ins> "config.smartCommitChanges.tracked": "Automatically stage tracked changes only.", </ins> "config.suggestSmartCommit": "Suggests to enable smart commit (commit all changes when there are no staged changes).", "config.enableCommitSigning": "Enables commit signing with GPG.", "config.discardAllScope": "Controls what changes are discarded by the `Discard all changes` command. `all` discards all changes. `tracked` discards only tracked files. `prompt` shows a prompt dialog every time the action is run.",


fi fi <del> if [ ! -L $0 ]; then </del> <ins> if [ ! -L "$0" ]; then </ins> # if path is not a symlink, find relatively <del> VSCODE_PATH="$(dirname $0)/.." </del> <ins> VSCODE_PATH="$(dirname "$0")/.." </ins> else if command -v readlink >/dev/null; then # if readlink exists, follow the symlink and find relatively <del> VSCODE_PATH="$(dirname $(readlink -f $0))/.." </del> <ins> VSCODE_PATH="$(dirname $(readlink -f "$0"))/.." </ins> else # else use the standard install location VSCODE_PATH="/usr/share/@@NAME@@"


// create the suggestion resolver if (typeof provider.resolveCompletionItem !== 'function') { this._resolveCache = Promise.resolve(); <ins> this._isResolved = true; </ins> } } // resolving get isResolved() { <del> return Boolean(this._resolveCache); </del> <ins> return Boolean(this._isResolved); </ins> } private _resolveCache?: Promise<void>; <ins> private _isResolved?: boolean; </ins> async resolve(token: CancellationToken) { if (!this._resolveCache) { const sub = token.onCancellationRequested(() => { this._resolveCache = undefined; <ins> this._isResolved = false; </ins> }); this._resolveCache = Promise.resolve(this.provider.resolveCompletionItem!(this.completion, token)).then(value => { Object.assign(this.completion, value); <ins> this._isResolved = true; </ins> sub.dispose(); }, err => { if (isPromiseCanceledError(err)) { // the IPC queue will reject the request with the // cancellation error -> reset cached this._resolveCache = undefined; <ins> this._isResolved = false; </ins> } }); }


import { EditorOption } from 'vs/editor/common/config/editorOptions'; import * as platform from 'vs/base/common/platform'; import { MenuRegistry } from 'vs/platform/actions/common/actions'; <ins> import { CancellationTokenSource } from 'vs/base/common/cancellation'; </ins> // sticky suggest widget which doesn't disappear on focus out and such let _sticky = false;


const modelVersionNow = model.getAlternativeVersionId(); const { item } = event; <ins> // const tasks: Promise<any>[] = []; const cts = new CancellationTokenSource(); </ins> // pushing undo stops *before* additional text edits and // *after* the main edit if (!(flags & InsertFlags.NoBeforeUndoStop)) {


// keep item in memory this._memoryService.memorize(model, this.editor.getPosition(), item); <del> const scrollState = StableEditorScrollState.capture(this.editor); </del> if (Array.isArray(item.completion.additionalTextEdits)) { <del> this.editor.executeEdits('suggestController.additionalTextEdits', item.completion.additionalTextEdits.map(edit => EditOperation.replace(Range.lift(edit.range), edit.text))); </del> <ins> // sync additional edits const scrollState = StableEditorScrollState.capture(this.editor); this.editor.executeEdits( 'suggestController.additionalTextEdits.sync', item.completion.additionalTextEdits.map(edit => EditOperation.replace(Range.lift(edit.range), edit.text)) ); scrollState.restoreRelativeVerticalPositionOfCursor(this.editor); } else if (!item.isResolved) { // async additional edits let position: IPosition | undefined; const docListener = model.onDidChangeContent(e => { if (e.isFlush) { cts.cancel(); docListener.dispose(); return; } for (let change of e.changes) { const thisPosition = Range.getEndPosition(change.range); if (!position || Position.isBefore(thisPosition, position)) { position = thisPosition; } } }); let oldFlags = flags; flags |= InsertFlags.NoAfterUndoStop; let didType = false; let typeListener = this.editor.onWillType(() => { typeListener.dispose(); didType = true; if (!(oldFlags & InsertFlags.NoAfterUndoStop)) { this.editor.pushUndoStop(); } }); tasks.push(item.resolve(cts.token).then(() => { if (!item.completion.additionalTextEdits || cts.token.isCancellationRequested) { return; } if (position && item.completion.additionalTextEdits.some(edit => Position.isBefore(position!, Range.getStartPosition(edit.range)))) { return; } if (didType) { this.editor.pushUndoStop(); } this.editor.executeEdits( 'suggestController.additionalTextEdits.async', item.completion.additionalTextEdits.map(edit => EditOperation.replace(Range.lift(edit.range), edit.text)) ); if (didType || !(oldFlags & InsertFlags.NoAfterUndoStop)) { this.editor.pushUndoStop(); } }).finally(() => { docListener.dispose(); typeListener.dispose(); })); </ins> } let { insertText } = item.completion;


adjustWhitespace: !(item.completion.insertTextRules! & CompletionItemInsertTextRule.KeepWhitespace) }); <del> scrollState.restoreRelativeVerticalPositionOfCursor(this.editor); </del> if (!(flags & InsertFlags.NoAfterUndoStop)) { this.editor.pushUndoStop(); }


if (!item.completion.command) { // done this.model.cancel(); <del> this.model.clear(); </del> } else if (item.completion.command.id === TriggerSuggestAction.id) { // retigger


} else { // exec command, done <del> this._commandService.executeCommand(item.completion.command.id, ...(item.completion.command.arguments ? [...item.completion.command.arguments] : [])) .catch(onUnexpectedError) .finally(() => this.model.clear()); // <- clear only now, keep commands alive </del> <ins> tasks.push(this._commandService.executeCommand(item.completion.command.id, ...(item.completion.command.arguments ? [...item.completion.command.arguments] : [])).catch(onUnexpectedError)); </ins> this.model.cancel(); } if (flags & InsertFlags.KeepAlternativeSuggestions) { this._alternatives.value.set(event, next => { <ins> // cancel resolving of additional edits cts.cancel(); </ins> // this is not so pretty. when inserting the 'next' // suggestion we undo until we are at the state at // which we were before inserting the previous suggestion...


} this._alertCompletionItem(item); <ins> // clear only now - after all tasks are done Promise.all(tasks).finally(() => { this.model.clear(); cts.dispose(); }); </ins> } getOverwriteInfo(item: CompletionItem, toggleMode: boolean): { overwriteBefore: number, overwriteAfter: number } {


import { SnippetController2 } from 'vs/editor/contrib/snippet/snippetController2'; import { IMenuService, IMenu } from 'vs/platform/actions/common/actions'; import { createTextModel } from 'vs/editor/test/common/editorTestUtils'; <ins> import { Range } from 'vs/editor/common/core/range'; import { timeout } from 'vs/base/common/async'; </ins> suite('SuggestController', function () {


assert.equal(editor.getValue(), '    let name = foo'); }); <ins> test('use additionalTextEdits sync when possible', async function () { disposables.add(CompletionProviderRegistry.register({ scheme: 'test-ctrl' }, { provideCompletionItems(doc, pos) { return { suggestions: [{ kind: CompletionItemKind.Snippet, label: 'let', insertText: 'hello', range: Range.fromPositions(pos), additionalTextEdits: [{ text: 'I came sync', range: { startLineNumber: 1, startColumn: 1, endLineNumber: 1, endColumn: 1 } }] }] }; }, async resolveCompletionItem(item) { return item; } })); editor.setValue('hellonhallo'); editor.setSelection(new Selection(2, 6, 2, 6)); // trigger let p1 = Event.toPromise(controller.model.onDidSuggest); controller.triggerSuggest(); await p1; // let p2 = Event.toPromise(controller.model.onDidCancel); controller.acceptSelectedSuggestion(false, false); await p2; // insertText happens sync! assert.equal(editor.getValue(), 'I came synchellonhallohello'); }); test('resolve additionalTextEdits async when needed', async function () { let resolveCallCount = 0; disposables.add(CompletionProviderRegistry.register({ scheme: 'test-ctrl' }, { provideCompletionItems(doc, pos) { return { suggestions: [{ kind: CompletionItemKind.Snippet, label: 'let', insertText: 'hello', range: Range.fromPositions(pos) }] }; }, async resolveCompletionItem(item) { resolveCallCount += 1; await timeout(10); item.additionalTextEdits = [{ text: 'I came late', range: { startLineNumber: 1, startColumn: 1, endLineNumber: 1, endColumn: 1 } }]; return item; } })); editor.setValue('hellonhallo'); editor.setSelection(new Selection(2, 6, 2, 6)); // trigger let p1 = Event.toPromise(controller.model.onDidSuggest); controller.triggerSuggest(); await p1; // let p2 = Event.toPromise(controller.model.onDidCancel); controller.acceptSelectedSuggestion(false, false); await p2; // insertText happens sync! assert.equal(editor.getValue(), 'hellonhallohello'); assert.equal(resolveCallCount, 1); // additional edits happened after a litte wait await timeout(20); assert.equal(editor.getValue(), 'I came latehellonhallohello'); // single undo stop editor.getModel()?.undo(); assert.equal(editor.getValue(), 'hellonhallo'); }); test('resolve additionalTextEdits async when needed (typing)', async function () { let resolveCallCount = 0; let resolve: Function = () => { }; disposables.add(CompletionProviderRegistry.register({ scheme: 'test-ctrl' }, { provideCompletionItems(doc, pos) { return { suggestions: [{ kind: CompletionItemKind.Snippet, label: 'let', insertText: 'hello', range: Range.fromPositions(pos) }] }; }, async resolveCompletionItem(item) { resolveCallCount += 1; await new Promise(_resolve => resolve = _resolve); item.additionalTextEdits = [{ text: 'I came late', range: { startLineNumber: 1, startColumn: 1, endLineNumber: 1, endColumn: 1 } }]; return item; } })); editor.setValue('hellonhallo'); editor.setSelection(new Selection(2, 6, 2, 6)); // trigger let p1 = Event.toPromise(controller.model.onDidSuggest); controller.triggerSuggest(); await p1; // let p2 = Event.toPromise(controller.model.onDidCancel); controller.acceptSelectedSuggestion(false, false); await p2; // insertText happens sync! assert.equal(editor.getValue(), 'hellonhallohello'); assert.equal(resolveCallCount, 1); // additional edits happened after a litte wait assert.ok(editor.getSelection()?.equalsSelection(new Selection(2, 11, 2, 11))); editor.trigger('test', 'type', { text: 'TYPING' }); assert.equal(editor.getValue(), 'hellonhallohelloTYPING'); resolve(); await timeout(10); assert.equal(editor.getValue(), 'I came latehellonhallohelloTYPING'); assert.ok(editor.getSelection()?.equalsSelection(new Selection(2, 17, 2, 17))); }); // additional edit come late and are AFTER the selection -> cancel test('resolve additionalTextEdits async when needed (simple conflict)', async function () { let resolveCallCount = 0; let resolve: Function = () => { }; disposables.add(CompletionProviderRegistry.register({ scheme: 'test-ctrl' }, { provideCompletionItems(doc, pos) { return { suggestions: [{ kind: CompletionItemKind.Snippet, label: 'let', insertText: 'hello', range: Range.fromPositions(pos) }] }; }, async resolveCompletionItem(item) { resolveCallCount += 1; await new Promise(_resolve => resolve = _resolve); item.additionalTextEdits = [{ text: 'I came late', range: { startLineNumber: 1, startColumn: 6, endLineNumber: 1, endColumn: 6 } }]; return item; } })); editor.setValue(''); editor.setSelection(new Selection(1, 1, 1, 1)); // trigger let p1 = Event.toPromise(controller.model.onDidSuggest); controller.triggerSuggest(); await p1; // let p2 = Event.toPromise(controller.model.onDidCancel); controller.acceptSelectedSuggestion(false, false); await p2; // insertText happens sync! assert.equal(editor.getValue(), 'hello'); assert.equal(resolveCallCount, 1); resolve(); await timeout(10); assert.equal(editor.getValue(), 'hello'); }); // additional edit come late and are AFTER the position at which the user typed -> cancelled test('resolve additionalTextEdits async when needed (conflict)', async function () { let resolveCallCount = 0; let resolve: Function = () => { }; disposables.add(CompletionProviderRegistry.register({ scheme: 'test-ctrl' }, { provideCompletionItems(doc, pos) { return { suggestions: [{ kind: CompletionItemKind.Snippet, label: 'let', insertText: 'hello', range: Range.fromPositions(pos) }] }; }, async resolveCompletionItem(item) { resolveCallCount += 1; await new Promise(_resolve => resolve = _resolve); item.additionalTextEdits = [{ text: 'I came late', range: { startLineNumber: 1, startColumn: 2, endLineNumber: 1, endColumn: 2 } }]; return item; } })); editor.setValue('hellonhallo'); editor.setSelection(new Selection(2, 6, 2, 6)); // trigger let p1 = Event.toPromise(controller.model.onDidSuggest); controller.triggerSuggest(); await p1; // let p2 = Event.toPromise(controller.model.onDidCancel); controller.acceptSelectedSuggestion(false, false); await p2; // insertText happens sync! assert.equal(editor.getValue(), 'hellonhallohello'); assert.equal(resolveCallCount, 1); // additional edits happened after a litte wait editor.setSelection(new Selection(1, 1, 1, 1)); editor.trigger('test', 'type', { text: 'TYPING' }); assert.equal(editor.getValue(), 'TYPINGhellonhallohello'); resolve(); await timeout(10); assert.equal(editor.getValue(), 'TYPINGhellonhallohello'); assert.ok(editor.getSelection()?.equalsSelection(new Selection(1, 7, 1, 7))); }); test('resolve additionalTextEdits async when needed (cancel)', async function () { let resolve: Function[] = []; disposables.add(CompletionProviderRegistry.register({ scheme: 'test-ctrl' }, { provideCompletionItems(doc, pos) { return { suggestions: [{ kind: CompletionItemKind.Snippet, label: 'let', insertText: 'hello', range: Range.fromPositions(pos) }, { kind: CompletionItemKind.Snippet, label: 'let', insertText: 'hallo', range: Range.fromPositions(pos) }] }; }, async resolveCompletionItem(item) { await new Promise(_resolve => resolve.push(_resolve)); item.additionalTextEdits = [{ text: 'additionalTextEdits', range: { startLineNumber: 1, startColumn: 2, endLineNumber: 1, endColumn: 2 } }]; return item; } })); editor.setValue('abc'); editor.setSelection(new Selection(1, 1, 1, 1)); // trigger let p1 = Event.toPromise(controller.model.onDidSuggest); controller.triggerSuggest(); await p1; // let p2 = Event.toPromise(controller.model.onDidCancel); controller.acceptSelectedSuggestion(true, false); await p2; // insertText happens sync! assert.equal(editor.getValue(), 'helloabc'); // next controller.acceptNextSuggestion(); // resolve additional edits (MUST be cancelled) resolve.forEach(fn => fn); resolve.length = 0; await timeout(10); // next suggestion used assert.equal(editor.getValue(), 'halloabc'); }); </ins> });


private cleanUp(): void { const cache = this.doLoad(); <del> // Remove groups from states that no longer exist cache.forEach((mapGroupToMemento, resource) => { </del> <ins> // Remove groups from states that no longer exist. Since we modify the // cache and its is a LRU cache make a copy to ensure iteration succeeds const entries = [...cache.entries()]; for (const [resource, mapGroupToMemento] of entries) { </ins> Object.keys(mapGroupToMemento).forEach(group => { const groupId: GroupIdentifier = Number(group); if (!this.editorGroupService.getGroup(groupId)) { delete mapGroupToMemento[groupId]; if (isEmptyObject(mapGroupToMemento)) { cache.delete(resource); } } }); <del> }); </del> <ins> } </ins> } }


return; } <ins> if (e.browserEvent.defaultPrevented) { return; } </ins> const focus = e.index; if (typeof focus === 'undefined') {


this.list.setSelection([focus], e.browserEvent); } <ins> e.browserEvent.preventDefault(); </ins> this._onPointer.fire(e); }


return; } <ins> if (e.browserEvent.defaultPrevented) { return; } </ins> const focus = this.list.getFocus(); this.list.setSelection(focus, e.browserEvent); <ins> e.browserEvent.preventDefault(); </ins> } private changeSelection(e: IListMouseEvent<T> | IListTouchEvent<T>): void {


return; } <ins> if (e.browserEvent.defaultPrevented) { return; } </ins> const node = e.element; if (!node) {


return; } <ins> if (e.browserEvent.defaultPrevented) { return; } </ins> super.onDoubleClick(e); } }


} if (node.collapsible) { <del> // Do not set this before calling a handler on the super class, because it will reject it as handled e.browserEvent.isHandledByList = true; </del> const location = this.tree.getNodeLocation(node); const recursive = e.browserEvent.altKey; this.tree.setFocus([location]); this.tree.toggleCollapsed(location, recursive); if (expandOnlyOnTwistieClick && onTwistie) { <ins> // Do not set this before calling a handler on the super class, because it will reject it as handled e.browserEvent.isHandledByList = true; </ins> return; } }


return message.replace(/^s*#.*$n?/gm, '').trim(); } <ins> async getSquashMessage(): Promise<string | undefined> { const squashMsgPath = path.join(this.repositoryRoot, '.git', 'SQUASH_MSG'); try { const raw = await fs.readFile(squashMsgPath, 'utf8'); return this.stripCommitMessageComments(raw); } catch { return undefined; } } </ins> async getMergeMessage(): Promise<string | undefined> { const mergeMsgPath = path.join(this.repositoryRoot, '.git', 'MERGE_MSG');


} async getInputTemplate(): Promise<string> { <del> const mergeMessage = await this.repository.getMergeMessage(); </del> <ins> const commitMessage = (await Promise.all([this.repository.getMergeMessage(), this.repository.getSquashMessage()])).find(msg => msg !== undefined); </ins> <del> if (mergeMessage) { return mergeMessage; </del> <ins> if (commitMessage) { return commitMessage; </ins> } return await this.repository.getCommitTemplate();


} } // New item was added <del> else if (template.objectWidget.isItemNew(e.originalItem)) { </del> <ins> else if (template.objectWidget.isItemNew(e.originalItem) && e.item.key.data !== '') { </ins> newValue[e.item.key.data] = e.item.value.data; newItems.push(e.item); }


} .monaco-workbench .repl .repl-tree .output.expression.value-and-source .value { <del> flex: 1; </del> <ins> margin-right: 4px; </ins> } .monaco-workbench .repl .repl-tree .monaco-tl-contents .arrow {


} .monaco-workbench .repl .repl-tree .output.expression.value-and-source .source { <del> margin-left: 4px; </del> <ins> margin-left: auto; </ins> margin-right: 8px; cursor: pointer; text-decoration: underline; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; <del> max-width: 150px; </del> <ins> text-align: right; </ins> } .monaco-workbench .repl .repl-tree .output.expression > .value,


const filesExcludeByRoot = Array.isArray(filesExclude) ? filesExclude : []; const excludesExpression: IExpression = Array.isArray(filesExclude) ? getEmptyExpression() : filesExclude; <ins> for (const { expression } of filesExcludeByRoot) { for (const pattern of Object.keys(expression)) { if (!pattern.endsWith('/**')) { // Append `/**` to pattern to match a parent folder #103631 expression[`${strings.rtrim(pattern, '/')}/**`] = expression[pattern]; } } } </ins> const negate = filter.startsWith('!'); this.textFilter = { text: (negate ? strings.ltrim(filter, '!') : filter).trim(), negate }; const includeExpression: IExpression = getEmptyExpression();


this.render(previousRenderRange, e.scrollTop, e.height, e.scrollLeft, e.scrollWidth); if (this.supportDynamicHeights) { <del> this._rerender(e.scrollTop, e.height); </del> <ins> // Don't update scrollTop from within an scroll event // so we don't break smooth scrolling. #104144 this._rerender(e.scrollTop, e.height, false); </ins> } } catch (err) { console.error('Got bad scroll event:', e);


* Given a stable rendered state, checks every rendered element whether it needs * to be probed for dynamic height. Adjusts scroll height and top if necessary. */ <del> private _rerender(renderTop: number, renderHeight: number): void { </del> <ins> private _rerender(renderTop: number, renderHeight: number, updateScrollTop: boolean = true): void { </ins> const previousRenderRange = this.getRenderRange(renderTop, renderHeight); // Let's remember the second element's position, this helps in scrolling up


} } <del> if (typeof anchorElementIndex === 'number') { </del> <ins> if (updateScrollTop && typeof anchorElementIndex === 'number') { </ins> this.scrollTop = this.elementTop(anchorElementIndex) - anchorElementTopDelta!; }


import { GetErrRoutingTsServer, ITypeScriptServer, ProcessBasedTsServer, SyntaxRoutingTsServer, TsServerDelegate, TsServerProcessFactory, TsServerProcessKind } from './server'; import { TypeScriptVersionManager } from './versionManager'; import { ITypeScriptVersionProvider, TypeScriptVersion } from './versionProvider'; <del> import * as semver from 'semver'; </del> const enum CompositeServerType { /** Run a single server that handles all commands  */


let tsServerLogFile: string | undefined; if (kind === TsServerProcessKind.Syntax) { <del> if (semver.gte(API.v400rc.fullVersionString, apiVersion.fullVersionString)) { args.push('--serverMode'); args.push('partialSemantic'); } else { </del> <ins> if (apiVersion.gte(API.v401)) { args.push('--serverMode', 'partialSemantic'); } else { </ins> args.push('--syntaxOnly'); } }


public static readonly v380 = API.fromSimpleString('3.8.0'); public static readonly v381 = API.fromSimpleString('3.8.1'); public static readonly v390 = API.fromSimpleString('3.9.0'); <del> public static readonly v400rc = API.fromSimpleString('4.0.0-rc'); </del> public static readonly v400 = API.fromSimpleString('4.0.0'); <ins> public static readonly v401 = API.fromSimpleString('4.0.1'); </ins> public static fromVersionString(versionString: string): API { let version = semver.valid(versionString);


} }, { <ins> "name": "Markdown Headings", "scope": "markup.heading.markdown", "settings": { "fontStyle": "bold" } }, { "name": "Markdown Quote", "scope": "markup.quote.markdown", "settings": { "fontStyle": "italic", "foreground": "" } }, { "name": "Markdown Bold", "scope": "markup.bold.markdown", "settings": { "fontStyle": "bold" } }, { "name": "Markdown Link Title/Description", "scope": "string.other.link.title.markdown,string.other.link.description.markdown", "settings": { "foreground": "#AE81FF" } }, { "name": "Markdown Underline Link/Image", "scope": "markup.underline.link.markdown,markup.underline.link.image.markdown", "settings": { "foreground": "" } }, { "name": "Markdown Emphasis", "scope": "markup.italic.markdown", "settings": { "fontStyle": "italic" } }, { "name": "Markdown Punctuation Definition Link", "scope": "markup.list.unnumbered.markdown, markup.list.numbered.markdown", "settings": { "foreground": "" } }, { "name": "Markdown List Punctuation", "scope": [ "punctuation.definition.list.begin.markdown" ], "settings": { "foreground": "" } }, { </ins> "scope": "token.info-token", "settings": { "foreground": "#6796e6"


*  Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ <del> import { ExtensionContext } from 'vscode'; </del> <ins> import { ExtensionContext, Uri } from 'vscode'; </ins> import { LanguageClientOptions } from 'vscode-languageclient'; import { startClient, LanguageClientConstructor } from '../cssClient'; import { LanguageClient } from 'vscode-languageclient/browser';


// this method is called when vs code is activated export function activate(context: ExtensionContext) { <del> const serverMain = context.asAbsolutePath('server/dist/browser/cssServerMain.js'); </del> <ins> const serverMain = Uri.joinPath(context.extensionUri, 'server/dist/browser/cssServerMain.js'); </ins> try { <del> const worker = new Worker(serverMain); </del> <ins> const worker = new Worker(serverMain.toString()); </ins> const newLanguageClient: LanguageClientConstructor = (id: string, name: string, clientOptions: LanguageClientOptions) => { return new LanguageClient(id, name, clientOptions, worker); };


*  Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ <del> import { ExtensionContext } from 'vscode'; </del> <ins> import { ExtensionContext, Uri } from 'vscode'; </ins> import { LanguageClientOptions } from 'vscode-languageclient'; import { startClient, LanguageClientConstructor } from '../htmlClient'; import { LanguageClient } from 'vscode-languageclient/browser';


// this method is called when vs code is activated export function activate(context: ExtensionContext) { <del> const serverMain = context.asAbsolutePath('server/dist/browser/htmlServerMain.js'); </del> <ins> const serverMain = Uri.joinPath(context.extensionUri, 'server/dist/browser/htmlServerMain.js'); </ins> try { <del> const worker = new Worker(serverMain); </del> <ins> const worker = new Worker(serverMain.toString()); </ins> const newLanguageClient: LanguageClientConstructor = (id: string, name: string, clientOptions: LanguageClientOptions) => { return new LanguageClient(id, name, clientOptions, worker); };


*  Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ <del> import { ExtensionContext } from 'vscode'; </del> <ins> import { ExtensionContext, Uri } from 'vscode'; </ins> import { LanguageClientOptions } from 'vscode-languageclient'; import { startClient, LanguageClientConstructor } from '../jsonClient'; import { LanguageClient } from 'vscode-languageclient/browser';


// this method is called when vs code is activated export function activate(context: ExtensionContext) { <del> const serverMain = context.asAbsolutePath('server/dist/browser/jsonServerMain.js'); </del> <ins> const serverMain = Uri.joinPath(context.extensionUri, 'server/dist/browser/jsonServerMain.js'); </ins> try { <del> const worker = new Worker(serverMain); </del> <ins> const worker = new Worker(serverMain.toString()); </ins> const newLanguageClient: LanguageClientConstructor = (id: string, name: string, clientOptions: LanguageClientOptions) => { return new LanguageClient(id, name, clientOptions, worker); };


const versionProvider = new StaticVersionProvider( new TypeScriptVersion( TypeScriptVersionSource.Bundled, <del> context.asAbsolutePath('dist/browser/typescript-web/tsserver.web.js'), </del> <ins> vscode.Uri.joinPath(context.extensionUri, 'dist/browser/typescript-web/tsserver.web.js').toString(), </ins> API.v400)); const lazyClientHost = createLazyClientHost(context, false, {


return getExtensionApi(onCompletionAccepted.event, pluginManager); }


"vscode-ripgrep": "^1.8.0", "vscode-sqlite3": "4.0.10", "vscode-textmate": "5.2.0", <del> "xterm": "4.9.0-beta.8", </del> <ins> "xterm": "4.9.0-beta.24", </ins> "xterm-addon-search": "0.7.0", "xterm-addon-unicode11": "0.2.0", "xterm-addon-webgl": "0.8.0",


"vscode-proxy-agent": "^0.5.2", "vscode-ripgrep": "^1.8.0", "vscode-textmate": "5.2.0", <del> "xterm": "4.9.0-beta.8", </del> <ins> "xterm": "4.9.0-beta.24", </ins> "xterm-addon-search": "0.7.0", "xterm-addon-unicode11": "0.2.0", "xterm-addon-webgl": "0.8.0",


"semver-umd": "^5.5.7", "vscode-oniguruma": "1.3.1", "vscode-textmate": "5.2.0", <del> "xterm": "4.9.0-beta.8", </del> <ins> "xterm": "4.9.0-beta.24", </ins> "xterm-addon-search": "0.7.0", "xterm-addon-unicode11": "0.2.0", "xterm-addon-webgl": "0.8.0"


resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.8.0.tgz#4bc6bb4dbfea5b0d2d7978d6c5cef922d584fb4f" integrity sha512-dlpYPsv0C9S6v6+T/h/d/otSbdUTizMJdxvSoS34tUpMOHev6iW7Zqt5KRFqYxl4vCqpDk9Wmhb3fKL3kwX5fQ== <del> xterm@4.9.0-beta.8: version "4.9.0-beta.8" resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.9.0-beta.8.tgz#ca121934d63f88668d2d5b11d9b2fc3bde7bd805" integrity sha512-EEonYBLANDUBfEeEnHG632bZdgBaAUWst8LFr6oC6f2uLFfJGHQvVJuLaEkPtRvS+jOeoorEXZRPmso1/ANHXA== </del> <ins> xterm@4.9.0-beta.24: version "4.9.0-beta.24" resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.9.0-beta.24.tgz#48f0990c6d32ad3a9bcc4fb49531d7effdaccea5" integrity sha512-CIVxxxbBiSw1WOMkIjjivaiIC9jNgih4klfWsRGx0qiDF5nbzHuLXkPTt+yAQUu9FCyTUwECm9Pkl3gUsSaGKg== </ins>


resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.8.0.tgz#4bc6bb4dbfea5b0d2d7978d6c5cef922d584fb4f" integrity sha512-dlpYPsv0C9S6v6+T/h/d/otSbdUTizMJdxvSoS34tUpMOHev6iW7Zqt5KRFqYxl4vCqpDk9Wmhb3fKL3kwX5fQ== <del> xterm@4.9.0-beta.8: version "4.9.0-beta.8" resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.9.0-beta.8.tgz#ca121934d63f88668d2d5b11d9b2fc3bde7bd805" integrity sha512-EEonYBLANDUBfEeEnHG632bZdgBaAUWst8LFr6oC6f2uLFfJGHQvVJuLaEkPtRvS+jOeoorEXZRPmso1/ANHXA== </del> <ins> xterm@4.9.0-beta.24: version "4.9.0-beta.24" resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.9.0-beta.24.tgz#48f0990c6d32ad3a9bcc4fb49531d7effdaccea5" integrity sha512-CIVxxxbBiSw1WOMkIjjivaiIC9jNgih4klfWsRGx0qiDF5nbzHuLXkPTt+yAQUu9FCyTUwECm9Pkl3gUsSaGKg== </ins> yauzl@^2.9.2: version "2.10.0"


// Listen for modifier before handing it off to the hover to handle so it gets disposed correctly this._hoverListeners = new DisposableStore(); this._hoverListeners.add(dom.addDisposableListener(document, 'keydown', e => { <del> if (this._isModifierDown(e)) { </del> <ins> if (!e.repeat && this._isModifierDown(e)) { </ins> this._enableDecorations(); } })); this._hoverListeners.add(dom.addDisposableListener(document, 'keyup', e => { <del> if (!this._isModifierDown(e)) { </del> <ins> if (!e.repeat && !this._isModifierDown(e)) { </ins> this._disableDecorations(); } }));