Merge branch 'master' into rename-workspaceedit-proto

This commit is contained in:
Johannes Rieken
2018-01-22 10:35:30 +01:00
1173 changed files with 18780 additions and 6297 deletions

View File

@@ -51,7 +51,6 @@ import { TextEditorCursorStyle } from 'vs/editor/common/config/editorOptions';
import { ProxyIdentifier } from 'vs/workbench/services/extensions/node/proxyIdentifier';
import { ExtHostDialogs } from 'vs/workbench/api/node/extHostDialogs';
import { ExtHostFileSystem } from 'vs/workbench/api/node/extHostFileSystem';
import { FileChangeType, FileType } from 'vs/platform/files/common/files';
import { ExtHostDecorations } from 'vs/workbench/api/node/extHostDecorations';
import { toGlobPattern, toLanguageSelector } from 'vs/workbench/api/node/extHostTypeConverters';
import { ExtensionActivatedByAPI } from 'vs/workbench/api/node/extHostExtensionActivator';
@@ -107,8 +106,8 @@ export function createApiFactory(
const extHostDebugService = rpcProtocol.set(ExtHostContext.ExtHostDebugService, new ExtHostDebugService(rpcProtocol, extHostWorkspace));
rpcProtocol.set(ExtHostContext.ExtHostConfiguration, extHostConfiguration);
const extHostDiagnostics = rpcProtocol.set(ExtHostContext.ExtHostDiagnostics, new ExtHostDiagnostics(rpcProtocol));
const languageFeatures = rpcProtocol.set(ExtHostContext.ExtHostLanguageFeatures, new ExtHostLanguageFeatures(rpcProtocol, extHostDocuments, extHostCommands, extHostHeapService, extHostDiagnostics));
const extHostFileSystem = rpcProtocol.set(ExtHostContext.ExtHostFileSystem, new ExtHostFileSystem(rpcProtocol));
const extHostLanguageFeatures = rpcProtocol.set(ExtHostContext.ExtHostLanguageFeatures, new ExtHostLanguageFeatures(rpcProtocol, extHostDocuments, extHostCommands, extHostHeapService, extHostDiagnostics));
const extHostFileSystem = rpcProtocol.set(ExtHostContext.ExtHostFileSystem, new ExtHostFileSystem(rpcProtocol, extHostLanguageFeatures));
const extHostFileSystemEvent = rpcProtocol.set(ExtHostContext.ExtHostFileSystemEventService, new ExtHostFileSystemEventService());
const extHostQuickOpen = rpcProtocol.set(ExtHostContext.ExtHostQuickOpen, new ExtHostQuickOpen(rpcProtocol, extHostWorkspace, extHostCommands));
const extHostTerminalService = rpcProtocol.set(ExtHostContext.ExtHostTerminalService, new ExtHostTerminalService(rpcProtocol));
@@ -237,61 +236,61 @@ export function createApiFactory(
return score(toLanguageSelector(selector), document.uri, document.languageId);
},
registerCodeActionsProvider(selector: vscode.DocumentSelector, provider: vscode.CodeActionProvider): vscode.Disposable {
return languageFeatures.registerCodeActionProvider(selector, provider);
return extHostLanguageFeatures.registerCodeActionProvider(selector, provider);
},
registerCodeLensProvider(selector: vscode.DocumentSelector, provider: vscode.CodeLensProvider): vscode.Disposable {
return languageFeatures.registerCodeLensProvider(selector, provider);
return extHostLanguageFeatures.registerCodeLensProvider(selector, provider);
},
registerDefinitionProvider(selector: vscode.DocumentSelector, provider: vscode.DefinitionProvider): vscode.Disposable {
return languageFeatures.registerDefinitionProvider(selector, provider);
return extHostLanguageFeatures.registerDefinitionProvider(selector, provider);
},
registerImplementationProvider(selector: vscode.DocumentSelector, provider: vscode.ImplementationProvider): vscode.Disposable {
return languageFeatures.registerImplementationProvider(selector, provider);
return extHostLanguageFeatures.registerImplementationProvider(selector, provider);
},
registerTypeDefinitionProvider(selector: vscode.DocumentSelector, provider: vscode.TypeDefinitionProvider): vscode.Disposable {
return languageFeatures.registerTypeDefinitionProvider(selector, provider);
return extHostLanguageFeatures.registerTypeDefinitionProvider(selector, provider);
},
registerHoverProvider(selector: vscode.DocumentSelector, provider: vscode.HoverProvider): vscode.Disposable {
return languageFeatures.registerHoverProvider(selector, provider, extension.id);
return extHostLanguageFeatures.registerHoverProvider(selector, provider, extension.id);
},
registerDocumentHighlightProvider(selector: vscode.DocumentSelector, provider: vscode.DocumentHighlightProvider): vscode.Disposable {
return languageFeatures.registerDocumentHighlightProvider(selector, provider);
return extHostLanguageFeatures.registerDocumentHighlightProvider(selector, provider);
},
registerReferenceProvider(selector: vscode.DocumentSelector, provider: vscode.ReferenceProvider): vscode.Disposable {
return languageFeatures.registerReferenceProvider(selector, provider);
return extHostLanguageFeatures.registerReferenceProvider(selector, provider);
},
registerRenameProvider(selector: vscode.DocumentSelector, provider: vscode.RenameProvider): vscode.Disposable {
return languageFeatures.registerRenameProvider(selector, provider);
return extHostLanguageFeatures.registerRenameProvider(selector, provider);
},
registerDocumentSymbolProvider(selector: vscode.DocumentSelector, provider: vscode.DocumentSymbolProvider): vscode.Disposable {
return languageFeatures.registerDocumentSymbolProvider(selector, provider);
return extHostLanguageFeatures.registerDocumentSymbolProvider(selector, provider);
},
registerWorkspaceSymbolProvider(provider: vscode.WorkspaceSymbolProvider): vscode.Disposable {
return languageFeatures.registerWorkspaceSymbolProvider(provider);
return extHostLanguageFeatures.registerWorkspaceSymbolProvider(provider);
},
registerDocumentFormattingEditProvider(selector: vscode.DocumentSelector, provider: vscode.DocumentFormattingEditProvider): vscode.Disposable {
return languageFeatures.registerDocumentFormattingEditProvider(selector, provider);
return extHostLanguageFeatures.registerDocumentFormattingEditProvider(selector, provider);
},
registerDocumentRangeFormattingEditProvider(selector: vscode.DocumentSelector, provider: vscode.DocumentRangeFormattingEditProvider): vscode.Disposable {
return languageFeatures.registerDocumentRangeFormattingEditProvider(selector, provider);
return extHostLanguageFeatures.registerDocumentRangeFormattingEditProvider(selector, provider);
},
registerOnTypeFormattingEditProvider(selector: vscode.DocumentSelector, provider: vscode.OnTypeFormattingEditProvider, firstTriggerCharacter: string, ...moreTriggerCharacters: string[]): vscode.Disposable {
return languageFeatures.registerOnTypeFormattingEditProvider(selector, provider, [firstTriggerCharacter].concat(moreTriggerCharacters));
return extHostLanguageFeatures.registerOnTypeFormattingEditProvider(selector, provider, [firstTriggerCharacter].concat(moreTriggerCharacters));
},
registerSignatureHelpProvider(selector: vscode.DocumentSelector, provider: vscode.SignatureHelpProvider, ...triggerCharacters: string[]): vscode.Disposable {
return languageFeatures.registerSignatureHelpProvider(selector, provider, triggerCharacters);
return extHostLanguageFeatures.registerSignatureHelpProvider(selector, provider, triggerCharacters);
},
registerCompletionItemProvider(selector: vscode.DocumentSelector, provider: vscode.CompletionItemProvider, ...triggerCharacters: string[]): vscode.Disposable {
return languageFeatures.registerCompletionItemProvider(selector, provider, triggerCharacters);
return extHostLanguageFeatures.registerCompletionItemProvider(selector, provider, triggerCharacters);
},
registerDocumentLinkProvider(selector: vscode.DocumentSelector, provider: vscode.DocumentLinkProvider): vscode.Disposable {
return languageFeatures.registerDocumentLinkProvider(selector, provider);
return extHostLanguageFeatures.registerDocumentLinkProvider(selector, provider);
},
registerColorProvider(selector: vscode.DocumentSelector, provider: vscode.DocumentColorProvider): vscode.Disposable {
return languageFeatures.registerColorProvider(selector, provider);
return extHostLanguageFeatures.registerColorProvider(selector, provider);
},
setLanguageConfiguration: (language: string, configuration: vscode.LanguageConfiguration): vscode.Disposable => {
return languageFeatures.setLanguageConfiguration(language, configuration);
return extHostLanguageFeatures.setLanguageConfiguration(language, configuration);
}
};
@@ -616,9 +615,8 @@ export function createApiFactory(
ConfigurationTarget: extHostTypes.ConfigurationTarget,
RelativePattern: extHostTypes.RelativePattern,
// TODO@JOH,remote
FileChangeType: <any>FileChangeType,
FileType: <any>FileType
FileChangeType: extHostTypes.FileChangeType,
FileType: extHostTypes.FileType
};
};
}

View File

@@ -48,11 +48,12 @@ import { ITreeItem } from 'vs/workbench/common/views';
import { ThemeColor } from 'vs/platform/theme/common/themeService';
import { IDisposable } from 'vs/base/common/lifecycle';
import { SerializedError } from 'vs/base/common/errors';
import { IStat, IFileChange } from 'vs/platform/files/common/files';
import { IStat, FileChangeType } from 'vs/platform/files/common/files';
import { ConfigurationScope } from 'vs/platform/configuration/common/configurationRegistry';
import { ParsedArgs } from 'vs/platform/environment/common/environment';
import { CommentRule, CharacterPair, EnterAction } from 'vs/editor/common/modes/languageConfiguration';
import { ISingleEditOperation } from 'vs/editor/common/model';
import { EndOfLineSequence, ISingleEditOperation } from 'vs/editor/common/model';
import { ILineMatch, IPatternInfo } from 'vs/platform/search/common/search';
export interface IEnvironment {
isExtensionDevelopmentDebug: boolean;
@@ -353,15 +354,20 @@ export interface MainThreadWorkspaceShape extends IDisposable {
$saveAll(includeUntitled?: boolean): Thenable<boolean>;
}
export interface IFileChangeDto {
resource: UriComponents;
type: FileChangeType;
}
export interface MainThreadFileSystemShape extends IDisposable {
$registerFileSystemProvider(handle: number, scheme: string): void;
$unregisterFileSystemProvider(handle: number): void;
$onDidAddFileSystemRoot(root: UriComponents): void;
$onFileSystemChange(handle: number, resource: IFileChange[]): void;
$onFileSystemChange(handle: number, resource: IFileChangeDto[]): void;
$reportFileChunk(handle: number, session: number, chunk: number[] | null): void;
$handleSearchProgress(handle: number, session: number, resource: UriComponents): void;
$handleFindMatch(handle: number, session, data: UriComponents | [UriComponents, ILineMatch]): void;
}
export interface MainThreadTaskShape extends IDisposable {
@@ -531,6 +537,7 @@ export interface ExtHostFileSystemShape {
$readdir(handle: number, resource: UriComponents): TPromise<[UriComponents, IStat][]>;
$rmdir(handle: number, resource: UriComponents): TPromise<void>;
$findFiles(handle: number, session: number, query: string): TPromise<void>;
$provideTextSearchResults(handle: number, session: number, pattern: IPatternInfo, options: { includes: string[], excludes: string[] }): TPromise<void>;
}
export interface ExtHostExtensionServiceShape {

View File

@@ -239,6 +239,15 @@ export class ExtHostApiCommands {
{ name: 'columnOrOptions', description: '(optional) Either the column in which to open or editor options, see vscode.TextDocumentShowOptions', constraint: v => v === void 0 || typeof v === 'number' || typeof v === 'object' }
]
});
this._register('vscode.removeFromRecentlyOpened', (path: string) => {
return this._commands.executeCommand('_workbench.removeFromRecentlyOpened', path);
}, {
description: 'Removes an entry with the given path from the recently opened list.',
args: [
{ name: 'path', description: 'Path to remove from recently opened.', constraint: value => typeof value === 'string' }
]
});
}
// --- command impl

View File

@@ -32,6 +32,8 @@ export class ExtHostDocumentContentProvider implements ExtHostDocumentContentPro
}
registerTextDocumentContentProvider(scheme: string, provider: vscode.TextDocumentContentProvider): vscode.Disposable {
// todo@remote
// check with scheme from fs-providers!
if (scheme === 'file' || scheme === 'untitled') {
throw new Error(`scheme '${scheme}' already registered`);
}

View File

@@ -68,6 +68,8 @@ export class ExtHostDocumentData extends MirrorTextModel {
this._document = {
get uri() { return data._uri; },
get fileName() { return data._uri.fsPath; },
// todo@remote
// documents from other fs-provider must not be untitled
get isUntitled() { return data._uri.scheme !== 'file'; },
get languageId() { return data._languageId; },
get version() { return data._versionId; },

View File

@@ -6,7 +6,7 @@
import { dispose } from 'vs/base/common/lifecycle';
import { join } from 'path';
import { mkdirp, dirExists, realpath } from 'vs/base/node/pfs';
import { mkdirp, dirExists, realpath, writeFile } from 'vs/base/node/pfs';
import Severity from 'vs/base/common/severity';
import { TPromise } from 'vs/base/common/winjs.base';
import { ExtensionDescriptionRegistry } from 'vs/workbench/services/extensions/node/extensionDescriptionRegistry';
@@ -88,24 +88,35 @@ class ExtensionStoragePath {
return undefined;
}
private _getOrCreateWorkspaceStoragePath(): TPromise<string> {
private async _getOrCreateWorkspaceStoragePath(): TPromise<string> {
if (!this._workspace) {
return TPromise.as(undefined);
}
const storageName = this._workspace.id;
const storagePath = join(this._environment.appSettingsHome, 'workspaceStorage', storageName);
return dirExists(storagePath).then(exists => {
if (exists) {
return storagePath;
}
const exists = await dirExists(storagePath);
return mkdirp(storagePath).then(success => {
return storagePath;
}, err => {
return undefined;
});
});
if (exists) {
return storagePath;
}
try {
await mkdirp(storagePath);
await writeFile(
join(storagePath, 'meta.json'),
JSON.stringify({
id: this._workspace.id,
name: this._workspace.name
}, undefined, 2)
);
return storagePath;
} catch (e) {
console.error(e);
return undefined;
}
}
}

View File

@@ -11,22 +11,72 @@ import * as vscode from 'vscode';
import { IStat } from 'vs/platform/files/common/files';
import { IDisposable } from 'vs/base/common/lifecycle';
import { asWinJsPromise } from 'vs/base/common/async';
import { IPatternInfo } from 'vs/platform/search/common/search';
import { values } from 'vs/base/common/map';
import { Range } from 'vs/workbench/api/node/extHostTypes';
import { ExtHostLanguageFeatures } from 'vs/workbench/api/node/extHostLanguageFeatures';
class FsLinkProvider implements vscode.DocumentLinkProvider {
private _schemes = new Set<string>();
private _regex: RegExp;
add(scheme: string): void {
this._regex = undefined;
this._schemes.add(scheme);
}
delete(scheme: string): void {
if (this._schemes.delete(scheme)) {
this._regex = undefined;
}
}
provideDocumentLinks(document: vscode.TextDocument, token: vscode.CancellationToken): vscode.ProviderResult<vscode.DocumentLink[]> {
if (this._schemes.size === 0) {
return undefined;
}
if (!this._regex) {
this._regex = new RegExp(`(${(values(this._schemes).join('|'))}):[^\\s]+`, 'gi');
}
let result: vscode.DocumentLink[] = [];
let max = Math.min(document.lineCount, 2500);
for (let line = 0; line < max; line++) {
this._regex.lastIndex = 0;
let textLine = document.lineAt(line);
let m: RegExpMatchArray;
while (m = this._regex.exec(textLine.text)) {
const target = URI.parse(m[0]);
const range = new Range(line, this._regex.lastIndex - m[0].length, line, this._regex.lastIndex);
result.push({ target, range });
}
}
return result;
}
}
export class ExtHostFileSystem implements ExtHostFileSystemShape {
private readonly _proxy: MainThreadFileSystemShape;
private readonly _provider = new Map<number, vscode.FileSystemProvider>();
private readonly _linkProvider = new FsLinkProvider();
private _handlePool: number = 0;
constructor(mainContext: IMainContext) {
constructor(mainContext: IMainContext, extHostLanguageFeatures: ExtHostLanguageFeatures) {
this._proxy = mainContext.getProxy(MainContext.MainThreadFileSystem);
extHostLanguageFeatures.registerDocumentLinkProvider('*', this._linkProvider);
}
registerFileSystemProvider(scheme: string, provider: vscode.FileSystemProvider) {
const handle = this._handlePool++;
this._linkProvider.add(scheme);
this._provider.set(handle, provider);
this._proxy.$registerFileSystemProvider(handle, scheme);
this._proxy.$onDidAddFileSystemRoot(<any>provider.root);
if (provider.root) {
// todo@remote
this._proxy.$onDidAddFileSystemRoot(provider.root);
}
let reg: IDisposable;
if (provider.onDidChange) {
reg = provider.onDidChange(event => this._proxy.$onFileSystemChange(handle, <any>event));
@@ -36,6 +86,7 @@ export class ExtHostFileSystem implements ExtHostFileSystemShape {
if (reg) {
reg.dispose();
}
this._linkProvider.delete(scheme);
this._provider.delete(handle);
this._proxy.$unregisterFileSystemProvider(handle);
}
@@ -79,7 +130,27 @@ export class ExtHostFileSystem implements ExtHostFileSystemShape {
if (!provider.findFiles) {
return TPromise.as(undefined);
}
const progress = { report: (uri) => this._proxy.$handleSearchProgress(handle, session, uri) };
const progress = {
report: (uri) => {
this._proxy.$handleFindMatch(handle, session, uri);
}
};
return asWinJsPromise(token => provider.findFiles(query, progress, token));
}
$provideTextSearchResults(handle: number, session: number, pattern: IPatternInfo, options: { includes: string[], excludes: string[] }): TPromise<void> {
const provider = this._provider.get(handle);
if (!provider.provideTextSearchResults) {
return TPromise.as(undefined);
}
const progress = {
report: (data: vscode.TextSearchResult) => {
this._proxy.$handleFindMatch(handle, session, [data.uri, {
lineNumber: 1 + data.range.start.line,
preview: data.preview.leading + data.preview.matching + data.preview.trailing,
offsetAndLengths: [[data.preview.leading.length, data.preview.matching.length]]
}]);
}
};
return asWinJsPromise(token => provider.provideTextSearchResults(pattern, options, progress, token));
}
}

View File

@@ -6,6 +6,7 @@
import { localize } from 'vs/nls';
import * as vscode from 'vscode';
import { basename } from 'vs/base/common/paths';
import URI from 'vs/base/common/uri';
import { debounceEvent } from 'vs/base/common/event';
import { TPromise } from 'vs/base/common/winjs.base';
@@ -77,7 +78,10 @@ interface TreeNode {
class ExtHostTreeView<T> extends Disposable {
private static ROOT_HANDLE = '0';
private static LABEL_HANDLE_PREFIX = '0';
private static ID_HANDLE_PREFIX = '1';
private rootHandles: TreeItemHandle[] = [];
private elements: Map<TreeItemHandle, T> = new Map<TreeItemHandle, T>();
private nodes: Map<T, TreeNode> = new Map<T, TreeNode>();
@@ -85,49 +89,39 @@ class ExtHostTreeView<T> extends Disposable {
super();
this.proxy.$registerView(viewId);
if (dataProvider.onDidChangeTreeData) {
this._register(debounceEvent<T, T[]>(dataProvider.onDidChangeTreeData, (last, current) => last ? [...last, current] : [current], 200)(elements => this._refresh(elements)));
this._register(debounceEvent<T, T[]>(dataProvider.onDidChangeTreeData, (last, current) => last ? [...last, current] : [current], 200)(elements => this.refresh(elements)));
}
}
getChildren(parentHandle?: TreeItemHandle): TPromise<ITreeItem[]> {
let parentElement;
if (parentHandle) {
parentElement = this.getExtensionElement(parentHandle);
if (!parentElement) {
return TPromise.wrapError<ITreeItem[]>(new Error(localize('treeItem.notFound', 'No tree item with id \'{0}\' found.', parentHandle)));
}
const parentElement = parentHandle ? this.getExtensionElement(parentHandle) : void 0;
if (parentHandle && !parentElement) {
console.error(`No tree item with id \'${parentHandle}\' found.`);
return TPromise.as([]);
}
this.clearChildren(parentElement);
return asWinJsPromise(() => this.dataProvider.getChildren(parentElement))
.then(elements => {
elements = coalesce(elements || []);
return TPromise.join(elements.map((element, index) => {
const node = this.nodes.get(element);
const currentHandle = node && node.parentHandle === parentHandle ? node.handle : void 0;
return this.resolveElement(element, currentHandle ? currentHandle : index, parentHandle)
.then(treeItem => {
if (treeItem) {
if (!currentHandle) {
// update the caches if current handle is not used
this.nodes.set(element, {
handle: treeItem.handle,
parentHandle,
childrenHandles: void 0
});
this.elements.set(treeItem.handle, element);
.then(elements => TPromise.join(
coalesce(elements || []).map(element =>
asWinJsPromise(() => this.dataProvider.getTreeItem(element))
.then(extTreeItem => {
if (extTreeItem) {
if (extTreeItem.id && this.elements.has(this.createHandle(element, extTreeItem))) {
throw new Error(localize('treeView.duplicateElement', 'Element with id {0} is already registered', extTreeItem.id));
}
return { element, extTreeItem };
}
return treeItem;
});
})).then(treeItems => this.updateChildren(coalesce(treeItems), parentElement));
});
return null;
})
))).then(extTreeItems => extTreeItems.map((({ element, extTreeItem }) => this.createTreeItem(element, extTreeItem, parentHandle))));
}
getExtensionElement(treeItemHandle: TreeItemHandle): T {
return this.elements.get(treeItemHandle);
}
private _refresh(elements: T[]): void {
private refresh(elements: T[]): void {
const hasRoot = elements.some(element => !element);
if (hasRoot) {
this.proxy.$refresh(this.viewId);
@@ -139,64 +133,6 @@ class ExtHostTreeView<T> extends Disposable {
}
}
private resolveElement(element: T, handleOrIndex: TreeItemHandle | number, parentHandle: TreeItemHandle): TPromise<ITreeItem> {
return asWinJsPromise(() => this.dataProvider.getTreeItem(element))
.then(extTreeItem => this.massageTreeItem(element, extTreeItem, handleOrIndex, parentHandle));
}
private massageTreeItem(element: T, extensionTreeItem: vscode.TreeItem, handleOrIndex: TreeItemHandle | number, parentHandle: TreeItemHandle): ITreeItem {
if (!extensionTreeItem) {
return null;
}
const icon = this.getLightIconPath(extensionTreeItem);
const label = extensionTreeItem.label;
const handle = typeof handleOrIndex === 'number' ?
this.generateHandle(label, handleOrIndex, parentHandle) // create the handle
: handleOrIndex; // reuse the passed handle
return {
handle,
parentHandle,
label,
command: extensionTreeItem.command ? this.commands.toInternal(extensionTreeItem.command) : void 0,
contextValue: extensionTreeItem.contextValue,
icon,
iconDark: this.getDarkIconPath(extensionTreeItem) || icon,
collapsibleState: extensionTreeItem.collapsibleState
};
}
private generateHandle(label: string, index: number, parentHandle: TreeItemHandle): TreeItemHandle {
parentHandle = parentHandle ? parentHandle : ExtHostTreeView.ROOT_HANDLE;
label = label.indexOf('/') !== -1 ? label.replace('/', '//') : label;
return `${parentHandle}/${index}:${label}`;
}
private getLightIconPath(extensionTreeItem: vscode.TreeItem): string {
if (extensionTreeItem.iconPath) {
if (typeof extensionTreeItem.iconPath === 'string' || extensionTreeItem.iconPath instanceof URI) {
return this.getIconPath(extensionTreeItem.iconPath);
}
return this.getIconPath(extensionTreeItem.iconPath['light']);
}
return void 0;
}
private getDarkIconPath(extensionTreeItem: vscode.TreeItem): string {
if (extensionTreeItem.iconPath && extensionTreeItem.iconPath['dark']) {
return this.getIconPath(extensionTreeItem.iconPath['dark']);
}
return void 0;
}
private getIconPath(iconPath: string | URI): string {
if (iconPath instanceof URI) {
return iconPath.toString();
}
return URI.file(iconPath).toString();
}
private getHandlesToRefresh(elements: T[]): TreeItemHandle[] {
const elementsToUpdate = new Set<TreeItemHandle>();
for (const element of elements) {
@@ -233,39 +169,125 @@ class ExtHostTreeView<T> extends Disposable {
itemHandles.forEach(treeItemHandle => {
const extElement = this.getExtensionElement(treeItemHandle);
const node = this.nodes.get(extElement);
promises.push(this.resolveElement(extElement, treeItemHandle, node.parentHandle)
.then(treeItem => {
itemsToRefresh[treeItemHandle] = treeItem;
promises.push(asWinJsPromise(() => this.dataProvider.getTreeItem(extElement))
.then(extTreeItem => {
if (extTreeItem) {
itemsToRefresh[treeItemHandle] = this.createTreeItem(extElement, extTreeItem, node.parentHandle);
}
}));
});
return TPromise.join(promises)
.then(treeItems => {
this.proxy.$refresh(this.viewId, itemsToRefresh);
});
.then(treeItems => this.proxy.$refresh(this.viewId, itemsToRefresh));
}
private updateChildren(newChildren: ITreeItem[], parentElement?: T): ITreeItem[] {
let existingChildrenHandles: TreeItemHandle[] = [];
if (parentElement) {
const parentNode = this.nodes.get(parentElement);
existingChildrenHandles = parentNode.childrenHandles || [];
parentNode.childrenHandles = newChildren.map(c => c.handle);
} else {
this.nodes.forEach(node => {
if (!node.parentHandle) {
existingChildrenHandles.push(node.handle);
}
});
private createTreeItem(element: T, extensionTreeItem: vscode.TreeItem, parentHandle: TreeItemHandle): ITreeItem {
const handle = this.createHandle(element, extensionTreeItem, parentHandle);
const icon = this.getLightIconPath(extensionTreeItem);
this.update(element, handle, parentHandle);
return {
handle,
parentHandle,
label: extensionTreeItem.label,
resourceUri: extensionTreeItem.resourceUri,
command: extensionTreeItem.command ? this.commands.toInternal(extensionTreeItem.command) : void 0,
contextValue: extensionTreeItem.contextValue,
icon,
iconDark: this.getDarkIconPath(extensionTreeItem) || icon,
collapsibleState: extensionTreeItem.collapsibleState
};
}
private createHandle(element: T, { id, label, resourceUri }: vscode.TreeItem, parentHandle?: TreeItemHandle): TreeItemHandle {
if (id) {
return `${ExtHostTreeView.ID_HANDLE_PREFIX}/${id}`;
}
for (const existingChildHandle of existingChildrenHandles) {
const existingChildElement = this.elements.get(existingChildHandle);
if (existingChildElement && newChildren.every(c => c.handle !== existingChildHandle)) {
this.clear(existingChildElement);
const prefix = parentHandle ? parentHandle : ExtHostTreeView.LABEL_HANDLE_PREFIX;
let elementId = label ? label : basename(resourceUri.path);
elementId = elementId.indexOf('/') !== -1 ? elementId.replace('/', '//') : elementId;
const existingHandle = this.nodes.has(element) ? this.nodes.get(element).handle : void 0;
for (let counter = 0; counter <= this.getChildrenHandles(parentHandle).length; counter++) {
const handle = `${prefix}/${counter}:${elementId}`;
if (!this.elements.has(handle) || existingHandle === handle) {
return handle;
}
}
return newChildren;
throw new Error('This should not be reached');
}
private getLightIconPath(extensionTreeItem: vscode.TreeItem): string {
if (extensionTreeItem.iconPath) {
if (typeof extensionTreeItem.iconPath === 'string' || extensionTreeItem.iconPath instanceof URI) {
return this.getIconPath(extensionTreeItem.iconPath);
}
return this.getIconPath(extensionTreeItem.iconPath['light']);
}
return void 0;
}
private getDarkIconPath(extensionTreeItem: vscode.TreeItem): string {
if (extensionTreeItem.iconPath && extensionTreeItem.iconPath['dark']) {
return this.getIconPath(extensionTreeItem.iconPath['dark']);
}
return void 0;
}
private getIconPath(iconPath: string | URI): string {
if (iconPath instanceof URI) {
return iconPath.toString();
}
return URI.file(iconPath).toString();
}
private getChildrenHandles(parentHandle?: TreeItemHandle): TreeItemHandle[] {
return parentHandle ? this.nodes.get(this.getExtensionElement(parentHandle)).childrenHandles : this.rootHandles;
}
private update(element: T, handle: TreeItemHandle, parentHandle: TreeItemHandle): void {
const node = this.nodes.get(element);
const childrenHandles = this.getChildrenHandles(parentHandle);
// Update parent node
if (node) {
if (node.handle !== handle) {
// Remove the old handle from the system
this.elements.delete(node.handle);
childrenHandles[childrenHandles.indexOf(node.handle)] = handle;
this.clearChildren(element);
}
} else {
childrenHandles.push(handle);
}
// Update element maps
this.elements.set(handle, element);
this.nodes.set(element, {
handle,
parentHandle,
childrenHandles: node ? node.childrenHandles : []
});
}
private clearChildren(parentElement?: T): void {
if (parentElement) {
let node = this.nodes.get(parentElement);
if (node.childrenHandles) {
for (const childHandle of node.childrenHandles) {
const childEleement = this.elements.get(childHandle);
if (childEleement) {
this.clear(childEleement);
}
}
}
node.childrenHandles = [];
} else {
this.clearAll();
}
}
private clear(element: T): void {
@@ -282,8 +304,13 @@ class ExtHostTreeView<T> extends Disposable {
this.elements.delete(node.handle);
}
dispose() {
private clearAll(): void {
this.rootHandles = [];
this.elements.clear();
this.nodes.clear();
}
dispose() {
this.clearAll();
}
}

View File

@@ -360,7 +360,8 @@ export namespace CompletionTriggerKind {
switch (kind) {
case modes.SuggestTriggerKind.TriggerCharacter:
return types.CompletionTriggerKind.TriggerCharacter;
case modes.SuggestTriggerKind.TriggerForIncompleteCompletions:
return types.CompletionTriggerKind.TriggerForIncompleteCompletions;
case modes.SuggestTriggerKind.Invoke:
default:
return types.CompletionTriggerKind.Invoke;

View File

@@ -946,7 +946,8 @@ export class SignatureHelp {
export enum CompletionTriggerKind {
Invoke = 0,
TriggerCharacter = 1
TriggerCharacter = 1,
TriggerForIncompleteCompletions = 2
}
export interface CompletionContext {
@@ -1479,11 +1480,20 @@ export enum ProgressLocation {
export class TreeItem {
label?: string;
resourceUri?: URI;
iconPath?: string | URI | { light: string | URI; dark: string | URI };
command?: vscode.Command;
contextValue?: string;
constructor(public label: string, public collapsibleState: vscode.TreeItemCollapsibleState = TreeItemCollapsibleState.None) {
constructor(label: string, collapsibleState?: vscode.TreeItemCollapsibleState)
constructor(resourceUri: URI, collapsibleState?: vscode.TreeItemCollapsibleState)
constructor(arg1: string | URI, public collapsibleState: vscode.TreeItemCollapsibleState = TreeItemCollapsibleState.None) {
if (arg1 instanceof URI) {
this.resourceUri = arg1;
} else {
this.label = arg1;
}
}
}
@@ -1575,3 +1585,19 @@ export enum LogLevel {
Critical = 6,
Off = 7
}
//#region file api
// todo@remote
export enum FileChangeType {
Updated = 0,
Added = 1,
Deleted = 2
}
export enum FileType {
File = 0,
Dir = 1,
Symlink = 2
}
//#endregion