mirror of
https://github.com/microsoft/vscode.git
synced 2026-04-25 19:18:59 +01:00
Merge branch 'master' into rename-workspaceedit-proto
This commit is contained in:
@@ -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
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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`);
|
||||
}
|
||||
|
||||
@@ -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; },
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user