未验证 提交 fcb78f59 编写于 作者: D Daniel Imms 提交者: GitHub

Merge branch 'master' into tyriar/69865_remove_renderers

...@@ -450,7 +450,7 @@ export class CommandCenter { ...@@ -450,7 +450,7 @@ export class CommandCenter {
return; return;
} }
url = url.replace(/^\s*git\s+clone\s+/, ''); url = url.trim().replace(/^git\s+clone\s+/, '');
const config = workspace.getConfiguration('git'); const config = workspace.getConfiguration('git');
let defaultCloneDirectory = config.get<string>('defaultCloneDirectory') || os.homedir(); let defaultCloneDirectory = config.get<string>('defaultCloneDirectory') || os.homedir();
...@@ -1924,7 +1924,17 @@ export class CommandCenter { ...@@ -1924,7 +1924,17 @@ export class CommandCenter {
private async _sync(repository: Repository, rebase: boolean): Promise<void> { private async _sync(repository: Repository, rebase: boolean): Promise<void> {
const HEAD = repository.HEAD; const HEAD = repository.HEAD;
if (!HEAD || !HEAD.upstream) { if (!HEAD) {
return;
} else if (!HEAD.upstream) {
const branchName = HEAD.name;
const message = localize('confirm publish branch', "The branch '{0}' has no upstream branch. Would you like to publish this branch?", branchName);
const yes = localize('ok', "OK");
const pick = await window.showWarningMessage(message, { modal: true }, yes);
if (pick === yes) {
await this.publish(repository);
}
return; return;
} }
......
...@@ -11,12 +11,15 @@ import * as which from 'which'; ...@@ -11,12 +11,15 @@ import * as which from 'which';
import { EventEmitter } from 'events'; import { EventEmitter } from 'events';
import iconv = require('iconv-lite'); import iconv = require('iconv-lite');
import * as filetype from 'file-type'; import * as filetype from 'file-type';
import { assign, groupBy, denodeify, IDisposable, toDisposable, dispose, mkdirp, readBytes, detectUnicodeEncoding, Encoding, onceEvent } from './util'; import { assign, groupBy, denodeify, IDisposable, toDisposable, dispose, mkdirp, readBytes, detectUnicodeEncoding, Encoding, onceEvent, splitInChunks, Limiter } from './util';
import { CancellationToken } from 'vscode'; import { CancellationToken } from 'vscode';
import { URI } from 'vscode-uri'; import { URI } from 'vscode-uri';
import { detectEncoding } from './encoding'; import { detectEncoding } from './encoding';
import { Ref, RefType, Branch, Remote, GitErrorCodes, LogOptions, Change, Status } from './api/git'; import { Ref, RefType, Branch, Remote, GitErrorCodes, LogOptions, Change, Status } from './api/git';
// https://github.com/microsoft/vscode/issues/65693
const MAX_CLI_LENGTH = 30000;
const readfile = denodeify<string, string | null, string>(fs.readFile); const readfile = denodeify<string, string | null, string>(fs.readFile);
export interface IGit { export interface IGit {
...@@ -1139,13 +1142,14 @@ export class Repository { ...@@ -1139,13 +1142,14 @@ export class Repository {
args.push(treeish); args.push(treeish);
} }
if (paths && paths.length) {
args.push('--');
args.push.apply(args, paths);
}
try { try {
await this.run(args); if (paths && paths.length > 0) {
for (const chunk of splitInChunks(paths, MAX_CLI_LENGTH)) {
await this.run([...args, '--', ...chunk]);
}
} else {
await this.run(args);
}
} catch (err) { } catch (err) {
if (/Please,? commit your changes or stash them/.test(err.stderr || '')) { if (/Please,? commit your changes or stash them/.test(err.stderr || '')) {
err.gitErrorCode = GitErrorCodes.DirtyWorkTree; err.gitErrorCode = GitErrorCodes.DirtyWorkTree;
...@@ -1276,11 +1280,17 @@ export class Repository { ...@@ -1276,11 +1280,17 @@ export class Repository {
async clean(paths: string[]): Promise<void> { async clean(paths: string[]): Promise<void> {
const pathsByGroup = groupBy(paths, p => path.dirname(p)); const pathsByGroup = groupBy(paths, p => path.dirname(p));
const groups = Object.keys(pathsByGroup).map(k => pathsByGroup[k]); const groups = Object.keys(pathsByGroup).map(k => pathsByGroup[k]);
const tasks = groups.map(paths => () => this.run(['clean', '-f', '-q', '--'].concat(paths)));
for (let task of tasks) { const limiter = new Limiter(5);
await task(); const promises: Promise<any>[] = [];
for (const paths of groups) {
for (const chunk of splitInChunks(paths, MAX_CLI_LENGTH)) {
promises.push(limiter.queue(() => this.run(['clean', '-f', '-q', '--', ...chunk])));
}
} }
await Promise.all(promises);
} }
async undo(): Promise<void> { async undo(): Promise<void> {
...@@ -1746,8 +1756,11 @@ export class Repository { ...@@ -1746,8 +1756,11 @@ export class Repository {
} }
async updateSubmodules(paths: string[]): Promise<void> { async updateSubmodules(paths: string[]): Promise<void> {
const args = ['submodule', 'update', '--', ...paths]; const args = ['submodule', 'update', '--'];
await this.run(args);
for (const chunk of splitInChunks(paths, MAX_CLI_LENGTH)) {
await this.run([...args, ...chunk]);
}
} }
async getSubmodules(): Promise<Submodule[]> { async getSubmodules(): Promise<Submodule[]> {
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
import { commands, Uri, Command, EventEmitter, Event, scm, SourceControl, SourceControlInputBox, SourceControlResourceGroup, SourceControlResourceState, SourceControlResourceDecorations, SourceControlInputBoxValidation, Disposable, ProgressLocation, window, workspace, WorkspaceEdit, ThemeColor, DecorationData, Memento, SourceControlInputBoxValidationType, OutputChannel, LogLevel, env, ProgressOptions, CancellationToken } from 'vscode'; import { commands, Uri, Command, EventEmitter, Event, scm, SourceControl, SourceControlInputBox, SourceControlResourceGroup, SourceControlResourceState, SourceControlResourceDecorations, SourceControlInputBoxValidation, Disposable, ProgressLocation, window, workspace, WorkspaceEdit, ThemeColor, DecorationData, Memento, SourceControlInputBoxValidationType, OutputChannel, LogLevel, env, ProgressOptions, CancellationToken } from 'vscode';
import { Repository as BaseRepository, Commit, Stash, GitError, Submodule, CommitOptions, ForcePushMode } from './git'; import { Repository as BaseRepository, Commit, Stash, GitError, Submodule, CommitOptions, ForcePushMode } from './git';
import { anyEvent, filterEvent, eventToPromise, dispose, find, isDescendant, IDisposable, onceEvent, EmptyDisposable, debounceEvent, combinedDisposable, watch, IFileWatcher } from './util'; import { anyEvent, filterEvent, eventToPromise, dispose, find, isDescendant, IDisposable, onceEvent, EmptyDisposable, debounceEvent, combinedDisposable } from './util';
import { memoize, throttle, debounce } from './decorators'; import { memoize, throttle, debounce } from './decorators';
import { toGitUri } from './uri'; import { toGitUri } from './uri';
import { AutoFetcher } from './autofetch'; import { AutoFetcher } from './autofetch';
...@@ -14,6 +14,7 @@ import * as nls from 'vscode-nls'; ...@@ -14,6 +14,7 @@ import * as nls from 'vscode-nls';
import * as fs from 'fs'; import * as fs from 'fs';
import { StatusBarCommands } from './statusbar'; import { StatusBarCommands } from './statusbar';
import { Branch, Ref, Remote, RefType, GitErrorCodes, Status, LogOptions, Change } from './api/git'; import { Branch, Ref, Remote, RefType, GitErrorCodes, Status, LogOptions, Change } from './api/git';
import { IFileWatcher, watch } from './watch';
const timeout = (millis: number) => new Promise(c => setTimeout(c, millis)); const timeout = (millis: number) => new Promise(c => setTimeout(c, millis));
...@@ -956,21 +957,9 @@ export class Repository implements Disposable { ...@@ -956,21 +957,9 @@ export class Repository implements Disposable {
} }
}); });
const promises: Promise<void>[] = []; await this.repository.clean(toClean);
await this.repository.checkout('', toCheckout);
if (toClean.length > 0) { await this.repository.updateSubmodules(submodulesToUpdate);
promises.push(this.repository.clean(toClean));
}
if (toCheckout.length > 0) {
promises.push(this.repository.checkout('', toCheckout));
}
if (submodulesToUpdate.length > 0) {
promises.push(this.repository.updateSubmodules(submodulesToUpdate));
}
await Promise.all(promises);
}); });
} }
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
import 'mocha'; import 'mocha';
import { GitStatusParser, parseGitCommit, parseGitmodules, parseLsTree, parseLsFiles } from '../git'; import { GitStatusParser, parseGitCommit, parseGitmodules, parseLsTree, parseLsFiles } from '../git';
import * as assert from 'assert'; import * as assert from 'assert';
import { splitInChunks } from '../util';
suite('git', () => { suite('git', () => {
suite('GitStatusParser', () => { suite('GitStatusParser', () => {
...@@ -292,4 +293,78 @@ This is a commit message.`; ...@@ -292,4 +293,78 @@ This is a commit message.`;
]); ]);
}); });
}); });
});
\ No newline at end of file suite('splitInChunks', () => {
test('unit tests', function () {
assert.deepEqual(
[...splitInChunks(['hello', 'there', 'cool', 'stuff'], 6)],
[['hello'], ['there'], ['cool'], ['stuff']]
);
assert.deepEqual(
[...splitInChunks(['hello', 'there', 'cool', 'stuff'], 10)],
[['hello', 'there'], ['cool', 'stuff']]
);
assert.deepEqual(
[...splitInChunks(['hello', 'there', 'cool', 'stuff'], 12)],
[['hello', 'there'], ['cool', 'stuff']]
);
assert.deepEqual(
[...splitInChunks(['hello', 'there', 'cool', 'stuff'], 14)],
[['hello', 'there', 'cool'], ['stuff']]
);
assert.deepEqual(
[...splitInChunks(['hello', 'there', 'cool', 'stuff'], 2000)],
[['hello', 'there', 'cool', 'stuff']]
);
assert.deepEqual(
[...splitInChunks(['0', '01', '012', '0', '01', '012', '0', '01', '012'], 1)],
[['0'], ['01'], ['012'], ['0'], ['01'], ['012'], ['0'], ['01'], ['012']]
);
assert.deepEqual(
[...splitInChunks(['0', '01', '012', '0', '01', '012', '0', '01', '012'], 2)],
[['0'], ['01'], ['012'], ['0'], ['01'], ['012'], ['0'], ['01'], ['012']]
);
assert.deepEqual(
[...splitInChunks(['0', '01', '012', '0', '01', '012', '0', '01', '012'], 3)],
[['0', '01'], ['012'], ['0', '01'], ['012'], ['0', '01'], ['012']]
);
assert.deepEqual(
[...splitInChunks(['0', '01', '012', '0', '01', '012', '0', '01', '012'], 4)],
[['0', '01'], ['012', '0'], ['01'], ['012', '0'], ['01'], ['012']]
);
assert.deepEqual(
[...splitInChunks(['0', '01', '012', '0', '01', '012', '0', '01', '012'], 5)],
[['0', '01'], ['012', '0'], ['01', '012'], ['0', '01'], ['012']]
);
assert.deepEqual(
[...splitInChunks(['0', '01', '012', '0', '01', '012', '0', '01', '012'], 6)],
[['0', '01', '012'], ['0', '01', '012'], ['0', '01', '012']]
);
assert.deepEqual(
[...splitInChunks(['0', '01', '012', '0', '01', '012', '0', '01', '012'], 7)],
[['0', '01', '012', '0'], ['01', '012', '0'], ['01', '012']]
);
assert.deepEqual(
[...splitInChunks(['0', '01', '012', '0', '01', '012', '0', '01', '012'], 8)],
[['0', '01', '012', '0'], ['01', '012', '0', '01'], ['012']]
);
assert.deepEqual(
[...splitInChunks(['0', '01', '012', '0', '01', '012', '0', '01', '012'], 9)],
[['0', '01', '012', '0', '01'], ['012', '0', '01', '012']]
);
});
});
});
...@@ -3,8 +3,8 @@ ...@@ -3,8 +3,8 @@
* Licensed under the MIT License. See License.txt in the project root for license information. * Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/ *--------------------------------------------------------------------------------------------*/
import { Event, EventEmitter, Uri } from 'vscode'; import { Event } from 'vscode';
import { dirname, sep, join } from 'path'; import { dirname, sep } from 'path';
import { Readable } from 'stream'; import { Readable } from 'stream';
import * as fs from 'fs'; import * as fs from 'fs';
import * as byline from 'byline'; import * as byline from 'byline';
...@@ -345,18 +345,69 @@ export function pathEquals(a: string, b: string): boolean { ...@@ -345,18 +345,69 @@ export function pathEquals(a: string, b: string): boolean {
return a === b; return a === b;
} }
export interface IFileWatcher extends IDisposable { export function* splitInChunks(array: string[], maxChunkLength: number): IterableIterator<string[]> {
readonly event: Event<Uri>; let current: string[] = [];
let length = 0;
for (const value of array) {
let newLength = length + value.length;
if (newLength > maxChunkLength && current.length > 0) {
yield current;
current = [];
newLength = value.length;
}
current.push(value);
length = newLength;
}
if (current.length > 0) {
yield current;
}
} }
export function watch(location: string): IFileWatcher { interface ILimitedTaskFactory<T> {
const dotGitWatcher = fs.watch(location); factory: () => Promise<T>;
const onDotGitFileChangeEmitter = new EventEmitter<Uri>(); c: (value?: T | Promise<T>) => void;
dotGitWatcher.on('change', (_, e) => onDotGitFileChangeEmitter.fire(Uri.file(join(location, e as string)))); e: (error?: any) => void;
dotGitWatcher.on('error', err => console.error(err)); }
return new class implements IFileWatcher { export class Limiter<T> {
event = onDotGitFileChangeEmitter.event;
dispose() { dotGitWatcher.close(); } private runningPromises: number;
}; private maxDegreeOfParalellism: number;
private outstandingPromises: ILimitedTaskFactory<T>[];
constructor(maxDegreeOfParalellism: number) {
this.maxDegreeOfParalellism = maxDegreeOfParalellism;
this.outstandingPromises = [];
this.runningPromises = 0;
}
queue(factory: () => Promise<T>): Promise<T> {
return new Promise<T>((c, e) => {
this.outstandingPromises.push({ factory, c, e });
this.consume();
});
}
private consume(): void {
while (this.outstandingPromises.length && this.runningPromises < this.maxDegreeOfParalellism) {
const iLimitedTask = this.outstandingPromises.shift()!;
this.runningPromises++;
const promise = iLimitedTask.factory();
promise.then(iLimitedTask.c, iLimitedTask.e);
promise.then(() => this.consumed(), () => this.consumed());
}
}
private consumed(): void {
this.runningPromises--;
if (this.outstandingPromises.length > 0) {
this.consume();
}
}
} }
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { Event, EventEmitter, Uri } from 'vscode';
import { join } from 'path';
import * as fs from 'fs';
import { IDisposable } from './util';
export interface IFileWatcher extends IDisposable {
readonly event: Event<Uri>;
}
export function watch(location: string): IFileWatcher {
const dotGitWatcher = fs.watch(location);
const onDotGitFileChangeEmitter = new EventEmitter<Uri>();
dotGitWatcher.on('change', (_, e) => onDotGitFileChangeEmitter.fire(Uri.file(join(location, e as string))));
dotGitWatcher.on('error', err => console.error(err));
return new class implements IFileWatcher {
event = onDotGitFileChangeEmitter.event;
dispose() { dotGitWatcher.close(); }
};
}
...@@ -465,11 +465,11 @@ ...@@ -465,11 +465,11 @@
"c": ".IsInRole", "c": ".IsInRole",
"t": "source.powershell meta.scriptblock.powershell meta.scriptblock.powershell variable.other.readwrite.powershell variable.other.member.powershell", "t": "source.powershell meta.scriptblock.powershell meta.scriptblock.powershell variable.other.readwrite.powershell variable.other.member.powershell",
"r": { "r": {
"dark_plus": "variable: #9CDCFE", "dark_plus": "source.powershell variable.other.member: #DCDCAA",
"light_plus": "variable: #001080", "light_plus": "source.powershell variable.other.member: #795E26",
"dark_vs": "default: #D4D4D4", "dark_vs": "default: #D4D4D4",
"light_vs": "default: #000000", "light_vs": "default: #000000",
"hc_black": "variable: #9CDCFE" "hc_black": "source.powershell variable.other.member: #DCDCAA"
} }
}, },
{ {
......
...@@ -8,7 +8,8 @@ ...@@ -8,7 +8,8 @@
"scope": [ "scope": [
"entity.name.function", "entity.name.function",
"support.function", "support.function",
"support.constant.handlebars" "support.constant.handlebars",
"source.powershell variable.other.member"
], ],
"settings": { "settings": {
"foreground": "#DCDCAA" "foreground": "#DCDCAA"
...@@ -171,4 +172,4 @@ ...@@ -171,4 +172,4 @@
} }
} }
] ]
} }
\ No newline at end of file
...@@ -13,7 +13,8 @@ ...@@ -13,7 +13,8 @@
"scope": [ "scope": [
"entity.name.function", "entity.name.function",
"support.function", "support.function",
"support.constant.handlebars" "support.constant.handlebars",
"source.powershell variable.other.member"
], ],
"settings": { "settings": {
"foreground": "#DCDCAA" "foreground": "#DCDCAA"
...@@ -115,4 +116,4 @@ ...@@ -115,4 +116,4 @@
} }
} }
] ]
} }
\ No newline at end of file
...@@ -8,7 +8,8 @@ ...@@ -8,7 +8,8 @@
"scope": [ "scope": [
"entity.name.function", "entity.name.function",
"support.function", "support.function",
"support.constant.handlebars" "support.constant.handlebars",
"source.powershell variable.other.member"
], ],
"settings": { "settings": {
"foreground": "#795E26" "foreground": "#795E26"
...@@ -172,4 +173,4 @@ ...@@ -172,4 +173,4 @@
} }
] ]
} }
\ No newline at end of file
...@@ -81,7 +81,7 @@ export class StorageService extends Disposable implements IStorageService { ...@@ -81,7 +81,7 @@ export class StorageService extends Disposable implements IStorageService {
const useInMemoryStorage = !!this.environmentService.extensionTestsLocationURI; // no storage during extension tests! const useInMemoryStorage = !!this.environmentService.extensionTestsLocationURI; // no storage during extension tests!
// Create workspace storage and initalize // Create workspace storage and initialize
mark('willInitWorkspaceStorage'); mark('willInitWorkspaceStorage');
try { try {
await this.createWorkspaceStorage(useInMemoryStorage ? SQLiteStorageDatabase.IN_MEMORY_PATH : join(result.path, StorageService.WORKSPACE_STORAGE_NAME), result.wasCreated ? StorageHint.STORAGE_DOES_NOT_EXIST : undefined).init(); await this.createWorkspaceStorage(useInMemoryStorage ? SQLiteStorageDatabase.IN_MEMORY_PATH : join(result.path, StorageService.WORKSPACE_STORAGE_NAME), result.wasCreated ? StorageHint.STORAGE_DOES_NOT_EXIST : undefined).init();
......
...@@ -16,9 +16,10 @@ import { Registry } from 'vs/platform/registry/common/platform'; ...@@ -16,9 +16,10 @@ import { Registry } from 'vs/platform/registry/common/platform';
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers'; import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
import { Extensions as PanelExtensions, PanelDescriptor, PanelRegistry } from 'vs/workbench/browser/panel'; import { Extensions as PanelExtensions, PanelDescriptor, PanelRegistry } from 'vs/workbench/browser/panel';
import { ICommentInfo, ICommentService } from 'vs/workbench/contrib/comments/browser/commentService'; import { ICommentInfo, ICommentService } from 'vs/workbench/contrib/comments/browser/commentService';
import { CommentsPanel, COMMENTS_PANEL_ID, COMMENTS_PANEL_TITLE } from 'vs/workbench/contrib/comments/browser/commentsPanel'; import { CommentsPanel } from 'vs/workbench/contrib/comments/browser/commentsPanel';
import { IPanelService } from 'vs/workbench/services/panel/common/panelService'; import { IPanelService } from 'vs/workbench/services/panel/common/panelService';
import { CommentProviderFeatures, ExtHostCommentsShape, ExtHostContext, IExtHostContext, MainContext, MainThreadCommentsShape } from '../common/extHost.protocol'; import { CommentProviderFeatures, ExtHostCommentsShape, ExtHostContext, IExtHostContext, MainContext, MainThreadCommentsShape } from '../common/extHost.protocol';
import { COMMENTS_PANEL_ID, COMMENTS_PANEL_TITLE } from 'vs/workbench/contrib/comments/browser/commentsTreeViewer';
export class MainThreadCommentThread implements modes.CommentThread { export class MainThreadCommentThread implements modes.CommentThread {
......
...@@ -153,13 +153,13 @@ export class MainThreadDebugService implements MainThreadDebugServiceShape, IDeb ...@@ -153,13 +153,13 @@ export class MainThreadDebugService implements MainThreadDebugServiceShape, IDeb
type: debugType type: debugType
}; };
if (hasProvide) { if (hasProvide) {
provider.provideDebugConfigurations = (folder) => { provider.provideDebugConfigurations = (folder, token) => {
return this._proxy.$provideDebugConfigurations(handle, folder); return this._proxy.$provideDebugConfigurations(handle, folder, token);
}; };
} }
if (hasResolve) { if (hasResolve) {
provider.resolveDebugConfiguration = (folder, config) => { provider.resolveDebugConfiguration = (folder, config, token) => {
return this._proxy.$resolveDebugConfiguration(handle, folder, config); return this._proxy.$resolveDebugConfiguration(handle, folder, config, token);
}; };
} }
if (hasProvideDebugAdapter) { if (hasProvideDebugAdapter) {
......
...@@ -1242,8 +1242,8 @@ export interface ExtHostDebugServiceShape { ...@@ -1242,8 +1242,8 @@ export interface ExtHostDebugServiceShape {
$startDASession(handle: number, session: IDebugSessionDto): Promise<void>; $startDASession(handle: number, session: IDebugSessionDto): Promise<void>;
$stopDASession(handle: number): Promise<void>; $stopDASession(handle: number): Promise<void>;
$sendDAMessage(handle: number, message: DebugProtocol.ProtocolMessage): void; $sendDAMessage(handle: number, message: DebugProtocol.ProtocolMessage): void;
$resolveDebugConfiguration(handle: number, folder: UriComponents | undefined, debugConfiguration: IConfig): Promise<IConfig | null | undefined>; $resolveDebugConfiguration(handle: number, folder: UriComponents | undefined, debugConfiguration: IConfig, token: CancellationToken): Promise<IConfig | null | undefined>;
$provideDebugConfigurations(handle: number, folder: UriComponents | undefined): Promise<IConfig[]>; $provideDebugConfigurations(handle: number, folder: UriComponents | undefined, token: CancellationToken): Promise<IConfig[]>;
$legacyDebugAdapterExecutable(handle: number, folderUri: UriComponents | undefined): Promise<IAdapterDescriptor>; // TODO@AW legacy $legacyDebugAdapterExecutable(handle: number, folderUri: UriComponents | undefined): Promise<IAdapterDescriptor>; // TODO@AW legacy
$provideDebugAdapter(handle: number, session: IDebugSessionDto): Promise<IAdapterDescriptor>; $provideDebugAdapter(handle: number, session: IDebugSessionDto): Promise<IAdapterDescriptor>;
$acceptDebugSessionStarted(session: IDebugSessionDto): void; $acceptDebugSessionStarted(session: IDebugSessionDto): void;
......
...@@ -599,7 +599,7 @@ export class ExtHostDebugService implements ExtHostDebugServiceShape { ...@@ -599,7 +599,7 @@ export class ExtHostDebugService implements ExtHostDebugServiceShape {
this.fireBreakpointChanges(a, r, c); this.fireBreakpointChanges(a, r, c);
} }
public $provideDebugConfigurations(configProviderHandle: number, folderUri: UriComponents | undefined): Promise<vscode.DebugConfiguration[]> { public $provideDebugConfigurations(configProviderHandle: number, folderUri: UriComponents | undefined, token: CancellationToken): Promise<vscode.DebugConfiguration[]> {
return asPromise(async () => { return asPromise(async () => {
const provider = this.getConfigProviderByHandle(configProviderHandle); const provider = this.getConfigProviderByHandle(configProviderHandle);
if (!provider) { if (!provider) {
...@@ -609,7 +609,7 @@ export class ExtHostDebugService implements ExtHostDebugServiceShape { ...@@ -609,7 +609,7 @@ export class ExtHostDebugService implements ExtHostDebugServiceShape {
throw new Error('DebugConfigurationProvider has no method provideDebugConfigurations'); throw new Error('DebugConfigurationProvider has no method provideDebugConfigurations');
} }
const folder = await this.getFolder(folderUri); const folder = await this.getFolder(folderUri);
return provider.provideDebugConfigurations(folder, CancellationToken.None); return provider.provideDebugConfigurations(folder, token);
}).then(debugConfigurations => { }).then(debugConfigurations => {
if (!debugConfigurations) { if (!debugConfigurations) {
throw new Error('nothing returned from DebugConfigurationProvider.provideDebugConfigurations'); throw new Error('nothing returned from DebugConfigurationProvider.provideDebugConfigurations');
...@@ -618,7 +618,7 @@ export class ExtHostDebugService implements ExtHostDebugServiceShape { ...@@ -618,7 +618,7 @@ export class ExtHostDebugService implements ExtHostDebugServiceShape {
}); });
} }
public $resolveDebugConfiguration(configProviderHandle: number, folderUri: UriComponents | undefined, debugConfiguration: vscode.DebugConfiguration): Promise<vscode.DebugConfiguration | null | undefined> { public $resolveDebugConfiguration(configProviderHandle: number, folderUri: UriComponents | undefined, debugConfiguration: vscode.DebugConfiguration, token: CancellationToken): Promise<vscode.DebugConfiguration | null | undefined> {
return asPromise(async () => { return asPromise(async () => {
const provider = this.getConfigProviderByHandle(configProviderHandle); const provider = this.getConfigProviderByHandle(configProviderHandle);
if (!provider) { if (!provider) {
...@@ -628,7 +628,7 @@ export class ExtHostDebugService implements ExtHostDebugServiceShape { ...@@ -628,7 +628,7 @@ export class ExtHostDebugService implements ExtHostDebugServiceShape {
throw new Error('DebugConfigurationProvider has no method resolveDebugConfiguration'); throw new Error('DebugConfigurationProvider has no method resolveDebugConfiguration');
} }
const folder = await this.getFolder(folderUri); const folder = await this.getFolder(folderUri);
return provider.resolveDebugConfiguration(folder, debugConfiguration, CancellationToken.None); return provider.resolveDebugConfiguration(folder, debugConfiguration, token);
}); });
} }
......
...@@ -4,34 +4,31 @@ ...@@ -4,34 +4,31 @@
*--------------------------------------------------------------------------------------------*/ *--------------------------------------------------------------------------------------------*/
import 'vs/css!./media/panel'; import 'vs/css!./media/panel';
import * as nls from 'vs/nls';
import * as dom from 'vs/base/browser/dom'; import * as dom from 'vs/base/browser/dom';
import { IAction } from 'vs/base/common/actions'; import { IAction, Action } from 'vs/base/common/actions';
import { Event } from 'vs/base/common/event'; import { CollapseAllAction } from 'vs/base/browser/ui/tree/treeDefaults';
import { CollapseAllAction, DefaultAccessibilityProvider, DefaultController, DefaultDragAndDrop } from 'vs/base/parts/tree/browser/treeDefaults';
import { isCodeEditor } from 'vs/editor/browser/editorBrowser'; import { isCodeEditor } from 'vs/editor/browser/editorBrowser';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { TreeResourceNavigator, WorkbenchTree } from 'vs/platform/list/browser/listService'; import { TreeResourceNavigator2 } from 'vs/platform/list/browser/listService';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { IThemeService } from 'vs/platform/theme/common/themeService'; import { IThemeService } from 'vs/platform/theme/common/themeService';
import { Panel } from 'vs/workbench/browser/panel'; import { Panel } from 'vs/workbench/browser/panel';
import { CommentNode, CommentsModel, ResourceWithCommentThreads, ICommentThreadChangedEvent } from 'vs/workbench/contrib/comments/common/commentModel'; import { CommentNode, CommentsModel, ResourceWithCommentThreads, ICommentThreadChangedEvent } from 'vs/workbench/contrib/comments/common/commentModel';
import { ReviewController } from 'vs/workbench/contrib/comments/browser/commentsEditorContribution'; import { ReviewController } from 'vs/workbench/contrib/comments/browser/commentsEditorContribution';
import { CommentsDataFilter, CommentsDataSource, CommentsModelRenderer } from 'vs/workbench/contrib/comments/browser/commentsTreeViewer';
import { ICommentService, IWorkspaceCommentThreadsEvent } from 'vs/workbench/contrib/comments/browser/commentService'; import { ICommentService, IWorkspaceCommentThreadsEvent } from 'vs/workbench/contrib/comments/browser/commentService';
import { IEditorService, ACTIVE_GROUP, SIDE_GROUP } from 'vs/workbench/services/editor/common/editorService'; import { IEditorService, ACTIVE_GROUP, SIDE_GROUP } from 'vs/workbench/services/editor/common/editorService';
import { CommandsRegistry } from 'vs/platform/commands/common/commands'; import { CommandsRegistry } from 'vs/platform/commands/common/commands';
import { textLinkForeground, textLinkActiveForeground, focusBorder, textPreformatForeground } from 'vs/platform/theme/common/colorRegistry'; import { textLinkForeground, textLinkActiveForeground, focusBorder, textPreformatForeground } from 'vs/platform/theme/common/colorRegistry';
import { IOpenerService } from 'vs/platform/opener/common/opener';
import { IStorageService } from 'vs/platform/storage/common/storage'; import { IStorageService } from 'vs/platform/storage/common/storage';
import { ResourceLabels } from 'vs/workbench/browser/labels'; import { ResourceLabels } from 'vs/workbench/browser/labels';
import { IPanelService } from 'vs/workbench/services/panel/common/panelService'; import { IPanelService } from 'vs/workbench/services/panel/common/panelService';
import { CommentsList, COMMENTS_PANEL_ID, COMMENTS_PANEL_TITLE } from 'vs/workbench/contrib/comments/browser/commentsTreeViewer';
export const COMMENTS_PANEL_ID = 'workbench.panel.comments';
export const COMMENTS_PANEL_TITLE = 'Comments';
export class CommentsPanel extends Panel { export class CommentsPanel extends Panel {
private treeLabels: ResourceLabels; private treeLabels: ResourceLabels;
private tree: WorkbenchTree; private tree: CommentsList;
private treeContainer: HTMLElement; private treeContainer: HTMLElement;
private messageBoxContainer: HTMLElement; private messageBoxContainer: HTMLElement;
private messageBox: HTMLElement; private messageBox: HTMLElement;
...@@ -42,7 +39,6 @@ export class CommentsPanel extends Panel { ...@@ -42,7 +39,6 @@ export class CommentsPanel extends Panel {
@IInstantiationService private readonly instantiationService: IInstantiationService, @IInstantiationService private readonly instantiationService: IInstantiationService,
@ICommentService private readonly commentService: ICommentService, @ICommentService private readonly commentService: ICommentService,
@IEditorService private readonly editorService: IEditorService, @IEditorService private readonly editorService: IEditorService,
@IOpenerService private readonly openerService: IOpenerService,
@ITelemetryService telemetryService: ITelemetryService, @ITelemetryService telemetryService: ITelemetryService,
@IThemeService themeService: IThemeService, @IThemeService themeService: IThemeService,
@IStorageService storageService: IStorageService @IStorageService storageService: IStorageService
...@@ -113,7 +109,7 @@ export class CommentsPanel extends Panel { ...@@ -113,7 +109,7 @@ export class CommentsPanel extends Panel {
public getActions(): IAction[] { public getActions(): IAction[] {
if (!this.collapseAllAction) { if (!this.collapseAllAction) {
this.collapseAllAction = this.instantiationService.createInstance(CollapseAllAction, this.tree, this.commentsModel.hasCommentThreads()); this.collapseAllAction = new Action('vs.tree.collapse', nls.localize('collapseAll', "Collapse All"), 'monaco-tree-action collapse-all', true, () => this.tree ? new CollapseAllAction<any, any>(this.tree, true).run() : Promise.resolve());
this._register(this.collapseAllAction); this._register(this.collapseAllAction);
} }
...@@ -141,22 +137,11 @@ export class CommentsPanel extends Panel { ...@@ -141,22 +137,11 @@ export class CommentsPanel extends Panel {
private createTree(): void { private createTree(): void {
this.treeLabels = this._register(this.instantiationService.createInstance(ResourceLabels, this)); this.treeLabels = this._register(this.instantiationService.createInstance(ResourceLabels, this));
this.tree = this._register(this.instantiationService.createInstance(CommentsList, this.treeLabels, this.treeContainer));
this.tree = this._register(this.instantiationService.createInstance(WorkbenchTree, this.treeContainer, { const commentsNavigator = this._register(new TreeResourceNavigator2(this.tree, { openOnFocus: true }));
dataSource: new CommentsDataSource(), this._register(commentsNavigator.onDidOpenResource(e => {
renderer: new CommentsModelRenderer(this.treeLabels, this.openerService), this.openFile(e.element, e.editorOptions.pinned, e.editorOptions.preserveFocus, e.sideBySide);
accessibilityProvider: new DefaultAccessibilityProvider,
controller: new DefaultController(),
dnd: new DefaultDragAndDrop(),
filter: new CommentsDataFilter()
}, {
twistiePixels: 20,
ariaLabel: COMMENTS_PANEL_TITLE
}));
const commentsNavigator = this._register(new TreeResourceNavigator(this.tree, { openOnFocus: true }));
this._register(Event.debounce(commentsNavigator.openResource, (last, event) => event, 100, true)(options => {
this.openFile(options.element, options.editorOptions.pinned, options.editorOptions.preserveFocus, options.sideBySide);
})); }));
} }
...@@ -213,7 +198,7 @@ export class CommentsPanel extends Panel { ...@@ -213,7 +198,7 @@ export class CommentsPanel extends Panel {
this.collapseAllAction.enabled = this.commentsModel.hasCommentThreads(); this.collapseAllAction.enabled = this.commentsModel.hasCommentThreads();
dom.toggleClass(this.treeContainer, 'hidden', !this.commentsModel.hasCommentThreads()); dom.toggleClass(this.treeContainer, 'hidden', !this.commentsModel.hasCommentThreads());
this.tree.refresh().then(() => { this.tree.updateChildren().then(() => {
this.renderMessage(); this.renderMessage();
}, (e) => { }, (e) => {
console.log(e); console.log(e);
...@@ -243,4 +228,4 @@ CommandsRegistry.registerCommand({ ...@@ -243,4 +228,4 @@ CommandsRegistry.registerCommand({
panelService.openPanel(COMMENTS_PANEL_ID, true); panelService.openPanel(COMMENTS_PANEL_ID, true);
} }
} }
}); });
\ No newline at end of file
...@@ -9,30 +9,28 @@ import { renderMarkdown } from 'vs/base/browser/htmlContentRenderer'; ...@@ -9,30 +9,28 @@ import { renderMarkdown } from 'vs/base/browser/htmlContentRenderer';
import { onUnexpectedError } from 'vs/base/common/errors'; import { onUnexpectedError } from 'vs/base/common/errors';
import { IDisposable, DisposableStore } from 'vs/base/common/lifecycle'; import { IDisposable, DisposableStore } from 'vs/base/common/lifecycle';
import { URI } from 'vs/base/common/uri'; import { URI } from 'vs/base/common/uri';
import { IDataSource, IFilter, IRenderer as ITreeRenderer, ITree } from 'vs/base/parts/tree/browser/tree';
import { IOpenerService } from 'vs/platform/opener/common/opener'; import { IOpenerService } from 'vs/platform/opener/common/opener';
import { IResourceLabel, ResourceLabels } from 'vs/workbench/browser/labels'; import { IResourceLabel, ResourceLabels } from 'vs/workbench/browser/labels';
import { CommentNode, CommentsModel, ResourceWithCommentThreads } from 'vs/workbench/contrib/comments/common/commentModel'; import { CommentNode, CommentsModel, ResourceWithCommentThreads } from 'vs/workbench/contrib/comments/common/commentModel';
import { IAsyncDataSource, ITreeNode } from 'vs/base/browser/ui/tree/tree';
export class CommentsDataSource implements IDataSource { import { IListVirtualDelegate, IListRenderer } from 'vs/base/browser/ui/list/list';
public getId(tree: ITree, element: any): string { import { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility';
if (element instanceof CommentsModel) { import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
return 'root'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
} import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
if (element instanceof ResourceWithCommentThreads) { import { WorkbenchAsyncDataTree, IListService } from 'vs/platform/list/browser/listService';
return `${element.owner}-${element.id}`; import { IThemeService } from 'vs/platform/theme/common/themeService';
} import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
if (element instanceof CommentNode) {
return `${element.owner}-${element.resource.toString()}-${element.threadId}-${element.comment.uniqueIdInThread}` + (element.isRoot ? '-root' : ''); export const COMMENTS_PANEL_ID = 'workbench.panel.comments';
} export const COMMENTS_PANEL_TITLE = 'Comments';
return '';
} export class CommentsAsyncDataSource implements IAsyncDataSource<any, any> {
hasChildren(element: any): boolean {
public hasChildren(tree: ITree, element: any): boolean {
return element instanceof CommentsModel || element instanceof ResourceWithCommentThreads || (element instanceof CommentNode && !!element.replies.length); return element instanceof CommentsModel || element instanceof ResourceWithCommentThreads || (element instanceof CommentNode && !!element.replies.length);
} }
public getChildren(tree: ITree, element: any): Promise<ResourceWithCommentThreads[] | CommentNode[]> { getChildren(element: any): any[] | Promise<any[]> {
if (element instanceof CommentsModel) { if (element instanceof CommentsModel) {
return Promise.resolve(element.resourceCommentThreads); return Promise.resolve(element.resourceCommentThreads);
} }
...@@ -44,14 +42,6 @@ export class CommentsDataSource implements IDataSource { ...@@ -44,14 +42,6 @@ export class CommentsDataSource implements IDataSource {
} }
return Promise.resolve([]); return Promise.resolve([]);
} }
public getParent(tree: ITree, element: any): Promise<void> {
return Promise.resolve(undefined);
}
public shouldAutoexpand(tree: ITree, element: any): boolean {
return true;
}
} }
interface IResourceTemplateData { interface IResourceTemplateData {
...@@ -65,61 +55,36 @@ interface ICommentThreadTemplateData { ...@@ -65,61 +55,36 @@ interface ICommentThreadTemplateData {
disposables: IDisposable[]; disposables: IDisposable[];
} }
export class CommentsModelRenderer implements ITreeRenderer { export class CommentsModelVirualDelegate implements IListVirtualDelegate<any> {
private static RESOURCE_ID = 'resource-with-comments'; private static RESOURCE_ID = 'resource-with-comments';
private static COMMENT_ID = 'comment-node'; private static COMMENT_ID = 'comment-node';
constructor(
private labels: ResourceLabels,
@IOpenerService private readonly openerService: IOpenerService
) {
}
public getHeight(tree: ITree, element: any): number { getHeight(element: any): number {
return 22; return 22;
} }
public getTemplateId(tree: ITree, element: any): string { public getTemplateId(element: any): string {
if (element instanceof ResourceWithCommentThreads) { if (element instanceof ResourceWithCommentThreads) {
return CommentsModelRenderer.RESOURCE_ID; return CommentsModelVirualDelegate.RESOURCE_ID;
} }
if (element instanceof CommentNode) { if (element instanceof CommentNode) {
return CommentsModelRenderer.COMMENT_ID; return CommentsModelVirualDelegate.COMMENT_ID;
} }
return ''; return '';
} }
}
public renderTemplate(ITree: ITree, templateId: string, container: HTMLElement): any { export class ResourceWithCommentsRenderer implements IListRenderer<ITreeNode<ResourceWithCommentThreads>, IResourceTemplateData> {
switch (templateId) { templateId: string = 'resource-with-comments';
case CommentsModelRenderer.RESOURCE_ID:
return this.renderResourceTemplate(container);
case CommentsModelRenderer.COMMENT_ID:
return this.renderCommentTemplate(container);
}
}
public disposeTemplate(tree: ITree, templateId: string, templateData: any): void {
switch (templateId) {
case CommentsModelRenderer.RESOURCE_ID:
(<IResourceTemplateData>templateData).resourceLabel.dispose();
break;
case CommentsModelRenderer.COMMENT_ID:
(<ICommentThreadTemplateData>templateData).disposables.forEach(disposeable => disposeable.dispose());
break;
}
}
public renderElement(tree: ITree, element: any, templateId: string, templateData: any): void { constructor(
switch (templateId) { private labels: ResourceLabels
case CommentsModelRenderer.RESOURCE_ID: ) {
return this.renderResourceElement(tree, element, templateData);
case CommentsModelRenderer.COMMENT_ID:
return this.renderCommentElement(tree, element, templateData);
}
} }
private renderResourceTemplate(container: HTMLElement): IResourceTemplateData { renderTemplate(container: HTMLElement) {
const data = <IResourceTemplateData>Object.create(null); const data = <IResourceTemplateData>Object.create(null);
const labelContainer = dom.append(container, dom.$('.resource-container')); const labelContainer = dom.append(container, dom.$('.resource-container'));
data.resourceLabel = this.labels.create(labelContainer); data.resourceLabel = this.labels.create(labelContainer);
...@@ -127,7 +92,23 @@ export class CommentsModelRenderer implements ITreeRenderer { ...@@ -127,7 +92,23 @@ export class CommentsModelRenderer implements ITreeRenderer {
return data; return data;
} }
private renderCommentTemplate(container: HTMLElement): ICommentThreadTemplateData { renderElement(node: ITreeNode<ResourceWithCommentThreads>, index: number, templateData: IResourceTemplateData, height: number | undefined): void {
templateData.resourceLabel.setFile(node.element.resource);
}
disposeTemplate(templateData: IResourceTemplateData): void {
templateData.resourceLabel.dispose();
}
}
export class CommentNodeRenderer implements IListRenderer<ITreeNode<CommentNode>, ICommentThreadTemplateData> {
templateId: string = 'comment-node';
constructor(
@IOpenerService private readonly openerService: IOpenerService
) { }
renderTemplate(container: HTMLElement) {
const data = <ICommentThreadTemplateData>Object.create(null); const data = <ICommentThreadTemplateData>Object.create(null);
const labelContainer = dom.append(container, dom.$('.comment-container')); const labelContainer = dom.append(container, dom.$('.comment-container'));
data.userName = dom.append(labelContainer, dom.$('.user')); data.userName = dom.append(labelContainer, dom.$('.user'));
...@@ -137,16 +118,12 @@ export class CommentsModelRenderer implements ITreeRenderer { ...@@ -137,16 +118,12 @@ export class CommentsModelRenderer implements ITreeRenderer {
return data; return data;
} }
private renderResourceElement(tree: ITree, element: ResourceWithCommentThreads, templateData: IResourceTemplateData) { renderElement(node: ITreeNode<CommentNode>, index: number, templateData: ICommentThreadTemplateData, height: number | undefined): void {
templateData.resourceLabel.setFile(element.resource); templateData.userName.textContent = node.element.comment.userName;
}
private renderCommentElement(tree: ITree, element: CommentNode, templateData: ICommentThreadTemplateData) {
templateData.userName.textContent = element.comment.userName;
templateData.commentText.innerHTML = ''; templateData.commentText.innerHTML = '';
const disposables = new DisposableStore(); const disposables = new DisposableStore();
templateData.disposables.push(disposables); templateData.disposables.push(disposables);
const renderedComment = renderMarkdown(element.comment.body, { const renderedComment = renderMarkdown(node.element.comment.body, {
inline: true, inline: true,
actionHandler: { actionHandler: {
callback: (content) => { callback: (content) => {
...@@ -171,16 +148,71 @@ export class CommentsModelRenderer implements ITreeRenderer { ...@@ -171,16 +148,71 @@ export class CommentsModelRenderer implements ITreeRenderer {
templateData.commentText.appendChild(renderedComment); templateData.commentText.appendChild(renderedComment);
} }
disposeTemplate(templateData: ICommentThreadTemplateData): void {
templateData.disposables.forEach(disposeable => disposeable.dispose());
}
} }
export class CommentsDataFilter implements IFilter { export class CommentsList extends WorkbenchAsyncDataTree<any, any> {
public isVisible(tree: ITree, element: any): boolean { constructor(
if (element instanceof CommentsModel) { labels: ResourceLabels,
return element.resourceCommentThreads.length > 0; container: HTMLElement,
} @IContextKeyService contextKeyService: IContextKeyService,
if (element instanceof ResourceWithCommentThreads) { @IListService listService: IListService,
return element.commentThreads.length > 0; @IThemeService themeService: IThemeService,
} @IInstantiationService instantiationService: IInstantiationService,
return true; @IConfigurationService configurationService: IConfigurationService,
@IKeybindingService keybindingService: IKeybindingService,
@IAccessibilityService accessibilityService: IAccessibilityService
) {
const delegate = new CommentsModelVirualDelegate();
const dataSource = new CommentsAsyncDataSource();
const renderers = [
instantiationService.createInstance(ResourceWithCommentsRenderer, labels),
instantiationService.createInstance(CommentNodeRenderer)
];
super(
container,
delegate,
renderers,
dataSource,
{
ariaLabel: COMMENTS_PANEL_TITLE,
keyboardSupport: true,
identityProvider: {
getId: (element: any) => {
if (element instanceof CommentsModel) {
return 'root';
}
if (element instanceof ResourceWithCommentThreads) {
return `${element.owner}-${element.id}`;
}
if (element instanceof CommentNode) {
return `${element.owner}-${element.resource.toString()}-${element.threadId}-${element.comment.uniqueIdInThread}` + (element.isRoot ? '-root' : '');
}
return '';
}
},
expandOnlyOnTwistieClick: (element: any) => {
if (element instanceof CommentsModel || element instanceof ResourceWithCommentThreads) {
return false;
}
return true;
},
collapseByDefault: () => {
return false;
}
},
contextKeyService,
listService,
themeService,
configurationService,
keybindingService,
accessibilityService
);
} }
} }
...@@ -34,6 +34,7 @@ import { IQuickInputService } from 'vs/platform/quickinput/common/quickInput'; ...@@ -34,6 +34,7 @@ import { IQuickInputService } from 'vs/platform/quickinput/common/quickInput';
import { IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey'; import { IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey';
import { onUnexpectedError } from 'vs/base/common/errors'; import { onUnexpectedError } from 'vs/base/common/errors';
import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
import { CancellationToken } from 'vs/base/common/cancellation';
const jsonRegistry = Registry.as<IJSONContributionRegistry>(JSONExtensions.JSONContribution); const jsonRegistry = Registry.as<IJSONContributionRegistry>(JSONExtensions.JSONContribution);
jsonRegistry.registerSchema(launchSchemaId, launchSchema); jsonRegistry.registerSchema(launchSchemaId, launchSchema);
...@@ -180,7 +181,7 @@ export class ConfigurationManager implements IConfigurationManager { ...@@ -180,7 +181,7 @@ export class ConfigurationManager implements IConfigurationManager {
return providers.length > 0; return providers.length > 0;
} }
resolveConfigurationByProviders(folderUri: uri | undefined, type: string | undefined, debugConfiguration: IConfig): Promise<IConfig | null | undefined> { resolveConfigurationByProviders(folderUri: uri | undefined, type: string | undefined, debugConfiguration: IConfig, token: CancellationToken): Promise<IConfig | null | undefined> {
return this.activateDebuggers('onDebugResolve', type).then(() => { return this.activateDebuggers('onDebugResolve', type).then(() => {
// pipe the config through the promises sequentially. Append at the end the '*' types // pipe the config through the promises sequentially. Append at the end the '*' types
const providers = this.configProviders.filter(p => p.type === type && p.resolveDebugConfiguration) const providers = this.configProviders.filter(p => p.type === type && p.resolveDebugConfiguration)
...@@ -189,7 +190,7 @@ export class ConfigurationManager implements IConfigurationManager { ...@@ -189,7 +190,7 @@ export class ConfigurationManager implements IConfigurationManager {
return providers.reduce((promise, provider) => { return providers.reduce((promise, provider) => {
return promise.then(config => { return promise.then(config => {
if (config) { if (config) {
return provider.resolveDebugConfiguration!(folderUri, config); return provider.resolveDebugConfiguration!(folderUri, config, token);
} else { } else {
return Promise.resolve(config); return Promise.resolve(config);
} }
...@@ -198,9 +199,9 @@ export class ConfigurationManager implements IConfigurationManager { ...@@ -198,9 +199,9 @@ export class ConfigurationManager implements IConfigurationManager {
}); });
} }
provideDebugConfigurations(folderUri: uri | undefined, type: string): Promise<any[]> { provideDebugConfigurations(folderUri: uri | undefined, type: string, token: CancellationToken): Promise<any[]> {
return this.activateDebuggers('onDebugInitialConfigurations') return this.activateDebuggers('onDebugInitialConfigurations')
.then(() => Promise.all(this.configProviders.filter(p => p.type === type && p.provideDebugConfigurations).map(p => p.provideDebugConfigurations!(folderUri))) .then(() => Promise.all(this.configProviders.filter(p => p.type === type && p.provideDebugConfigurations).map(p => p.provideDebugConfigurations!(folderUri, token)))
.then(results => results.reduce((first, second) => first.concat(second), []))); .then(results => results.reduce((first, second) => first.concat(second), [])));
} }
...@@ -531,7 +532,7 @@ class Launch extends AbstractLaunch implements ILaunch { ...@@ -531,7 +532,7 @@ class Launch extends AbstractLaunch implements ILaunch {
return this.configurationService.inspect<IGlobalConfig>('launch', { resource: this.workspace.uri }).workspaceFolder; return this.configurationService.inspect<IGlobalConfig>('launch', { resource: this.workspace.uri }).workspaceFolder;
} }
openConfigFile(sideBySide: boolean, preserveFocus: boolean, type?: string): Promise<{ editor: IEditor | null, created: boolean }> { openConfigFile(sideBySide: boolean, preserveFocus: boolean, type?: string, token?: CancellationToken): Promise<{ editor: IEditor | null, created: boolean }> {
const resource = this.uri; const resource = this.uri;
let created = false; let created = false;
...@@ -539,7 +540,7 @@ class Launch extends AbstractLaunch implements ILaunch { ...@@ -539,7 +540,7 @@ class Launch extends AbstractLaunch implements ILaunch {
// launch.json not found: create one by collecting launch configs from debugConfigProviders // launch.json not found: create one by collecting launch configs from debugConfigProviders
return this.configurationManager.guessDebugger(type).then(adapter => { return this.configurationManager.guessDebugger(type).then(adapter => {
if (adapter) { if (adapter) {
return this.configurationManager.provideDebugConfigurations(this.workspace.uri, adapter.type).then(initialConfigs => { return this.configurationManager.provideDebugConfigurations(this.workspace.uri, adapter.type, token || CancellationToken.None).then(initialConfigs => {
return adapter.getInitialConfigurationContent(initialConfigs); return adapter.getInitialConfigurationContent(initialConfigs);
}); });
} else { } else {
......
...@@ -47,6 +47,7 @@ import { isErrorWithActions, createErrorWithActions } from 'vs/base/common/error ...@@ -47,6 +47,7 @@ import { isErrorWithActions, createErrorWithActions } from 'vs/base/common/error
import { RunOnceScheduler } from 'vs/base/common/async'; import { RunOnceScheduler } from 'vs/base/common/async';
import { IExtensionHostDebugService } from 'vs/platform/debug/common/extensionHostDebug'; import { IExtensionHostDebugService } from 'vs/platform/debug/common/extensionHostDebug';
import { isCodeEditor } from 'vs/editor/browser/editorBrowser'; import { isCodeEditor } from 'vs/editor/browser/editorBrowser';
import { CancellationTokenSource } from 'vs/base/common/cancellation';
const DEBUG_BREAKPOINTS_KEY = 'debug.breakpoint'; const DEBUG_BREAKPOINTS_KEY = 'debug.breakpoint';
const DEBUG_BREAKPOINTS_ACTIVATED_KEY = 'debug.breakpointactivated'; const DEBUG_BREAKPOINTS_ACTIVATED_KEY = 'debug.breakpointactivated';
...@@ -88,6 +89,7 @@ export class DebugService implements IDebugService { ...@@ -88,6 +89,7 @@ export class DebugService implements IDebugService {
private breakpointsToSendOnResourceSaved: Set<string>; private breakpointsToSendOnResourceSaved: Set<string>;
private initializing = false; private initializing = false;
private previousState: State | undefined; private previousState: State | undefined;
private initCancellationToken: CancellationTokenSource | undefined;
constructor( constructor(
@IStorageService private readonly storageService: IStorageService, @IStorageService private readonly storageService: IStorageService,
...@@ -211,6 +213,10 @@ export class DebugService implements IDebugService { ...@@ -211,6 +213,10 @@ export class DebugService implements IDebugService {
} }
private endInitializingState() { private endInitializingState() {
if (this.initCancellationToken) {
this.initCancellationToken.cancel();
this.initCancellationToken = undefined;
}
if (this.initializing) { if (this.initializing) {
this.initializing = false; this.initializing = false;
this.onStateChange(); this.onStateChange();
...@@ -355,8 +361,9 @@ export class DebugService implements IDebugService { ...@@ -355,8 +361,9 @@ export class DebugService implements IDebugService {
} }
const debuggerThenable: Promise<void> = type ? Promise.resolve() : this.configurationManager.guessDebugger().then(dbgr => { type = dbgr && dbgr.type; }); const debuggerThenable: Promise<void> = type ? Promise.resolve() : this.configurationManager.guessDebugger().then(dbgr => { type = dbgr && dbgr.type; });
return debuggerThenable.then(() => return debuggerThenable.then(() => {
this.configurationManager.resolveConfigurationByProviders(launch && launch.workspace ? launch.workspace.uri : undefined, type, config!).then(config => { this.initCancellationToken = new CancellationTokenSource();
return this.configurationManager.resolveConfigurationByProviders(launch && launch.workspace ? launch.workspace.uri : undefined, type, config!, this.initCancellationToken.token).then(config => {
// a falsy config indicates an aborted launch // a falsy config indicates an aborted launch
if (config && config.type) { if (config && config.type) {
return this.substituteVariables(launch, config).then(resolvedConfig => { return this.substituteVariables(launch, config).then(resolvedConfig => {
...@@ -396,17 +403,17 @@ export class DebugService implements IDebugService { ...@@ -396,17 +403,17 @@ export class DebugService implements IDebugService {
.then(() => false); .then(() => false);
} }
return launch && launch.openConfigFile(false, true).then(() => false); return launch && launch.openConfigFile(false, true, undefined, this.initCancellationToken ? this.initCancellationToken.token : undefined).then(() => false);
}); });
} }
if (launch && type && config === null) { // show launch.json only for "config" being "null". if (launch && type && config === null) { // show launch.json only for "config" being "null".
return launch.openConfigFile(false, true, type).then(() => false); return launch.openConfigFile(false, true, type, this.initCancellationToken ? this.initCancellationToken.token : undefined).then(() => false);
} }
return false; return false;
}) });
); });
} }
/** /**
...@@ -587,7 +594,8 @@ export class DebugService implements IDebugService { ...@@ -587,7 +594,8 @@ export class DebugService implements IDebugService {
let substitutionThenable: Promise<IConfig | null | undefined> = Promise.resolve(session.configuration); let substitutionThenable: Promise<IConfig | null | undefined> = Promise.resolve(session.configuration);
if (launch && needsToSubstitute && unresolved) { if (launch && needsToSubstitute && unresolved) {
substitutionThenable = this.configurationManager.resolveConfigurationByProviders(launch.workspace ? launch.workspace.uri : undefined, unresolved.type, unresolved) this.initCancellationToken = new CancellationTokenSource();
substitutionThenable = this.configurationManager.resolveConfigurationByProviders(launch.workspace ? launch.workspace.uri : undefined, unresolved.type, unresolved, this.initCancellationToken.token)
.then(resolved => { .then(resolved => {
if (resolved) { if (resolved) {
// start debugging // start debugging
......
...@@ -169,7 +169,7 @@ export class DebugSession implements IDebugSession { ...@@ -169,7 +169,7 @@ export class DebugSession implements IDebugSession {
this.raw = new RawDebugSession(debugAdapter, dbgr, this.telemetryService, customTelemetryService, this.windowsService); this.raw = new RawDebugSession(debugAdapter, dbgr, this.telemetryService, customTelemetryService, this.windowsService);
return this.raw!.start().then(() => { return this.raw.start().then(() => {
this.registerListeners(); this.registerListeners();
......
...@@ -25,6 +25,7 @@ import { Registry } from 'vs/platform/registry/common/platform'; ...@@ -25,6 +25,7 @@ import { Registry } from 'vs/platform/registry/common/platform';
import { TaskIdentifier } from 'vs/workbench/contrib/tasks/common/tasks'; import { TaskIdentifier } from 'vs/workbench/contrib/tasks/common/tasks';
import { TelemetryService } from 'vs/platform/telemetry/common/telemetryService'; import { TelemetryService } from 'vs/platform/telemetry/common/telemetryService';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { CancellationToken } from 'vs/base/common/cancellation';
export const VIEWLET_ID = 'workbench.view.debug'; export const VIEWLET_ID = 'workbench.view.debug';
export const VIEW_CONTAINER: ViewContainer = Registry.as<IViewContainersRegistry>(ViewContainerExtensions.ViewContainersRegistry).registerViewContainer(VIEWLET_ID); export const VIEW_CONTAINER: ViewContainer = Registry.as<IViewContainersRegistry>(ViewContainerExtensions.ViewContainersRegistry).registerViewContainer(VIEWLET_ID);
...@@ -557,8 +558,8 @@ export interface IDebuggerContribution extends IPlatformSpecificAdapterContribut ...@@ -557,8 +558,8 @@ export interface IDebuggerContribution extends IPlatformSpecificAdapterContribut
export interface IDebugConfigurationProvider { export interface IDebugConfigurationProvider {
readonly type: string; readonly type: string;
resolveDebugConfiguration?(folderUri: uri | undefined, debugConfiguration: IConfig): Promise<IConfig | null | undefined>; resolveDebugConfiguration?(folderUri: uri | undefined, debugConfiguration: IConfig, token: CancellationToken): Promise<IConfig | null | undefined>;
provideDebugConfigurations?(folderUri: uri | undefined): Promise<IConfig[]>; provideDebugConfigurations?(folderUri: uri | undefined, token: CancellationToken): Promise<IConfig[]>;
debugAdapterExecutable?(folderUri: uri | undefined): Promise<IAdapterDescriptor>; // TODO@AW legacy debugAdapterExecutable?(folderUri: uri | undefined): Promise<IAdapterDescriptor>; // TODO@AW legacy
} }
...@@ -610,7 +611,7 @@ export interface IConfigurationManager { ...@@ -610,7 +611,7 @@ export interface IConfigurationManager {
registerDebugAdapterDescriptorFactory(debugAdapterDescriptorFactory: IDebugAdapterDescriptorFactory): IDisposable; registerDebugAdapterDescriptorFactory(debugAdapterDescriptorFactory: IDebugAdapterDescriptorFactory): IDisposable;
unregisterDebugAdapterDescriptorFactory(debugAdapterDescriptorFactory: IDebugAdapterDescriptorFactory): void; unregisterDebugAdapterDescriptorFactory(debugAdapterDescriptorFactory: IDebugAdapterDescriptorFactory): void;
resolveConfigurationByProviders(folderUri: uri | undefined, type: string | undefined, debugConfiguration: any): Promise<any>; resolveConfigurationByProviders(folderUri: uri | undefined, type: string | undefined, debugConfiguration: any, token: CancellationToken): Promise<any>;
getDebugAdapterDescriptor(session: IDebugSession): Promise<IAdapterDescriptor | undefined>; getDebugAdapterDescriptor(session: IDebugSession): Promise<IAdapterDescriptor | undefined>;
registerDebugAdapterFactory(debugTypes: string[], debugAdapterFactory: IDebugAdapterFactory): IDisposable; registerDebugAdapterFactory(debugTypes: string[], debugAdapterFactory: IDebugAdapterFactory): IDisposable;
...@@ -663,7 +664,7 @@ export interface ILaunch { ...@@ -663,7 +664,7 @@ export interface ILaunch {
/** /**
* Opens the launch.json file. Creates if it does not exist. * Opens the launch.json file. Creates if it does not exist.
*/ */
openConfigFile(sideBySide: boolean, preserveFocus: boolean, type?: string): Promise<{ editor: IEditor | null, created: boolean }>; openConfigFile(sideBySide: boolean, preserveFocus: boolean, type?: string, token?: CancellationToken): Promise<{ editor: IEditor | null, created: boolean }>;
} }
// Debug service interfaces // Debug service interfaces
......
...@@ -502,7 +502,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer ...@@ -502,7 +502,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer
if (!this.versionAndEngineCompatible(filter)) { if (!this.versionAndEngineCompatible(filter)) {
return Promise.resolve<Task[]>([]); return Promise.resolve<Task[]>([]);
} }
return this.getGroupedTasks().then((map) => { return this.getGroupedTasks(filter ? filter.type : undefined).then((map) => {
if (!filter || !filter.type) { if (!filter || !filter.type) {
return map.all(); return map.all();
} }
...@@ -1117,7 +1117,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer ...@@ -1117,7 +1117,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer
protected abstract getTaskSystem(): ITaskSystem; protected abstract getTaskSystem(): ITaskSystem;
private getGroupedTasks(): Promise<TaskMap> { private getGroupedTasks(type?: string): Promise<TaskMap> {
return Promise.all([this.extensionService.activateByEvent('onCommand:workbench.action.tasks.runTask'), TaskDefinitionRegistry.onReady()]).then(() => { return Promise.all([this.extensionService.activateByEvent('onCommand:workbench.action.tasks.runTask'), TaskDefinitionRegistry.onReady()]).then(() => {
let validTypes: IStringDictionary<boolean> = Object.create(null); let validTypes: IStringDictionary<boolean> = Object.create(null);
TaskDefinitionRegistry.all().forEach(definition => validTypes[definition.taskType] = true); TaskDefinitionRegistry.all().forEach(definition => validTypes[definition.taskType] = true);
...@@ -1152,10 +1152,12 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer ...@@ -1152,10 +1152,12 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer
} }
}; };
if (this.schemaVersion === JsonSchemaVersion.V2_0_0 && this._providers.size > 0) { if (this.schemaVersion === JsonSchemaVersion.V2_0_0 && this._providers.size > 0) {
this._providers.forEach((provider) => { for (const [handle, provider] of this._providers) {
counter++; if ((type === undefined) || (type === this._providerTypes.get(handle))) {
provider.provideTasks(validTypes).then(done, error); counter++;
}); provider.provideTasks(validTypes).then(done, error);
}
}
} else { } else {
resolve(result); resolve(result);
} }
......
...@@ -762,8 +762,8 @@ export class RemoteFileDialog { ...@@ -762,8 +762,8 @@ export class RemoteFileDialog {
private pathAppend(uri: URI, additional: string): string { private pathAppend(uri: URI, additional: string): string {
if ((additional === '..') || (additional === '.')) { if ((additional === '..') || (additional === '.')) {
const basePath = this.pathFromUri(uri); const basePath = this.pathFromUri(uri, true);
return basePath + this.separator + additional; return basePath + additional;
} else { } else {
return this.pathFromUri(resources.joinPath(uri, additional)); return this.pathFromUri(resources.joinPath(uri, additional));
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册