placeHolders: IParsedLinePlaceHolderInfo[]; } <del> const InternalFormatSnippetParser = new class implements ISnippetParser { private _lastGeneratedId: number; private _snippet: CodeSnippet; parse(template: string): CodeSnippet { this._lastGeneratedId = 0; this._snippet = new CodeSnippet(); this.parseTemplate(template); return this._snippet; } private parseTemplate(template: string): void { var placeHoldersMap: collections.IStringDictionary<IPlaceHolder> = Object.create(null); var i: number, len: number, j: number, lenJ: number, templateLines = template.split('n'); for (i = 0, len = templateLines.length; i < len; i++) { var parsedLine = this.parseLine(templateLines[i], (id: string) => { if (placeHoldersMap[id]) { return placeHoldersMap[id].value; } return ''; }); for (j = 0, lenJ = parsedLine.placeHolders.length; j < lenJ; j++) { var linePlaceHolder = parsedLine.placeHolders[j]; var occurence = new Range(i + 1, linePlaceHolder.startColumn, i + 1, linePlaceHolder.endColumn); var placeHolder: IPlaceHolder; if (placeHoldersMap[linePlaceHolder.id]) { placeHolder = placeHoldersMap[linePlaceHolder.id]; } else { placeHolder = { id: linePlaceHolder.id, value: linePlaceHolder.value, occurences: [] }; this._snippet.placeHolders.push(placeHolder); placeHoldersMap[linePlaceHolder.id] = placeHolder; } placeHolder.occurences.push(occurence); } this._snippet.lines.push(parsedLine.line); } // Named variables (e.g. {greeting} and {greeting:Hello}) are sorted first, followed by // tab-stops and numeric variables (e.g. $1, $2, ${3:foo}) which are sorted in ascending order this._snippet.placeHolders.sort((a, b) => { let nonIntegerId = (v: IPlaceHolder) => !(/^d+$/).test(v.id); let isFinishPlaceHolder = (v: IPlaceHolder) => v.id === '' && v.value === ''; // Sort finish placeholder last if (isFinishPlaceHolder(a)) { return 1; } else if (isFinishPlaceHolder(b)) { return -1; } // Sort named placeholders first if (nonIntegerId(a) && nonIntegerId(b)) { return 0; } else if (nonIntegerId(a)) { return -1; } else if (nonIntegerId(b)) { return 1; } if (a.id === b.id) { return 0; } return Number(a.id) < Number(b.id) ? -1 : 1; }); if (this._snippet.placeHolders.length > 0 && this._snippet.placeHolders[this._snippet.placeHolders.length - 1].value === '') { this._snippet.finishPlaceHolderIndex = this._snippet.placeHolders.length - 1; } } private parseLine(line: string, findDefaultValueForIdFromPrevLines: (id: string) => string): IParsedLine { // Placeholder 0 is the entire line var placeHolderStack: { placeHolderId: string; placeHolderText: string; }[] = [{ placeHolderId: '', placeHolderText: '' }]; var placeHolders: IParsedLinePlaceHolderInfo[] = []; const findDefaultValueForId = (id) => { const result = findDefaultValueForIdFromPrevLines(id); if (result) { return result; } for (const placeHolder of placeHolders) { if (placeHolder.id === id && placeHolder.value) { return placeHolder.value; } } return ''; }; var i = 0; var len = line.length; var resultIndex = 0; while (i < len) { var restOfLine = line.substr(i); // Look for the start of a placeholder {{ if (/^{{/.test(restOfLine)) { i += 2; placeHolderStack.push({ placeHolderId: '', placeHolderText: '' }); // Look for id var matches = restOfLine.match(/^{{(w+):/); if (Array.isArray(matches) && matches.length === 2) { placeHolderStack[placeHolderStack.length - 1].placeHolderId = matches[1]; i += matches[1].length + 1; // +1 to account for the : at the end of the id } continue; } // Look for the end of a placeholder. placeHolderStack[0] is the top-level line. if (placeHolderStack.length > 1 && /^}}/.test(restOfLine)) { i += 2; if (placeHolderStack[placeHolderStack.length - 1].placeHolderId.length === 0) { // This placeholder did not have an explicit id placeHolderStack[placeHolderStack.length - 1].placeHolderId = placeHolderStack[placeHolderStack.length - 1].placeHolderText; if (placeHolderStack[placeHolderStack.length - 1].placeHolderId === '_') { // This is just an empty tab stop placeHolderStack[placeHolderStack.length - 1].placeHolderId = 'TAB_STOP_' + String(++this._lastGeneratedId); placeHolderStack[placeHolderStack.length - 1].placeHolderText = ''; --resultIndex; // Roll back one iteration of the result index as we made the text empty } } if (placeHolderStack[placeHolderStack.length - 1].placeHolderText.length === 0) { // This placeholder is empty or was a mirror var defaultValue = findDefaultValueForId(placeHolderStack[placeHolderStack.length - 1].placeHolderId); placeHolderStack[placeHolderStack.length - 1].placeHolderText = defaultValue; resultIndex += defaultValue.length; } placeHolders.push({ id: placeHolderStack[placeHolderStack.length - 1].placeHolderId, value: placeHolderStack[placeHolderStack.length - 1].placeHolderText, startColumn: resultIndex + 1 - placeHolderStack[placeHolderStack.length - 1].placeHolderText.length, endColumn: resultIndex + 1 }); // Insert our text into the previous placeholder placeHolderStack[placeHolderStack.length - 2].placeHolderText += placeHolderStack[placeHolderStack.length - 1].placeHolderText; placeHolderStack.pop(); continue; } // Look for escapes if (/^./.test(restOfLine)) { if (restOfLine.charAt(1) === '{' || restOfLine.charAt(1) === '}' || restOfLine.charAt(1) === '') { ++i; // Skip the escape slash and take the character literally } else { // invalid escapes placeHolderStack[placeHolderStack.length - 1].placeHolderText += line.charAt(i); ++resultIndex; ++i; } } //This is an escape sequence or not a special character, just insert it placeHolderStack[placeHolderStack.length - 1].placeHolderText += line.charAt(i); ++resultIndex; ++i; } // Sort the placeholder in order of apperance: placeHolders.sort((a, b) => { if (a.startColumn < b.startColumn) { return -1; } if (a.startColumn > b.startColumn) { return 1; } if (a.endColumn < b.endColumn) { return -1; } if (a.endColumn > b.endColumn) { return 1; } return 0; }); return { line: placeHolderStack[0].placeHolderText, placeHolders: placeHolders }; } }; const EmmetSnippetParser = new class implements ISnippetParser { parse(template: string): CodeSnippet { template = _convertExternalSnippet(template, ExternalSnippetType.EmmetSnippet); return InternalFormatSnippetParser.parse(template); } }; export enum ExternalSnippetType { TextMateSnippet, EmmetSnippet } // This is used for both TextMate and Emmet function _convertExternalSnippet(snippet: string, snippetType: ExternalSnippetType): string { var openBraces = 0; var convertedSnippet = ''; var i = 0; var len = snippet.length; while (i < len) { var restOfLine = snippet.substr(i); // Cursor tab stop if (/^$0/.test(restOfLine)) { i += 2; convertedSnippet += snippetType === ExternalSnippetType.EmmetSnippet ? '{{_}}' : '{{}}'; continue; } if (/^${0}/.test(restOfLine)) { i += 4; convertedSnippet += snippetType === ExternalSnippetType.EmmetSnippet ? '{{_}}' : '{{}}'; continue; } // Tab stops var matches = restOfLine.match(/^$(d+)/); if (Array.isArray(matches) && matches.length === 2) { i += 1 + matches[1].length; convertedSnippet += '{{' + matches[1] + ':}}'; continue; } matches = restOfLine.match(/^${(d+)}/); if (Array.isArray(matches) && matches.length === 2) { i += 3 + matches[1].length; convertedSnippet += '{{' + matches[1] + ':}}'; continue; } // Open brace patterns placeholder if (/^${/.test(restOfLine)) { i += 2; ++openBraces; convertedSnippet += '{{'; continue; } // Close brace patterns placeholder if (openBraces > 0 && /^}/.test(restOfLine)) { i += 1; --openBraces; convertedSnippet += '}}'; continue; } // Escapes if (/^./.test(restOfLine)) { i += 2; if (/^$/.test(restOfLine)) { convertedSnippet += '$'; } else { convertedSnippet += restOfLine.substr(0, 2); } continue; } // Escape braces that don't belong to a placeholder matches = restOfLine.match(/^({|})/); if (Array.isArray(matches) && matches.length === 2) { i += 1; convertedSnippet += '' + matches[1]; continue; } i += 1; convertedSnippet += restOfLine.charAt(0); } return convertedSnippet; }; </del> function _resolveSnippetVariables(marker: Marker[], resolver: ISnippetVariableResolver) { if (resolver) { const stack = [...marker];


} public getHeight(tree: ITree, element: any): number { <del> if (element instanceof Variable) { </del> <ins> if (element instanceof Variable && (element.hasChildren || (element.name !== null))) { </ins> return ReplExpressionsRenderer.LINE_HEIGHT_PX; } if (element instanceof Expression && element.hasChildren) {


options.minimap = { enabled: false }; const outputConfig = this.baseConfigurationService.getValue('[Log]'); <del> if (outputConfig && outputConfig['editor.minimap.enabled']) { options.minimap = { enabled: true }; </del> <ins> if (outputConfig) { if (outputConfig['editor.minimap.enabled']) { options.minimap = { enabled: true }; } if ('editor.wordWrap' in outputConfig) { options.wordWrap = outputConfig['editor.wordWrap']; } </ins> } return options;


continue; } <del> // Make sure the entire line matches, not just a subpart. </del> let matches = firstLine.match(association.firstline); <del> if (matches && matches.length > 0 && matches[0].length === firstLine.length) { </del> <ins> if (matches && matches.length > 0) { </ins> return association.mime; } }


guess = guessMimeTypes('Randomfile.noregistration', 'RegexesAreNice'); assert.deepEqual(guess, ['text/nice-regex', 'text/plain']); <del> guess = guessMimeTypes('Randomfile.noregistration', 'RegexesAreNiceee'); </del> <ins> guess = guessMimeTypes('Randomfile.noregistration', 'RegexesAreNotNice'); </ins> assert.deepEqual(guess, ['application/unknown']); guess = guessMimeTypes('Codefile', 'RegexesAreNice');


<array> <dict> <key>include</key> <del> <string>#list_paragraph</string> </del> <ins> <string>#block</string> </ins> </dict> <dict> <key>include</key> <del> <string>#block</string> </del> <ins> <string>#list_paragraph</string> </ins> </dict> </array> <key>while</key>


} function getNixIPCHandle(userDataPath: string, type: string): string { <ins> if (process.env['XDG_RUNTIME_DIR']) { return path.join(process.env['XDG_RUNTIME_DIR'], `${pkg.name}-${pkg.version}-${type}.sock`); } </ins> return path.join(userDataPath, `${pkg.version}-${type}.sock`); }


overviewRulerBorder, overviewRulerLanes, parameterHints, <ins> peekWidgetFocusInlineEditor, </ins> quickSuggestions, quickSuggestionsDelay, readOnly,


3, 0, 3 )), parameterHints: register(new EditorParameterHints()), <ins> peekWidgetFocusInlineEditor: register(new EditorBooleanOption( EditorOption.peekWidgetFocusInlineEditor, 'peekWidgetFocusInlineEditor', false, { description: nls.localize('peekWidgetFocusInlineEditor', "Controls whether to focus the inline editor in the peek widget by default.") } )), </ins> quickSuggestions: register(new EditorQuickSuggestions()), quickSuggestionsDelay: register(new EditorIntOption( EditorOption.quickSuggestionsDelay, 'quickSuggestionsDelay',


import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; import { KeyCode, KeyMod, KeyChord } from 'vs/base/common/keyCodes'; import { CommandsRegistry } from 'vs/platform/commands/common/commands'; <ins> import { EditorOption } from 'vs/editor/common/config/editorOptions'; </ins> export const ctxReferenceSearchVisible = new RawContextKey<boolean>('referenceSearchVisible', false);


let pos = new Position(range.startLineNumber, range.startColumn); let selection = this._model.nearestReference(uri, pos); if (selection) { <del> return this._widget.setSelection(selection); </del> <ins> return this._widget.setSelection(selection).then(() => { if (this._widget && this._editor.getOption(EditorOption.peekWidgetFocusInlineEditor)) { this._widget.focusOnPreviewEditor(); } }); </ins> } } return undefined;


} const target = this._model.nextOrPreviousReference(source, fwd); const editorFocus = this._editor.hasTextFocus(); <ins> const previewEditorFocus = this._widget.isPreviewEditorFocused(); </ins> await this._widget.setSelection(target); await this._gotoReference(target); if (editorFocus) { this._editor.focus(); <ins> } else if (this._widget && previewEditorFocus) { this._widget.focusOnPreviewEditor(); </ins> } }


* Controls fading out of unused variables. */ showUnused?: boolean; <ins> /** * Controls whether to focus the inline editor in the peek widget by default. * Defaults to false. */ peekWidgetFocusInlineEditor?: boolean; </ins> } export interface IEditorConstructionOptions extends IEditorOptions {


background-color: transparent!important; color: #333; -webkit-user-select: initial; <del> overflow: hidden; /* prevents the terminal output being incorrectly placed over the title */ </del> position: relative; } .vs-dark .monaco-workbench .panel.integrated-terminal { color: #CCC; }


}, 'terminal.integrated.enableBold': { 'type': 'boolean', <del> 'description': nls.localize('terminal.integrated.enableBold', "Whether to enable bold text within the terminal."), </del> <ins> 'description': nls.localize('terminal.integrated.enableBold', "Whether to enable bold text within the terminal, this requires support from the termianl shell."), </ins> 'default': true }, 'terminal.integrated.cursorBlinking': {


}); } <del> public setWidgetManager(widgetManager: TerminalWidgetManager) { </del> <ins> public setWidgetManager(widgetManager: TerminalWidgetManager): void { </ins> this._widgetManager = widgetManager; }


callback(true); } <del> private _addTooltipEventListeners(element: HTMLElement) { </del> <ins> private _addTooltipEventListeners(element: HTMLElement): void { </ins> let timeout = null; let isMessageShowing = false; this._tooltipDisposables.push(dom.addDisposableListener(element, dom.EventType.MOUSE_OVER, () => {


title: locations.length === 1 ? localize('oneImplementationLabel', '1 implementation') : localize('manyImplementationLabel', '{0} implementations', locations.length), <del> command: 'editor.action.showReferences', </del> <ins> command: locations.length ? 'editor.action.showReferences' : '', </ins> arguments: [codeLens.document, codeLens.range.start, locations] }; return codeLens;


title: locations.length === 1 ? localize('oneReferenceLabel', '1 reference') : localize('manyReferenceLabel', '{0} references', locations.length), <del> command: 'editor.action.showReferences', </del> <ins> command: locations.length ? 'editor.action.showReferences' : '', </ins> arguments: [codeLens.document, codeLens.range.start, locations] }; return codeLens;


title: command.title }; <del> if (!isFalsyOrEmpty(command.arguments)) { </del> <ins> if (command.command && !isFalsyOrEmpty(command.arguments)) { </ins> // we have a contributed command with arguments. that // means we don't want to send the arguments around


border-left: 3px solid rgba(0, 0, 0, 0.40); } <ins> .vscode-light.showEditorSelection .code-line .code-line:hover:before { border-left: none; } </ins> .vscode-dark.showEditorSelection .code-active-line:before { border-left: 3px solid rgba(255, 255, 255, 0.4); }


border-left: 3px solid rgba(255, 255, 255, 0.60); } <ins> .vscode-dark.showEditorSelection .code-line .code-line:hover:before { border-left: none; } </ins> .vscode-high-contrast.showEditorSelection .code-active-line:before { border-left: 3px solid rgba(255, 160, 0, 0.7); }


border-left: 3px solid rgba(255, 160, 0, 1); } <ins> .vscode-high-contrast.showEditorSelection .code-line .code-line:hover:before { border-left: none; } </ins> img { max-width: 100%; max-height: 100%;


[deltaY, deltaX] = [deltaX, deltaY]; } <del> if (this._options.scrollYToX && !deltaX) { </del> <ins> // Convert vertical scrolling to horizontal if shift is held, this // is handled at a higher level on Mac const shiftConvert = !Platform.isMacintosh && e.browserEvent.shiftKey; if ((this._options.scrollYToX || shiftConvert) && !deltaX) { </ins> deltaX = deltaY; deltaY = 0; }


await this._openResource(resource); } <del> private async _openResource(resource: Resource): Promise<void> { </del> <ins> private async _openResource(resource: Resource, preview?: boolean): Promise<void> { </ins> const left = this.getLeftResource(resource); const right = this.getRightResource(resource); const title = this.getTitle(resource);


const viewColumn = window.activeTextEditor && window.activeTextEditor.viewColumn || ViewColumn.One; <del> if (!left) { return await commands.executeCommand<void>('vscode.open', right, viewColumn); } </del> const opts: TextDocumentShowOptions = { <ins> preserveFocus: true, preview: preview, </ins> viewColumn };


opts.selection = activeTextEditor.selection; } <ins> if (!left) { const document = await workspace.openTextDocument(right); await window.showTextDocument(document, opts); return; } </ins> return await commands.executeCommand<void>('vscode.diff', left, right, title, opts); }


} @command('git.openFile') <del> async openFile(arg?: Resource | Uri): Promise<void> { let uri: Uri | undefined; </del> <ins> async openFile(arg?: Resource | Uri, ...resourceStates: SourceControlResourceState[]): Promise<void> { let uris: Uri[] | undefined; </ins> if (arg instanceof Uri) { if (arg.scheme === 'git') { <del> uri = Uri.file(fromGitUri(arg).path); </del> <ins> uris = [Uri.file(fromGitUri(arg).path)]; </ins> } else if (arg.scheme === 'file') { <del> uri = arg; </del> <ins> uris = [arg]; </ins> } } else { let resource = arg;


} if (resource) { <del> uri = resource.resourceUri; </del> <ins> uris = [...resourceStates.map(r => r.resourceUri), resource.resourceUri]; </ins> } } <del> if (!uri) { </del> <ins> if (!uris) { </ins> return; } <del> const activeTextEditor = window.activeTextEditor && window.activeTextEditor; const isSameUri = activeTextEditor && activeTextEditor.document.uri.toString() === uri.toString(); const selections = activeTextEditor && activeTextEditor.selections; const viewColumn = activeTextEditor && activeTextEditor.viewColumn || ViewColumn.One; await commands.executeCommand<void>('vscode.open', uri, viewColumn); if (isSameUri && selections && window.activeTextEditor) { window.activeTextEditor.selections = selections; </del> <ins> const preview = uris.length === 1 ? true : false; const activeTextEditor = window.activeTextEditor; for (const uri of uris) { // If the active editor matches the current uri, get its selection const selections = activeTextEditor && activeTextEditor.document.uri.toString() === uri.toString() ? activeTextEditor.selections : undefined; const opts: TextDocumentShowOptions = { preserveFocus: true, preview: preview, viewColumn: activeTextEditor && activeTextEditor.viewColumn || ViewColumn.One }; const document = await workspace.openTextDocument(uri); await window.showTextDocument(document, opts); if (selections && window.activeTextEditor) { window.activeTextEditor.selections = selections; } </ins> } }


} @command('git.openChange') <del> async openChange(arg?: Resource | Uri): Promise<void> { let resource: Resource | undefined = undefined; </del> <ins> async openChange(arg?: Resource | Uri, ...resourceStates: SourceControlResourceState[]): Promise<void> { let resources: Resource[] | undefined = undefined; </ins> <del> if (arg instanceof Resource) { resource = arg; } else if (arg instanceof Uri) { resource = this.getSCMResource(arg); } else { resource = this.getSCMResource(); </del> <ins> if (arg instanceof Uri) { const resource = this.getSCMResource(arg); if (resource !== undefined) { resources = [resource]; } </ins> } <ins> else { let resource: Resource | undefined = undefined; if (arg instanceof Resource) { resource = arg; } else { resource = this.getSCMResource(); } </ins> <del> if (!resource) { </del> <ins> if (resource) { resources = [...resourceStates as Resource[], resource]; } } if (!resources) { </ins> return; } <del> return await this._openResource(resource); </del> <ins> const preview = resources.length === 1 ? undefined : false; for (const resource of resources) { await this._openResource(resource, preview); } </ins> } @command('git.stage')


} } <ins> export class CachedNavTreeResponse { response?: Promise<Proto.NavTreeResponse>; version: number = -1; document: string = ''; matches(document: TextDocument): boolean { return this.version === document.version && this.document === document.uri.toString(); } update(document: TextDocument, response: Promise<Proto.NavTreeResponse>) { this.response = response; this.version = document.version; this.document = document.uri.toString(); } } </ins> export abstract class TypeScriptBaseCodeLensProvider implements CodeLensProvider { private enabled: boolean = true; private onDidChangeCodeLensesEmitter = new EventEmitter<void>(); public constructor( <del> protected client: ITypeScriptServiceClient </del> <ins> protected client: ITypeScriptServiceClient, private cachedResponse: CachedNavTreeResponse </ins> ) { } public get onDidChangeCodeLenses(): Event<void> {


return []; } try { <del> const response = await this.client.execute('navtree', { file: filepath }, token); </del> <ins> if (!this.cachedResponse.matches(document)) { this.cachedResponse.update(document, this.client.execute('navtree', { file: filepath }, token)); } const response = await this.cachedResponse.response; </ins> if (!response) { return []; } const tree = response.body; const referenceableSpans: Range[] = []; if (tree && tree.childItems) {


export default class TypeScriptImplementationsCodeLensProvider extends TypeScriptBaseCodeLensProvider { public constructor( client: ITypeScriptServiceClient, <del> private readonly language: string </del> <ins> private readonly language: string, cachedResponse: CachedNavTreeResponse </ins> ) { <del> super(client); </del> <ins> super(client, cachedResponse); </ins> } public updateConfiguration(): void {


import * as Proto from '../protocol'; import * as PConst from '../protocol.const'; <del> import { TypeScriptBaseCodeLensProvider, ReferencesCodeLens } from './baseCodeLensProvider'; </del> <ins> import { TypeScriptBaseCodeLensProvider, ReferencesCodeLens, CachedNavTreeResponse } from './baseCodeLensProvider'; </ins> import { ITypeScriptServiceClient } from '../typescriptService'; import { tsTextSpanToVsRange, vsPositionToTsFileLocation } from '../utils/convert';


export default class TypeScriptReferencesCodeLensProvider extends TypeScriptBaseCodeLensProvider { public constructor( client: ITypeScriptServiceClient, <del> private readonly language: string </del> <ins> private readonly language: string, cachedResponse: CachedNavTreeResponse </ins> ) { <del> super(client); </del> <ins> super(client, cachedResponse); </ins> } public updateConfiguration(): void {


import DiagnosticsManager from './features/diagnostics'; import { LanguageDescription } from './utils/languageDescription'; import * as fileSchemes from './utils/fileSchemes'; <ins> import { CachedNavTreeResponse } from './features/baseCodeLensProvider'; </ins> const validateSetting = 'validate.enable';


this.disposables.push(languages.registerCodeActionsProvider(selector, new (await import('./features/refactorProvider')).default(client, this.formattingOptionsManager, commandManager))); this.registerVersionDependentProviders(); <del> const referenceCodeLensProvider = new (await import('./features/referencesCodeLensProvider')).default(client, this.description.id); </del> <ins> const cachedResponse = new CachedNavTreeResponse(); const referenceCodeLensProvider = new (await import('./features/referencesCodeLensProvider')).default(client, this.description.id, cachedResponse); </ins> referenceCodeLensProvider.updateConfiguration(); this.toUpdateOnConfigurationChanged.push(referenceCodeLensProvider); this.disposables.push(languages.registerCodeLensProvider(selector, referenceCodeLensProvider)); <del> const implementationCodeLensProvider = new (await import('./features/implementationsCodeLensProvider')).default(client, this.description.id); </del> <ins> const implementationCodeLensProvider = new (await import('./features/implementationsCodeLensProvider')).default(client, this.description.id, cachedResponse); </ins> implementationCodeLensProvider.updateConfiguration(); this.toUpdateOnConfigurationChanged.push(implementationCodeLensProvider); this.disposables.push(languages.registerCodeLensProvider(selector, implementationCodeLensProvider));


{ "name": "code-oss-dev", "version": "1.16.0", <del> "electronVersion": "1.7.4", </del> <ins> "electronVersion": "1.7.5", </ins> "distro": "724097db097bfde7796fcca70aaac83ba80a95f8", "author": { "name": "Microsoft Corporation"


import * as glob from 'vs/base/common/glob'; import * as paths from 'vs/base/common/paths'; import uri from 'vs/base/common/uri'; <ins> import { untildify } from 'vs/base/common/labels'; </ins> import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; import { IPatternInfo, IQueryOptions, IFolderQuery, ISearchQuery, QueryType, ISearchConfiguration, getExcludes, pathIncludedInQuery } from 'vs/platform/search/common/search'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; <ins> import { IEnvironmentService } from 'vs/platform/environment/common/environment'; </ins> export interface ISearchPathPattern { searchPath: uri;


constructor( @IConfigurationService private configurationService: IConfigurationService, <del> @IWorkspaceContextService private workspaceContextService: IWorkspaceContextService) { } </del> <ins> @IWorkspaceContextService private workspaceContextService: IWorkspaceContextService, @IEnvironmentService private environmentService: IEnvironmentService ) { } </ins> public text(contentPattern: IPatternInfo, folderResources?: uri[], options?: IQueryOptions): ISearchQuery { return this.query(QueryType.Text, contentPattern, folderResources, options);


return paths.isAbsolute(segment) || /^..?[/]/.test(segment); }; <del> const segments = splitGlobPattern(pattern); </del> <ins> const segments = splitGlobPattern(pattern) .map(segment => untildify(segment, this.environmentService.userHome)); </ins> const groups = collections.groupBy(segments, segment => isSearchPath(segment) ? 'searchPaths' : 'exprSegments');


import { IWorkspaceContextService, Workspace, toWorkspaceFolders } from 'vs/platform/workspace/common/workspace'; import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService'; import { QueryBuilder, ISearchPathsResult } from 'vs/workbench/parts/search/common/queryBuilder'; <del> import { TestContextService } from 'vs/workbench/test/workbenchTestServices'; </del> <ins> import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { TestContextService, TestEnvironmentService } from 'vs/workbench/test/workbenchTestServices'; </ins> import { ISearchQuery, QueryType, IPatternInfo, IFolderQuery } from 'vs/platform/search/common/search';


mockContextService.setWorkspace(mockWorkspace); instantiationService.stub(IWorkspaceContextService, mockContextService); <ins> instantiationService.stub(IEnvironmentService, TestEnvironmentService); </ins> queryBuilder = instantiationService.createInstance(QueryBuilder); });


kbOpts: { weight: CORE_WEIGHT, kbExpr: EditorContextKeys.textInputFocus, <del> primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyMod.Alt | KeyCode.UpArrow, </del> <ins> primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.UpArrow, </ins> linux: { primary: 0 } } }));


kbOpts: { weight: CORE_WEIGHT, kbExpr: EditorContextKeys.textInputFocus, <del> primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyMod.Alt | KeyCode.DownArrow, </del> <ins> primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.DownArrow, </ins> linux: { primary: 0 } } }));


weight: CORE_WEIGHT, kbExpr: EditorContextKeys.textInputFocus, primary: KeyMod.Shift | KeyCode.UpArrow, <del> secondary: [KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.UpArrow], </del> mac: { primary: KeyMod.Shift | KeyCode.UpArrow }, linux: { primary: KeyMod.Shift | KeyCode.UpArrow } }


weight: CORE_WEIGHT, kbExpr: EditorContextKeys.textInputFocus, primary: KeyMod.Shift | KeyCode.DownArrow, <del> secondary: [KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.DownArrow], </del> mac: { primary: KeyMod.Shift | KeyCode.DownArrow }, linux: { primary: KeyMod.Shift | KeyCode.DownArrow } }


} } <del> return true; </del> <ins> return false; </ins> } public getSurroundingPairs(): IAutoClosingPair[] {


test('shouldAutoClosePair in empty line', () => { let sup = new CharacterPairSupport({ autoClosingPairs: [{ open: '{', close: '}', notIn: ['string', 'comment'] }] }); <del> assert.equal(testShouldAutoClose(sup, [], 'a', 1), true); </del> <ins> assert.equal(testShouldAutoClose(sup, [], 'a', 1), false); </ins> assert.equal(testShouldAutoClose(sup, [], '{', 1), true); }); test('shouldAutoClosePair in not interesting line 1', () => { let sup = new CharacterPairSupport({ autoClosingPairs: [{ open: '{', close: '}', notIn: ['string', 'comment'] }] }); assert.equal(testShouldAutoClose(sup, [{ text: 'do', type: StandardTokenType.Other }], '{', 3), true); <del> assert.equal(testShouldAutoClose(sup, [{ text: 'do', type: StandardTokenType.Other }], 'a', 3), true); </del> <ins> assert.equal(testShouldAutoClose(sup, [{ text: 'do', type: StandardTokenType.Other }], 'a', 3), false); </ins> }); test('shouldAutoClosePair in not interesting line 2', () => { let sup = new CharacterPairSupport({ autoClosingPairs: [{ open: '{', close: '}' }] }); assert.equal(testShouldAutoClose(sup, [{ text: 'do', type: StandardTokenType.String }], '{', 3), true); <del> assert.equal(testShouldAutoClose(sup, [{ text: 'do', type: StandardTokenType.String }], 'a', 3), true); </del> <ins> assert.equal(testShouldAutoClose(sup, [{ text: 'do', type: StandardTokenType.String }], 'a', 3), false); </ins> }); test('shouldAutoClosePair in interesting line 1', () => { let sup = new CharacterPairSupport({ autoClosingPairs: [{ open: '{', close: '}', notIn: ['string', 'comment'] }] }); assert.equal(testShouldAutoClose(sup, [{ text: '"a"', type: StandardTokenType.String }], '{', 1), false); <del> assert.equal(testShouldAutoClose(sup, [{ text: '"a"', type: StandardTokenType.String }], 'a', 1), true); </del> <ins> assert.equal(testShouldAutoClose(sup, [{ text: '"a"', type: StandardTokenType.String }], 'a', 1), false); </ins> assert.equal(testShouldAutoClose(sup, [{ text: '"a"', type: StandardTokenType.String }], '{', 2), false); <del> assert.equal(testShouldAutoClose(sup, [{ text: '"a"', type: StandardTokenType.String }], 'a', 2), true); </del> <ins> assert.equal(testShouldAutoClose(sup, [{ text: '"a"', type: StandardTokenType.String }], 'a', 2), false); </ins> assert.equal(testShouldAutoClose(sup, [{ text: '"a"', type: StandardTokenType.String }], '{', 3), false); <del> assert.equal(testShouldAutoClose(sup, [{ text: '"a"', type: StandardTokenType.String }], 'a', 3), true); </del> <ins> assert.equal(testShouldAutoClose(sup, [{ text: '"a"', type: StandardTokenType.String }], 'a', 3), false); </ins> assert.equal(testShouldAutoClose(sup, [{ text: '"a"', type: StandardTokenType.String }], '{', 4), false); <del> assert.equal(testShouldAutoClose(sup, [{ text: '"a"', type: StandardTokenType.String }], 'a', 4), true); </del> <ins> assert.equal(testShouldAutoClose(sup, [{ text: '"a"', type: StandardTokenType.String }], 'a', 4), false); </ins> }); test('shouldAutoClosePair in interesting line 2', () => { let sup = new CharacterPairSupport({ autoClosingPairs: [{ open: '{', close: '}', notIn: ['string', 'comment'] }] }); assert.equal(testShouldAutoClose(sup, [{ text: 'x=', type: StandardTokenType.Other }, { text: '"a"', type: StandardTokenType.String }, { text: ';', type: StandardTokenType.Other }], '{', 1), true); <del> assert.equal(testShouldAutoClose(sup, [{ text: 'x=', type: StandardTokenType.Other }, { text: '"a"', type: StandardTokenType.String }, { text: ';', type: StandardTokenType.Other }], 'a', 1), true); </del> <ins> assert.equal(testShouldAutoClose(sup, [{ text: 'x=', type: StandardTokenType.Other }, { text: '"a"', type: StandardTokenType.String }, { text: ';', type: StandardTokenType.Other }], 'a', 1), false); </ins> assert.equal(testShouldAutoClose(sup, [{ text: 'x=', type: StandardTokenType.Other }, { text: '"a"', type: StandardTokenType.String }, { text: ';', type: StandardTokenType.Other }], '{', 2), true); <del> assert.equal(testShouldAutoClose(sup, [{ text: 'x=', type: StandardTokenType.Other }, { text: '"a"', type: StandardTokenType.String }, { text: ';', type: StandardTokenType.Other }], 'a', 2), true); </del> <ins> assert.equal(testShouldAutoClose(sup, [{ text: 'x=', type: StandardTokenType.Other }, { text: '"a"', type: StandardTokenType.String }, { text: ';', type: StandardTokenType.Other }], 'a', 2), false); </ins> assert.equal(testShouldAutoClose(sup, [{ text: 'x=', type: StandardTokenType.Other }, { text: '"a"', type: StandardTokenType.String }, { text: ';', type: StandardTokenType.Other }], '{', 3), true); <del> assert.equal(testShouldAutoClose(sup, [{ text: 'x=', type: StandardTokenType.Other }, { text: '"a"', type: StandardTokenType.String }, { text: ';', type: StandardTokenType.Other }], 'a', 3), true); </del> <ins> assert.equal(testShouldAutoClose(sup, [{ text: 'x=', type: StandardTokenType.Other }, { text: '"a"', type: StandardTokenType.String }, { text: ';', type: StandardTokenType.Other }], 'a', 3), false); </ins> assert.equal(testShouldAutoClose(sup, [{ text: 'x=', type: StandardTokenType.Other }, { text: '"a"', type: StandardTokenType.String }, { text: ';', type: StandardTokenType.Other }], '{', 4), false); <del> assert.equal(testShouldAutoClose(sup, [{ text: 'x=', type: StandardTokenType.Other }, { text: '"a"', type: StandardTokenType.String }, { text: ';', type: StandardTokenType.Other }], 'a', 4), true); </del> <ins> assert.equal(testShouldAutoClose(sup, [{ text: 'x=', type: StandardTokenType.Other }, { text: '"a"', type: StandardTokenType.String }, { text: ';', type: StandardTokenType.Other }], 'a', 4), false); </ins> assert.equal(testShouldAutoClose(sup, [{ text: 'x=', type: StandardTokenType.Other }, { text: '"a"', type: StandardTokenType.String }, { text: ';', type: StandardTokenType.Other }], '{', 5), false); <del> assert.equal(testShouldAutoClose(sup, [{ text: 'x=', type: StandardTokenType.Other }, { text: '"a"', type: StandardTokenType.String }, { text: ';', type: StandardTokenType.Other }], 'a', 5), true); </del> <ins> assert.equal(testShouldAutoClose(sup, [{ text: 'x=', type: StandardTokenType.Other }, { text: '"a"', type: StandardTokenType.String }, { text: ';', type: StandardTokenType.Other }], 'a', 5), false); </ins> assert.equal(testShouldAutoClose(sup, [{ text: 'x=', type: StandardTokenType.Other }, { text: '"a"', type: StandardTokenType.String }, { text: ';', type: StandardTokenType.Other }], '{', 6), false); <del> assert.equal(testShouldAutoClose(sup, [{ text: 'x=', type: StandardTokenType.Other }, { text: '"a"', type: StandardTokenType.String }, { text: ';', type: StandardTokenType.Other }], 'a', 6), true); </del> <ins> assert.equal(testShouldAutoClose(sup, [{ text: 'x=', type: StandardTokenType.Other }, { text: '"a"', type: StandardTokenType.String }, { text: ';', type: StandardTokenType.Other }], 'a', 6), false); </ins> assert.equal(testShouldAutoClose(sup, [{ text: 'x=', type: StandardTokenType.Other }, { text: '"a"', type: StandardTokenType.String }, { text: ';', type: StandardTokenType.Other }], '{', 7), true); <del> assert.equal(testShouldAutoClose(sup, [{ text: 'x=', type: StandardTokenType.Other }, { text: '"a"', type: StandardTokenType.String }, { text: ';', type: StandardTokenType.Other }], 'a', 7), true); </del> <ins> assert.equal(testShouldAutoClose(sup, [{ text: 'x=', type: StandardTokenType.Other }, { text: '"a"', type: StandardTokenType.String }, { text: ';', type: StandardTokenType.Other }], 'a', 7), false); </ins> }); test('shouldAutoClosePair in interesting line 3', () => { let sup = new CharacterPairSupport({ autoClosingPairs: [{ open: '{', close: '}', notIn: ['string', 'comment'] }] }); assert.equal(testShouldAutoClose(sup, [{ text: ' ', type: StandardTokenType.Other }, { text: '//a', type: StandardTokenType.Comment }], '{', 1), true); <del> assert.equal(testShouldAutoClose(sup, [{ text: ' ', type: StandardTokenType.Other }, { text: '//a', type: StandardTokenType.Comment }], 'a', 1), true); </del> <ins> assert.equal(testShouldAutoClose(sup, [{ text: ' ', type: StandardTokenType.Other }, { text: '//a', type: StandardTokenType.Comment }], 'a', 1), false); </ins> assert.equal(testShouldAutoClose(sup, [{ text: ' ', type: StandardTokenType.Other }, { text: '//a', type: StandardTokenType.Comment }], '{', 2), true); <del> assert.equal(testShouldAutoClose(sup, [{ text: ' ', type: StandardTokenType.Other }, { text: '//a', type: StandardTokenType.Comment }], 'a', 2), true); </del> <ins> assert.equal(testShouldAutoClose(sup, [{ text: ' ', type: StandardTokenType.Other }, { text: '//a', type: StandardTokenType.Comment }], 'a', 2), false); </ins> assert.equal(testShouldAutoClose(sup, [{ text: ' ', type: StandardTokenType.Other }, { text: '//a', type: StandardTokenType.Comment }], '{', 3), false); <del> assert.equal(testShouldAutoClose(sup, [{ text: ' ', type: StandardTokenType.Other }, { text: '//a', type: StandardTokenType.Comment }], 'a', 3), true); </del> <ins> assert.equal(testShouldAutoClose(sup, [{ text: ' ', type: StandardTokenType.Other }, { text: '//a', type: StandardTokenType.Comment }], 'a', 3), false); </ins> assert.equal(testShouldAutoClose(sup, [{ text: ' ', type: StandardTokenType.Other }, { text: '//a', type: StandardTokenType.Comment }], '{', 4), false); <del> assert.equal(testShouldAutoClose(sup, [{ text: ' ', type: StandardTokenType.Other }, { text: '//a', type: StandardTokenType.Comment }], 'a', 4), true); </del> <ins> assert.equal(testShouldAutoClose(sup, [{ text: ' ', type: StandardTokenType.Other }, { text: '//a', type: StandardTokenType.Comment }], 'a', 4), false); </ins> assert.equal(testShouldAutoClose(sup, [{ text: ' ', type: StandardTokenType.Other }, { text: '//a', type: StandardTokenType.Comment }], '{', 5), false); <del> assert.equal(testShouldAutoClose(sup, [{ text: ' ', type: StandardTokenType.Other }, { text: '//a', type: StandardTokenType.Comment }], 'a', 5), true); </del> <ins> assert.equal(testShouldAutoClose(sup, [{ text: ' ', type: StandardTokenType.Other }, { text: '//a', type: StandardTokenType.Comment }], 'a', 5), false); </ins> }); });


import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { UNTITLED_WORKSPACE_NAME } from 'vs/platform/workspaces/common/workspaces'; import { coalesce } from 'vs/base/common/arrays'; <ins> import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService'; import { EmbeddedCodeEditorWidget } from 'vs/editor/browser/widget/embeddedCodeEditorWidget'; import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; </ins> // Commands


// Save / Save As / Save All / Revert <del> function saveSelectedEditors(accessor: ServicesAccessor, options?: ISaveEditorsOptions): Promise<void> { </del> <ins> async function saveSelectedEditors(accessor: ServicesAccessor, options?: ISaveEditorsOptions): Promise<void> { </ins> const listService = accessor.get(IListService); const editorGroupsService = accessor.get(IEditorGroupsService); <del> return doSaveEditors(accessor, getMultiSelectedEditors(listService, editorGroupsService), options); </del> <ins> const codeEditorService = accessor.get(ICodeEditorService); const textFileService = accessor.get(ITextFileService); // Save editors const editors = getMultiSelectedEditors(listService, editorGroupsService); await doSaveEditors(accessor, editors, options); // Special treatment for embedded editors: if we detect that focus is // inside an embedded code editor, we save that model as well if we // find it in our text file models. Currently, only textual editors // support embedded editors. const focusedCodeEditor = codeEditorService.getFocusedCodeEditor(); if (focusedCodeEditor instanceof EmbeddedCodeEditorWidget) { const resource = focusedCodeEditor.getModel()?.uri; // Check that the resource of the model was not saved already if (resource && !editors.some(({ editor }) => isEqual(toResource(editor, { supportSideBySide: SideBySideEditor.MASTER }), resource))) { const model = textFileService.models.get(resource); if (!model?.isReadonly()) { await textFileService.save(resource, options); } } } </ins> } function saveDirtyEditorsOfGroups(accessor: ServicesAccessor, groups: ReadonlyArray<IEditorGroup>, options?: ISaveEditorsOptions): Promise<void> {


this.selectEntry(keybinding); this.reportKeybindingAction(KEYBINDINGS_EDITOR_COMMAND_COPY, keybinding.keybindingItem.command, keybinding.keybindingItem.keybinding); const userFriendlyKeybinding: IUserFriendlyKeybinding = { <del> command: keybinding.keybindingItem.command, key: keybinding.keybindingItem.keybinding ? keybinding.keybindingItem.keybinding.getUserSettingsLabel() : '' </del> <ins> key: keybinding.keybindingItem.keybinding ? keybinding.keybindingItem.keybinding.getUserSettingsLabel() : '', command: keybinding.keybindingItem.command </ins> }; if (keybinding.keybindingItem.when) { userFriendlyKeybinding.when = keybinding.keybindingItem.when;


return ''; } <ins> private handlePathTilde(path: string): string { return path.replace(/^~/, os.homedir()); } </ins> private static cloneId = 0; @command('git.clone')


const config = workspace.getConfiguration('git'); let value = config.get<string>('defaultCloneDirectory') || os.homedir(); <del> value = value.replace(/^~/, os.homedir()); </del> const parentPath = await window.showInputBox({ prompt: localize('parent', "Parent Directory"), <del> value, </del> <ins> value: this.handlePathTilde(value), </ins> ignoreFocusOut: true });


statusBarItem.command = cancelCommandId; statusBarItem.show(); <del> const clonePromise = this.git.clone(url, parentPath, tokenSource.token); </del> <ins> const clonePromise = this.git.clone(url, this.handlePathTilde(parentPath), tokenSource.token); </ins> try { window.withProgress({ location: ProgressLocation.SourceControl, title: localize('cloning', "Cloning git repository...") }, () => clonePromise);


import * as strings from 'vs/base/common/strings'; import * as objects from 'vs/base/common/objects'; import * as platform from 'vs/base/common/platform'; <del> import * as stdfork from 'vs/base/node/stdFork'; </del> import { Emitter, Event } from 'vs/base/common/event'; import { TPromise } from 'vs/base/common/winjs.base'; import { ExtensionsChannelId } from 'vs/platform/extensionManagement/common/extensionManagement';


if (this.adapterExecutable.command === 'node' && this.outputService) { if (Array.isArray(this.adapterExecutable.args) && this.adapterExecutable.args.length > 0) { <del> stdfork.fork(this.adapterExecutable.args[0], this.adapterExecutable.args.slice(1), {}, (err, child) => { if (err) { e(new Error(nls.localize('unableToLaunchDebugAdapter', "Unable to launch debug adapter from '{0}'.", this.adapterExecutable.args[0]))); } this.serverProcess = child; c(null); </del> <ins> const child = cp.fork(this.adapterExecutable.args[0], this.adapterExecutable.args.slice(1), { execArgv: ['-e', 'delete process.env.ELECTRON_RUN_AS_NODE;require(process.argv[1])'].concat(process.execArgv || []), silent: true </ins> }); <ins> if (!child.pid) { e(new Error(nls.localize('unableToLaunchDebugAdapter', "Unable to launch debug adapter from '{0}'.", this.adapterExecutable.args[0]))); } this.serverProcess = child; c(null); </ins> } else { e(new Error(nls.localize('unableToLaunchDebugAdapterNoArgs', "Unable to launch debug adapter."))); }


if (previous) { if (next) { const betweenProgress = (offset - window.scrollY - previous.element.getBoundingClientRect().top) / (next.element.getBoundingClientRect().top - previous.element.getBoundingClientRect().top); <del> return previous.line + betweenProgress * (next.line - previous.line); </del> <ins> const line = previous.line + betweenProgress * (next.line - previous.line); return (0 <= line) ? line : 0; </ins> } else { <del> return previous.line; </del> <ins> return (0 <= previous.line) ? previous.line : 0; </ins> } } return null;


else { // Do open files <del> usedWindows.push(this.doOpenFilesInExistingWindow(bestWindowOrFolder, filesToOpen, filesToCreate, filesToDiff, filesToWait)); </del> <ins> usedWindows.push(this.doOpenFilesInExistingWindow(openConfig, bestWindowOrFolder, filesToOpen, filesToCreate, filesToDiff, filesToWait)); </ins> // Reset these because we handled them filesToOpen = [];


const windowOnWorkspace = windowsOnWorkspace[0]; // Do open files <del> usedWindows.push(this.doOpenFilesInExistingWindow(windowOnWorkspace, filesToOpen, filesToCreate, filesToDiff, filesToWait)); </del> <ins> usedWindows.push(this.doOpenFilesInExistingWindow(openConfig, windowOnWorkspace, filesToOpen, filesToCreate, filesToDiff, filesToWait)); </ins> // Reset these because we handled them filesToOpen = [];


const windowOnFolderPath = windowsOnFolderPath[0]; // Do open files <del> usedWindows.push(this.doOpenFilesInExistingWindow(windowOnFolderPath, filesToOpen, filesToCreate, filesToDiff, filesToWait)); </del> <ins> usedWindows.push(this.doOpenFilesInExistingWindow(openConfig, windowOnFolderPath, filesToOpen, filesToCreate, filesToDiff, filesToWait)); </ins> // Reset these because we handled them filesToOpen = [];


return arrays.distinct(usedWindows); } <del> private doOpenFilesInExistingWindow(window: ICodeWindow, filesToOpen: IPath[], filesToCreate: IPath[], filesToDiff: IPath[], filesToWait: IPathsToWaitFor): ICodeWindow { </del> <ins> private doOpenFilesInExistingWindow(configuration: IOpenConfiguration, window: ICodeWindow, filesToOpen: IPath[], filesToCreate: IPath[], filesToDiff: IPath[], filesToWait: IPathsToWaitFor): ICodeWindow { </ins> window.focus(); // make sure window has focus window.ready().then(readyWindow => { <del> readyWindow.send('vscode:openFiles', { filesToOpen, filesToCreate, filesToDiff, filesToWait }); </del> <ins> const termProgram = configuration.userEnv ? configuration.userEnv['TERM_PROGRAM'] : void 0; readyWindow.send('vscode:openFiles', { filesToOpen, filesToCreate, filesToDiff, filesToWait, termProgram }); </ins> }); return window;


filesToCreate?: IPath[]; filesToDiff?: IPath[]; filesToWait?: IPathsToWaitFor; <ins> termProgram?: string; </ins> } export interface IAddFoldersRequest {


import { TERMINAL_BACKGROUND_COLOR, TERMINAL_BORDER_COLOR } from 'vs/workbench/parts/terminal/electron-browser/terminalColorRegistry'; import { DataTransfers } from 'vs/base/browser/dnd'; import { ILifecycleService, LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle'; <ins> import { ipcRenderer as ipc } from 'electron'; import { IOpenFileRequest } from 'vs/platform/windows/common/windows'; import { whenDeleted } from 'vs/base/node/pfs'; </ins> export class TerminalPanel extends Panel {


this._updateFont(); this._updateTheme(); <ins> 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 // marker file to get deleted and then focus back to the integrated terminal. if (request.termProgram === 'vscode' && request.filesToWait) { whenDeleted(request.filesToWait.waitMarkerFilePath).then(() => this.focus()); } }); </ins> // Force another layout (first is setContainers) since config has changed this.layout(new Dimension(this._terminalContainer.offsetWidth, this._terminalContainer.offsetHeight)); return TPromise.as(void 0);


if (this.partService.isCreated() && !errors.isPromiseCanceledError(error)) { const actions: INotificationActions = { primary: [] }; if (errors.isErrorWithActions(error)) { <del> actions.primary = error.actions; </del> <ins> actions.primary = (error as errors.IErrorWithActions).actions; </ins> } const handle = this.notificationService.notify({


for (let i = 0, len = events.length; i < len; i++) { const resource = events[i].resource; const isJson = paths.extname(resource.fsPath) === '.json'; <del> const isDeletedSettingsFolder = (events[i].type === FileChangeType.DELETED && paths.isEqual(paths.basename(resource.fsPath), this.configFolderRelativePath)); </del> <ins> const isDeletedSettingsFolder = (events[i].type === FileChangeType.DELETED && paths.basename(resource.fsPath) === this.configFolderRelativePath); </ins> if (!isJson && !isDeletedSettingsFolder) { continue; // only JSON files or the actual settings folder }


<del> <?xml version='1.0' standalone='no' ?> <svg xmlns='http://www.w3.org/2000/svg' version='1.1' width='10px' height='10px'> <style> circle { animation: ball 0.6s linear infinite; } circle:nth-child(2) { animation-delay: 0.075s; } circle:nth-child(3) { animation-delay: 0.15s; } circle:nth-child(4) { animation-delay: 0.225s; } circle:nth-child(5) { animation-delay: 0.3s; } circle:nth-child(6) { animation-delay: 0.375s; } circle:nth-child(7) { animation-delay: 0.45s; } circle:nth-child(8) { animation-delay: 0.525s; } @keyframes ball { from { opacity: 1; } to { opacity: 0.3; } } </style> <g style="fill:white;"> <circle cx='5' cy='1' r='1' style='opacity:0.3;' /> <circle cx='7.8284' cy='2.1716' r='1' style='opacity:0.3;' /> <circle cx='9' cy='5' r='1' style='opacity:0.3;' /> <circle cx='7.8284' cy='7.8284' r='1' style='opacity:0.3;' /> <circle cx='5' cy='9' r='1' style='opacity:0.3;' /> <circle cx='2.1716' cy='7.8284' r='1' style='opacity:0.3;' /> <circle cx='1' cy='5' r='1' style='opacity:0.3;' /> <circle cx='2.1716' cy='2.1716' r='1' style='opacity:0.3;' /> </g> </svg> </del>


*--------------------------------------------------------------------------------------------*/ .monaco-workbench > .part.statusbar > .statusbar-item.progress { <del> background-image: url(progress.svg); background-repeat: no-repeat; background-position: left; padding-left: 14px; display: inline; </del> <ins> padding-left: 5px; } .monaco-workbench > .part.statusbar > .statusbar-item.progress .spinner-container { padding-right: 5px; </ins> } .monaco-workbench .progress-badge > .badge-content {


render(element: HTMLElement): IDisposable { this._element = element; <del> this._label = new OcticonLabel(this._element); </del> this._element.classList.add('progress'); <ins> const container = document.createElement('span'); this._element.appendChild(container); const spinnerContainer = document.createElement('span'); spinnerContainer.classList.add('spinner-container'); container.appendChild(spinnerContainer); const spinner = new OcticonLabel(spinnerContainer); spinner.text = '$(sync~spin)'; const labelContainer = document.createElement('span'); container.appendChild(labelContainer); this._label = new OcticonLabel(labelContainer); </ins> this.hide(); return null; }


const info = document.createElement('div'); const building = document.createElement('div'); <ins> const errorTitle = n => nls.localize('totalErrors', "{0} Errors", n); const warningTitle = n => nls.localize('totalWarnings', "{0} Warnings", n); const infoTitle = n => nls.localize('totalInfos', "{0} Infos", n); </ins> Dom.addClass(element, 'task-statusbar-item'); Dom.addClass(label, 'task-statusbar-item-label'); element.appendChild(label); <del> element.title = nls.localize('problems', "Problems"); </del> Dom.addClass(errorIcon, 'task-statusbar-item-label-error'); Dom.addClass(errorIcon, 'mask-icon');


Dom.addClass(error, 'task-statusbar-item-label-counter'); error.innerHTML = '0'; <ins> error.title = errorIcon.title = errorTitle(0); </ins> label.appendChild(error); Dom.addClass(warningIcon, 'task-statusbar-item-label-warning');


Dom.addClass(warning, 'task-statusbar-item-label-counter'); warning.innerHTML = '0'; <ins> warning.title = warningIcon.title = warningTitle(0); </ins> label.appendChild(warning); Dom.addClass(infoIcon, 'task-statusbar-item-label-info');


} })); <del> let updateStatus = (element: HTMLDivElement, icon: HTMLDivElement, stats: number): boolean => { if (stats > 0) { element.innerHTML = stats.toString(); $(element).show(); $(icon).show(); return true; </del> <ins> const manyProblems = nls.localize('manyProblems', "10K+"); const packNumber = n => n > 9999 ? manyProblems : n > 999 ? n.toString().charAt(0) + 'K' : n.toString(); let updateLabel = (stats: MarkerStatistics) => { error.innerHTML = packNumber(stats.errors); error.title = errorIcon.title = errorTitle(stats.errors); warning.innerHTML = packNumber(stats.warnings); warning.title = warningIcon.title = warningTitle(stats.warnings); if (stats.infos > 0) { info.innerHTML = packNumber(stats.infos); info.title = infoIcon.title = infoTitle(stats.infos); $(info).show(); $(infoIcon).show(); </ins> } else { <del> $(element).hide(); $(icon).hide(); return false; </del> <ins> $(info).hide(); $(infoIcon).hide(); </ins> } }; <del> let manyMarkers = nls.localize('manyMarkers', "99+"); let updateLabel = (stats: MarkerStatistics) => { error.innerHTML = stats.errors < 100 ? stats.errors.toString() : manyMarkers; warning.innerHTML = stats.warnings < 100 ? stats.warnings.toString() : manyMarkers; updateStatus(info, infoIcon, stats.infos); }; </del> this.markerService.onMarkerChanged((changedResources) => { updateLabel(this.markerService.getStatistics()); });


top, left, canUseZeroSizeTextarea ? 0 : 1, this._lineHeight ); <ins> // In case the textarea contains a word, we're going to try to align the textarea's cursor // with our cursor by scrolling the textarea as much as possible this.textArea.domNode.scrollLeft = 1000000; </ins> return; }


if (optionDisabled) { dom.addClass((<HTMLElement>data.root), 'option-disabled'); } else { <del> // TODO: verify if there is a list issue with old classes on rows // This class removal should not be necessary </del> <ins> // Make sure we do class removal from prior template rendering </ins> dom.removeClass((<HTMLElement>data.root), 'option-disabled'); } }


hoverMessage.appendMarkdown('n'); for (const { message, resource, startLineNumber, startColumn } of relatedInformation) { hoverMessage.appendMarkdown( <del> `* [${basename(resource.path)}(${startLineNumber}, ${startColumn})](${resource.toString(false)}#${startLineNumber},${startColumn}): `${message}` n` </del> <ins> `* [${basename(resource.path)}(${startLineNumber}, ${startColumn})](${resource.toString(false)}#${startLineNumber},${startColumn}): ` </ins> ); <ins> hoverMessage.appendText(`${message}`); hoverMessage.appendMarkdown('n'); </ins> } hoverMessage.appendMarkdown('n'); }


<del> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><defs><style>.icon-canvas-transparent,.icon-vs-out{fill:#f6f6f6;}.icon-canvas-transparent{opacity:0;}.icon-disabled-grey{fill:#848484;}</style></defs><title>breakpoint-function-unverified</title><g id="canvas"><path class="icon-canvas-transparent" d="M16,0V16H0V0Z"/></g><g id="outline" style="display: none;"><path class="icon-vs-out" d="M13.7,13H2.3L8,2.741Z"/></g><g id="iconBg"><path class="icon-disabled-grey" d="M8,4.8,4,12h8ZM8,6.859,10.3,11H5.7Z"/></g></svg> </del>  No newline at end of file <ins> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><defs><style>.icon-canvas-transparent,.icon-vs-out{fill:#f6f6f6;}.icon-canvas-transparent{opacity:0;}.icon-disabled-grey{fill:#848484;}</style></defs><title>breakpoint-function-unverified</title><g id="canvas"><path class="icon-canvas-transparent" d="M16,0V16H0V0Z"/></g><g id="outline" style="display: none;"><path class="icon-vs-out" d="M13.95,13H2.05L8,2.291Z"/></g><g id="iconBg"><path class="icon-disabled-grey" d="M8,4.35,3.75,12h8.5ZM8,6.924l2.125,3.826H5.875Z"/></g></svg> </ins>  No newline at end of file


<del> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><defs><style>.icon-canvas-transparent,.icon-vs-out{fill:#f6f6f6;}.icon-canvas-transparent{opacity:0;}.icon-disabled-grey{fill:#848484;}</style></defs><title>breakpoint-log-unverified</title><g id="canvas"><path class="icon-canvas-transparent" d="M16,0V16H0V0Z"/></g><g id="outline" style="display: none;"><path class="icon-vs-out" d="M13.414,8,8,13.414,2.586,8,8,2.586Z"/></g><g id="iconBg"><path class="icon-disabled-grey" d="M8,4,4,8l4,4,4-4ZM5.414,8,8,5.414,10.586,8,8,10.586Z"/></g></svg> </del>  No newline at end of file <ins> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><defs><style>.icon-canvas-transparent,.icon-vs-out{fill:#f6f6f6;}.icon-canvas-transparent{opacity:0;}.icon-disabled-grey{fill:#848484;}</style></defs><title>breakpoint-log-unverified</title><g id="canvas"><path class="icon-canvas-transparent" d="M16,0V16H0V0Z"/></g><g id="outline" style="display: none;"><path class="icon-vs-out" d="M13.664,8,8,13.664,2.336,8,8,2.336Z"/></g><g id="iconBg"><path class="icon-disabled-grey" d="M8,3.75,3.75,8,8,12.25,12.25,8ZM5.518,8,8,5.518,10.482,8,8,10.482Z"/></g></svg> </ins>  No newline at end of file


<del> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><defs><style>.icon-canvas-transparent,.icon-vs-out{fill:#f6f6f6;}.icon-canvas-transparent{opacity:0;}.icon-disabled-grey{fill:#848484;}</style></defs><title>breakpoint-unverified</title><g id="canvas"><path class="icon-canvas-transparent" d="M16,0V16H0V0Z"/></g><g id="outline" style="display: none;"><path class="icon-vs-out" d="M12.632,8A4.632,4.632,0,1,1,8,3.368,4.638,4.638,0,0,1,12.632,8Z"/></g><g id="iconBg"><path class="icon-disabled-grey" d="M8,4.211A3.789,3.789,0,1,0,11.789,8,3.788,3.788,0,0,0,8,4.211ZM8,10.79A2.79,2.79,0,1,1,10.79,8,2.794,2.794,0,0,1,8,10.79Z"/></g></svg> </del>  No newline at end of file <ins> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><defs><style>.icon-canvas-transparent,.icon-vs-out{fill:#f6f6f6;}.icon-canvas-transparent{opacity:0;}.icon-disabled-grey{fill:#848484;}</style></defs><title>breakpoint-unverified</title><g id="canvas"><path class="icon-canvas-transparent" d="M16,0V16H0V0Z"/></g><g id="outline" style="display: none;"><path class="icon-vs-out" d="M12.632,8A4.632,4.632,0,1,1,8,3.368,4.638,4.638,0,0,1,12.632,8Z"/></g><g id="iconBg"><path class="icon-disabled-grey" d="M8,4.211A3.789,3.789,0,1,0,11.79,8,3.788,3.788,0,0,0,8,4.211ZM8,10.29A2.29,2.29,0,1,1,10.29,8,2.292,2.292,0,0,1,8,10.29Z"/></g></svg> </ins>  No newline at end of file


const extRecommendations = this.extensionTipsService.getAllRecommendationsWithReason(); if (extRecommendations[extension.id.toLowerCase()]) { <del> data.root.setAttribute('aria-label', extension.displayName + '. ' + extRecommendations[extension.id]); </del> <ins> data.root.setAttribute('aria-label', extension.displayName + '. ' + extRecommendations[extension.id.toLowerCase()].reasonText); </ins> addClass(data.root, 'recommended'); data.root.title = extRecommendations[extension.id.toLowerCase()].reasonText; }


"command": "git.stashPopLatest", "title": "%command.stashPopLatest%", "category": "Git" <ins> }, { "command": "git.stashApply", "title": "%command.stashApply%", "category": "Git" }, { "command": "git.stashApplyLatest", "title": "%command.stashApplyLatest%", "category": "Git" </ins> } ], "menus": {


{ "command": "git.stashPopLatest", "when": "config.git.enabled && gitOpenRepositoryCount != 0" <ins> }, { "command": "git.stashApply", "when": "config.git.enabled && gitOpenRepositoryCount != 0" }, { "command": "git.stashApplyLatest", "when": "config.git.enabled && gitOpenRepositoryCount != 0" </ins> } ], "scm/title": [


"when": "scmProvider == git" }, { <ins> "command": "git.stashApply", "group": "5_stash", "when": "scmProvider == git" }, { "command": "git.stashApplyLatest", "group": "5_stash", "when": "scmProvider == git" }, { </ins> "command": "git.showOutput", "group": "7_repository", "when": "scmProvider == git"


"command.stash": "Stash", "command.stashPop": "Pop Stash...", "command.stashPopLatest": "Pop Latest Stash", <ins> "command.stashApply": "Apply Stash...", "command.stashApplyLatest": "Apply Latest Stash", </ins> "config.enabled": "Whether git is enabled", "config.path": "Path to the git executable", "config.autoRepositoryDetection": "Configures when repositories should be automatically detected.",


'use strict'; import { Uri, commands, Disposable, window, workspace, QuickPickItem, OutputChannel, Range, WorkspaceEdit, Position, LineChange, SourceControlResourceState, TextDocumentShowOptions, ViewColumn, ProgressLocation, TextEditor, MessageOptions } from 'vscode'; <del> import { Ref, RefType, Git, GitErrorCodes, Branch } from './git'; </del> <ins> import { Ref, RefType, Git, GitErrorCodes, Branch, Stash } from './git'; </ins> import { Repository, Resource, Status, CommitOptions, ResourceGroupType } from './repository'; import { Model } from './model'; import { toGitUri, fromGitUri } from './uri';


@command('git.stashPop', { repository: true }) async stashPop(repository: Repository): Promise<void> { <ins> const placeHolder = localize('pick stash to pop', "Pick a stash to pop"); const choice = await this.pickStash(repository, placeHolder); if (!choice) { return; } await repository.popStash(choice.id); } @command('git.stashPopLatest', { repository: true }) async stashPopLatest(repository: Repository): Promise<void> { </ins> const stashes = await repository.getStashes(); <del> if (stashes.length === 0) { window.showInformationMessage(localize('no stashes', "There are no stashes to restore.")); </del> <ins> if (!this.anyStashesAvailableToRestore(stashes)) { </ins> return; } <del> const picks = stashes.map(r => ({ label: `#${r.index}:  ${r.description}`, description: '', details: '', id: r.index })); const placeHolder = localize('pick stash to pop', "Pick a stash to pop"); const choice = await window.showQuickPick(picks, { placeHolder }); </del> <ins> await repository.popStash(); } @command('git.stashApply', { repository: true }) async stashApply(repository: Repository): Promise<void> { const placeHolder = localize('pick stash to apply', "Pick a stash to apply"); const choice = await this.pickStash(repository, placeHolder); </ins> if (!choice) { return; } <del> await repository.popStash(choice.id); </del> <ins> await repository.applyStash(choice.id); </ins> } <del> @command('git.stashPopLatest', { repository: true }) async stashPopLatest(repository: Repository): Promise<void> { </del> <ins> @command('git.stashApplyLatest', { repository: true }) async stashApplyLatest(repository: Repository): Promise<void> { </ins> const stashes = await repository.getStashes(); <del> if (stashes.length === 0) { </del> <ins> if (!this.anyStashesAvailableToRestore(stashes)) { return; } await repository.applyStash(); } private anyStashesAvailableToRestore(stashes: Stash[]): boolean { const stashesAvailable = stashes.length > 0; if (!stashesAvailable) { </ins> window.showInformationMessage(localize('no stashes', "There are no stashes to restore.")); <ins> } return stashesAvailable; } private async pickStash(repository: Repository, placeHolder: string) { const stashes = await repository.getStashes(); if (!this.anyStashesAvailableToRestore(stashes)) { </ins> return; } <del> await repository.popStash(); </del> <ins> const picks = stashes.map(r => ({ label: `#${r.index}:  ${r.description}`, description: '', details: '', id: r.index })); return await window.showQuickPick(picks, { placeHolder }); </ins> } private createCommand(id: string, key: string, method: Function, options: CommandOptions): (...args: any[]) => any { const result = (...args: any[]) => { let result: Promise<any>;


} async popStash(index?: number): Promise<void> { <del> try { const args = ['stash', 'pop']; </del> <ins> const args = ['stash', 'pop']; this.popOrApplyStash(args, index); } async applyStash(index?: number): Promise<void> { const args = ['stash', 'apply']; this.popOrApplyStash(args, index); } private async popOrApplyStash(args: string[], index?: number): Promise<void> { try { </ins> if (typeof index === 'number') { args.push(`stash@{${index}}`); }


} } getStatus(limit = 5000): Promise<{ status: IFileStatus[]; didHitLimit: boolean; }> { return new Promise<{ status: IFileStatus[]; didHitLimit: boolean; }>((c, e) => { const parser = new GitStatusParser();


return await this.run(Operation.Stash, () => this.repository.popStash(index)); } <ins> async applyStash(index?: number): Promise<void> { return await this.run(Operation.Stash, () => this.repository.applyStash(index)); } </ins> async getCommitTemplate(): Promise<string> { return await this.run(Operation.GetCommitTemplate, async () => this.repository.getCommitTemplate()); }


this._toDispose.push(this._editor.onContextMenu((e: IEditorMouseEvent) => this._onContextMenu(e))); this._toDispose.push(this._editor.onDidScrollChange((e: IScrollEvent) => { <del> if (this._contextMenuIsBeingShownCount > 0) { </del> <ins> if (this._contextMenuIsBeingShownCount > 0 && e.scrollTopChanged) { </ins> this._contextViewService.hideContextView(); } }));


} // 1.file.txt=>2.file.txt <del> let prefixFileRegex = RegExp('(d+)(' + separators + '.*)(..*)$'); </del> <ins> let prefixFileRegex = RegExp('^(d+)(' + separators + '.*)(..*)$'); </ins> if (!isFolder && name.match(prefixFileRegex)) { return name.replace(prefixFileRegex, (match, g1?, g2?, g3?) => { let number = parseInt(g1);


} // 1.txt=>2.txt <del> let prefixFileNoNameRegex = RegExp('(d+)(..*)$'); </del> <ins> let prefixFileNoNameRegex = RegExp('^(d+)(..*)$'); </ins> if (!isFolder && name.match(prefixFileNoNameRegex)) { return name.replace(prefixFileNoNameRegex, (match, g1?, g2?) => { let number = parseInt(g1);


assert.strictEqual(result, '2.test.js'); }); <ins> test('Increment file name with prefix version - check if starting from digit', function () { const name = 'F1.test.js'; const result = incrementFileName(name, false); assert.strictEqual(result, 'F1.test.1.js'); }); </ins> test('Increment file name with just version in name', function () { const name = '1.js'; const result = incrementFileName(name, false); assert.strictEqual(result, '2.js'); }); <ins> test('Increment file name with just version in name - check if starting from digit', function () { const name = 'F1.js'; const result = incrementFileName(name, false); assert.strictEqual(result, 'F1.1.js'); }); </ins> test('Increment file name with just version in name, too big number', function () { const name = '9007199254740992.js'; const result = incrementFileName(name, false);


this.value = value.trim(); } <del> static autocompletions(): string[] { </del> <ins> static autocompletions(query: string): string[] { </ins> const commands = ['installed', 'outdated', 'enabled', 'disabled', 'builtin', 'recommended', 'sort', 'category', 'tag', 'ext']; const subcommands = { 'sort': ['installs', 'rating', 'name'],


'ext': [''] }; <ins> let queryContains = (substr: string) => query.indexOf(substr) > -1; let hasSort = subcommands.sort.some(subcommand => queryContains(`@sort:${subcommand}`)); let hasCategory = subcommands.category.some(subcommand => queryContains(`@category:${subcommand}`)); </ins> return flatten( <del> commands.map(command => subcommands[command] ? subcommands[command].map(subcommand => `@${command}:${subcommand}${subcommand === '' ? '' : ' '}`) : [`@${command} `])); </del> <ins> commands.map(command => { if (hasSort && command === 'sort' || hasCategory && command === 'category') { return []; } if (subcommands[command]) { return subcommands[command].map(subcommand => `@${command}:${subcommand}${subcommand === '' ? '' : ' '}`); } else { return [`@${command} `]; } })); </ins> } static parse(value: string): Query {


// dont show autosuggestions if the user has typed something, but hasn't used the trigger character if (alreadyTypedCount > 0 && query[wordStart] !== '@') { return []; } <del> return Query.autocompletions().map(replacement => ({ fullText: replacement, overwrite: alreadyTypedCount })); </del> <ins> return Query.autocompletions(query).map(replacement => ({ fullText: replacement, overwrite: alreadyTypedCount })); </ins> } private count(): number {


query2 = new Query('hello', 'installs', ''); assert(!query1.equals(query2)); }); <ins> test('autocomplete', () => { Query.autocompletions('@sort:in').some(x => x === '@sort:installs '); Query.autocompletions('@sort:installs').every(x => x !== '@sort:rating '); Query.autocompletions('@category:blah').some(x => x === '@category:"extension packs" '); Query.autocompletions('@category:"extension packs"').every(x => x !== '@category:formatters '); }); </ins> });  No newline at end of file


config.wordWrap = 'off'; config.scrollbar.vertical = 'hidden'; config.ariaLabel = ariaLabel || ''; <ins> config.renderIndentGuides = false; </ins> config.cursorWidth = 1; config.snippetSuggestions = 'none'; config.suggest = { filterGraceful: false };


this.overriddenScopeList = overriddenScopeList; this.description = this.setting.description.join('n'); <del> if (this.setting.enum && (this.setting.type === 'string' || !this.setting.type)) { </del> <ins> if (this.setting.enum && (!this.setting.type || settingTypeEnumRenderable(this.setting.type))) { </ins> this.valueType = 'enum'; } else if (this.setting.type === 'string') { this.valueType = 'string';


setting.key === 'search.exclude'; } <ins> function settingTypeEnumRenderable(_type: string | string[]) { const enumRenderableSettingTypes = ['string', 'boolean', 'null', 'integer', 'number']; let type = isArray(_type) ? _type : [_type]; return type.every(type => enumRenderableSettingTypes.indexOf(type) > -1); } </ins> export enum SearchResultIdx { Local = 0, Remote = 1,


"rimraf": "^2.6.1", "strip-json-comments": "^2.0.1", "tmp": "0.0.33", <del> "typescript": "2.5.2", </del> <ins> "typescript": "2.9.2", </ins> "watch": "^1.0.2" } }


version "0.0.6" resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" <del> typescript@2.5.2: version "2.5.2" resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.5.2.tgz#038a95f7d9bbb420b1bf35ba31d4c5c1dd3ffe34" </del> <ins> typescript@2.9.2: version "2.9.2" resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.9.2.tgz#1cbf61d05d6b96269244eb6a3bce4bd914e0f00c" </ins> uid-number@^0.0.6: version "0.0.6"


import { isWindows } from 'vs/base/common/platform'; import URI from 'vs/base/common/uri'; import { ltrim } from 'vs/base/common/strings'; <ins> import { RunOnceScheduler } from 'vs/base/common/async'; import { memoize } from 'vs/base/common/decorators'; </ins> const SMART = true;


private treeContainer: HTMLElement; private loadedScriptsItemType: IContextKey<string>; private settings: any; <ins> private shouldRefreshRecursive; </ins> constructor( options: IViewletViewOptions,


this.loadedScriptsItemType = CONTEXT_LOADED_SCRIPTS_ITEM_TYPE.bindTo(contextKeyService); } <ins> @memoize private get treeRefreshScheduler(): RunOnceScheduler { return new RunOnceScheduler(() => { if (this.tree) { this.tree.refresh(undefined, this.shouldRefreshRecursive); this.shouldRefreshRecursive = false; } }, 300); } </ins> protected renderBody(container: HTMLElement): void { dom.addClass(container, 'debug-loaded-scripts');


const root = new RootTreeItem(this.debugService.getModel(), this.environmentService, this.contextService); this.tree.setInput(root); <del> let timeout: number; </del> const registerLoadedSourceListener = (session: ISession) => { this.disposables.push(session.onDidLoadedSource(event => { const sessionRoot = root.add(session); sessionRoot.addPath(event.source); <del> clearTimeout(timeout); timeout = setTimeout(() => { if (this.tree) { this.tree.refresh(root, true); } }, 300); </del> <ins> this.shouldRefreshRecursive = true; this.treeRefreshScheduler.schedule(); </ins> })); };


this.debugService.getModel().getSessions().forEach(registerLoadedSourceListener); this.disposables.push(this.debugService.onDidEndSession(session => { <del> clearTimeout(timeout); </del> root.remove(session.getId()); <del> if (this.tree) { this.tree.refresh(root, false); } </del> <ins> this.treeRefreshScheduler.schedule(); </ins> })); }


this.settings[LoadedScriptsView.MEMENTO] = !this.isExpanded(); super.shutdown(); } <ins> dispose(): void { super.dispose(); this.tree = undefined; } </ins> } // A good example of data source, renderers, action providers and accessibilty providers can be found in the callStackView.ts


} .hljs-addition { <del> background-color: #144212; </del> <ins> background-color: var(--vscode-diffEditor-insertedTextBackground, rgba(155, 185, 85, 0.2)); color: rgb(155, 185, 85); </ins> display: inline-block; width: 100%; } .hljs-deletion { <del> background-color: #600; </del> <ins> background: var(--vscode-diffEditor-removedTextBackground, rgba(255, 0, 0, 0.2)); color: rgb(255, 0, 0); </ins> display: inline-block; width: 100%; }


.vscode-light .hljs-literal, .vscode-light .hljs-template-tag, .vscode-light .hljs-template-variable, <del> .vscode-light .hljs-type, .vscode-light .hljs-addition { </del> <ins> .vscode-light .hljs-type { </ins> color: #a31515; } <del> .vscode-light .hljs-deletion, </del> .vscode-light .hljs-selector-attr, .vscode-light .hljs-selector-pseudo, .vscode-light .hljs-meta {


white-space: nowrap; } <del> .monaco-select-box-dropdown-container > .select-box-dropdown-list-container .monaco-list .monaco-list-row > .option-text-description { display: none; </del> <ins> /* Accepted CSS hiding technique for accessibility reader text  */ /* https://webaim.org/techniques/css/invisiblecontent/ */ .monaco-select-box-dropdown-container > .select-box-dropdown-list-container .monaco-list .monaco-list-row > .visually-hidden { position: absolute; left: -10000px; top: auto; width: 1px; height: 1px; overflow: hidden; </ins> } .monaco-select-box-dropdown-container > .select-box-dropdown-container-width-control {


import 'vs/css!./selectBoxCustom'; <del> import * as nls from 'vs/nls'; </del> import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { Event, Emitter, chain } from 'vs/base/common/event'; import { KeyCode, KeyCodeUtils } from 'vs/base/common/keyCodes';


data.root = container; data.optionText = dom.append(container, $('.option-text')); data.optionDescriptionText = dom.append(container, $('.option-text-description')); <ins> dom.addClass(data.optionDescriptionText, 'visually-hidden'); </ins> return data; }


const optionDisabled = (<ISelectOptionItem>element).optionDisabled; data.optionText.textContent = optionText; <del> data.root.setAttribute('aria-label', nls.localize('selectAriaOption', "{0}", optionText) + ',.'); </del> if (typeof element.optionDescriptionText === 'string') { const optionDescriptionId = (optionText.replace(/ /g, '_').toLowerCase() + '_description_' + data.root.id); <del> data.root.setAttribute('aria-describedby', optionDescriptionId); </del> <ins> data.optionText.setAttribute('aria-describedby', optionDescriptionId); </ins> data.optionDescriptionText.id = optionDescriptionId; <del> data.optionDescriptionText.setAttribute('aria-label', element.optionDescriptionText); </del> <ins> data.optionDescriptionText.innerText = element.optionDescriptionText; </ins> } <del> // Workaround for list labels data.root.setAttribute('aria-selected', 'true'); </del> // pseudo-select disabled option if (optionDisabled) { dom.addClass((<HTMLElement>data.root), 'option-disabled');


}; registerTouchBarEntry(StartAction.ID, StartAction.LABEL, 0, CONTEXT_IN_DEBUG_MODE.toNegated(), 'continue-tb.png'); <ins> registerTouchBarEntry(RunAction.ID, RunAction.LABEL, 1, CONTEXT_IN_DEBUG_MODE.toNegated(), 'continue-without-debugging-tb.png'); </ins> registerTouchBarEntry(ContinueAction.ID, ContinueAction.LABEL, 0, CONTEXT_DEBUG_STATE.isEqualTo('stopped'), 'continue-tb.png'); registerTouchBarEntry(PauseAction.ID, PauseAction.LABEL, 1, ContextKeyExpr.and(CONTEXT_IN_DEBUG_MODE, ContextKeyExpr.notEquals('debugState', 'stopped')), 'pause-tb.png'); registerTouchBarEntry(StepOverAction.ID, StepOverAction.LABEL, 2, CONTEXT_DEBUG_STATE.isEqualTo('stopped'), 'stepover-tb.png');


} // Do not auto-close ' or " after a word character <del> if (autoClosingPair.open.length === 1 && chIsQuote && autoCloseConfig !== 'always') { </del> <ins> if (autoClosingPair.open.length === 1 && (ch === ''' || ch === '"') && autoCloseConfig !== 'always') { </ins> const wordSeparators = getMapForWordSeparators(config.wordSeparators); if (insertOpenCharacter && position.column > 1 && wordSeparators.get(lineText.charCodeAt(position.column - 2)) === WordCharacterClass.Regular) { return null;


model.undo(); } <ins> test('issue #61070: backtick (`) should auto-close after a word character', () => { let mode = new AutoClosingMode(); usingCursor({ text: ['const markup = highlight'], languageId: mode.languageId }, (editor, model, viewModel) => { model.forceTokenization(1); assertType(editor, model, viewModel, 1, 25, '`', '``', `auto closes ` @ (1, 25)`); }); mode.dispose(); }); </ins> test('open parens: default', () => { let mode = new AutoClosingMode(); usingCursor({


} .settings-editor > .settings-header > .settings-header-controls .settings-tabs-widget .action-label.checked { <del> font-weight: 500; </del> opacity: 1; }


import 'vs/css!./media/settingsWidgets'; import { localize } from 'vs/nls'; import { IContextViewService } from 'vs/platform/contextview/browser/contextView'; <del> import { foreground, inputBackground, inputBorder, inputForeground, listActiveSelectionBackground, listActiveSelectionForeground, listHoverBackground, listHoverForeground, listInactiveSelectionBackground, listInactiveSelectionForeground, registerColor, selectBackground, selectBorder, selectForeground, textLinkForeground, textPreformatForeground, editorWidgetBorder } from 'vs/platform/theme/common/colorRegistry'; </del> <ins> import { foreground, inputBackground, inputBorder, inputForeground, listActiveSelectionBackground, listActiveSelectionForeground, listHoverBackground, listHoverForeground, listInactiveSelectionBackground, listInactiveSelectionForeground, registerColor, selectBackground, selectBorder, selectForeground, textLinkForeground, textPreformatForeground, editorWidgetBorder, textLinkActiveForeground } from 'vs/platform/theme/common/colorRegistry'; </ins> import { attachButtonStyler, attachInputBoxStyler } from 'vs/platform/theme/common/styler'; import { ICssStyleCollector, ITheme, IThemeService, registerThemingParticipant } from 'vs/platform/theme/common/themeService'; import { disposableTimeout } from 'vs/base/common/async';


collector.addRule(`.monaco-select-box-dropdown-container > .select-box-details-pane > .select-box-description-markdown a > code { color: ${link}; }`); } <ins> const activeLink = theme.getColor(textLinkActiveForeground); if (activeLink) { collector.addRule(`.settings-editor > .settings-body > .settings-tree-container .setting-item .setting-item-description-markdown a:hover, .settings-editor > .settings-body > .settings-tree-container .setting-item .setting-item-description-markdown a:active { color: ${activeLink}; }`); collector.addRule(`.settings-editor > .settings-body > .settings-tree-container .setting-item .setting-item-description-markdown a:hover > code, .settings-editor > .settings-body > .settings-tree-container .setting-item .setting-item-description-markdown a:active > code { color: ${activeLink}; }`); collector.addRule(`.monaco-select-box-dropdown-container > .select-box-details-pane > .select-box-description-markdown a:hover, .monaco-select-box-dropdown-container > .select-box-details-pane > .select-box-description-markdown a:active { color: ${activeLink}; }`); collector.addRule(`.monaco-select-box-dropdown-container > .select-box-details-pane > .select-box-description-markdown a:hover > code, .monaco-select-box-dropdown-container > .select-box-details-pane > .select-box-description-markdown a:active > code { color: ${activeLink}; }`); } </ins> const headerForegroundColor = theme.getColor(settingsHeaderForeground); if (headerForegroundColor) { collector.addRule(`.settings-editor > .settings-header > .settings-header-controls .settings-tabs-widget .action-label.checked { color: ${headerForegroundColor}; border-bottom-color: ${headerForegroundColor}; }`);


["'", "'"] ], "indentationRules": { <del> "increaseIndentPattern": "^s*((b(else|function|then|do|repeat)b((?!b(end|until)b).)*)|({s*))$", </del> <ins> "increaseIndentPattern": "^((?!(--)).)*((b(else|function|then|do|repeat)b((?!b(end|until)b).)*)|({s*))$", </ins> "decreaseIndentPattern": "^s*((b(elseif|else|end|until)b)|(})|()))" } }


private selectionDetailsPane: HTMLElement; private _skipLayout: boolean = false; <del> private _sticky: boolean = true; // for dev purposes only </del> <ins> private _sticky: boolean = false; // for dev purposes only </ins> constructor(options: string[], selected: number, contextViewProvider: IContextViewProvider, styles: ISelectBoxStyles, selectBoxOptions?: ISelectBoxOptions) {


private static getCommandLabel(menuCommand: ICommandAction, editorActionLabel: string): string { if (menuCommand) { <del> return typeof menuCommand.title === 'string' ? menuCommand.title : menuCommand.title.value; </del> <ins> let category; if (menuCommand.category) { category = typeof menuCommand.category === 'string' ? menuCommand.category : menuCommand.category.value; } const title = typeof menuCommand.title === 'string' ? menuCommand.title : menuCommand.title.value; return category ? `${category}: ${title}` : title; </ins> } if (editorActionLabel) {


padding: 0px 8px; border-radius: 2px; position: absolute; <del> right: 10px; </del> <ins> right: 35px; top: 0; } .settings-editor > .settings-header > .search-container > .settings-clear-widget { margin: 6px 0px; padding: 0px 8px; border-radius: 2px; position: absolute; right: 0px; </ins> top: 0; }


import { ISettingsEditorViewState, parseQuery, SearchResultIdx, SearchResultModel, SettingsTreeElement, SettingsTreeGroupChild, SettingsTreeGroupElement, SettingsTreeModel, SettingsTreeSettingElement } from 'vs/workbench/contrib/preferences/browser/settingsTreeModels'; import { settingsTextInputBorder } from 'vs/workbench/contrib/preferences/browser/settingsWidgets'; import { createTOCIterator, TOCTree, TOCTreeModel } from 'vs/workbench/contrib/preferences/browser/tocTree'; <del> import { CONTEXT_SETTINGS_EDITOR, CONTEXT_SETTINGS_SEARCH_FOCUS, CONTEXT_TOC_ROW_FOCUS, EXTENSION_SETTING_TAG, IPreferencesSearchService, ISearchProvider, MODIFIED_SETTING_TAG, SETTINGS_EDITOR_COMMAND_SHOW_CONTEXT_MENU } from 'vs/workbench/contrib/preferences/common/preferences'; </del> <ins> import { CONTEXT_SETTINGS_EDITOR, CONTEXT_SETTINGS_SEARCH_FOCUS, CONTEXT_TOC_ROW_FOCUS, EXTENSION_SETTING_TAG, IPreferencesSearchService, ISearchProvider, MODIFIED_SETTING_TAG, SETTINGS_EDITOR_COMMAND_SHOW_CONTEXT_MENU, SETTINGS_EDITOR_COMMAND_CLEAR_SEARCH_RESULTS } from 'vs/workbench/contrib/preferences/common/preferences'; </ins> import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService'; import { IPreferencesService, ISearchResult, ISettingsEditorModel, ISettingsEditorOptions, SettingsEditorOptions, SettingValueType } from 'vs/workbench/services/preferences/common/preferences'; import { SettingsEditor2Input } from 'vs/workbench/services/preferences/common/preferencesEditorInput'; import { Settings2EditorModel } from 'vs/workbench/services/preferences/common/preferencesModels'; <ins> import { Action } from 'vs/base/common/actions'; import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar'; </ins> function createGroupIterator(group: SettingsTreeGroupElement): Iterator<ITreeElement<SettingsTreeGroupChild>> { const groupsIt = Iterator.fromArray(group.children);


private scheduledRefreshes: Map<string, DOM.IFocusTracker>; private lastFocusedSettingElement: string | null = null; <ins> private actionBar: ActionBar; private actionsContainer: HTMLElement; </ins> /** Don't spam warnings */ private hasWarnedMissingSettings = false;


this.searchWidget.setValue(query.trim()); } <ins> clearSearch(): void { this.clearSearchResults(); this.focusSearch(); } </ins> private createHeader(parent: HTMLElement): void { this.headerContainer = DOM.append(parent, $('.settings-header')); const searchContainer = DOM.append(this.headerContainer, $('.search-container')); <ins> const clearInputAction = new Action(SETTINGS_EDITOR_COMMAND_CLEAR_SEARCH_RESULTS, localize('clearInput', "Clear Settings Search Input"), 'codicon-clear-all', false, () => { this.clearSearch(); return Promise.resolve(null); }); </ins> const searchBoxLabel = localize('SearchSettings.AriaLabel', "Search settings"); this.searchWidget = this._register(this.instantiationService.createInstance(SuggestEnabledInput, `${SettingsEditor2.ID}.searchbox`, searchContainer, { triggerCharacters: ['@'],


this.countElement.style.borderColor = border; })); <del> this._register(this.searchWidget.onInputDidChange(() => this.onSearchInputChanged())); </del> <ins> this._register(this.searchWidget.onInputDidChange(() => { const searchVal = this.searchWidget.getValue(); clearInputAction.enabled = !!searchVal; this.onSearchInputChanged(); })); </ins> const headerControlsContainer = DOM.append(this.headerContainer, $('.settings-header-controls')); const targetWidgetContainer = DOM.append(headerControlsContainer, $('.settings-target-container')); this.settingsTargetsWidget = this._register(this.instantiationService.createInstance(SettingsTargetsWidget, targetWidgetContainer, { enableRemoteSettings: true })); this.settingsTargetsWidget.settingsTarget = ConfigurationTarget.USER_LOCAL; this.settingsTargetsWidget.onDidTargetChange(target => this.onDidSettingsTargetChange(target)); <ins> this.actionsContainer = DOM.append(searchContainer, DOM.$('.settings-clear-widget')); this.actionBar = this._register(new ActionBar(this.actionsContainer, { animated: false, actionViewItemProvider: (action: Action) => { return undefined; } })); this.actionBar.push([clearInputAction], { label: false, icon: true }); </ins> } private onDidSettingsTargetChange(target: SettingsTarget): void {


if (stagedUnsavedTextDocuments.length > 0) { const message = stagedUnsavedTextDocuments.length === 1 <del> ? localize('unsaved files single', "The following file is unsaved: {0}.nnWould you like to save it before committing?", path.basename(stagedUnsavedTextDocuments[0].uri.fsPath)) : localize('unsaved files', "There are {0} unsaved files.nnWould you like to save them before committing?", stagedUnsavedTextDocuments.length); </del> <ins> ? localize('unsaved files single', "The following staged file is unsaved: {0}.nnWould you like to save it before committing?", path.basename(stagedUnsavedTextDocuments[0].uri.fsPath)) : localize('unsaved files', "There are {0} unsaved staged files.nnWould you like to save them before committing?", stagedUnsavedTextDocuments.length); </ins> const saveAndCommit = localize('save and commit', "Save All & Commit"); const commit = localize('commit', "Commit Anyway"); const pick = await window.showWarningMessage(message, { modal: true }, saveAndCommit, commit);


text-decoration: underline; } <del> .settings-editor.no-toc-search > .settings-body .settings-tree-container .monaco-list-rows, </del> .settings-editor.narrow-width > .settings-body .settings-tree-container .monaco-list-rows { margin-left: 0px; }


this._register(DOM.addDisposableListener(this.container, DOM.EventType.FOCUS_OUT, (e) => { let event = e as FocusEvent; <del> if (event.relatedTarget) { if (!this.container.contains(event.relatedTarget as HTMLElement)) { this.focusToReturn = undefined; this.setUnfocusedState(); } </del> <ins> if (!event.relatedTarget || !this.container.contains(event.relatedTarget as HTMLElement)) { this.focusToReturn = undefined; this.setUnfocusedState(); </ins> } }));


cursor: pointer; } <del> .monaco-workbench .monaco-font-aliasing-antialiased { </del> <ins> .monaco-workbench.monaco-font-aliasing-antialiased { </ins> -webkit-font-smoothing: antialiased; } <del> .monaco-workbench .monaco-font-aliasing-none { </del> <ins> .monaco-workbench.monaco-font-aliasing-none { </ins> -webkit-font-smoothing: none; } @media (-webkit-min-device-pixel-ratio: 2), (min-resolution: 192dpi) { <del> .monaco-workbench .monaco-font-aliasing-auto { </del> <ins> .monaco-workbench.monaco-font-aliasing-auto { </ins> -webkit-font-smoothing: antialiased; } }


return; } <del> const root = element instanceof SearchResult ? null : element; this.tree.setChildren(root, this.createIterator(element, collapseResults)); </del> <ins> if (element instanceof SearchResult) { this.tree.setChildren(null, this.createIterator(element, collapseResults)); } else { this.tree.setChildren(element, this.createIterator(element, collapseResults)); this.tree.rerender(element); } </ins> }); } }


layout(dimension: dom.Dimension): void { this.dimension = dimension; if (this.tree) { <ins> const lastElementVisible = this.tree.scrollTop + this.tree.renderHeight >= this.tree.scrollHeight; </ins> const treeHeight = dimension.height - this.replInputHeight; this.tree.getHTMLElement().style.height = `${treeHeight}px`; this.tree.layout(treeHeight, dimension.width); <ins> if (lastElementVisible) { revealLastElement(this.tree); } </ins> } this.replInputContainer.style.height = `${this.replInputHeight}px`;


if (this.replElementsChangeListener) { this.replElementsChangeListener.dispose(); } <ins> this.refreshScheduler.dispose(); </ins> super.dispose(); } }


constructor(private configurationService: IConfigurationService) { } getHeight(element: IReplElement): number { <ins> const countNumberOfLines = (str: string) => Math.max(1, (str.match(/rn|n/g) || []).length); </ins> // Give approximate heights. Repl has dynamic height so the tree will measure the actual height on its own. const fontSize = this.configurationService.getValue<IDebugConfiguration>('debug').console.fontSize; const rowHeight = Math.ceil(1.4 * fontSize); <del> if (element instanceof Expression && element.hasChildren) { return 2 * rowHeight; } </del> // In order to keep scroll position we need to give a good approximation to the tree <del> if (element instanceof SimpleReplElement) { // For every 150 characters increase the number of lines needed let count = Math.ceil(element.value.length / 150); for (let i = 0; i < element.value.length; i++) { if (element.value[i] === 'n' || element.value[i] === 'rn') { count++; } </del> <ins> // For every 150 characters increase the number of lines needed if (element instanceof Expression) { let { name, value } = element; let nameRows = countNumberOfLines(name) + Math.floor(name.length / 150); if (element.hasChildren) { return (nameRows + 1) * rowHeight; </ins> } <del> return Math.max(1, count) * rowHeight; </del> <ins> let valueRows = countNumberOfLines(value) + Math.floor(value.length / 150); return rowHeight * (nameRows + valueRows); } if (element instanceof SimpleReplElement) { let value = element.value; let valueRows = countNumberOfLines(value) + Math.floor(value.length / 150); return valueRows * rowHeight; </ins> } return rowHeight;


this._ui.update(newState); } <del> public showCodeActions(actions: Promise<CodeActionSet>, at: IAnchor | IPosition) { </del> <ins> public showCodeActions(actions: CodeActionSet, at: IAnchor | IPosition) { </ins> return this._ui.showCodeActionList(actions, at); }


} } <del> public async showCodeActionList(codeActions: Promise<CodeActionSet>, at?: IAnchor | IPosition): Promise<void> { let actions: CodeActionSet; try { actions = await codeActions; } catch (e) { onUnexpectedError(e); return; } </del> <ins> public async showCodeActionList(actions: CodeActionSet, at?: IAnchor | IPosition): Promise<void> { </ins> this._codeActionWidget.show(actions, at); }


import { Position } from 'vs/editor/common/core/position'; import { IRange, Range } from 'vs/editor/common/core/range'; import { ModelDecorationOptions } from 'vs/editor/common/model/textModel'; <del> import { DocumentColorProvider, Hover as MarkdownHover, HoverProviderRegistry, IColor, CodeAction } from 'vs/editor/common/modes'; </del> <ins> import { DocumentColorProvider, Hover as MarkdownHover, HoverProviderRegistry, IColor } from 'vs/editor/common/modes'; </ins> import { getColorPresentations } from 'vs/editor/contrib/colorPicker/color'; import { ColorDetector } from 'vs/editor/contrib/colorPicker/colorDetector'; import { ColorPickerModel } from 'vs/editor/contrib/colorPicker/colorPickerModel';


const hoverElement = $('div.hover-row.status-bar'); const disposables = new DisposableStore(); const actionsElement = dom.append(hoverElement, $('div.actions')); <del> disposables.add(this.renderAction(actionsElement, { label: nls.localize('quick fixes', "Quick Fix..."), commandId: QuickFixAction.Id, run: async (target) => { const codeActionsPromise = this.getCodeActions(markerHover.marker); disposables.add(toDisposable(() => codeActionsPromise.cancel())); const controller = QuickFixController.get(this._editor); const elementPosition = dom.getDomNodePagePosition(target); controller.showCodeActions(codeActionsPromise, { x: elementPosition.left + 6, y: elementPosition.top + elementPosition.height + 6 }); } })); </del> if (markerHover.marker.severity === MarkerSeverity.Error || markerHover.marker.severity === MarkerSeverity.Warning || markerHover.marker.severity === MarkerSeverity.Info) { disposables.add(this.renderAction(actionsElement, { label: nls.localize('peek problem', "Peek Problem"),


} })); } <ins> const quickfixPlaceholderElement = dom.append(actionsElement, $('div')); quickfixPlaceholderElement.style.opacity = '0'; quickfixPlaceholderElement.style.transition = 'opacity 0.2s'; setTimeout(() => quickfixPlaceholderElement.style.opacity = '1', 200); quickfixPlaceholderElement.textContent = nls.localize('checkingForQuickFixes', "Checking for quick fixes..."); disposables.add(toDisposable(() => quickfixPlaceholderElement.remove())); const codeActionsPromise = this.getCodeActions(markerHover.marker); disposables.add(toDisposable(() => codeActionsPromise.cancel())); codeActionsPromise.then(actions => { quickfixPlaceholderElement.style.transition = ''; quickfixPlaceholderElement.style.opacity = '1'; if (!actions.actions.length) { actions.dispose(); quickfixPlaceholderElement.textContent = nls.localize('noQuickFixes', "No quick fixes available"); return; } quickfixPlaceholderElement.remove(); let showing = false; disposables.add(toDisposable(() => { if (!showing) { actions.dispose(); } })); disposables.add(this.renderAction(actionsElement, { label: nls.localize('quick fixes', "Quick Fix..."), commandId: QuickFixAction.Id, run: (target) => { showing = true; const controller = QuickFixController.get(this._editor); const elementPosition = dom.getDomNodePagePosition(target); controller.showCodeActions(actions, { x: elementPosition.left + 6, y: elementPosition.top + elementPosition.height + 6 }); } })); }); </ins> this.renderDisposable.value = disposables; return hoverElement; } private getCodeActions(marker: IMarker): CancelablePromise<CodeActionSet> { <del> const noAction: CodeAction = { title: nls.localize('editor.action.quickFix.noneMessage', "No code actions available"), kind: CodeActionKind.QuickFix.value, }; return createCancelablePromise(async (cancellationToken): Promise<CodeActionSet> => { const result = await getCodeActions( </del> <ins> return createCancelablePromise(cancellationToken => { return getCodeActions( </ins> this._editor.getModel()!, new Range(marker.startLineNumber, marker.startColumn, marker.endLineNumber, marker.endColumn), { type: 'manual', filter: { kind: CodeActionKind.QuickFix } }, cancellationToken); <del> return { actions: result.actions.length ? result.actions : [noAction], hasAutoFix: result.hasAutoFix, dispose: () => result.dispose(), }; </del> }); }


import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; import { ILogService } from 'vs/platform/log/common/log'; import { SnippetSession } from './snippetSession'; <del> import { EditorState, CodeEditorStateFlag } from 'vs/editor/browser/core/editorState'; </del> export class SnippetController2 implements IEditorContribution {


this._updateState(); <del> // we listen on model and selection changes. usually // both events come in together and this is to prevent // that we don't call _updateState twice. let state: EditorState; let dedupedUpdateState = () => { if (!state || !state.validate(this._editor)) { this._updateState(); state = new EditorState(this._editor, CodeEditorStateFlag.Selection | CodeEditorStateFlag.Value); } }; </del> this._snippetListener = [ <del> this._editor.onDidChangeModelContent(e => { if (e.isFlush) { this.cancel(); } else { setTimeout(dedupedUpdateState, 0); } }), this._editor.onDidChangeCursorSelection(dedupedUpdateState), </del> <ins> this._editor.onDidChangeModelContent(e => e.isFlush && this.cancel()), </ins> this._editor.onDidChangeModel(() => this.cancel()), <ins> this._editor.onDidChangeCursorSelection(() => this._updateState()) </ins> ]; }


let ranges: Range[] | undefined; for (const placeholder of placeholdersWithEqualIndex) { <ins> if (placeholder.isFinalTabstop) { // ignore those break; } </ins> if (!ranges) { ranges = [];


return false; } <del> if (allPossibleSelections.has(0)) { // selection overlaps with a final tab stop which means // we done return false; } </del> // add selections from 'this' snippet so that we know all // selections for this placeholder allPossibleSelections.forEach((array, index) => {


import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; import { NullLogService } from 'vs/platform/log/common/log'; import { Handler } from 'vs/editor/common/editorCommon'; <del> import { timeout } from 'vs/base/common/async'; </del> suite('SnippetController2', function () {


assertSelections(editor, new Selection(1, 1, 1, 7), new Selection(2, 5, 2, 11)); editor.trigger('test', 'cut', {}); <del> assertContextKeys(contextKeys, false, false, false); </del> <ins> assertContextKeys(contextKeys, true, false, true); </ins> assertSelections(editor, new Selection(1, 1, 1, 1), new Selection(2, 5, 2, 5)); editor.trigger('test', 'type', { text: 'abc' }); <del> assertContextKeys(contextKeys, false, false, false); </del> <ins> assertContextKeys(contextKeys, true, false, true); </ins> ctrl.next(); assertContextKeys(contextKeys, false, false, false);


assertSelections(editor, new Selection(1, 4, 1, 4), new Selection(2, 8, 2, 8)); assertContextKeys(contextKeys, true, false, true); <del> // ctrl.next(); // assertSelections(editor, new Selection(1, 7, 1, 7), new Selection(2, 11, 2, 11)); // assertContextKeys(contextKeys, true, true, true); </del> <ins> ctrl.next(); assertSelections(editor, new Selection(1, 7, 1, 7), new Selection(2, 11, 2, 11)); assertContextKeys(contextKeys, true, true, true); </ins> ctrl.next(); assertSelections(editor, new Selection(1, 7, 1, 7), new Selection(2, 11, 2, 11));


ctrl.insert('farboo'); assertSelections(editor, new Selection(1, 7, 1, 7), new Selection(2, 11, 2, 11)); <del> // assertContextKeys(contextKeys, true, false, true); </del> <ins> assertContextKeys(contextKeys, true, false, true); </ins> <del> // ctrl.next(); // assertSelections(editor, new Selection(1, 7, 1, 7), new Selection(2, 11, 2, 11)); </del> <ins> ctrl.next(); assertSelections(editor, new Selection(1, 7, 1, 7), new Selection(2, 11, 2, 11)); </ins> assertContextKeys(contextKeys, false, false, false); });


assertSelections(editor, new Selection(1, 22, 1, 22)); }); <del> test('A little confusing visual effect of highlighting for snippet tabstop #43270', async function () { </del> <ins> test('User defined snippet tab stops ignored #72862', function () { </ins> const ctrl = new SnippetController2(editor, logService, contextKeys); model.setValue(''); editor.setSelection(new Selection(1, 1, 1, 1)); <del> ctrl.insert('background-color: ${1:fff};$0'); assertSelections(editor, new Selection(1, 19, 1, 22)); editor.setSelection(new Selection(1, 22, 1, 22)); </del> <ins> ctrl.insert('export default $1'); </ins> assertContextKeys(contextKeys, true, false, true); <del> editor.trigger('', 'deleteRight', null); assert.equal(model.getValue(), 'background-color: fff'); await timeout(0); // this depends on re-scheduling of events... assertContextKeys(contextKeys, false, false, false); </del> }); });