mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-01-27 17:23:21 -05:00
Merge from vscode 8e0f348413f4f616c23a88ae30030efa85811973 (#6381)
* Merge from vscode 8e0f348413f4f616c23a88ae30030efa85811973 * disable strict null check
This commit is contained in:
72
src/vs/workbench/api/browser/extensionHost.contribution.ts
Normal file
72
src/vs/workbench/api/browser/extensionHost.contribution.ts
Normal file
@@ -0,0 +1,72 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { IWorkbenchContribution, IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions';
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle';
|
||||
|
||||
// --- other interested parties
|
||||
import { JSONValidationExtensionPoint } from 'vs/workbench/api/common/jsonValidationExtensionPoint';
|
||||
import { ColorExtensionPoint } from 'vs/workbench/services/themes/common/colorExtensionPoint';
|
||||
import { LanguageConfigurationFileHandler } from 'vs/workbench/contrib/codeEditor/browser/languageConfigurationExtensionPoint';
|
||||
|
||||
// --- mainThread participants
|
||||
import './mainThreadCodeInsets';
|
||||
import './mainThreadClipboard';
|
||||
import './mainThreadCommands';
|
||||
import './mainThreadConfiguration';
|
||||
import './mainThreadConsole';
|
||||
// import './mainThreadDebugService'; {{SQL CARBON EDIT}} @anthonydresser comment out debug service
|
||||
import './mainThreadDecorations';
|
||||
import './mainThreadDiagnostics';
|
||||
import './mainThreadDialogs';
|
||||
import './mainThreadDocumentContentProviders';
|
||||
import './mainThreadDocuments';
|
||||
import './mainThreadDocumentsAndEditors';
|
||||
import './mainThreadEditor';
|
||||
import './mainThreadEditors';
|
||||
import './mainThreadErrors';
|
||||
import './mainThreadExtensionService';
|
||||
import './mainThreadFileSystem';
|
||||
import './mainThreadFileSystemEventService';
|
||||
import './mainThreadKeytar';
|
||||
import './mainThreadLanguageFeatures';
|
||||
import './mainThreadLanguages';
|
||||
import './mainThreadLogService';
|
||||
import './mainThreadMessageService';
|
||||
import './mainThreadOutputService';
|
||||
import './mainThreadProgress';
|
||||
import './mainThreadQuickOpen';
|
||||
import './mainThreadSaveParticipant';
|
||||
import './mainThreadSCM';
|
||||
import './mainThreadSearch';
|
||||
import './mainThreadStatusBar';
|
||||
import './mainThreadStorage';
|
||||
import './mainThreadTelemetry';
|
||||
import './mainThreadTerminalService';
|
||||
import './mainThreadTreeViews';
|
||||
import './mainThreadUrls';
|
||||
import './mainThreadWindow';
|
||||
import './mainThreadWebview';
|
||||
import './mainThreadWorkspace';
|
||||
import './mainThreadComments';
|
||||
// import './mainThreadTask'; {{SQL CARBON EDIT}} @anthonydresser comment out task
|
||||
import './mainThreadLabelService';
|
||||
import 'vs/workbench/api/common/apiCommands';
|
||||
|
||||
export class ExtensionPoints implements IWorkbenchContribution {
|
||||
|
||||
constructor(
|
||||
@IInstantiationService private readonly instantiationService: IInstantiationService
|
||||
) {
|
||||
// Classes that handle extension points...
|
||||
this.instantiationService.createInstance(JSONValidationExtensionPoint);
|
||||
this.instantiationService.createInstance(ColorExtensionPoint);
|
||||
this.instantiationService.createInstance(LanguageConfigurationFileHandler);
|
||||
}
|
||||
}
|
||||
|
||||
Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench).registerWorkbenchContribution(ExtensionPoints, LifecyclePhase.Starting);
|
||||
@@ -8,7 +8,7 @@ import { MainContext, MainThreadClipboardShape } from '../common/extHost.protoco
|
||||
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
|
||||
|
||||
@extHostNamedCustomer(MainContext.MainThreadClipboard)
|
||||
export class MainThreadCommands implements MainThreadClipboardShape {
|
||||
export class MainThreadClipboard implements MainThreadClipboardShape {
|
||||
|
||||
constructor(
|
||||
_context: any,
|
||||
@@ -20,11 +20,10 @@ export class MainThreadCommands implements MainThreadClipboardShape {
|
||||
}
|
||||
|
||||
$readText(): Promise<string> {
|
||||
return Promise.resolve(this._clipboardService.readText());
|
||||
return this._clipboardService.readText();
|
||||
}
|
||||
|
||||
$writeText(value: string): Promise<void> {
|
||||
this._clipboardService.writeText(value);
|
||||
return Promise.resolve();
|
||||
return this._clipboardService.writeText(value);
|
||||
}
|
||||
}
|
||||
|
||||
148
src/vs/workbench/api/browser/mainThreadCodeInsets.ts
Normal file
148
src/vs/workbench/api/browser/mainThreadCodeInsets.ts
Normal file
@@ -0,0 +1,148 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { UriComponents, URI } from 'vs/base/common/uri';
|
||||
import * as modes from 'vs/editor/common/modes';
|
||||
import { MainContext, MainThreadEditorInsetsShape, IExtHostContext, ExtHostEditorInsetsShape, ExtHostContext } from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { extHostNamedCustomer } from '../common/extHostCustomers';
|
||||
import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';
|
||||
import { IWebviewService, Webview } from 'vs/workbench/contrib/webview/common/webview';
|
||||
import { DisposableStore } from 'vs/base/common/lifecycle';
|
||||
import { IActiveCodeEditor, IViewZone } from 'vs/editor/browser/editorBrowser';
|
||||
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
|
||||
|
||||
// todo@joh move these things back into something like contrib/insets
|
||||
class EditorWebviewZone implements IViewZone {
|
||||
|
||||
readonly domNode: HTMLElement;
|
||||
readonly afterLineNumber: number;
|
||||
readonly afterColumn: number;
|
||||
readonly heightInLines: number;
|
||||
|
||||
private _id: number;
|
||||
// suppressMouseDown?: boolean | undefined;
|
||||
// heightInPx?: number | undefined;
|
||||
// minWidthInPx?: number | undefined;
|
||||
// marginDomNode?: HTMLElement | null | undefined;
|
||||
// onDomNodeTop?: ((top: number) => void) | undefined;
|
||||
// onComputedHeight?: ((height: number) => void) | undefined;
|
||||
|
||||
constructor(
|
||||
readonly editor: IActiveCodeEditor,
|
||||
readonly line: number,
|
||||
readonly height: number,
|
||||
readonly webview: Webview,
|
||||
) {
|
||||
this.domNode = document.createElement('div');
|
||||
this.domNode.style.zIndex = '10'; // without this, the webview is not interactive
|
||||
this.afterLineNumber = line;
|
||||
this.afterColumn = 1;
|
||||
this.heightInLines = height;
|
||||
|
||||
editor.changeViewZones(accessor => this._id = accessor.addZone(this));
|
||||
webview.mountTo(this.domNode);
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
this.editor.changeViewZones(accessor => accessor.removeZone(this._id));
|
||||
}
|
||||
}
|
||||
|
||||
@extHostNamedCustomer(MainContext.MainThreadEditorInsets)
|
||||
export class MainThreadEditorInsets implements MainThreadEditorInsetsShape {
|
||||
|
||||
private readonly _proxy: ExtHostEditorInsetsShape;
|
||||
private readonly _disposables = new DisposableStore();
|
||||
private readonly _insets = new Map<number, EditorWebviewZone>();
|
||||
|
||||
constructor(
|
||||
context: IExtHostContext,
|
||||
@ICodeEditorService private readonly _editorService: ICodeEditorService,
|
||||
@IWebviewService private readonly _webviewService: IWebviewService,
|
||||
) {
|
||||
this._proxy = context.getProxy(ExtHostContext.ExtHostEditorInsets);
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
this._disposables.dispose();
|
||||
}
|
||||
|
||||
async $createEditorInset(handle: number, id: string, uri: UriComponents, line: number, height: number, options: modes.IWebviewOptions, extensionId: ExtensionIdentifier, extensionLocation: UriComponents): Promise<void> {
|
||||
|
||||
let editor: IActiveCodeEditor | undefined;
|
||||
id = id.substr(0, id.indexOf(',')); //todo@joh HACK
|
||||
|
||||
for (const candidate of this._editorService.listCodeEditors()) {
|
||||
if (candidate.getId() === id && candidate.hasModel() && candidate.getModel()!.uri.toString() === URI.revive(uri).toString()) {
|
||||
editor = candidate;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!editor) {
|
||||
setTimeout(() => this._proxy.$onDidDispose(handle));
|
||||
return;
|
||||
}
|
||||
|
||||
const disposables = new DisposableStore();
|
||||
|
||||
const webview = this._webviewService.createWebview('' + handle, {
|
||||
enableFindWidget: false,
|
||||
allowSvgs: false,
|
||||
extension: { id: extensionId, location: URI.revive(extensionLocation) }
|
||||
}, {
|
||||
allowScripts: options.enableScripts,
|
||||
localResourceRoots: options.localResourceRoots ? options.localResourceRoots.map(uri => URI.revive(uri)) : undefined
|
||||
});
|
||||
|
||||
const webviewZone = new EditorWebviewZone(editor, line, height, webview);
|
||||
|
||||
const remove = () => {
|
||||
disposables.dispose();
|
||||
this._proxy.$onDidDispose(handle);
|
||||
this._insets.delete(handle);
|
||||
};
|
||||
|
||||
disposables.add(editor.onDidChangeModel(remove));
|
||||
disposables.add(editor.onDidDispose(remove));
|
||||
disposables.add(webviewZone);
|
||||
disposables.add(webview);
|
||||
disposables.add(webview.onMessage(msg => this._proxy.$onDidReceiveMessage(handle, msg)));
|
||||
|
||||
this._insets.set(handle, webviewZone);
|
||||
}
|
||||
|
||||
$disposeEditorInset(handle: number): void {
|
||||
const inset = this.getInset(handle);
|
||||
this._insets.delete(handle);
|
||||
inset.dispose();
|
||||
|
||||
}
|
||||
|
||||
$setHtml(handle: number, value: string): void {
|
||||
const inset = this.getInset(handle);
|
||||
inset.webview.html = value;
|
||||
|
||||
}
|
||||
|
||||
$setOptions(handle: number, options: modes.IWebviewOptions): void {
|
||||
const inset = this.getInset(handle);
|
||||
inset.webview.options = options;
|
||||
}
|
||||
|
||||
async $postMessage(handle: number, value: any): Promise<boolean> {
|
||||
const inset = this.getInset(handle);
|
||||
inset.webview.sendMessage(value);
|
||||
return true;
|
||||
}
|
||||
|
||||
private getInset(handle: number): EditorWebviewZone {
|
||||
const inset = this._insets.get(handle);
|
||||
if (!inset) {
|
||||
throw new Error('Unknown inset');
|
||||
}
|
||||
return inset;
|
||||
}
|
||||
}
|
||||
@@ -12,7 +12,7 @@ import { revive } from 'vs/base/common/marshalling';
|
||||
@extHostNamedCustomer(MainContext.MainThreadCommands)
|
||||
export class MainThreadCommands implements MainThreadCommandsShape {
|
||||
|
||||
private readonly _disposables = new Map<string, IDisposable>();
|
||||
private readonly _commandRegistrations = new Map<string, IDisposable>();
|
||||
private readonly _generateCommandsDocumentationRegistration: IDisposable;
|
||||
private readonly _proxy: ExtHostCommandsShape;
|
||||
|
||||
@@ -26,8 +26,8 @@ export class MainThreadCommands implements MainThreadCommandsShape {
|
||||
}
|
||||
|
||||
dispose() {
|
||||
this._disposables.forEach(value => value.dispose());
|
||||
this._disposables.clear();
|
||||
this._commandRegistrations.forEach(value => value.dispose());
|
||||
this._commandRegistrations.clear();
|
||||
|
||||
this._generateCommandsDocumentationRegistration.dispose();
|
||||
}
|
||||
@@ -36,10 +36,9 @@ export class MainThreadCommands implements MainThreadCommandsShape {
|
||||
return this._proxy.$getContributedCommandHandlerDescriptions().then(result => {
|
||||
// add local commands
|
||||
const commands = CommandsRegistry.getCommands();
|
||||
for (let id in commands) {
|
||||
let { description } = commands[id];
|
||||
if (description) {
|
||||
result[id] = description;
|
||||
for (const [id, command] of commands) {
|
||||
if (command.description) {
|
||||
result[id] = command.description;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,7 +52,7 @@ export class MainThreadCommands implements MainThreadCommandsShape {
|
||||
}
|
||||
|
||||
$registerCommand(id: string): void {
|
||||
this._disposables.set(
|
||||
this._commandRegistrations.set(
|
||||
id,
|
||||
CommandsRegistry.registerCommand(id, (accessor, ...args) => {
|
||||
return this._proxy.$executeContributedCommand(id, ...args).then(result => {
|
||||
@@ -64,10 +63,10 @@ export class MainThreadCommands implements MainThreadCommandsShape {
|
||||
}
|
||||
|
||||
$unregisterCommand(id: string): void {
|
||||
const command = this._disposables.get(id);
|
||||
const command = this._commandRegistrations.get(id);
|
||||
if (command) {
|
||||
command.dispose();
|
||||
this._disposables.delete(id);
|
||||
this._commandRegistrations.delete(id);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -79,7 +78,7 @@ export class MainThreadCommands implements MainThreadCommandsShape {
|
||||
}
|
||||
|
||||
$getCommands(): Promise<string[]> {
|
||||
return Promise.resolve(Object.keys(CommandsRegistry.getCommands()));
|
||||
return Promise.resolve([...CommandsRegistry.getCommands().keys()]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,85 +3,25 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { Disposable, IDisposable, dispose } from 'vs/base/common/lifecycle';
|
||||
import { ICodeEditor, isCodeEditor, isDiffEditor, IDiffEditor } from 'vs/editor/browser/editorBrowser';
|
||||
import * as modes from 'vs/editor/common/modes';
|
||||
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { Emitter, Event } from 'vs/base/common/event';
|
||||
import { Disposable, DisposableStore, dispose, IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { keys } from 'vs/base/common/map';
|
||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { ExtHostCommentsShape, ExtHostContext, IExtHostContext, MainContext, MainThreadCommentsShape, CommentProviderFeatures } from '../common/extHost.protocol';
|
||||
|
||||
import { ICommentService, ICommentInfo } from 'vs/workbench/contrib/comments/browser/commentService';
|
||||
import { COMMENTS_PANEL_ID, CommentsPanel, COMMENTS_PANEL_TITLE } from 'vs/workbench/contrib/comments/browser/commentsPanel';
|
||||
import { IPanelService } from 'vs/workbench/services/panel/common/panelService';
|
||||
import { URI, UriComponents } from 'vs/base/common/uri';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { generateUuid } from 'vs/base/common/uuid';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { ICommentsConfiguration } from 'vs/workbench/contrib/comments/browser/comments.contribution';
|
||||
import { IRange } from 'vs/editor/common/core/range';
|
||||
import * as modes from 'vs/editor/common/modes';
|
||||
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { PanelRegistry, Extensions as PanelExtensions, PanelDescriptor } from 'vs/workbench/browser/panel';
|
||||
import { IRange, Range } from 'vs/editor/common/core/range';
|
||||
import { Emitter, Event } from 'vs/base/common/event';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
|
||||
export class MainThreadDocumentCommentProvider implements modes.DocumentCommentProvider {
|
||||
private readonly _proxy: ExtHostCommentsShape;
|
||||
private readonly _handle: number;
|
||||
private readonly _features: CommentProviderFeatures;
|
||||
get startDraftLabel(): string | undefined { return this._features.startDraftLabel; }
|
||||
get deleteDraftLabel(): string | undefined { return this._features.deleteDraftLabel; }
|
||||
get finishDraftLabel(): string | undefined { return this._features.finishDraftLabel; }
|
||||
get reactionGroup(): modes.CommentReaction[] | undefined { return this._features.reactionGroup; }
|
||||
|
||||
constructor(proxy: ExtHostCommentsShape, handle: number, features: CommentProviderFeatures) {
|
||||
this._proxy = proxy;
|
||||
this._handle = handle;
|
||||
this._features = features;
|
||||
}
|
||||
|
||||
async provideDocumentComments(uri: URI, token: CancellationToken) {
|
||||
return this._proxy.$provideDocumentComments(this._handle, uri);
|
||||
}
|
||||
|
||||
async createNewCommentThread(uri: URI, range: Range, text: string, token: CancellationToken) {
|
||||
return this._proxy.$createNewCommentThread(this._handle, uri, range, text);
|
||||
}
|
||||
|
||||
async replyToCommentThread(uri: URI, range: Range, thread: modes.CommentThread, text: string, token: CancellationToken) {
|
||||
return this._proxy.$replyToCommentThread(this._handle, uri, range, thread, text);
|
||||
}
|
||||
|
||||
async editComment(uri: URI, comment: modes.Comment, text: string, token: CancellationToken) {
|
||||
return this._proxy.$editComment(this._handle, uri, comment, text);
|
||||
}
|
||||
|
||||
async deleteComment(uri: URI, comment: modes.Comment, token: CancellationToken) {
|
||||
return this._proxy.$deleteComment(this._handle, uri, comment);
|
||||
}
|
||||
|
||||
async startDraft(uri: URI, token: CancellationToken): Promise<void> {
|
||||
return this._proxy.$startDraft(this._handle, uri);
|
||||
}
|
||||
async deleteDraft(uri: URI, token: CancellationToken): Promise<void> {
|
||||
return this._proxy.$deleteDraft(this._handle, uri);
|
||||
}
|
||||
async finishDraft(uri: URI, token: CancellationToken): Promise<void> {
|
||||
return this._proxy.$finishDraft(this._handle, uri);
|
||||
}
|
||||
async addReaction(uri: URI, comment: modes.Comment, reaction: modes.CommentReaction, token: CancellationToken): Promise<void> {
|
||||
return this._proxy.$addReaction(this._handle, uri, comment, reaction);
|
||||
}
|
||||
async deleteReaction(uri: URI, comment: modes.Comment, reaction: modes.CommentReaction, token: CancellationToken): Promise<void> {
|
||||
return this._proxy.$deleteReaction(this._handle, uri, comment, reaction);
|
||||
}
|
||||
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
|
||||
import { Extensions as PanelExtensions, PanelDescriptor, PanelRegistry } from 'vs/workbench/browser/panel';
|
||||
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 { IPanelService } from 'vs/workbench/services/panel/common/panelService';
|
||||
import { CommentProviderFeatures, ExtHostCommentsShape, ExtHostContext, IExtHostContext, MainContext, MainThreadCommentsShape } from '../common/extHost.protocol';
|
||||
|
||||
|
||||
// onDidChangeCommentThreads = null;
|
||||
}
|
||||
|
||||
export class MainThreadCommentThread implements modes.CommentThread2 {
|
||||
export class MainThreadCommentThread implements modes.CommentThread {
|
||||
private _input?: modes.CommentInput;
|
||||
get input(): modes.CommentInput | undefined {
|
||||
return this._input;
|
||||
@@ -117,7 +57,7 @@ export class MainThreadCommentThread implements modes.CommentThread2 {
|
||||
}
|
||||
|
||||
private _onDidChangeLabel = new Emitter<string>();
|
||||
get onDidChangeLabel(): Event<string> { return this._onDidChangeLabel.event; }
|
||||
readonly onDidChangeLabel: Event<string> = this._onDidChangeLabel.event;
|
||||
|
||||
private _comments: modes.Comment[] | undefined;
|
||||
|
||||
@@ -133,42 +73,6 @@ export class MainThreadCommentThread implements modes.CommentThread2 {
|
||||
private _onDidChangeComments = new Emitter<modes.Comment[] | undefined>();
|
||||
get onDidChangeComments(): Event<modes.Comment[] | undefined> { return this._onDidChangeComments.event; }
|
||||
|
||||
private _acceptInputCommand: modes.Command | undefined;
|
||||
set acceptInputCommand(newCommand: modes.Command | undefined) {
|
||||
this._acceptInputCommand = newCommand;
|
||||
this._onDidChangeAcceptInputCommand.fire(this._acceptInputCommand);
|
||||
}
|
||||
|
||||
get acceptInputCommand(): modes.Command | undefined {
|
||||
return this._acceptInputCommand!;
|
||||
}
|
||||
|
||||
private _onDidChangeAcceptInputCommand = new Emitter<modes.Command | undefined>();
|
||||
get onDidChangeAcceptInputCommand(): Event<modes.Command | undefined> { return this._onDidChangeAcceptInputCommand.event; }
|
||||
|
||||
private _additionalCommands: modes.Command[] | undefined;
|
||||
set additionalCommands(newCommands: modes.Command[] | undefined) {
|
||||
this._additionalCommands = newCommands;
|
||||
this._onDidChangeAdditionalCommands.fire(this._additionalCommands);
|
||||
}
|
||||
|
||||
get additionalCommands(): modes.Command[] | undefined {
|
||||
return this._additionalCommands;
|
||||
}
|
||||
|
||||
private _onDidChangeAdditionalCommands = new Emitter<modes.Command[] | undefined>();
|
||||
get onDidChangeAdditionalCommands(): Event<modes.Command[] | undefined> { return this._onDidChangeAdditionalCommands.event; }
|
||||
|
||||
private _deleteCommand: modes.Command | undefined;
|
||||
|
||||
set deleteCommand(newCommand: modes.Command | undefined) {
|
||||
this._deleteCommand = newCommand;
|
||||
}
|
||||
|
||||
get deleteCommand(): modes.Command | undefined {
|
||||
return this._deleteCommand;
|
||||
}
|
||||
|
||||
set range(range: IRange) {
|
||||
this._range = range;
|
||||
this._onDidChangeRange.fire(this._range);
|
||||
@@ -216,24 +120,16 @@ export class MainThreadCommentThread implements modes.CommentThread2 {
|
||||
label: string,
|
||||
contextValue: string | undefined,
|
||||
comments: modes.Comment[],
|
||||
acceptInputCommand: modes.Command | undefined,
|
||||
additionalCommands: modes.Command[],
|
||||
deleteCommand: modes.Command | undefined,
|
||||
collapsibleState: modes.CommentThreadCollapsibleState) {
|
||||
this._range = range;
|
||||
this._label = label;
|
||||
this._contextValue = contextValue;
|
||||
this._comments = comments;
|
||||
this._acceptInputCommand = acceptInputCommand;
|
||||
this._additionalCommands = additionalCommands;
|
||||
this._deleteCommand = deleteCommand;
|
||||
this._collapsibleState = collapsibleState;
|
||||
}
|
||||
|
||||
dispose() {
|
||||
this._isDisposed = true;
|
||||
this._onDidChangeAcceptInputCommand.dispose();
|
||||
this._onDidChangeAdditionalCommands.dispose();
|
||||
this._onDidChangeCollasibleState.dispose();
|
||||
this._onDidChangeComments.dispose();
|
||||
this._onDidChangeInput.dispose();
|
||||
@@ -284,6 +180,9 @@ export class MainThreadCommentController {
|
||||
private readonly _threads: Map<number, MainThreadCommentThread> = new Map<number, MainThreadCommentThread>();
|
||||
public activeCommentThread?: MainThreadCommentThread;
|
||||
|
||||
get features(): CommentProviderFeatures {
|
||||
return this._features;
|
||||
}
|
||||
|
||||
constructor(
|
||||
private readonly _proxy: ExtHostCommentsShape,
|
||||
@@ -299,15 +198,16 @@ export class MainThreadCommentController {
|
||||
this._features = features;
|
||||
}
|
||||
|
||||
createCommentThread(commentThreadHandle: number,
|
||||
createCommentThread(extensionId: string,
|
||||
commentThreadHandle: number,
|
||||
threadId: string,
|
||||
resource: UriComponents,
|
||||
range: IRange,
|
||||
): modes.CommentThread2 {
|
||||
): modes.CommentThread {
|
||||
let thread = new MainThreadCommentThread(
|
||||
commentThreadHandle,
|
||||
this.handle,
|
||||
'',
|
||||
extensionId,
|
||||
threadId,
|
||||
URI.revive(resource).toString(),
|
||||
range
|
||||
@@ -315,17 +215,11 @@ export class MainThreadCommentController {
|
||||
|
||||
this._threads.set(commentThreadHandle, thread);
|
||||
|
||||
// As we create comment thread from template and then restore from the newly created maint thread comment thread,
|
||||
// we postpone the update event to avoid duplication.
|
||||
// This can be actually removed once we are on the new API.
|
||||
setTimeout(() => {
|
||||
this._commentService.updateComments(this._uniqueId, {
|
||||
added: [thread],
|
||||
removed: [],
|
||||
changed: [],
|
||||
draftMode: modes.DraftMode.NotSupported
|
||||
});
|
||||
}, 0);
|
||||
this._commentService.updateComments(this._uniqueId, {
|
||||
added: [thread],
|
||||
removed: [],
|
||||
changed: []
|
||||
});
|
||||
|
||||
return thread;
|
||||
}
|
||||
@@ -337,18 +231,14 @@ export class MainThreadCommentController {
|
||||
label: string,
|
||||
contextValue: string | undefined,
|
||||
comments: modes.Comment[],
|
||||
acceptInputCommand: modes.Command | undefined,
|
||||
additionalCommands: modes.Command[],
|
||||
deleteCommand: modes.Command | undefined,
|
||||
collapsibleState: modes.CommentThreadCollapsibleState): void {
|
||||
let thread = this.getKnownThread(commentThreadHandle);
|
||||
thread.batchUpdate(range, label, contextValue, comments, acceptInputCommand, additionalCommands, deleteCommand, collapsibleState);
|
||||
thread.batchUpdate(range, label, contextValue, comments, collapsibleState);
|
||||
|
||||
this._commentService.updateComments(this._uniqueId, {
|
||||
added: [],
|
||||
removed: [],
|
||||
changed: [thread],
|
||||
draftMode: modes.DraftMode.NotSupported
|
||||
changed: [thread]
|
||||
});
|
||||
}
|
||||
|
||||
@@ -359,8 +249,7 @@ export class MainThreadCommentController {
|
||||
this._commentService.updateComments(this._uniqueId, {
|
||||
added: [],
|
||||
removed: [thread],
|
||||
changed: [],
|
||||
draftMode: modes.DraftMode.NotSupported
|
||||
changed: []
|
||||
});
|
||||
|
||||
thread.dispose();
|
||||
@@ -393,7 +282,7 @@ export class MainThreadCommentController {
|
||||
}
|
||||
|
||||
async getDocumentComments(resource: URI, token: CancellationToken) {
|
||||
let ret: modes.CommentThread2[] = [];
|
||||
let ret: modes.CommentThread[] = [];
|
||||
for (let thread of keys(this._threads)) {
|
||||
const commentThread = this._threads.get(thread)!;
|
||||
if (commentThread.resource === resource.toString()) {
|
||||
@@ -402,26 +291,15 @@ export class MainThreadCommentController {
|
||||
}
|
||||
|
||||
let commentingRanges = await this._proxy.$provideCommentingRanges(this.handle, resource, token);
|
||||
let staticContribution = await this._proxy.$checkStaticContribution(this.handle);
|
||||
|
||||
return <ICommentInfo>{
|
||||
owner: this._uniqueId,
|
||||
label: this.label,
|
||||
threads: ret,
|
||||
commentingRanges: commentingRanges ? {
|
||||
commentingRanges: {
|
||||
resource: resource,
|
||||
ranges: commentingRanges,
|
||||
newCommentThreadCallback: staticContribution ? undefined : async (uri: UriComponents, range: IRange) => {
|
||||
let threadHandle = await this._proxy.$createNewCommentWidgetCallback(this.handle, uri, range, token);
|
||||
|
||||
// if (threadHandle !== undefined) { {{SQL CARBON EDIT}} @anthonydresser this never happens but throws error because of strict null checks
|
||||
// return this.getKnownThread(threadHandle);
|
||||
// }
|
||||
|
||||
return undefined; // {{SQL CARBON EDIT}} @anthonydresser revert back after strict-null-check
|
||||
}
|
||||
} : [],
|
||||
draftMode: modes.DraftMode.NotSupported
|
||||
ranges: commentingRanges || []
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -434,7 +312,7 @@ export class MainThreadCommentController {
|
||||
return this._features.reactionGroup;
|
||||
}
|
||||
|
||||
async toggleReaction(uri: URI, thread: modes.CommentThread2, comment: modes.Comment, reaction: modes.CommentReaction, token: CancellationToken): Promise<void> {
|
||||
async toggleReaction(uri: URI, thread: modes.CommentThread, comment: modes.Comment, reaction: modes.CommentReaction, token: CancellationToken): Promise<void> {
|
||||
return this._proxy.$toggleReaction(this._handle, thread.commentThreadHandle, uri, comment, reaction);
|
||||
}
|
||||
|
||||
@@ -451,6 +329,10 @@ export class MainThreadCommentController {
|
||||
this._proxy.$createCommentThreadTemplate(this.handle, resource, range);
|
||||
}
|
||||
|
||||
async updateCommentThreadTemplate(threadHandle: number, range: IRange) {
|
||||
await this._proxy.$updateCommentThreadTemplate(this.handle, threadHandle, range);
|
||||
}
|
||||
|
||||
toJSON(): any {
|
||||
return {
|
||||
$mid: 6,
|
||||
@@ -461,28 +343,38 @@ export class MainThreadCommentController {
|
||||
|
||||
@extHostNamedCustomer(MainContext.MainThreadComments)
|
||||
export class MainThreadComments extends Disposable implements MainThreadCommentsShape {
|
||||
private _disposables: IDisposable[];
|
||||
private _activeCommentThreadDisposables: IDisposable[];
|
||||
private readonly _proxy: ExtHostCommentsShape;
|
||||
private _documentProviders = new Map<number, IDisposable>();
|
||||
private _workspaceProviders = new Map<number, IDisposable>();
|
||||
private _handlers = new Map<number, string>();
|
||||
private _commentControllers = new Map<number, MainThreadCommentController>();
|
||||
|
||||
private _activeCommentThread?: MainThreadCommentThread;
|
||||
private readonly _activeCommentThreadDisposables = this._register(new DisposableStore());
|
||||
|
||||
private _openPanelListener: IDisposable | null;
|
||||
|
||||
|
||||
constructor(
|
||||
extHostContext: IExtHostContext,
|
||||
@IEditorService private readonly _editorService: IEditorService,
|
||||
@ICommentService private readonly _commentService: ICommentService,
|
||||
@IPanelService private readonly _panelService: IPanelService,
|
||||
@ITelemetryService private readonly _telemetryService: ITelemetryService,
|
||||
@IConfigurationService private readonly _configurationService: IConfigurationService,
|
||||
@IPanelService private readonly _panelService: IPanelService
|
||||
) {
|
||||
super();
|
||||
this._disposables = [];
|
||||
this._activeCommentThreadDisposables = [];
|
||||
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostComments);
|
||||
|
||||
this._register(this._commentService.onDidChangeActiveCommentThread(async thread => {
|
||||
let handle = (thread as MainThreadCommentThread).controllerHandle;
|
||||
let controller = this._commentControllers.get(handle);
|
||||
|
||||
if (!controller) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._activeCommentThreadDisposables.clear();
|
||||
this._activeCommentThread = thread as MainThreadCommentThread;
|
||||
controller.activeCommentThread = this._activeCommentThread;
|
||||
}));
|
||||
}
|
||||
|
||||
$registerCommentController(handle: number, id: string, label: string): void {
|
||||
@@ -525,15 +417,16 @@ export class MainThreadComments extends Disposable implements MainThreadComments
|
||||
commentThreadHandle: number,
|
||||
threadId: string,
|
||||
resource: UriComponents,
|
||||
range: IRange
|
||||
): modes.CommentThread2 | undefined {
|
||||
range: IRange,
|
||||
extensionId: ExtensionIdentifier
|
||||
): modes.CommentThread | undefined {
|
||||
let provider = this._commentControllers.get(handle);
|
||||
|
||||
if (!provider) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return provider.createCommentThread(commentThreadHandle, threadId, resource, range);
|
||||
return provider.createCommentThread(extensionId.value, commentThreadHandle, threadId, resource, range);
|
||||
}
|
||||
|
||||
$updateCommentThread(handle: number,
|
||||
@@ -544,9 +437,6 @@ export class MainThreadComments extends Disposable implements MainThreadComments
|
||||
label: string,
|
||||
contextValue: string | undefined,
|
||||
comments: modes.Comment[],
|
||||
acceptInputCommand: modes.Command | undefined,
|
||||
additionalCommands: modes.Command[],
|
||||
deleteCommand: modes.Command,
|
||||
collapsibleState: modes.CommentThreadCollapsibleState): void {
|
||||
let provider = this._commentControllers.get(handle);
|
||||
|
||||
@@ -554,7 +444,7 @@ export class MainThreadComments extends Disposable implements MainThreadComments
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return provider.updateCommentThread(commentThreadHandle, threadId, resource, range, label, contextValue, comments, acceptInputCommand, additionalCommands, deleteCommand, collapsibleState);
|
||||
return provider.updateCommentThread(commentThreadHandle, threadId, resource, range, label, contextValue, comments, collapsibleState);
|
||||
}
|
||||
|
||||
$deleteCommentThread(handle: number, commentThreadHandle: number) {
|
||||
@@ -567,26 +457,6 @@ export class MainThreadComments extends Disposable implements MainThreadComments
|
||||
return provider.deleteCommentThread(commentThreadHandle);
|
||||
}
|
||||
|
||||
$setInputValue(handle: number, input: string) {
|
||||
let provider = this._commentControllers.get(handle);
|
||||
|
||||
if (!provider) {
|
||||
return;
|
||||
}
|
||||
|
||||
provider.updateInput(input);
|
||||
}
|
||||
|
||||
$registerDocumentCommentProvider(handle: number, features: CommentProviderFeatures): void {
|
||||
this._documentProviders.set(handle, undefined);
|
||||
const handler = new MainThreadDocumentCommentProvider(this._proxy, handle, features);
|
||||
|
||||
const providerId = generateUuid();
|
||||
this._handlers.set(handle, providerId);
|
||||
|
||||
this._commentService.registerDataProvider(providerId, handler);
|
||||
}
|
||||
|
||||
private registerPanel(commentsPanelAlreadyConstructed: boolean) {
|
||||
if (!commentsPanelAlreadyConstructed) {
|
||||
Registry.as<PanelRegistry>(PanelExtensions.Panels).registerPanel(new PanelDescriptor(
|
||||
@@ -608,15 +478,6 @@ export class MainThreadComments extends Disposable implements MainThreadComments
|
||||
if (!commentsPanelAlreadyConstructed && !this._openPanelListener) {
|
||||
this._openPanelListener = this._panelService.onDidPanelOpen(e => {
|
||||
if (e.panel.getId() === COMMENTS_PANEL_ID) {
|
||||
keys(this._workspaceProviders).forEach(handle => {
|
||||
this._proxy.$provideWorkspaceComments(handle).then(commentThreads => {
|
||||
if (commentThreads) {
|
||||
const providerId = this.getHandler(handle);
|
||||
this._commentService.setWorkspaceComments(providerId, commentThreads);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
keys(this._commentControllers).forEach(handle => {
|
||||
let threads = this._commentControllers.get(handle)!.getAllComments();
|
||||
|
||||
@@ -642,119 +503,14 @@ export class MainThreadComments extends Disposable implements MainThreadComments
|
||||
return this._handlers.get(handle)!;
|
||||
}
|
||||
|
||||
$registerWorkspaceCommentProvider(handle: number, extensionId: ExtensionIdentifier): void {
|
||||
this._workspaceProviders.set(handle, undefined);
|
||||
|
||||
const providerId = generateUuid();
|
||||
this._handlers.set(handle, providerId);
|
||||
|
||||
const commentsPanelAlreadyConstructed = this._panelService.getPanels().some(panel => panel.id === COMMENTS_PANEL_ID);
|
||||
if (!commentsPanelAlreadyConstructed) {
|
||||
this.registerPanel(commentsPanelAlreadyConstructed);
|
||||
}
|
||||
|
||||
const openPanel = this._configurationService.getValue<ICommentsConfiguration>('comments').openPanel;
|
||||
|
||||
if (openPanel === 'neverOpen') {
|
||||
this.registerOpenPanelListener(commentsPanelAlreadyConstructed);
|
||||
}
|
||||
|
||||
if (openPanel === 'openOnSessionStart') {
|
||||
this._panelService.openPanel(COMMENTS_PANEL_ID);
|
||||
}
|
||||
|
||||
this._proxy.$provideWorkspaceComments(handle).then(commentThreads => {
|
||||
if (commentThreads) {
|
||||
if (openPanel === 'openOnSessionStartWithComments' && commentThreads.length) {
|
||||
if (commentThreads.length) {
|
||||
this._panelService.openPanel(COMMENTS_PANEL_ID);
|
||||
} else {
|
||||
this.registerOpenPanelListener(commentsPanelAlreadyConstructed);
|
||||
}
|
||||
}
|
||||
|
||||
this._commentService.setWorkspaceComments(providerId, commentThreads);
|
||||
}
|
||||
});
|
||||
|
||||
/* __GDPR__
|
||||
"comments:registerWorkspaceCommentProvider" : {
|
||||
"extensionId" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
|
||||
}
|
||||
*/
|
||||
this._telemetryService.publicLog('comments:registerWorkspaceCommentProvider', {
|
||||
extensionId: extensionId.value
|
||||
});
|
||||
}
|
||||
|
||||
$unregisterDocumentCommentProvider(handle: number): void {
|
||||
this._documentProviders.delete(handle);
|
||||
const handlerId = this.getHandler(handle);
|
||||
this._commentService.unregisterDataProvider(handlerId);
|
||||
this._handlers.delete(handle);
|
||||
}
|
||||
|
||||
$unregisterWorkspaceCommentProvider(handle: number): void {
|
||||
this._workspaceProviders.delete(handle);
|
||||
if (this._workspaceProviders.size === 0) {
|
||||
Registry.as<PanelRegistry>(PanelExtensions.Panels).deregisterPanel(COMMENTS_PANEL_ID);
|
||||
|
||||
if (this._openPanelListener) {
|
||||
this._openPanelListener.dispose();
|
||||
this._openPanelListener = null;
|
||||
}
|
||||
}
|
||||
|
||||
const handlerId = this.getHandler(handle);
|
||||
this._commentService.removeWorkspaceComments(handlerId);
|
||||
this._handlers.delete(handle);
|
||||
}
|
||||
|
||||
$onDidCommentThreadsChange(handle: number, event: modes.CommentThreadChangedEvent) {
|
||||
// notify comment service
|
||||
const providerId = this.getHandler(handle);
|
||||
this._commentService.updateComments(providerId, event);
|
||||
}
|
||||
|
||||
getVisibleEditors(): ICodeEditor[] {
|
||||
let ret: ICodeEditor[] = [];
|
||||
|
||||
this._editorService.visibleControls.forEach(control => {
|
||||
if (isCodeEditor(control.getControl())) {
|
||||
ret.push(control.getControl() as ICodeEditor);
|
||||
}
|
||||
|
||||
if (isDiffEditor(control.getControl())) {
|
||||
let diffEditor = control.getControl() as IDiffEditor;
|
||||
ret.push(diffEditor.getOriginalEditor(), diffEditor.getModifiedEditor());
|
||||
}
|
||||
});
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
async provideWorkspaceComments(): Promise<modes.CommentThread[]> {
|
||||
const result: modes.CommentThread[] = [];
|
||||
for (const handle of keys(this._workspaceProviders)) {
|
||||
const result = await this._proxy.$provideWorkspaceComments(handle);
|
||||
if (Array.isArray(result)) {
|
||||
result.push(...result);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
async provideDocumentComments(resource: URI): Promise<Array<modes.CommentInfo | null>> {
|
||||
const result: Array<modes.CommentInfo | null> = [];
|
||||
for (const handle of keys(this._documentProviders)) {
|
||||
result.push(await this._proxy.$provideDocumentComments(handle, resource));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
this._disposables = dispose(this._disposables);
|
||||
this._activeCommentThreadDisposables = dispose(this._activeCommentThreadDisposables);
|
||||
super.dispose();
|
||||
this._workspaceProviders.forEach(value => dispose(value));
|
||||
this._workspaceProviders.clear();
|
||||
this._documentProviders.forEach(value => dispose(value));
|
||||
|
||||
@@ -33,7 +33,7 @@ export class MainThreadConfiguration implements MainThreadConfigurationShape {
|
||||
}
|
||||
|
||||
private _getConfigurationData(): IConfigurationInitData {
|
||||
const configurationData: IConfigurationInitData = { ...(this.configurationService.getConfigurationData()!), configurationScopes: {} };
|
||||
const configurationData: IConfigurationInitData = { ...(this.configurationService.getConfigurationData()!), configurationScopes: [] };
|
||||
// Send configurations scopes only in development mode.
|
||||
if (!this._environmentService.isBuilt || this._environmentService.isExtensionDevelopment) {
|
||||
configurationData.configurationScopes = getScopes();
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
|
||||
import { DisposableStore } from 'vs/base/common/lifecycle';
|
||||
import { URI as uri } from 'vs/base/common/uri';
|
||||
import { IDebugService, IConfig, IDebugConfigurationProvider, IBreakpoint, IFunctionBreakpoint, IBreakpointData, ITerminalSettings, IDebugAdapter, IDebugAdapterDescriptorFactory, IDebugSession, IDebugAdapterFactory } from 'vs/workbench/contrib/debug/common/debug';
|
||||
import {
|
||||
@@ -20,7 +20,7 @@ import { convertToVSCPaths, convertToDAPaths } from 'vs/workbench/contrib/debug/
|
||||
export class MainThreadDebugService implements MainThreadDebugServiceShape, IDebugAdapterFactory {
|
||||
|
||||
private readonly _proxy: ExtHostDebugServiceShape;
|
||||
private _toDispose: IDisposable[];
|
||||
private readonly _toDispose = new DisposableStore();
|
||||
private _breakpointEventsActive: boolean;
|
||||
private readonly _debugAdapters: Map<number, ExtensionHostDebugAdapter>;
|
||||
private _debugAdaptersHandleCounter = 1;
|
||||
@@ -33,19 +33,18 @@ export class MainThreadDebugService implements MainThreadDebugServiceShape, IDeb
|
||||
@IDebugService private readonly debugService: IDebugService
|
||||
) {
|
||||
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostDebugService);
|
||||
this._toDispose = [];
|
||||
this._toDispose.push(debugService.onDidNewSession(session => {
|
||||
this._toDispose.add(debugService.onDidNewSession(session => {
|
||||
this._proxy.$acceptDebugSessionStarted(this.getSessionDto(session));
|
||||
}));
|
||||
// Need to start listening early to new session events because a custom event can come while a session is initialising
|
||||
this._toDispose.push(debugService.onWillNewSession(session => {
|
||||
this._toDispose.push(session.onDidCustomEvent(event => this._proxy.$acceptDebugSessionCustomEvent(this.getSessionDto(session), event)));
|
||||
this._toDispose.add(debugService.onWillNewSession(session => {
|
||||
this._toDispose.add(session.onDidCustomEvent(event => this._proxy.$acceptDebugSessionCustomEvent(this.getSessionDto(session), event)));
|
||||
}));
|
||||
this._toDispose.push(debugService.onDidEndSession(session => {
|
||||
this._toDispose.add(debugService.onDidEndSession(session => {
|
||||
this._proxy.$acceptDebugSessionTerminated(this.getSessionDto(session));
|
||||
this._sessions.delete(session.getId());
|
||||
}));
|
||||
this._toDispose.push(debugService.getViewModel().onDidFocusSession(session => {
|
||||
this._toDispose.add(debugService.getViewModel().onDidFocusSession(session => {
|
||||
this._proxy.$acceptDebugSessionActiveChanged(this.getSessionDto(session));
|
||||
}));
|
||||
|
||||
@@ -56,7 +55,7 @@ export class MainThreadDebugService implements MainThreadDebugServiceShape, IDeb
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
this._toDispose = dispose(this._toDispose);
|
||||
this._toDispose.dispose();
|
||||
}
|
||||
|
||||
// interface IDebugAdapterProvider
|
||||
@@ -79,7 +78,7 @@ export class MainThreadDebugService implements MainThreadDebugServiceShape, IDeb
|
||||
// RPC methods (MainThreadDebugServiceShape)
|
||||
|
||||
public $registerDebugTypes(debugTypes: string[]) {
|
||||
this._toDispose.push(this.debugService.getConfigurationManager().registerDebugAdapterFactory(debugTypes, this));
|
||||
this._toDispose.add(this.debugService.getConfigurationManager().registerDebugAdapterFactory(debugTypes, this));
|
||||
}
|
||||
|
||||
public $startBreakpointEvents(): void {
|
||||
@@ -88,7 +87,7 @@ export class MainThreadDebugService implements MainThreadDebugServiceShape, IDeb
|
||||
this._breakpointEventsActive = true;
|
||||
|
||||
// set up a handler to send more
|
||||
this._toDispose.push(this.debugService.getModel().onDidChangeBreakpoints(e => {
|
||||
this._toDispose.add(this.debugService.getModel().onDidChangeBreakpoints(e => {
|
||||
// Ignore session only breakpoint events since they should only reflect in the UI
|
||||
if (e && !e.sessionOnly) {
|
||||
const delta: IBreakpointsDeltaDto = {};
|
||||
@@ -170,7 +169,7 @@ export class MainThreadDebugService implements MainThreadDebugServiceShape, IDeb
|
||||
};
|
||||
}
|
||||
this._debugConfigurationProviders.set(handle, provider);
|
||||
this._toDispose.push(this.debugService.getConfigurationManager().registerDebugConfigurationProvider(provider));
|
||||
this._toDispose.add(this.debugService.getConfigurationManager().registerDebugConfigurationProvider(provider));
|
||||
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
@@ -192,7 +191,7 @@ export class MainThreadDebugService implements MainThreadDebugServiceShape, IDeb
|
||||
}
|
||||
};
|
||||
this._debugAdapterDescriptorFactories.set(handle, provider);
|
||||
this._toDispose.push(this.debugService.getConfigurationManager().registerDebugAdapterDescriptorFactory(provider));
|
||||
this._toDispose.add(this.debugService.getConfigurationManager().registerDebugAdapterDescriptorFactory(provider));
|
||||
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ export class MainThreadDocumentContentProviders implements MainThreadDocumentCon
|
||||
return this._proxy.$provideTextDocumentContent(handle, uri).then(value => {
|
||||
if (typeof value === 'string') {
|
||||
const firstLineText = value.substr(0, 1 + value.search(/\r?\n/));
|
||||
const languageSelection = this._modeService.createByFilepathOrFirstLine(uri.fsPath, firstLineText);
|
||||
const languageSelection = this._modeService.createByFilepathOrFirstLine(uri, firstLineText);
|
||||
return this._modelService.createModel(value, languageSelection, uri);
|
||||
}
|
||||
return null;
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { toErrorMessage } from 'vs/base/common/errorMessage';
|
||||
import { IDisposable, IReference, dispose } from 'vs/base/common/lifecycle';
|
||||
import { IDisposable, IReference, dispose, DisposableStore } from 'vs/base/common/lifecycle';
|
||||
import { Schemas } from 'vs/base/common/network';
|
||||
import { URI, UriComponents } from 'vs/base/common/uri';
|
||||
import { ITextModel } from 'vs/editor/common/model';
|
||||
@@ -73,10 +73,10 @@ export class MainThreadDocuments implements MainThreadDocumentsShape {
|
||||
private readonly _untitledEditorService: IUntitledEditorService;
|
||||
private readonly _environmentService: IWorkbenchEnvironmentService;
|
||||
|
||||
private _toDispose: IDisposable[];
|
||||
private readonly _toDispose = new DisposableStore();
|
||||
private _modelToDisposeMap: { [modelUrl: string]: IDisposable; };
|
||||
private readonly _proxy: ExtHostDocumentsShape;
|
||||
private readonly _modelIsSynced: { [modelId: string]: boolean; };
|
||||
private readonly _modelIsSynced = new Set<string>();
|
||||
private _modelReferenceCollection = new BoundModelReferenceCollection();
|
||||
|
||||
constructor(
|
||||
@@ -98,25 +98,23 @@ export class MainThreadDocuments implements MainThreadDocumentsShape {
|
||||
this._environmentService = environmentService;
|
||||
|
||||
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostDocuments);
|
||||
this._modelIsSynced = {};
|
||||
|
||||
this._toDispose = [];
|
||||
this._toDispose.push(documentsAndEditors.onDocumentAdd(models => models.forEach(this._onModelAdded, this)));
|
||||
this._toDispose.push(documentsAndEditors.onDocumentRemove(urls => urls.forEach(this._onModelRemoved, this)));
|
||||
this._toDispose.push(this._modelReferenceCollection);
|
||||
this._toDispose.push(modelService.onModelModeChanged(this._onModelModeChanged, this));
|
||||
this._toDispose.add(documentsAndEditors.onDocumentAdd(models => models.forEach(this._onModelAdded, this)));
|
||||
this._toDispose.add(documentsAndEditors.onDocumentRemove(urls => urls.forEach(this._onModelRemoved, this)));
|
||||
this._toDispose.add(this._modelReferenceCollection);
|
||||
this._toDispose.add(modelService.onModelModeChanged(this._onModelModeChanged, this));
|
||||
|
||||
this._toDispose.push(textFileService.models.onModelSaved(e => {
|
||||
this._toDispose.add(textFileService.models.onModelSaved(e => {
|
||||
if (this._shouldHandleFileEvent(e)) {
|
||||
this._proxy.$acceptModelSaved(e.resource);
|
||||
}
|
||||
}));
|
||||
this._toDispose.push(textFileService.models.onModelReverted(e => {
|
||||
this._toDispose.add(textFileService.models.onModelReverted(e => {
|
||||
if (this._shouldHandleFileEvent(e)) {
|
||||
this._proxy.$acceptDirtyStateChanged(e.resource, false);
|
||||
}
|
||||
}));
|
||||
this._toDispose.push(textFileService.models.onModelDirty(e => {
|
||||
this._toDispose.add(textFileService.models.onModelDirty(e => {
|
||||
if (this._shouldHandleFileEvent(e)) {
|
||||
this._proxy.$acceptDirtyStateChanged(e.resource, true);
|
||||
}
|
||||
@@ -130,7 +128,7 @@ export class MainThreadDocuments implements MainThreadDocumentsShape {
|
||||
this._modelToDisposeMap[modelUrl].dispose();
|
||||
});
|
||||
this._modelToDisposeMap = Object.create(null);
|
||||
this._toDispose = dispose(this._toDispose);
|
||||
this._toDispose.dispose();
|
||||
}
|
||||
|
||||
private _shouldHandleFileEvent(e: TextFileModelChangeEvent): boolean {
|
||||
@@ -145,7 +143,7 @@ export class MainThreadDocuments implements MainThreadDocumentsShape {
|
||||
return;
|
||||
}
|
||||
const modelUrl = model.uri;
|
||||
this._modelIsSynced[modelUrl.toString()] = true;
|
||||
this._modelIsSynced.add(modelUrl.toString());
|
||||
this._modelToDisposeMap[modelUrl.toString()] = model.onDidChangeContent((e) => {
|
||||
this._proxy.$acceptModelChanged(modelUrl, e, this._textFileService.isDirty(modelUrl));
|
||||
});
|
||||
@@ -154,7 +152,7 @@ export class MainThreadDocuments implements MainThreadDocumentsShape {
|
||||
private _onModelModeChanged(event: { model: ITextModel; oldModeId: string; }): void {
|
||||
let { model, oldModeId } = event;
|
||||
const modelUrl = model.uri;
|
||||
if (!this._modelIsSynced[modelUrl.toString()]) {
|
||||
if (!this._modelIsSynced.has(modelUrl.toString())) {
|
||||
return;
|
||||
}
|
||||
this._proxy.$acceptModelModeChanged(model.uri, oldModeId, model.getLanguageIdentifier().language);
|
||||
@@ -162,10 +160,10 @@ export class MainThreadDocuments implements MainThreadDocumentsShape {
|
||||
|
||||
private _onModelRemoved(modelUrl: URI): void {
|
||||
const strModelUrl = modelUrl.toString();
|
||||
if (!this._modelIsSynced[strModelUrl]) {
|
||||
if (!this._modelIsSynced.has(strModelUrl)) {
|
||||
return;
|
||||
}
|
||||
delete this._modelIsSynced[strModelUrl];
|
||||
this._modelIsSynced.delete(strModelUrl);
|
||||
this._modelToDisposeMap[strModelUrl].dispose();
|
||||
delete this._modelToDisposeMap[strModelUrl];
|
||||
}
|
||||
@@ -196,7 +194,7 @@ export class MainThreadDocuments implements MainThreadDocumentsShape {
|
||||
return promise.then(success => {
|
||||
if (!success) {
|
||||
return Promise.reject(new Error('cannot open ' + uri.toString()));
|
||||
} else if (!this._modelIsSynced[uri.toString()]) {
|
||||
} else if (!this._modelIsSynced.has(uri.toString())) {
|
||||
return Promise.reject(new Error('cannot open ' + uri.toString() + '. Detail: Files above 50MB cannot be synchronized with extensions.'));
|
||||
} else {
|
||||
return undefined;
|
||||
@@ -237,7 +235,7 @@ export class MainThreadDocuments implements MainThreadDocumentsShape {
|
||||
}).then(model => {
|
||||
const resource = model.getResource();
|
||||
|
||||
if (!this._modelIsSynced[resource.toString()]) {
|
||||
if (!this._modelIsSynced.has(resource.toString())) {
|
||||
throw new Error(`expected URI ${resource.toString()} to have come to LIFE`);
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { Emitter, Event } from 'vs/base/common/event';
|
||||
import { IDisposable, combinedDisposable, dispose } from 'vs/base/common/lifecycle';
|
||||
import { IDisposable, combinedDisposable, DisposableStore } from 'vs/base/common/lifecycle';
|
||||
import { values } from 'vs/base/common/map';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { ICodeEditor, isCodeEditor, isDiffEditor, IActiveCodeEditor } from 'vs/editor/browser/editorBrowser';
|
||||
@@ -144,7 +144,7 @@ const enum ActiveEditorOrder {
|
||||
|
||||
class MainThreadDocumentAndEditorStateComputer {
|
||||
|
||||
private _toDispose: IDisposable[] = [];
|
||||
private readonly _toDispose = new DisposableStore();
|
||||
private _toDisposeOnEditorRemove = new Map<string, IDisposable>();
|
||||
private _currentState: DocumentAndEditorState;
|
||||
private _activeEditorOrder: ActiveEditorOrder = ActiveEditorOrder.Editor;
|
||||
@@ -172,15 +172,15 @@ class MainThreadDocumentAndEditorStateComputer {
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
this._toDispose = dispose(this._toDispose);
|
||||
this._toDispose.dispose();
|
||||
}
|
||||
|
||||
private _onDidAddEditor(e: ICodeEditor): void {
|
||||
this._toDisposeOnEditorRemove.set(e.getId(), combinedDisposable([
|
||||
this._toDisposeOnEditorRemove.set(e.getId(), combinedDisposable(
|
||||
e.onDidChangeModel(() => this._updateState()),
|
||||
e.onDidFocusEditorText(() => this._updateState()),
|
||||
e.onDidFocusEditorWidget(() => this._updateState(e))
|
||||
]));
|
||||
));
|
||||
this._updateState();
|
||||
}
|
||||
|
||||
@@ -304,10 +304,9 @@ class MainThreadDocumentAndEditorStateComputer {
|
||||
@extHostCustomer
|
||||
export class MainThreadDocumentsAndEditors {
|
||||
|
||||
private _toDispose: IDisposable[];
|
||||
private readonly _toDispose = new DisposableStore();
|
||||
private readonly _proxy: ExtHostDocumentsAndEditorsShape;
|
||||
private readonly _stateComputer: MainThreadDocumentAndEditorStateComputer;
|
||||
private _textEditors = <{ [id: string]: MainThreadTextEditor }>Object.create(null);
|
||||
private readonly _textEditors = new Map<string, MainThreadTextEditor>();
|
||||
|
||||
private _onTextEditorAdd = new Emitter<MainThreadTextEditor[]>();
|
||||
private _onTextEditorRemove = new Emitter<string[]>();
|
||||
@@ -336,28 +335,23 @@ export class MainThreadDocumentsAndEditors {
|
||||
) {
|
||||
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostDocumentsAndEditors);
|
||||
|
||||
const mainThreadDocuments = new MainThreadDocuments(this, extHostContext, this._modelService, modeService, this._textFileService, fileService, textModelResolverService, untitledEditorService, environmentService);
|
||||
const mainThreadDocuments = this._toDispose.add(new MainThreadDocuments(this, extHostContext, this._modelService, modeService, this._textFileService, fileService, textModelResolverService, untitledEditorService, environmentService));
|
||||
extHostContext.set(MainContext.MainThreadDocuments, mainThreadDocuments);
|
||||
|
||||
const mainThreadTextEditors = new MainThreadTextEditors(this, extHostContext, codeEditorService, bulkEditService, this._editorService, this._editorGroupService);
|
||||
const mainThreadTextEditors = this._toDispose.add(new MainThreadTextEditors(this, extHostContext, codeEditorService, bulkEditService, this._editorService, this._editorGroupService));
|
||||
extHostContext.set(MainContext.MainThreadTextEditors, mainThreadTextEditors);
|
||||
|
||||
// It is expected that the ctor of the state computer calls our `_onDelta`.
|
||||
this._stateComputer = new MainThreadDocumentAndEditorStateComputer(delta => this._onDelta(delta), _modelService, codeEditorService, this._editorService, panelService);
|
||||
this._toDispose.add(new MainThreadDocumentAndEditorStateComputer(delta => this._onDelta(delta), _modelService, codeEditorService, this._editorService, panelService));
|
||||
|
||||
this._toDispose = [
|
||||
mainThreadDocuments,
|
||||
mainThreadTextEditors,
|
||||
this._stateComputer,
|
||||
this._onTextEditorAdd,
|
||||
this._onTextEditorRemove,
|
||||
this._onDocumentAdd,
|
||||
this._onDocumentRemove,
|
||||
];
|
||||
this._toDispose.add(this._onTextEditorAdd);
|
||||
this._toDispose.add(this._onTextEditorRemove);
|
||||
this._toDispose.add(this._onDocumentAdd);
|
||||
this._toDispose.add(this._onDocumentRemove);
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
this._toDispose = dispose(this._toDispose);
|
||||
this._toDispose.dispose();
|
||||
}
|
||||
|
||||
private _onDelta(delta: DocumentAndEditorStateDelta): void {
|
||||
@@ -374,16 +368,16 @@ export class MainThreadDocumentsAndEditors {
|
||||
const mainThreadEditor = new MainThreadTextEditor(apiEditor.id, apiEditor.editor.getModel(),
|
||||
apiEditor.editor, { onGainedFocus() { }, onLostFocus() { } }, this._modelService);
|
||||
|
||||
this._textEditors[apiEditor.id] = mainThreadEditor;
|
||||
this._textEditors.set(apiEditor.id, mainThreadEditor);
|
||||
addedEditors.push(mainThreadEditor);
|
||||
}
|
||||
|
||||
// removed editors
|
||||
for (const { id } of delta.removedEditors) {
|
||||
const mainThreadEditor = this._textEditors[id];
|
||||
const mainThreadEditor = this._textEditors.get(id);
|
||||
if (mainThreadEditor) {
|
||||
mainThreadEditor.dispose();
|
||||
delete this._textEditors[id];
|
||||
this._textEditors.delete(id);
|
||||
removedEditors.push(id);
|
||||
}
|
||||
}
|
||||
@@ -454,16 +448,16 @@ export class MainThreadDocumentsAndEditors {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
findTextEditorIdFor(editor: IWorkbenchEditor): string | undefined {
|
||||
for (const id in this._textEditors) {
|
||||
if (this._textEditors[id].matches(editor)) {
|
||||
findTextEditorIdFor(inputEditor: IWorkbenchEditor): string | undefined {
|
||||
for (const [id, editor] of this._textEditors) {
|
||||
if (editor.matches(inputEditor)) {
|
||||
return id;
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
getEditor(id: string): MainThreadTextEditor {
|
||||
return this._textEditors[id];
|
||||
getEditor(id: string): MainThreadTextEditor | undefined {
|
||||
return this._textEditors.get(id);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { Emitter, Event } from 'vs/base/common/event';
|
||||
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
|
||||
import { DisposableStore } from 'vs/base/common/lifecycle';
|
||||
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
|
||||
import { RenderLineNumbersType, TextEditorCursorStyle, cursorStyleToString } from 'vs/editor/common/config/editorOptions';
|
||||
import { IRange, Range } from 'vs/editor/common/core/range';
|
||||
@@ -173,10 +173,10 @@ export class MainThreadTextEditor {
|
||||
private readonly _id: string;
|
||||
private _model: ITextModel;
|
||||
private readonly _modelService: IModelService;
|
||||
private _modelListeners: IDisposable[];
|
||||
private readonly _modelListeners = new DisposableStore();
|
||||
private _codeEditor: ICodeEditor | null;
|
||||
private readonly _focusTracker: IFocusTracker;
|
||||
private _codeEditorListeners: IDisposable[];
|
||||
private readonly _codeEditorListeners = new DisposableStore();
|
||||
|
||||
private _properties: MainThreadTextEditorProperties;
|
||||
private readonly _onPropertiesChanged: Emitter<IEditorPropertiesChangeData>;
|
||||
@@ -193,12 +193,10 @@ export class MainThreadTextEditor {
|
||||
this._codeEditor = null;
|
||||
this._focusTracker = focusTracker;
|
||||
this._modelService = modelService;
|
||||
this._codeEditorListeners = [];
|
||||
|
||||
this._onPropertiesChanged = new Emitter<IEditorPropertiesChangeData>();
|
||||
|
||||
this._modelListeners = [];
|
||||
this._modelListeners.push(this._model.onDidChangeOptions((e) => {
|
||||
this._modelListeners.add(this._model.onDidChangeOptions((e) => {
|
||||
this._updatePropertiesNow(null);
|
||||
}));
|
||||
|
||||
@@ -208,9 +206,9 @@ export class MainThreadTextEditor {
|
||||
|
||||
public dispose(): void {
|
||||
this._model = null!;
|
||||
this._modelListeners = dispose(this._modelListeners);
|
||||
this._modelListeners.dispose();
|
||||
this._codeEditor = null;
|
||||
this._codeEditorListeners = dispose(this._codeEditorListeners);
|
||||
this._codeEditorListeners.dispose();
|
||||
}
|
||||
|
||||
private _updatePropertiesNow(selectionChangeSource: string | null): void {
|
||||
@@ -249,36 +247,36 @@ export class MainThreadTextEditor {
|
||||
// Nothing to do...
|
||||
return;
|
||||
}
|
||||
this._codeEditorListeners = dispose(this._codeEditorListeners);
|
||||
this._codeEditorListeners.clear();
|
||||
|
||||
this._codeEditor = codeEditor;
|
||||
if (this._codeEditor) {
|
||||
|
||||
// Catch early the case that this code editor gets a different model set and disassociate from this model
|
||||
this._codeEditorListeners.push(this._codeEditor.onDidChangeModel(() => {
|
||||
this._codeEditorListeners.add(this._codeEditor.onDidChangeModel(() => {
|
||||
this.setCodeEditor(null);
|
||||
}));
|
||||
|
||||
this._codeEditorListeners.push(this._codeEditor.onDidFocusEditorWidget(() => {
|
||||
this._codeEditorListeners.add(this._codeEditor.onDidFocusEditorWidget(() => {
|
||||
this._focusTracker.onGainedFocus();
|
||||
}));
|
||||
this._codeEditorListeners.push(this._codeEditor.onDidBlurEditorWidget(() => {
|
||||
this._codeEditorListeners.add(this._codeEditor.onDidBlurEditorWidget(() => {
|
||||
this._focusTracker.onLostFocus();
|
||||
}));
|
||||
|
||||
this._codeEditorListeners.push(this._codeEditor.onDidChangeCursorSelection((e) => {
|
||||
this._codeEditorListeners.add(this._codeEditor.onDidChangeCursorSelection((e) => {
|
||||
// selection
|
||||
this._updatePropertiesNow(e.source);
|
||||
}));
|
||||
this._codeEditorListeners.push(this._codeEditor.onDidChangeConfiguration(() => {
|
||||
this._codeEditorListeners.add(this._codeEditor.onDidChangeConfiguration(() => {
|
||||
// options
|
||||
this._updatePropertiesNow(null);
|
||||
}));
|
||||
this._codeEditorListeners.push(this._codeEditor.onDidLayoutChange(() => {
|
||||
this._codeEditorListeners.add(this._codeEditor.onDidLayoutChange(() => {
|
||||
// visibleRanges
|
||||
this._updatePropertiesNow(null);
|
||||
}));
|
||||
this._codeEditorListeners.push(this._codeEditor.onDidScrollChange(() => {
|
||||
this._codeEditorListeners.add(this._codeEditor.onDidScrollChange(() => {
|
||||
// visibleRanges
|
||||
this._updatePropertiesNow(null);
|
||||
}));
|
||||
@@ -469,7 +467,7 @@ export class MainThreadTextEditor {
|
||||
return true;
|
||||
}
|
||||
|
||||
insertSnippet(template: string, ranges: IRange[], opts: IUndoStopOptions) {
|
||||
insertSnippet(template: string, ranges: readonly IRange[], opts: IUndoStopOptions) {
|
||||
|
||||
if (!this._codeEditor) {
|
||||
return false;
|
||||
@@ -486,7 +484,7 @@ export class MainThreadTextEditor {
|
||||
this._codeEditor.focus();
|
||||
|
||||
// make modifications
|
||||
snippetController.insert(template, 0, 0, opts.undoStopBefore, opts.undoStopAfter);
|
||||
snippetController.insert(template, { overwriteBefore: 0, overwriteAfter: 0, undoStopBefore: opts.undoStopBefore, undoStopAfter: opts.undoStopAfter });
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
import { localize } from 'vs/nls';
|
||||
import { disposed } from 'vs/base/common/errors';
|
||||
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
|
||||
import { IDisposable, dispose, DisposableStore } from 'vs/base/common/lifecycle';
|
||||
import { equals as objectEquals } from 'vs/base/common/objects';
|
||||
import { URI, UriComponents } from 'vs/base/common/uri';
|
||||
import { IBulkEditService } from 'vs/editor/browser/services/bulkEditService';
|
||||
@@ -15,7 +15,7 @@ import { ISelection } from 'vs/editor/common/core/selection';
|
||||
import { IDecorationOptions, IDecorationRenderOptions, ILineChange } from 'vs/editor/common/editorCommon';
|
||||
import { ISingleEditOperation } from 'vs/editor/common/model';
|
||||
import { CommandsRegistry } from 'vs/platform/commands/common/commands';
|
||||
import { IEditorOptions, ITextEditorOptions } from 'vs/platform/editor/common/editor';
|
||||
import { IEditorOptions, ITextEditorOptions, IResourceInput } from 'vs/platform/editor/common/editor';
|
||||
import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IOpenerService } from 'vs/platform/opener/common/opener';
|
||||
import { MainThreadDocumentsAndEditors } from 'vs/workbench/api/browser/mainThreadDocumentsAndEditors';
|
||||
@@ -32,7 +32,7 @@ export class MainThreadTextEditors implements MainThreadTextEditorsShape {
|
||||
private readonly _instanceId: string;
|
||||
private readonly _proxy: ExtHostEditorsShape;
|
||||
private readonly _documentsAndEditors: MainThreadDocumentsAndEditors;
|
||||
private _toDispose: IDisposable[];
|
||||
private readonly _toDispose = new DisposableStore();
|
||||
private _textEditorsListenersMap: { [editorId: string]: IDisposable[]; };
|
||||
private _editorPositionData: ITextEditorPositionData | null;
|
||||
private _registeredDecorationTypes: { [decorationType: string]: boolean; };
|
||||
@@ -48,16 +48,16 @@ export class MainThreadTextEditors implements MainThreadTextEditorsShape {
|
||||
this._instanceId = String(++MainThreadTextEditors.INSTANCE_COUNT);
|
||||
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostEditors);
|
||||
this._documentsAndEditors = documentsAndEditors;
|
||||
this._toDispose = [];
|
||||
|
||||
this._textEditorsListenersMap = Object.create(null);
|
||||
this._editorPositionData = null;
|
||||
|
||||
this._toDispose.push(documentsAndEditors.onTextEditorAdd(editors => editors.forEach(this._onTextEditorAdd, this)));
|
||||
this._toDispose.push(documentsAndEditors.onTextEditorRemove(editors => editors.forEach(this._onTextEditorRemove, this)));
|
||||
this._toDispose.add(documentsAndEditors.onTextEditorAdd(editors => editors.forEach(this._onTextEditorAdd, this)));
|
||||
this._toDispose.add(documentsAndEditors.onTextEditorRemove(editors => editors.forEach(this._onTextEditorRemove, this)));
|
||||
|
||||
this._toDispose.push(this._editorService.onDidVisibleEditorsChange(() => this._updateActiveAndVisibleTextEditors()));
|
||||
this._toDispose.push(this._editorGroupService.onDidRemoveGroup(() => this._updateActiveAndVisibleTextEditors()));
|
||||
this._toDispose.push(this._editorGroupService.onDidMoveGroup(() => this._updateActiveAndVisibleTextEditors()));
|
||||
this._toDispose.add(this._editorService.onDidVisibleEditorsChange(() => this._updateActiveAndVisibleTextEditors()));
|
||||
this._toDispose.add(this._editorGroupService.onDidRemoveGroup(() => this._updateActiveAndVisibleTextEditors()));
|
||||
this._toDispose.add(this._editorGroupService.onDidMoveGroup(() => this._updateActiveAndVisibleTextEditors()));
|
||||
|
||||
this._registeredDecorationTypes = Object.create(null);
|
||||
}
|
||||
@@ -67,7 +67,7 @@ export class MainThreadTextEditors implements MainThreadTextEditorsShape {
|
||||
dispose(this._textEditorsListenersMap[editorId]);
|
||||
});
|
||||
this._textEditorsListenersMap = Object.create(null);
|
||||
this._toDispose = dispose(this._toDispose);
|
||||
this._toDispose.dispose();
|
||||
for (let decorationType in this._registeredDecorationTypes) {
|
||||
this._codeEditorService.removeDecorationType(decorationType);
|
||||
}
|
||||
@@ -112,7 +112,7 @@ export class MainThreadTextEditors implements MainThreadTextEditorsShape {
|
||||
|
||||
// --- from extension host process
|
||||
|
||||
$tryShowTextDocument(resource: UriComponents, options: ITextDocumentShowOptions): Promise<string | undefined> {
|
||||
async $tryShowTextDocument(resource: UriComponents, options: ITextDocumentShowOptions): Promise<string | undefined> {
|
||||
const uri = URI.revive(resource);
|
||||
|
||||
const editorOptions: ITextEditorOptions = {
|
||||
@@ -121,91 +121,95 @@ export class MainThreadTextEditors implements MainThreadTextEditorsShape {
|
||||
selection: options.selection
|
||||
};
|
||||
|
||||
const input = {
|
||||
const input: IResourceInput = {
|
||||
resource: uri,
|
||||
options: editorOptions
|
||||
};
|
||||
|
||||
return this._editorService.openEditor(input, viewColumnToEditorGroup(this._editorGroupService, options.position)).then(editor => {
|
||||
if (!editor) {
|
||||
return undefined;
|
||||
}
|
||||
return this._documentsAndEditors.findTextEditorIdFor(editor);
|
||||
});
|
||||
const editor = await this._editorService.openEditor(input, viewColumnToEditorGroup(this._editorGroupService, options.position));
|
||||
if (!editor) {
|
||||
return undefined;
|
||||
}
|
||||
return this._documentsAndEditors.findTextEditorIdFor(editor);
|
||||
}
|
||||
|
||||
$tryShowEditor(id: string, position?: EditorViewColumn): Promise<void> {
|
||||
async $tryShowEditor(id: string, position?: EditorViewColumn): Promise<void> {
|
||||
const mainThreadEditor = this._documentsAndEditors.getEditor(id);
|
||||
if (mainThreadEditor) {
|
||||
const model = mainThreadEditor.getModel();
|
||||
return this._editorService.openEditor({
|
||||
await this._editorService.openEditor({
|
||||
resource: model.uri,
|
||||
options: { preserveFocus: false }
|
||||
}, viewColumnToEditorGroup(this._editorGroupService, position)).then(() => { return; });
|
||||
}, viewColumnToEditorGroup(this._editorGroupService, position));
|
||||
return;
|
||||
}
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
$tryHideEditor(id: string): Promise<void> {
|
||||
async $tryHideEditor(id: string): Promise<void> {
|
||||
const mainThreadEditor = this._documentsAndEditors.getEditor(id);
|
||||
if (mainThreadEditor) {
|
||||
const editors = this._editorService.visibleControls;
|
||||
for (let editor of editors) {
|
||||
if (mainThreadEditor.matches(editor)) {
|
||||
return editor.group.closeEditor(editor.input).then(() => { return; });
|
||||
return editor.group.closeEditor(editor.input);
|
||||
}
|
||||
}
|
||||
}
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
$trySetSelections(id: string, selections: ISelection[]): Promise<void> {
|
||||
if (!this._documentsAndEditors.getEditor(id)) {
|
||||
const editor = this._documentsAndEditors.getEditor(id);
|
||||
if (!editor) {
|
||||
return Promise.reject(disposed(`TextEditor(${id})`));
|
||||
}
|
||||
this._documentsAndEditors.getEditor(id).setSelections(selections);
|
||||
editor.setSelections(selections);
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
|
||||
$trySetDecorations(id: string, key: string, ranges: IDecorationOptions[]): Promise<void> {
|
||||
key = `${this._instanceId}-${key}`;
|
||||
if (!this._documentsAndEditors.getEditor(id)) {
|
||||
const editor = this._documentsAndEditors.getEditor(id);
|
||||
if (!editor) {
|
||||
return Promise.reject(disposed(`TextEditor(${id})`));
|
||||
}
|
||||
this._documentsAndEditors.getEditor(id).setDecorations(key, ranges);
|
||||
editor.setDecorations(key, ranges);
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
|
||||
$trySetDecorationsFast(id: string, key: string, ranges: number[]): Promise<void> {
|
||||
key = `${this._instanceId}-${key}`;
|
||||
if (!this._documentsAndEditors.getEditor(id)) {
|
||||
const editor = this._documentsAndEditors.getEditor(id);
|
||||
if (!editor) {
|
||||
return Promise.reject(disposed(`TextEditor(${id})`));
|
||||
}
|
||||
this._documentsAndEditors.getEditor(id).setDecorationsFast(key, ranges);
|
||||
editor.setDecorationsFast(key, ranges);
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
|
||||
$tryRevealRange(id: string, range: IRange, revealType: TextEditorRevealType): Promise<void> {
|
||||
if (!this._documentsAndEditors.getEditor(id)) {
|
||||
const editor = this._documentsAndEditors.getEditor(id);
|
||||
if (!editor) {
|
||||
return Promise.reject(disposed(`TextEditor(${id})`));
|
||||
}
|
||||
this._documentsAndEditors.getEditor(id).revealRange(range, revealType);
|
||||
editor.revealRange(range, revealType);
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
$trySetOptions(id: string, options: ITextEditorConfigurationUpdate): Promise<void> {
|
||||
if (!this._documentsAndEditors.getEditor(id)) {
|
||||
const editor = this._documentsAndEditors.getEditor(id);
|
||||
if (!editor) {
|
||||
return Promise.reject(disposed(`TextEditor(${id})`));
|
||||
}
|
||||
this._documentsAndEditors.getEditor(id).setConfiguration(options);
|
||||
editor.setConfiguration(options);
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
|
||||
$tryApplyEdits(id: string, modelVersionId: number, edits: ISingleEditOperation[], opts: IApplyEditsOptions): Promise<boolean> {
|
||||
if (!this._documentsAndEditors.getEditor(id)) {
|
||||
const editor = this._documentsAndEditors.getEditor(id);
|
||||
if (!editor) {
|
||||
return Promise.reject(disposed(`TextEditor(${id})`));
|
||||
}
|
||||
return Promise.resolve(this._documentsAndEditors.getEditor(id).applyEdits(modelVersionId, edits, opts));
|
||||
return Promise.resolve(editor.applyEdits(modelVersionId, edits, opts));
|
||||
}
|
||||
|
||||
$tryApplyWorkspaceEdit(dto: WorkspaceEditDto): Promise<boolean> {
|
||||
@@ -213,11 +217,12 @@ export class MainThreadTextEditors implements MainThreadTextEditorsShape {
|
||||
return this._bulkEditService.apply({ edits }, undefined).then(() => true, err => false);
|
||||
}
|
||||
|
||||
$tryInsertSnippet(id: string, template: string, ranges: IRange[], opts: IUndoStopOptions): Promise<boolean> {
|
||||
if (!this._documentsAndEditors.getEditor(id)) {
|
||||
$tryInsertSnippet(id: string, template: string, ranges: readonly IRange[], opts: IUndoStopOptions): Promise<boolean> {
|
||||
const editor = this._documentsAndEditors.getEditor(id);
|
||||
if (!editor) {
|
||||
return Promise.reject(disposed(`TextEditor(${id})`));
|
||||
}
|
||||
return Promise.resolve(this._documentsAndEditors.getEditor(id).insertSnippet(template, ranges, opts));
|
||||
return Promise.resolve(editor.insertSnippet(template, ranges, opts));
|
||||
}
|
||||
|
||||
$registerTextEditorDecorationType(key: string, options: IDecorationRenderOptions): void {
|
||||
|
||||
@@ -5,11 +5,10 @@
|
||||
|
||||
import { Emitter, Event } from 'vs/base/common/event';
|
||||
import { IDisposable, dispose, toDisposable } from 'vs/base/common/lifecycle';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { FileWriteOptions, FileSystemProviderCapabilities, IFileChange, IFileService, IFileSystemProvider, IStat, IWatchOptions, FileType, FileOverwriteOptions, FileDeleteOptions, FileOpenOptions } from 'vs/platform/files/common/files';
|
||||
import { URI, UriComponents } from 'vs/base/common/uri';
|
||||
import { FileWriteOptions, FileSystemProviderCapabilities, IFileChange, IFileService, IFileSystemProvider, IStat, IWatchOptions, FileType, FileOverwriteOptions, FileDeleteOptions, FileOpenOptions, IFileStat, FileOperationError, FileOperationResult, FileSystemProviderErrorCode } from 'vs/platform/files/common/files';
|
||||
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
|
||||
import { ExtHostContext, ExtHostFileSystemShape, IExtHostContext, IFileChangeDto, MainContext, MainThreadFileSystemShape } from '../common/extHost.protocol';
|
||||
import { ResourceLabelFormatter, ILabelService } from 'vs/platform/label/common/label';
|
||||
import { VSBuffer } from 'vs/base/common/buffer';
|
||||
|
||||
@extHostNamedCustomer(MainContext.MainThreadFileSystem)
|
||||
@@ -17,12 +16,10 @@ export class MainThreadFileSystem implements MainThreadFileSystemShape {
|
||||
|
||||
private readonly _proxy: ExtHostFileSystemShape;
|
||||
private readonly _fileProvider = new Map<number, RemoteFileSystemProvider>();
|
||||
private readonly _resourceLabelFormatters = new Map<number, IDisposable>();
|
||||
|
||||
constructor(
|
||||
extHostContext: IExtHostContext,
|
||||
@IFileService private readonly _fileService: IFileService,
|
||||
@ILabelService private readonly _labelService: ILabelService
|
||||
) {
|
||||
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostFileSystem);
|
||||
}
|
||||
@@ -41,18 +38,6 @@ export class MainThreadFileSystem implements MainThreadFileSystemShape {
|
||||
this._fileProvider.delete(handle);
|
||||
}
|
||||
|
||||
$registerResourceLabelFormatter(handle: number, formatter: ResourceLabelFormatter): void {
|
||||
// Dynamicily registered formatters should have priority over those contributed via package.json
|
||||
formatter.priority = true;
|
||||
const disposable = this._labelService.registerFormatter(formatter);
|
||||
this._resourceLabelFormatters.set(handle, disposable);
|
||||
}
|
||||
|
||||
$unregisterResourceLabelFormatter(handle: number): void {
|
||||
dispose(this._resourceLabelFormatters.get(handle));
|
||||
this._resourceLabelFormatters.delete(handle);
|
||||
}
|
||||
|
||||
$onFileSystemChange(handle: number, changes: IFileChangeDto[]): void {
|
||||
const fileProvider = this._fileProvider.get(handle);
|
||||
if (!fileProvider) {
|
||||
@@ -60,6 +45,80 @@ export class MainThreadFileSystem implements MainThreadFileSystemShape {
|
||||
}
|
||||
fileProvider.$onFileSystemChange(changes);
|
||||
}
|
||||
|
||||
|
||||
// --- consumer fs, vscode.workspace.fs
|
||||
|
||||
$stat(uri: UriComponents): Promise<IStat> {
|
||||
return this._fileService.resolve(URI.revive(uri), { resolveMetadata: true }).then(stat => {
|
||||
return {
|
||||
ctime: 0,
|
||||
mtime: stat.mtime,
|
||||
size: stat.size,
|
||||
type: MainThreadFileSystem._getFileType(stat)
|
||||
};
|
||||
}).catch(MainThreadFileSystem._handleError);
|
||||
}
|
||||
|
||||
$readdir(uri: UriComponents): Promise<[string, FileType][]> {
|
||||
return this._fileService.resolve(URI.revive(uri), { resolveMetadata: false }).then(stat => {
|
||||
if (!stat.isDirectory) {
|
||||
const err = new Error(stat.name);
|
||||
err.name = FileSystemProviderErrorCode.FileNotADirectory;
|
||||
throw err;
|
||||
}
|
||||
return !stat.children ? [] : stat.children.map(child => [child.name, MainThreadFileSystem._getFileType(child)]);
|
||||
}).catch(MainThreadFileSystem._handleError);
|
||||
}
|
||||
|
||||
private static _getFileType(stat: IFileStat): FileType {
|
||||
return (stat.isDirectory ? FileType.Directory : FileType.File) + (stat.isSymbolicLink ? FileType.SymbolicLink : 0);
|
||||
}
|
||||
|
||||
$readFile(uri: UriComponents): Promise<VSBuffer> {
|
||||
return this._fileService.readFile(URI.revive(uri)).then(file => file.value).catch(MainThreadFileSystem._handleError);
|
||||
}
|
||||
|
||||
$writeFile(uri: UriComponents, content: VSBuffer): Promise<void> {
|
||||
return this._fileService.writeFile(URI.revive(uri), content).catch(MainThreadFileSystem._handleError);
|
||||
}
|
||||
|
||||
$rename(source: UriComponents, target: UriComponents, opts: FileOverwriteOptions): Promise<void> {
|
||||
return this._fileService.move(URI.revive(source), URI.revive(target), opts.overwrite).catch(MainThreadFileSystem._handleError);
|
||||
}
|
||||
|
||||
$copy(source: UriComponents, target: UriComponents, opts: FileOverwriteOptions): Promise<void> {
|
||||
return this._fileService.copy(URI.revive(source), URI.revive(target), opts.overwrite).catch(MainThreadFileSystem._handleError);
|
||||
}
|
||||
|
||||
$mkdir(uri: UriComponents): Promise<void> {
|
||||
return this._fileService.createFolder(URI.revive(uri)).catch(MainThreadFileSystem._handleError);
|
||||
}
|
||||
|
||||
$delete(uri: UriComponents, opts: FileDeleteOptions): Promise<void> {
|
||||
return this._fileService.del(URI.revive(uri), opts).catch(MainThreadFileSystem._handleError);
|
||||
}
|
||||
|
||||
private static _handleError(err: any): never {
|
||||
if (err instanceof FileOperationError) {
|
||||
switch (err.fileOperationResult) {
|
||||
case FileOperationResult.FILE_NOT_FOUND:
|
||||
err.name = FileSystemProviderErrorCode.FileNotFound;
|
||||
break;
|
||||
case FileOperationResult.FILE_IS_DIRECTORY:
|
||||
err.name = FileSystemProviderErrorCode.FileIsADirectory;
|
||||
break;
|
||||
case FileOperationResult.FILE_PERMISSION_DENIED:
|
||||
err.name = FileSystemProviderErrorCode.NoPermissions;
|
||||
break;
|
||||
case FileOperationResult.FILE_MOVE_CONFLICT:
|
||||
err.name = FileSystemProviderErrorCode.FileExists;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
class RemoteFileSystemProvider implements IFileSystemProvider {
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { ExtHostContext, IExtHostContext } from '../common/extHost.protocol';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { extHostCustomer } from 'vs/workbench/api/common/extHostCustomers';
|
||||
import { IHeapService } from 'vs/workbench/services/heap/common/heap';
|
||||
|
||||
@extHostCustomer
|
||||
export class MainThreadHeapService extends Disposable {
|
||||
|
||||
constructor(
|
||||
extHostContext: IExtHostContext,
|
||||
@IHeapService heapService: IHeapService,
|
||||
) {
|
||||
super();
|
||||
const proxy = extHostContext.getProxy(ExtHostContext.ExtHostHeapService);
|
||||
this._register(heapService.onGarbageCollection((ids) => {
|
||||
// send to ext host
|
||||
proxy.$onGarbageCollection(ids);
|
||||
}));
|
||||
}
|
||||
}
|
||||
@@ -5,27 +5,19 @@
|
||||
|
||||
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
|
||||
import { MainContext, MainThreadKeytarShape, IExtHostContext } from 'vs/workbench/api/common/extHost.protocol';
|
||||
|
||||
interface IKeytarModule {
|
||||
getPassword(service: string, account: string): Promise<string | null>;
|
||||
setPassword(service: string, account: string, password: string): Promise<void>;
|
||||
deletePassword(service: string, account: string): Promise<boolean>;
|
||||
findPassword(service: string): Promise<string | null>;
|
||||
}
|
||||
import { ICredentialsService } from 'vs/platform/credentials/common/credentials';
|
||||
import { optional } from 'vs/platform/instantiation/common/instantiation';
|
||||
|
||||
@extHostNamedCustomer(MainContext.MainThreadKeytar)
|
||||
export class MainThreadKeytar implements MainThreadKeytarShape {
|
||||
|
||||
private _keytar: IKeytarModule | null;
|
||||
private readonly _credentialsService?: ICredentialsService;
|
||||
|
||||
constructor(
|
||||
extHostContext: IExtHostContext
|
||||
_extHostContext: IExtHostContext,
|
||||
@optional(ICredentialsService) credentialsService: ICredentialsService,
|
||||
) {
|
||||
try {
|
||||
this._keytar = <IKeytarModule>require.__$__nodeRequire('keytar');
|
||||
} catch (e) {
|
||||
this._keytar = null;
|
||||
}
|
||||
this._credentialsService = credentialsService;
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
@@ -33,28 +25,28 @@ export class MainThreadKeytar implements MainThreadKeytarShape {
|
||||
}
|
||||
|
||||
async $getPassword(service: string, account: string): Promise<string | null> {
|
||||
if (this._keytar) {
|
||||
return this._keytar.getPassword(service, account);
|
||||
if (this._credentialsService) {
|
||||
return this._credentialsService.getPassword(service, account);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
async $setPassword(service: string, account: string, password: string): Promise<void> {
|
||||
if (this._keytar) {
|
||||
return this._keytar.setPassword(service, account, password);
|
||||
if (this._credentialsService) {
|
||||
return this._credentialsService.setPassword(service, account, password);
|
||||
}
|
||||
}
|
||||
|
||||
async $deletePassword(service: string, account: string): Promise<boolean> {
|
||||
if (this._keytar) {
|
||||
return this._keytar.deletePassword(service, account);
|
||||
if (this._credentialsService) {
|
||||
return this._credentialsService.deletePassword(service, account);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
async $findPassword(service: string): Promise<string | null> {
|
||||
if (this._keytar) {
|
||||
return this._keytar.findPassword(service);
|
||||
if (this._credentialsService) {
|
||||
return this._credentialsService.findPassword(service);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
36
src/vs/workbench/api/browser/mainThreadLabelService.ts
Normal file
36
src/vs/workbench/api/browser/mainThreadLabelService.ts
Normal file
@@ -0,0 +1,36 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { MainContext, MainThreadLabelServiceShape, IExtHostContext } from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
|
||||
import { ResourceLabelFormatter, ILabelService } from 'vs/platform/label/common/label';
|
||||
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
|
||||
|
||||
@extHostNamedCustomer(MainContext.MainThreadLabelService)
|
||||
export class MainThreadLabelService implements MainThreadLabelServiceShape {
|
||||
|
||||
private readonly _resourceLabelFormatters = new Map<number, IDisposable>();
|
||||
|
||||
constructor(
|
||||
_: IExtHostContext,
|
||||
@ILabelService private readonly _labelService: ILabelService
|
||||
) { }
|
||||
|
||||
$registerResourceLabelFormatter(handle: number, formatter: ResourceLabelFormatter): void {
|
||||
// Dynamicily registered formatters should have priority over those contributed via package.json
|
||||
formatter.priority = true;
|
||||
const disposable = this._labelService.registerFormatter(formatter);
|
||||
this._resourceLabelFormatters.set(handle, disposable);
|
||||
}
|
||||
|
||||
$unregisterResourceLabelFormatter(handle: number): void {
|
||||
dispose(this._resourceLabelFormatters.get(handle));
|
||||
this._resourceLabelFormatters.delete(handle);
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
// noop
|
||||
}
|
||||
}
|
||||
@@ -11,48 +11,44 @@ import * as search from 'vs/workbench/contrib/search/common/search';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { Position as EditorPosition } from 'vs/editor/common/core/position';
|
||||
import { Range as EditorRange, IRange } from 'vs/editor/common/core/range';
|
||||
import { ExtHostContext, MainThreadLanguageFeaturesShape, ExtHostLanguageFeaturesShape, MainContext, IExtHostContext, ISerializedLanguageConfiguration, ISerializedRegExp, ISerializedIndentationRule, ISerializedOnEnterRule, LocationDto, WorkspaceSymbolDto, CodeActionDto, reviveWorkspaceEditDto, ISerializedDocumentFilter, DefinitionLinkDto, ISerializedSignatureHelpProviderMetadata, CodeInsetDto, LinkDto, CallHierarchyDto, SuggestDataDto } from '../common/extHost.protocol';
|
||||
import { ExtHostContext, MainThreadLanguageFeaturesShape, ExtHostLanguageFeaturesShape, MainContext, IExtHostContext, ISerializedLanguageConfiguration, ISerializedRegExp, ISerializedIndentationRule, ISerializedOnEnterRule, LocationDto, WorkspaceSymbolDto, reviveWorkspaceEditDto, ISerializedDocumentFilter, DefinitionLinkDto, ISerializedSignatureHelpProviderMetadata, LinkDto, CallHierarchyDto, SuggestDataDto, CodeActionDto } from '../common/extHost.protocol';
|
||||
import { LanguageConfigurationRegistry } from 'vs/editor/common/modes/languageConfigurationRegistry';
|
||||
import { LanguageConfiguration, IndentationRule, OnEnterRule } from 'vs/editor/common/modes/languageConfiguration';
|
||||
import { IModeService } from 'vs/editor/common/services/modeService';
|
||||
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { Selection } from 'vs/editor/common/core/selection';
|
||||
import * as codeInset from 'vs/workbench/contrib/codeinset/common/codeInset';
|
||||
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
|
||||
import * as callh from 'vs/workbench/contrib/callHierarchy/common/callHierarchy';
|
||||
import { IHeapService } from 'vs/workbench/services/heap/common/heap';
|
||||
import { mixin } from 'vs/base/common/objects';
|
||||
|
||||
@extHostNamedCustomer(MainContext.MainThreadLanguageFeatures)
|
||||
export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesShape {
|
||||
|
||||
private readonly _proxy: ExtHostLanguageFeaturesShape;
|
||||
private readonly _heapService: IHeapService;
|
||||
private readonly _modeService: IModeService;
|
||||
private readonly _registrations: { [handle: number]: IDisposable; } = Object.create(null);
|
||||
private readonly _registrations = new Map<number, IDisposable>();
|
||||
|
||||
constructor(
|
||||
extHostContext: IExtHostContext,
|
||||
@IHeapService heapService: IHeapService,
|
||||
@IModeService modeService: IModeService,
|
||||
) {
|
||||
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostLanguageFeatures);
|
||||
this._heapService = heapService;
|
||||
this._modeService = modeService;
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
for (const key in this._registrations) {
|
||||
this._registrations[key].dispose();
|
||||
for (const registration of this._registrations.values()) {
|
||||
registration.dispose();
|
||||
}
|
||||
this._registrations.clear();
|
||||
}
|
||||
|
||||
$unregister(handle: number): void {
|
||||
const registration = this._registrations[handle];
|
||||
const registration = this._registrations.get(handle);
|
||||
if (registration) {
|
||||
registration.dispose();
|
||||
delete this._registrations[handle];
|
||||
this._registrations.delete(handle);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -101,7 +97,7 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
|
||||
}
|
||||
}
|
||||
|
||||
private static _reviveCodeActionDto(data: CodeActionDto[] | undefined): modes.CodeAction[] {
|
||||
private static _reviveCodeActionDto(data: ReadonlyArray<CodeActionDto>): modes.CodeAction[] {
|
||||
if (data) {
|
||||
data.forEach(code => reviveWorkspaceEditDto(code.edit));
|
||||
}
|
||||
@@ -127,12 +123,12 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
|
||||
// --- outline
|
||||
|
||||
$registerDocumentSymbolProvider(handle: number, selector: ISerializedDocumentFilter[], displayName: string): void {
|
||||
this._registrations[handle] = modes.DocumentSymbolProviderRegistry.register(selector, <modes.DocumentSymbolProvider>{
|
||||
this._registrations.set(handle, modes.DocumentSymbolProviderRegistry.register(selector, <modes.DocumentSymbolProvider>{
|
||||
displayName,
|
||||
provideDocumentSymbols: (model: ITextModel, token: CancellationToken): Promise<modes.DocumentSymbol[] | undefined> => {
|
||||
return this._proxy.$provideDocumentSymbols(handle, model.uri, token);
|
||||
}
|
||||
});
|
||||
}));
|
||||
}
|
||||
|
||||
// --- code lens
|
||||
@@ -140,190 +136,161 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
|
||||
$registerCodeLensSupport(handle: number, selector: ISerializedDocumentFilter[], eventHandle: number | undefined): void {
|
||||
|
||||
const provider = <modes.CodeLensProvider>{
|
||||
provideCodeLenses: (model: ITextModel, token: CancellationToken): modes.ICodeLensSymbol[] | Promise<modes.ICodeLensSymbol[]> => {
|
||||
return this._proxy.$provideCodeLenses(handle, model.uri, token).then(dto => {
|
||||
if (dto) {
|
||||
dto.forEach(obj => {
|
||||
this._heapService.trackObject(obj);
|
||||
this._heapService.trackObject(obj.command);
|
||||
});
|
||||
provideCodeLenses: (model: ITextModel, token: CancellationToken): Promise<modes.CodeLensList | undefined> => {
|
||||
return this._proxy.$provideCodeLenses(handle, model.uri, token).then(listDto => {
|
||||
if (!listDto) {
|
||||
return undefined;
|
||||
}
|
||||
return dto;
|
||||
return {
|
||||
lenses: listDto.lenses,
|
||||
dispose: () => listDto.cacheId && this._proxy.$releaseCodeLenses(handle, listDto.cacheId)
|
||||
};
|
||||
});
|
||||
},
|
||||
resolveCodeLens: (_model: ITextModel, codeLens: modes.ICodeLensSymbol, token: CancellationToken): Promise<modes.ICodeLensSymbol | undefined> => {
|
||||
return this._proxy.$resolveCodeLens(handle, codeLens, token).then(obj => {
|
||||
if (obj) {
|
||||
this._heapService.trackObject(obj);
|
||||
this._heapService.trackObject(obj.command);
|
||||
}
|
||||
return obj;
|
||||
});
|
||||
resolveCodeLens: (_model: ITextModel, codeLens: modes.CodeLens, token: CancellationToken): Promise<modes.CodeLens | undefined> => {
|
||||
return this._proxy.$resolveCodeLens(handle, codeLens, token);
|
||||
}
|
||||
};
|
||||
|
||||
if (typeof eventHandle === 'number') {
|
||||
const emitter = new Emitter<modes.CodeLensProvider>();
|
||||
this._registrations[eventHandle] = emitter;
|
||||
this._registrations.set(eventHandle, emitter);
|
||||
provider.onDidChange = emitter.event;
|
||||
}
|
||||
|
||||
this._registrations[handle] = modes.CodeLensProviderRegistry.register(selector, provider);
|
||||
this._registrations.set(handle, modes.CodeLensProviderRegistry.register(selector, provider));
|
||||
}
|
||||
|
||||
$emitCodeLensEvent(eventHandle: number, event?: any): void {
|
||||
const obj = this._registrations[eventHandle];
|
||||
const obj = this._registrations.get(eventHandle);
|
||||
if (obj instanceof Emitter) {
|
||||
obj.fire(event);
|
||||
}
|
||||
}
|
||||
|
||||
// -- code inset
|
||||
|
||||
$registerCodeInsetSupport(handle: number, selector: ISerializedDocumentFilter[], eventHandle: number): void {
|
||||
|
||||
const provider = <codeInset.CodeInsetProvider>{
|
||||
provideCodeInsets: (model: ITextModel, token: CancellationToken): CodeInsetDto[] | Thenable<CodeInsetDto[]> => {
|
||||
return this._proxy.$provideCodeInsets(handle, model.uri, token).then(dto => {
|
||||
if (dto) { dto.forEach(obj => this._heapService.trackObject(obj)); }
|
||||
return dto;
|
||||
});
|
||||
},
|
||||
resolveCodeInset: (model: ITextModel, codeInset: CodeInsetDto, token: CancellationToken): CodeInsetDto | Thenable<CodeInsetDto> => {
|
||||
return this._proxy.$resolveCodeInset(handle, model.uri, codeInset, token).then(obj => {
|
||||
this._heapService.trackObject(obj);
|
||||
return obj;
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
if (typeof eventHandle === 'number') {
|
||||
const emitter = new Emitter<codeInset.CodeInsetProvider>();
|
||||
this._registrations[eventHandle] = emitter;
|
||||
provider.onDidChange = emitter.event;
|
||||
}
|
||||
|
||||
const langSelector = selector;
|
||||
this._registrations[handle] = codeInset.CodeInsetProviderRegistry.register(langSelector, provider);
|
||||
}
|
||||
|
||||
// --- declaration
|
||||
|
||||
$registerDefinitionSupport(handle: number, selector: ISerializedDocumentFilter[]): void {
|
||||
this._registrations[handle] = modes.DefinitionProviderRegistry.register(selector, <modes.DefinitionProvider>{
|
||||
this._registrations.set(handle, modes.DefinitionProviderRegistry.register(selector, <modes.DefinitionProvider>{
|
||||
provideDefinition: (model, position, token): Promise<modes.LocationLink[]> => {
|
||||
return this._proxy.$provideDefinition(handle, model.uri, position, token).then(MainThreadLanguageFeatures._reviveLocationLinkDto);
|
||||
}
|
||||
});
|
||||
}));
|
||||
}
|
||||
|
||||
$registerDeclarationSupport(handle: number, selector: ISerializedDocumentFilter[]): void {
|
||||
this._registrations[handle] = modes.DeclarationProviderRegistry.register(selector, <modes.DeclarationProvider>{
|
||||
this._registrations.set(handle, modes.DeclarationProviderRegistry.register(selector, <modes.DeclarationProvider>{
|
||||
provideDeclaration: (model, position, token) => {
|
||||
return this._proxy.$provideDeclaration(handle, model.uri, position, token).then(MainThreadLanguageFeatures._reviveLocationLinkDto);
|
||||
}
|
||||
});
|
||||
}));
|
||||
}
|
||||
|
||||
$registerImplementationSupport(handle: number, selector: ISerializedDocumentFilter[]): void {
|
||||
this._registrations[handle] = modes.ImplementationProviderRegistry.register(selector, <modes.ImplementationProvider>{
|
||||
this._registrations.set(handle, modes.ImplementationProviderRegistry.register(selector, <modes.ImplementationProvider>{
|
||||
provideImplementation: (model, position, token): Promise<modes.LocationLink[]> => {
|
||||
return this._proxy.$provideImplementation(handle, model.uri, position, token).then(MainThreadLanguageFeatures._reviveLocationLinkDto);
|
||||
}
|
||||
});
|
||||
}));
|
||||
}
|
||||
|
||||
$registerTypeDefinitionSupport(handle: number, selector: ISerializedDocumentFilter[]): void {
|
||||
this._registrations[handle] = modes.TypeDefinitionProviderRegistry.register(selector, <modes.TypeDefinitionProvider>{
|
||||
this._registrations.set(handle, modes.TypeDefinitionProviderRegistry.register(selector, <modes.TypeDefinitionProvider>{
|
||||
provideTypeDefinition: (model, position, token): Promise<modes.LocationLink[]> => {
|
||||
return this._proxy.$provideTypeDefinition(handle, model.uri, position, token).then(MainThreadLanguageFeatures._reviveLocationLinkDto);
|
||||
}
|
||||
});
|
||||
}));
|
||||
}
|
||||
|
||||
// --- extra info
|
||||
|
||||
$registerHoverProvider(handle: number, selector: ISerializedDocumentFilter[]): void {
|
||||
this._registrations[handle] = modes.HoverProviderRegistry.register(selector, <modes.HoverProvider>{
|
||||
this._registrations.set(handle, modes.HoverProviderRegistry.register(selector, <modes.HoverProvider>{
|
||||
provideHover: (model: ITextModel, position: EditorPosition, token: CancellationToken): Promise<modes.Hover | undefined> => {
|
||||
return this._proxy.$provideHover(handle, model.uri, position, token);
|
||||
}
|
||||
});
|
||||
}));
|
||||
}
|
||||
|
||||
// --- occurrences
|
||||
|
||||
$registerDocumentHighlightProvider(handle: number, selector: ISerializedDocumentFilter[]): void {
|
||||
this._registrations[handle] = modes.DocumentHighlightProviderRegistry.register(selector, <modes.DocumentHighlightProvider>{
|
||||
this._registrations.set(handle, modes.DocumentHighlightProviderRegistry.register(selector, <modes.DocumentHighlightProvider>{
|
||||
provideDocumentHighlights: (model: ITextModel, position: EditorPosition, token: CancellationToken): Promise<modes.DocumentHighlight[] | undefined> => {
|
||||
return this._proxy.$provideDocumentHighlights(handle, model.uri, position, token);
|
||||
}
|
||||
});
|
||||
}));
|
||||
}
|
||||
|
||||
// --- references
|
||||
|
||||
$registerReferenceSupport(handle: number, selector: ISerializedDocumentFilter[]): void {
|
||||
this._registrations[handle] = modes.ReferenceProviderRegistry.register(selector, <modes.ReferenceProvider>{
|
||||
this._registrations.set(handle, modes.ReferenceProviderRegistry.register(selector, <modes.ReferenceProvider>{
|
||||
provideReferences: (model: ITextModel, position: EditorPosition, context: modes.ReferenceContext, token: CancellationToken): Promise<modes.Location[]> => {
|
||||
return this._proxy.$provideReferences(handle, model.uri, position, context, token).then(MainThreadLanguageFeatures._reviveLocationDto);
|
||||
}
|
||||
});
|
||||
}));
|
||||
}
|
||||
|
||||
// --- quick fix
|
||||
|
||||
$registerQuickFixSupport(handle: number, selector: ISerializedDocumentFilter[], providedCodeActionKinds?: string[]): void {
|
||||
this._registrations[handle] = modes.CodeActionProviderRegistry.register(selector, <modes.CodeActionProvider>{
|
||||
provideCodeActions: (model: ITextModel, rangeOrSelection: EditorRange | Selection, context: modes.CodeActionContext, token: CancellationToken): Promise<modes.CodeAction[]> => {
|
||||
return this._proxy.$provideCodeActions(handle, model.uri, rangeOrSelection, context, token).then(dto => {
|
||||
if (dto) {
|
||||
dto.forEach(obj => { this._heapService.trackObject(obj.command); });
|
||||
this._registrations.set(handle, modes.CodeActionProviderRegistry.register(selector, <modes.CodeActionProvider>{
|
||||
provideCodeActions: async (model: ITextModel, rangeOrSelection: EditorRange | Selection, context: modes.CodeActionContext, token: CancellationToken): Promise<modes.CodeActionList | undefined> => {
|
||||
const listDto = await this._proxy.$provideCodeActions(handle, model.uri, rangeOrSelection, context, token);
|
||||
if (!listDto) {
|
||||
return undefined;
|
||||
}
|
||||
return <modes.CodeActionList>{
|
||||
actions: MainThreadLanguageFeatures._reviveCodeActionDto(listDto.actions),
|
||||
dispose: () => {
|
||||
if (typeof listDto.cacheId === 'number') {
|
||||
this._proxy.$releaseCodeActions(handle, listDto.cacheId);
|
||||
}
|
||||
}
|
||||
return MainThreadLanguageFeatures._reviveCodeActionDto(dto);
|
||||
});
|
||||
};
|
||||
},
|
||||
providedCodeActionKinds
|
||||
});
|
||||
}));
|
||||
}
|
||||
|
||||
// --- formatting
|
||||
|
||||
$registerDocumentFormattingSupport(handle: number, selector: ISerializedDocumentFilter[], extensionId: ExtensionIdentifier, displayName: string): void {
|
||||
this._registrations[handle] = modes.DocumentFormattingEditProviderRegistry.register(selector, <modes.DocumentFormattingEditProvider>{
|
||||
this._registrations.set(handle, modes.DocumentFormattingEditProviderRegistry.register(selector, <modes.DocumentFormattingEditProvider>{
|
||||
extensionId,
|
||||
displayName,
|
||||
provideDocumentFormattingEdits: (model: ITextModel, options: modes.FormattingOptions, token: CancellationToken): Promise<ISingleEditOperation[] | undefined> => {
|
||||
return this._proxy.$provideDocumentFormattingEdits(handle, model.uri, options, token);
|
||||
}
|
||||
});
|
||||
}));
|
||||
}
|
||||
|
||||
$registerRangeFormattingSupport(handle: number, selector: ISerializedDocumentFilter[], extensionId: ExtensionIdentifier, displayName: string): void {
|
||||
this._registrations[handle] = modes.DocumentRangeFormattingEditProviderRegistry.register(selector, <modes.DocumentRangeFormattingEditProvider>{
|
||||
this._registrations.set(handle, modes.DocumentRangeFormattingEditProviderRegistry.register(selector, <modes.DocumentRangeFormattingEditProvider>{
|
||||
extensionId,
|
||||
displayName,
|
||||
provideDocumentRangeFormattingEdits: (model: ITextModel, range: EditorRange, options: modes.FormattingOptions, token: CancellationToken): Promise<ISingleEditOperation[] | undefined> => {
|
||||
return this._proxy.$provideDocumentRangeFormattingEdits(handle, model.uri, range, options, token);
|
||||
}
|
||||
});
|
||||
}));
|
||||
}
|
||||
|
||||
$registerOnTypeFormattingSupport(handle: number, selector: ISerializedDocumentFilter[], autoFormatTriggerCharacters: string[], extensionId: ExtensionIdentifier): void {
|
||||
this._registrations[handle] = modes.OnTypeFormattingEditProviderRegistry.register(selector, <modes.OnTypeFormattingEditProvider>{
|
||||
this._registrations.set(handle, modes.OnTypeFormattingEditProviderRegistry.register(selector, <modes.OnTypeFormattingEditProvider>{
|
||||
extensionId,
|
||||
autoFormatTriggerCharacters,
|
||||
provideOnTypeFormattingEdits: (model: ITextModel, position: EditorPosition, ch: string, options: modes.FormattingOptions, token: CancellationToken): Promise<ISingleEditOperation[] | undefined> => {
|
||||
return this._proxy.$provideOnTypeFormattingEdits(handle, model.uri, position, ch, options, token);
|
||||
}
|
||||
});
|
||||
}));
|
||||
}
|
||||
|
||||
// --- navigate type
|
||||
|
||||
$registerNavigateTypeSupport(handle: number): void {
|
||||
let lastResultId: number | undefined;
|
||||
this._registrations[handle] = search.WorkspaceSymbolProviderRegistry.register(<search.IWorkspaceSymbolProvider>{
|
||||
this._registrations.set(handle, search.WorkspaceSymbolProviderRegistry.register(<search.IWorkspaceSymbolProvider>{
|
||||
provideWorkspaceSymbols: (search: string, token: CancellationToken): Promise<search.IWorkspaceSymbol[]> => {
|
||||
return this._proxy.$provideWorkspaceSymbols(handle, search, token).then(result => {
|
||||
if (lastResultId !== undefined) {
|
||||
@@ -341,21 +308,20 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
|
||||
return undefined;
|
||||
});
|
||||
}
|
||||
});
|
||||
}));
|
||||
}
|
||||
|
||||
// --- rename
|
||||
|
||||
$registerRenameSupport(handle: number, selector: ISerializedDocumentFilter[], supportResolveLocation: boolean): void {
|
||||
|
||||
this._registrations[handle] = modes.RenameProviderRegistry.register(selector, <modes.RenameProvider>{
|
||||
this._registrations.set(handle, modes.RenameProviderRegistry.register(selector, <modes.RenameProvider>{
|
||||
provideRenameEdits: (model: ITextModel, position: EditorPosition, newName: string, token: CancellationToken): Promise<modes.WorkspaceEdit> => {
|
||||
return this._proxy.$provideRenameEdits(handle, model.uri, position, newName, token).then(reviveWorkspaceEditDto);
|
||||
},
|
||||
resolveRenameLocation: supportResolveLocation
|
||||
? (model: ITextModel, position: EditorPosition, token: CancellationToken): Promise<modes.RenameLocation | undefined> => this._proxy.$resolveRenameLocation(handle, model.uri, position, token)
|
||||
: undefined
|
||||
});
|
||||
}));
|
||||
}
|
||||
|
||||
// --- suggest
|
||||
@@ -380,9 +346,10 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
|
||||
};
|
||||
}
|
||||
|
||||
$registerSuggestSupport(handle: number, selector: ISerializedDocumentFilter[], triggerCharacters: string[], supportsResolveDetails: boolean): void {
|
||||
$registerSuggestSupport(handle: number, selector: ISerializedDocumentFilter[], triggerCharacters: string[], supportsResolveDetails: boolean, extensionId: ExtensionIdentifier): void {
|
||||
const provider: modes.CompletionItemProvider = {
|
||||
triggerCharacters,
|
||||
_debugDisplayName: extensionId.value,
|
||||
provideCompletionItems: (model: ITextModel, position: EditorPosition, context: modes.CompletionContext, token: CancellationToken): Promise<modes.CompletionList | undefined> => {
|
||||
return this._proxy.$provideCompletionItems(handle, model.uri, position, context, token).then(result => {
|
||||
if (!result) {
|
||||
@@ -408,21 +375,30 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
|
||||
});
|
||||
};
|
||||
}
|
||||
this._registrations[handle] = modes.CompletionProviderRegistry.register(selector, provider);
|
||||
this._registrations.set(handle, modes.CompletionProviderRegistry.register(selector, provider));
|
||||
}
|
||||
|
||||
// --- parameter hints
|
||||
|
||||
$registerSignatureHelpProvider(handle: number, selector: ISerializedDocumentFilter[], metadata: ISerializedSignatureHelpProviderMetadata): void {
|
||||
this._registrations[handle] = modes.SignatureHelpProviderRegistry.register(selector, <modes.SignatureHelpProvider>{
|
||||
this._registrations.set(handle, modes.SignatureHelpProviderRegistry.register(selector, <modes.SignatureHelpProvider>{
|
||||
|
||||
signatureHelpTriggerCharacters: metadata.triggerCharacters,
|
||||
signatureHelpRetriggerCharacters: metadata.retriggerCharacters,
|
||||
|
||||
provideSignatureHelp: (model: ITextModel, position: EditorPosition, token: CancellationToken, context: modes.SignatureHelpContext): Promise<modes.SignatureHelp | undefined> => {
|
||||
return this._proxy.$provideSignatureHelp(handle, model.uri, position, context, token);
|
||||
provideSignatureHelp: async (model: ITextModel, position: EditorPosition, token: CancellationToken, context: modes.SignatureHelpContext): Promise<modes.SignatureHelpResult | undefined> => {
|
||||
const result = await this._proxy.$provideSignatureHelp(handle, model.uri, position, context, token);
|
||||
if (!result) {
|
||||
return undefined;
|
||||
}
|
||||
return {
|
||||
value: result,
|
||||
dispose: () => {
|
||||
this._proxy.$releaseSignatureHelp(handle, result.id);
|
||||
}
|
||||
};
|
||||
}
|
||||
});
|
||||
}));
|
||||
}
|
||||
|
||||
// --- links
|
||||
@@ -456,14 +432,14 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
|
||||
});
|
||||
};
|
||||
}
|
||||
this._registrations[handle] = modes.LinkProviderRegistry.register(selector, provider);
|
||||
this._registrations.set(handle, modes.LinkProviderRegistry.register(selector, provider));
|
||||
}
|
||||
|
||||
// --- colors
|
||||
|
||||
$registerDocumentColorProvider(handle: number, selector: ISerializedDocumentFilter[]): void {
|
||||
const proxy = this._proxy;
|
||||
this._registrations[handle] = modes.ColorProviderRegistry.register(selector, <modes.DocumentColorProvider>{
|
||||
this._registrations.set(handle, modes.ColorProviderRegistry.register(selector, <modes.DocumentColorProvider>{
|
||||
provideDocumentColors: (model, token) => {
|
||||
return proxy.$provideDocumentColors(handle, model.uri, token)
|
||||
.then(documentColors => {
|
||||
@@ -490,34 +466,34 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
|
||||
range: colorInfo.range
|
||||
}, token);
|
||||
}
|
||||
});
|
||||
}));
|
||||
}
|
||||
|
||||
// --- folding
|
||||
|
||||
$registerFoldingRangeProvider(handle: number, selector: ISerializedDocumentFilter[]): void {
|
||||
const proxy = this._proxy;
|
||||
this._registrations[handle] = modes.FoldingRangeProviderRegistry.register(selector, <modes.FoldingRangeProvider>{
|
||||
this._registrations.set(handle, modes.FoldingRangeProviderRegistry.register(selector, <modes.FoldingRangeProvider>{
|
||||
provideFoldingRanges: (model, context, token) => {
|
||||
return proxy.$provideFoldingRanges(handle, model.uri, context, token);
|
||||
}
|
||||
});
|
||||
}));
|
||||
}
|
||||
|
||||
// -- smart select
|
||||
|
||||
$registerSelectionRangeProvider(handle: number, selector: ISerializedDocumentFilter[]): void {
|
||||
this._registrations[handle] = modes.SelectionRangeRegistry.register(selector, {
|
||||
this._registrations.set(handle, modes.SelectionRangeRegistry.register(selector, {
|
||||
provideSelectionRanges: (model, positions, token) => {
|
||||
return this._proxy.$provideSelectionRanges(handle, model.uri, positions, token);
|
||||
}
|
||||
});
|
||||
}));
|
||||
}
|
||||
|
||||
// --- call hierarchy
|
||||
|
||||
$registerCallHierarchyProvider(handle: number, selector: ISerializedDocumentFilter[]): void {
|
||||
this._registrations[handle] = callh.CallHierarchyProviderRegistry.register(selector, {
|
||||
this._registrations.set(handle, callh.CallHierarchyProviderRegistry.register(selector, {
|
||||
provideCallHierarchyItem: (document, position, token) => {
|
||||
return this._proxy.$provideCallHierarchyItem(handle, document.uri, position, token).then(MainThreadLanguageFeatures._reviveCallHierarchyItemDto);
|
||||
},
|
||||
@@ -535,7 +511,7 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
|
||||
return data as [callh.CallHierarchyItem, modes.Location[]][];
|
||||
});
|
||||
}
|
||||
});
|
||||
}));
|
||||
}
|
||||
|
||||
// --- configuration
|
||||
@@ -596,7 +572,7 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
|
||||
|
||||
const languageIdentifier = this._modeService.getLanguageIdentifier(languageId);
|
||||
if (languageIdentifier) {
|
||||
this._registrations[handle] = LanguageConfigurationRegistry.register(languageIdentifier, configuration);
|
||||
this._registrations.set(handle, LanguageConfigurationRegistry.register(languageIdentifier, configuration));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -90,7 +90,8 @@ export class MainThreadMessageService implements MainThreadMessageServiceShape {
|
||||
// if promise has not been resolved yet, now is the time to ensure a return value
|
||||
// otherwise if already resolved it means the user clicked one of the buttons
|
||||
Event.once(messageHandle.onDidClose)(() => {
|
||||
dispose(...primaryActions, ...secondaryActions);
|
||||
dispose(primaryActions);
|
||||
dispose(secondaryActions);
|
||||
resolve(undefined);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { IProgress, IProgressService2, IProgressStep, ProgressLocation, IProgressOptions, IProgressNotificationOptions } from 'vs/platform/progress/common/progress';
|
||||
import { IProgress, IProgressService, IProgressStep, ProgressLocation, IProgressOptions, IProgressNotificationOptions } from 'vs/platform/progress/common/progress';
|
||||
import { MainThreadProgressShape, MainContext, IExtHostContext, ExtHostProgressShape, ExtHostContext } from '../common/extHost.protocol';
|
||||
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
|
||||
import { Action } from 'vs/base/common/actions';
|
||||
@@ -22,13 +22,13 @@ class ManageExtensionAction extends Action {
|
||||
@extHostNamedCustomer(MainContext.MainThreadProgress)
|
||||
export class MainThreadProgress implements MainThreadProgressShape {
|
||||
|
||||
private readonly _progressService: IProgressService2;
|
||||
private readonly _progressService: IProgressService;
|
||||
private _progress = new Map<number, { resolve: () => void, progress: IProgress<IProgressStep> }>();
|
||||
private readonly _proxy: ExtHostProgressShape;
|
||||
|
||||
constructor(
|
||||
extHostContext: IExtHostContext,
|
||||
@IProgressService2 progressService: IProgressService2,
|
||||
@IProgressService progressService: IProgressService,
|
||||
@ICommandService private readonly _commandService: ICommandService
|
||||
) {
|
||||
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostProgress);
|
||||
|
||||
@@ -174,13 +174,13 @@ export class MainThreadQuickOpen implements MainThreadQuickOpenShape {
|
||||
params[param].forEach((item: TransferQuickPickItems) => {
|
||||
handlesToItems.set(item.handle, item);
|
||||
});
|
||||
input[param] = params[param];
|
||||
(input as any)[param] = params[param];
|
||||
} else if (param === 'activeItems' || param === 'selectedItems') {
|
||||
input[param] = params[param]
|
||||
(input as any)[param] = params[param]
|
||||
.filter((handle: number) => handlesToItems.has(handle))
|
||||
.map((handle: number) => handlesToItems.get(handle));
|
||||
} else if (param === 'buttons') {
|
||||
input[param] = params.buttons!.map(button => {
|
||||
(input as any)[param] = params.buttons!.map(button => {
|
||||
if (button.handle === -1) {
|
||||
return this._quickInputService.backButton;
|
||||
}
|
||||
@@ -195,7 +195,7 @@ export class MainThreadQuickOpen implements MainThreadQuickOpenShape {
|
||||
};
|
||||
});
|
||||
} else {
|
||||
input[param] = params[param];
|
||||
(input as any)[param] = params[param];
|
||||
}
|
||||
}
|
||||
return Promise.resolve(undefined);
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
import { URI, UriComponents } from 'vs/base/common/uri';
|
||||
import { Event, Emitter } from 'vs/base/common/event';
|
||||
import { assign } from 'vs/base/common/objects';
|
||||
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
|
||||
import { IDisposable, DisposableStore } from 'vs/base/common/lifecycle';
|
||||
import { ISCMService, ISCMRepository, ISCMProvider, ISCMResource, ISCMResourceGroup, ISCMResourceDecorations, IInputValidation } from 'vs/workbench/contrib/scm/common/scm';
|
||||
import { ExtHostContext, MainThreadSCMShape, ExtHostSCMShape, SCMProviderFeatures, SCMRawResourceSplices, SCMGroupFeatures, MainContext, IExtHostContext } from '../common/extHost.protocol';
|
||||
import { Command } from 'vs/editor/common/modes';
|
||||
@@ -24,7 +24,7 @@ class MainThreadSCMResourceGroup implements ISCMResourceGroup {
|
||||
get hideWhenEmpty(): boolean { return !!this.features.hideWhenEmpty; }
|
||||
|
||||
private _onDidChange = new Emitter<void>();
|
||||
get onDidChange(): Event<void> { return this._onDidChange.event; }
|
||||
readonly onDidChange: Event<void> = this._onDidChange.event;
|
||||
|
||||
constructor(
|
||||
private readonly sourceControlHandle: number,
|
||||
@@ -105,7 +105,7 @@ class MainThreadSCMProvider implements ISCMProvider {
|
||||
// }
|
||||
|
||||
private _onDidChangeResources = new Emitter<void>();
|
||||
get onDidChangeResources(): Event<void> { return this._onDidChangeResources.event; }
|
||||
readonly onDidChangeResources: Event<void> = this._onDidChangeResources.event;
|
||||
|
||||
private features: SCMProviderFeatures = {};
|
||||
|
||||
@@ -120,13 +120,13 @@ class MainThreadSCMProvider implements ISCMProvider {
|
||||
get count(): number | undefined { return this.features.count; }
|
||||
|
||||
private _onDidChangeCommitTemplate = new Emitter<string>();
|
||||
get onDidChangeCommitTemplate(): Event<string> { return this._onDidChangeCommitTemplate.event; }
|
||||
readonly onDidChangeCommitTemplate: Event<string> = this._onDidChangeCommitTemplate.event;
|
||||
|
||||
private _onDidChangeStatusBarCommands = new Emitter<Command[]>();
|
||||
get onDidChangeStatusBarCommands(): Event<Command[]> { return this._onDidChangeStatusBarCommands.event; }
|
||||
|
||||
private _onDidChange = new Emitter<void>();
|
||||
get onDidChange(): Event<void> { return this._onDidChange.event; }
|
||||
readonly onDidChange: Event<void> = this._onDidChange.event;
|
||||
|
||||
constructor(
|
||||
private readonly proxy: ExtHostSCMShape,
|
||||
@@ -266,9 +266,9 @@ class MainThreadSCMProvider implements ISCMProvider {
|
||||
export class MainThreadSCM implements MainThreadSCMShape {
|
||||
|
||||
private readonly _proxy: ExtHostSCMShape;
|
||||
private _repositories: { [handle: number]: ISCMRepository; } = Object.create(null);
|
||||
private _inputDisposables: { [handle: number]: IDisposable; } = Object.create(null);
|
||||
private _disposables: IDisposable[] = [];
|
||||
private _repositories = new Map<number, ISCMRepository>();
|
||||
private _inputDisposables = new Map<number, IDisposable>();
|
||||
private readonly _disposables = new DisposableStore();
|
||||
|
||||
constructor(
|
||||
extHostContext: IExtHostContext,
|
||||
@@ -281,28 +281,26 @@ export class MainThreadSCM implements MainThreadSCMShape {
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
Object.keys(this._repositories)
|
||||
.forEach(id => this._repositories[id].dispose());
|
||||
this._repositories = Object.create(null);
|
||||
this._repositories.forEach(r => r.dispose());
|
||||
this._repositories.clear();
|
||||
|
||||
Object.keys(this._inputDisposables)
|
||||
.forEach(id => this._inputDisposables[id].dispose());
|
||||
this._inputDisposables = Object.create(null);
|
||||
this._inputDisposables.forEach(d => d.dispose());
|
||||
this._inputDisposables.clear();
|
||||
|
||||
this._disposables = dispose(this._disposables);
|
||||
this._disposables.dispose();
|
||||
}
|
||||
|
||||
$registerSourceControl(handle: number, id: string, label: string, rootUri: UriComponents | undefined): void {
|
||||
const provider = new MainThreadSCMProvider(this._proxy, handle, id, label, rootUri && URI.revive(rootUri), this.scmService);
|
||||
const repository = this.scmService.registerSCMProvider(provider);
|
||||
this._repositories[handle] = repository;
|
||||
this._repositories.set(handle, repository);
|
||||
|
||||
const inputDisposable = repository.input.onDidChange(value => this._proxy.$onInputBoxValueChange(handle, value));
|
||||
this._inputDisposables[handle] = inputDisposable;
|
||||
this._inputDisposables.set(handle, inputDisposable);
|
||||
}
|
||||
|
||||
$updateSourceControl(handle: number, features: SCMProviderFeatures): void {
|
||||
const repository = this._repositories[handle];
|
||||
const repository = this._repositories.get(handle);
|
||||
|
||||
if (!repository) {
|
||||
return;
|
||||
@@ -313,21 +311,21 @@ export class MainThreadSCM implements MainThreadSCMShape {
|
||||
}
|
||||
|
||||
$unregisterSourceControl(handle: number): void {
|
||||
const repository = this._repositories[handle];
|
||||
const repository = this._repositories.get(handle);
|
||||
|
||||
if (!repository) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._inputDisposables[handle].dispose();
|
||||
delete this._inputDisposables[handle];
|
||||
this._inputDisposables.get(handle)!.dispose();
|
||||
this._inputDisposables.delete(handle);
|
||||
|
||||
repository.dispose();
|
||||
delete this._repositories[handle];
|
||||
this._repositories.delete(handle);
|
||||
}
|
||||
|
||||
$registerGroup(sourceControlHandle: number, groupHandle: number, id: string, label: string): void {
|
||||
const repository = this._repositories[sourceControlHandle];
|
||||
const repository = this._repositories.get(sourceControlHandle);
|
||||
|
||||
if (!repository) {
|
||||
return;
|
||||
@@ -338,7 +336,7 @@ export class MainThreadSCM implements MainThreadSCMShape {
|
||||
}
|
||||
|
||||
$updateGroup(sourceControlHandle: number, groupHandle: number, features: SCMGroupFeatures): void {
|
||||
const repository = this._repositories[sourceControlHandle];
|
||||
const repository = this._repositories.get(sourceControlHandle);
|
||||
|
||||
if (!repository) {
|
||||
return;
|
||||
@@ -349,7 +347,7 @@ export class MainThreadSCM implements MainThreadSCMShape {
|
||||
}
|
||||
|
||||
$updateGroupLabel(sourceControlHandle: number, groupHandle: number, label: string): void {
|
||||
const repository = this._repositories[sourceControlHandle];
|
||||
const repository = this._repositories.get(sourceControlHandle);
|
||||
|
||||
if (!repository) {
|
||||
return;
|
||||
@@ -360,7 +358,7 @@ export class MainThreadSCM implements MainThreadSCMShape {
|
||||
}
|
||||
|
||||
$spliceResourceStates(sourceControlHandle: number, splices: SCMRawResourceSplices[]): void {
|
||||
const repository = this._repositories[sourceControlHandle];
|
||||
const repository = this._repositories.get(sourceControlHandle);
|
||||
|
||||
if (!repository) {
|
||||
return;
|
||||
@@ -371,7 +369,7 @@ export class MainThreadSCM implements MainThreadSCMShape {
|
||||
}
|
||||
|
||||
$unregisterGroup(sourceControlHandle: number, handle: number): void {
|
||||
const repository = this._repositories[sourceControlHandle];
|
||||
const repository = this._repositories.get(sourceControlHandle);
|
||||
|
||||
if (!repository) {
|
||||
return;
|
||||
@@ -382,7 +380,7 @@ export class MainThreadSCM implements MainThreadSCMShape {
|
||||
}
|
||||
|
||||
$setInputBoxValue(sourceControlHandle: number, value: string): void {
|
||||
const repository = this._repositories[sourceControlHandle];
|
||||
const repository = this._repositories.get(sourceControlHandle);
|
||||
|
||||
if (!repository) {
|
||||
return;
|
||||
@@ -392,7 +390,7 @@ export class MainThreadSCM implements MainThreadSCMShape {
|
||||
}
|
||||
|
||||
$setInputBoxPlaceholder(sourceControlHandle: number, placeholder: string): void {
|
||||
const repository = this._repositories[sourceControlHandle];
|
||||
const repository = this._repositories.get(sourceControlHandle);
|
||||
|
||||
if (!repository) {
|
||||
return;
|
||||
@@ -402,7 +400,7 @@ export class MainThreadSCM implements MainThreadSCMShape {
|
||||
}
|
||||
|
||||
$setInputBoxVisibility(sourceControlHandle: number, visible: boolean): void {
|
||||
const repository = this._repositories[sourceControlHandle];
|
||||
const repository = this._repositories.get(sourceControlHandle);
|
||||
|
||||
if (!repository) {
|
||||
return;
|
||||
@@ -412,7 +410,7 @@ export class MainThreadSCM implements MainThreadSCMShape {
|
||||
}
|
||||
|
||||
$setValidationProviderIsEnabled(sourceControlHandle: number, enabled: boolean): void {
|
||||
const repository = this._repositories[sourceControlHandle];
|
||||
const repository = this._repositories.get(sourceControlHandle);
|
||||
|
||||
if (!repository) {
|
||||
return;
|
||||
|
||||
@@ -28,7 +28,7 @@ import { ICommandService } from 'vs/platform/commands/common/commands';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { IProgressService2, ProgressLocation } from 'vs/platform/progress/common/progress';
|
||||
import { IProgressService, ProgressLocation } from 'vs/platform/progress/common/progress';
|
||||
import { extHostCustomer } from 'vs/workbench/api/common/extHostCustomers';
|
||||
import { TextFileEditorModel } from 'vs/workbench/services/textfile/common/textFileEditorModel';
|
||||
// {{SQL CARBON EDIT}}
|
||||
@@ -299,10 +299,10 @@ class CodeActionOnSaveParticipant implements ISaveParticipant {
|
||||
if (CodeActionKind.SourceFixAll.contains(b)) {
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
return -1;
|
||||
}
|
||||
if (CodeActionKind.SourceFixAll.contains(b)) {
|
||||
return -1;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
});
|
||||
@@ -334,6 +334,8 @@ class CodeActionOnSaveParticipant implements ISaveParticipant {
|
||||
await this.applyCodeActions(actionsToRun.actions);
|
||||
} catch {
|
||||
// Failure to apply a code action should not block other on save actions
|
||||
} finally {
|
||||
actionsToRun.dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -391,7 +393,7 @@ export class SaveParticipant implements ISaveParticipant {
|
||||
constructor(
|
||||
extHostContext: IExtHostContext,
|
||||
@IInstantiationService instantiationService: IInstantiationService,
|
||||
@IProgressService2 private readonly _progressService: IProgressService2,
|
||||
@IProgressService private readonly _progressService: IProgressService,
|
||||
@ILogService private readonly _logService: ILogService
|
||||
) {
|
||||
this._saveParticipants = new IdleValue(() => [
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { dispose, IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { dispose, IDisposable, DisposableStore } from 'vs/base/common/lifecycle';
|
||||
import { values } from 'vs/base/common/map';
|
||||
import { URI, UriComponents } from 'vs/base/common/uri';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
@@ -96,7 +96,7 @@ class SearchOperation {
|
||||
|
||||
class RemoteSearchProvider implements ISearchResultProvider, IDisposable {
|
||||
|
||||
private readonly _registrations: IDisposable[];
|
||||
private readonly _registrations = new DisposableStore();
|
||||
private readonly _searches = new Map<number, SearchOperation>();
|
||||
|
||||
constructor(
|
||||
@@ -106,11 +106,11 @@ class RemoteSearchProvider implements ISearchResultProvider, IDisposable {
|
||||
private readonly _handle: number,
|
||||
private readonly _proxy: ExtHostSearchShape
|
||||
) {
|
||||
this._registrations = [searchService.registerSearchResultProvider(this._scheme, type, this)];
|
||||
this._registrations.add(searchService.registerSearchResultProvider(this._scheme, type, this));
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
dispose(this._registrations);
|
||||
this._registrations.dispose();
|
||||
}
|
||||
|
||||
fileSearch(query: IFileQuery, token: CancellationToken = CancellationToken.None): Promise<ISearchComplete> {
|
||||
|
||||
@@ -3,11 +3,10 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { IStatusbarService, StatusbarAlignment as MainThreadStatusBarAlignment, IStatusbarEntryAccessor } from 'vs/platform/statusbar/common/statusbar';
|
||||
import { IStatusbarService, StatusbarAlignment as MainThreadStatusBarAlignment, IStatusbarEntryAccessor, IStatusbarEntry } from 'vs/platform/statusbar/common/statusbar';
|
||||
import { MainThreadStatusBarShape, MainContext, IExtHostContext } from '../common/extHost.protocol';
|
||||
import { ThemeColor } from 'vs/platform/theme/common/themeService';
|
||||
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
|
||||
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
|
||||
import { dispose } from 'vs/base/common/lifecycle';
|
||||
|
||||
@extHostNamedCustomer(MainContext.MainThreadStatusBar)
|
||||
@@ -25,8 +24,8 @@ export class MainThreadStatusBar implements MainThreadStatusBarShape {
|
||||
this.entries.clear();
|
||||
}
|
||||
|
||||
$setEntry(id: number, extensionId: ExtensionIdentifier, text: string, tooltip: string, command: string, color: string | ThemeColor, alignment: MainThreadStatusBarAlignment, priority: number): void {
|
||||
const entry = { text, tooltip, command, color, extensionId };
|
||||
$setEntry(id: number, statusId: string, statusName: string, text: string, tooltip: string, command: string, color: string | ThemeColor, alignment: MainThreadStatusBarAlignment, priority: number): void {
|
||||
const entry: IStatusbarEntry = { text, tooltip, command, color };
|
||||
|
||||
// Reset existing entry if alignment or priority changed
|
||||
let existingEntry = this.entries.get(id);
|
||||
@@ -38,7 +37,7 @@ export class MainThreadStatusBar implements MainThreadStatusBarShape {
|
||||
|
||||
// Create new entry if not existing
|
||||
if (!existingEntry) {
|
||||
this.entries.set(id, { accessor: this.statusbarService.addEntry(entry, alignment, priority), alignment, priority });
|
||||
this.entries.set(id, { accessor: this.statusbarService.addEntry(entry, statusId, statusName, alignment, priority), alignment, priority });
|
||||
}
|
||||
|
||||
// Otherwise update
|
||||
|
||||
@@ -16,7 +16,7 @@ import { IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { IWorkspaceContextService, IWorkspaceFolder } from 'vs/platform/workspace/common/workspace';
|
||||
|
||||
import {
|
||||
ContributedTask, KeyedTaskIdentifier, TaskExecution, Task, TaskEvent, TaskEventKind,
|
||||
ContributedTask, ConfiguringTask, KeyedTaskIdentifier, TaskExecution, Task, TaskEvent, TaskEventKind,
|
||||
PresentationOptions, CommandOptions, CommandConfiguration, RuntimeType, CustomTask, TaskScope, TaskSource,
|
||||
TaskSourceKind, ExtensionTaskSource, RunOptions, TaskSet, TaskDefinition
|
||||
} from 'vs/workbench/contrib/tasks/common/tasks';
|
||||
@@ -29,7 +29,7 @@ import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
|
||||
import { ExtHostContext, MainThreadTaskShape, ExtHostTaskShape, MainContext, IExtHostContext } from 'vs/workbench/api/common/extHost.protocol';
|
||||
import {
|
||||
TaskDefinitionDTO, TaskExecutionDTO, ProcessExecutionOptionsDTO, TaskPresentationOptionsDTO,
|
||||
ProcessExecutionDTO, ShellExecutionDTO, ShellExecutionOptionsDTO, CustomExecutionDTO, TaskDTO, TaskSourceDTO, TaskHandleDTO, TaskFilterDTO, TaskProcessStartedDTO, TaskProcessEndedDTO, TaskSystemInfoDTO,
|
||||
ProcessExecutionDTO, ShellExecutionDTO, ShellExecutionOptionsDTO, CustomExecutionDTO, CustomExecution2DTO, TaskDTO, TaskSourceDTO, TaskHandleDTO, TaskFilterDTO, TaskProcessStartedDTO, TaskProcessEndedDTO, TaskSystemInfoDTO,
|
||||
RunOptionsDTO
|
||||
} from 'vs/workbench/api/common/shared/tasks';
|
||||
import { IConfigurationResolverService } from 'vs/workbench/services/configurationResolver/common/configurationResolver';
|
||||
@@ -131,7 +131,7 @@ namespace ProcessExecutionOptionsDTO {
|
||||
}
|
||||
|
||||
namespace ProcessExecutionDTO {
|
||||
export function is(value: ShellExecutionDTO | ProcessExecutionDTO | CustomExecutionDTO): value is ProcessExecutionDTO {
|
||||
export function is(value: ShellExecutionDTO | ProcessExecutionDTO | CustomExecutionDTO | CustomExecution2DTO): value is ProcessExecutionDTO {
|
||||
const candidate = value as ProcessExecutionDTO;
|
||||
return candidate && !!candidate.process;
|
||||
}
|
||||
@@ -199,7 +199,7 @@ namespace ShellExecutionOptionsDTO {
|
||||
}
|
||||
|
||||
namespace ShellExecutionDTO {
|
||||
export function is(value: ShellExecutionDTO | ProcessExecutionDTO | CustomExecutionDTO): value is ShellExecutionDTO {
|
||||
export function is(value: ShellExecutionDTO | ProcessExecutionDTO | CustomExecutionDTO | CustomExecution2DTO): value is ShellExecutionDTO {
|
||||
const candidate = value as ShellExecutionDTO;
|
||||
return candidate && (!!candidate.commandLine || !!candidate.command);
|
||||
}
|
||||
@@ -231,7 +231,7 @@ namespace ShellExecutionDTO {
|
||||
}
|
||||
|
||||
namespace CustomExecutionDTO {
|
||||
export function is(value: ShellExecutionDTO | ProcessExecutionDTO | CustomExecutionDTO): value is CustomExecutionDTO {
|
||||
export function is(value: ShellExecutionDTO | ProcessExecutionDTO | CustomExecutionDTO | CustomExecution2DTO): value is CustomExecutionDTO {
|
||||
const candidate = value as CustomExecutionDTO;
|
||||
return candidate && candidate.customExecution === 'customExecution';
|
||||
}
|
||||
@@ -250,6 +250,26 @@ namespace CustomExecutionDTO {
|
||||
}
|
||||
}
|
||||
|
||||
namespace CustomExecution2DTO {
|
||||
export function is(value: ShellExecutionDTO | ProcessExecutionDTO | CustomExecutionDTO | CustomExecution2DTO): value is CustomExecution2DTO {
|
||||
const candidate = value as CustomExecution2DTO;
|
||||
return candidate && candidate.customExecution === 'customExecution2';
|
||||
}
|
||||
|
||||
export function from(value: CommandConfiguration): CustomExecution2DTO {
|
||||
return {
|
||||
customExecution: 'customExecution2'
|
||||
};
|
||||
}
|
||||
|
||||
export function to(value: CustomExecution2DTO): CommandConfiguration {
|
||||
return {
|
||||
runtime: RuntimeType.CustomExecution2,
|
||||
presentation: undefined
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
namespace TaskSourceDTO {
|
||||
export function from(value: TaskSource): TaskSourceDTO {
|
||||
const result: TaskSourceDTO = {
|
||||
@@ -304,8 +324,8 @@ namespace TaskHandleDTO {
|
||||
}
|
||||
|
||||
namespace TaskDTO {
|
||||
export function from(task: Task): TaskDTO | undefined {
|
||||
if (task === undefined || task === null || (!CustomTask.is(task) && !ContributedTask.is(task))) {
|
||||
export function from(task: Task | ConfiguringTask): TaskDTO | undefined {
|
||||
if (task === undefined || task === null || (!CustomTask.is(task) && !ContributedTask.is(task) && !ConfiguringTask.is(task))) {
|
||||
return undefined;
|
||||
}
|
||||
const result: TaskDTO = {
|
||||
@@ -314,7 +334,7 @@ namespace TaskDTO {
|
||||
definition: TaskDefinitionDTO.from(task.getDefinition()),
|
||||
source: TaskSourceDTO.from(task._source),
|
||||
execution: undefined,
|
||||
presentationOptions: task.command ? TaskPresentationOptionsDTO.from(task.command.presentation) : undefined,
|
||||
presentationOptions: !ConfiguringTask.is(task) && task.command ? TaskPresentationOptionsDTO.from(task.command.presentation) : undefined,
|
||||
isBackground: task.configurationProperties.isBackground,
|
||||
problemMatchers: [],
|
||||
hasDefinedMatchers: ContributedTask.is(task) ? task.hasDefinedMatchers : false,
|
||||
@@ -323,7 +343,7 @@ namespace TaskDTO {
|
||||
if (task.configurationProperties.group) {
|
||||
result.group = task.configurationProperties.group;
|
||||
}
|
||||
if (task.command) {
|
||||
if (!ConfiguringTask.is(task) && task.command) {
|
||||
if (task.command.runtime === RuntimeType.Process) {
|
||||
result.execution = ProcessExecutionDTO.from(task.command);
|
||||
} else if (task.command.runtime === RuntimeType.Shell) {
|
||||
@@ -353,6 +373,8 @@ namespace TaskDTO {
|
||||
command = ProcessExecutionDTO.to(task.execution);
|
||||
} else if (CustomExecutionDTO.is(task.execution)) {
|
||||
command = CustomExecutionDTO.to(task.execution);
|
||||
} else if (CustomExecution2DTO.is(task.execution)) {
|
||||
command = CustomExecution2DTO.to(task.execution);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -442,7 +464,7 @@ export class MainThreadTask implements MainThreadTaskShape {
|
||||
});
|
||||
}
|
||||
|
||||
public $registerTaskProvider(handle: number): Promise<void> {
|
||||
public $registerTaskProvider(handle: number, type: string): Promise<void> {
|
||||
const provider: ITaskProvider = {
|
||||
provideTasks: (validTypes: IStringDictionary<boolean>) => {
|
||||
return Promise.resolve(this._proxy.$provideTasks(handle, validTypes)).then((value) => {
|
||||
@@ -460,9 +482,24 @@ export class MainThreadTask implements MainThreadTaskShape {
|
||||
extension: value.extension
|
||||
} as TaskSet;
|
||||
});
|
||||
},
|
||||
resolveTask: (task: ConfiguringTask) => {
|
||||
const dto = TaskDTO.from(task);
|
||||
|
||||
if (dto) {
|
||||
dto.name = ((dto.name === undefined) ? '' : dto.name); // Using an empty name causes the name to default to the one given by the provider.
|
||||
return Promise.resolve(this._proxy.$resolveTask(handle, dto)).then(resolvedTask => {
|
||||
if (resolvedTask) {
|
||||
return TaskDTO.to(resolvedTask, this._workspaceContextServer, true);
|
||||
}
|
||||
|
||||
return undefined;
|
||||
});
|
||||
}
|
||||
return Promise.resolve<ContributedTask | undefined>(undefined);
|
||||
}
|
||||
};
|
||||
const disposable = this._taskService.registerTaskProvider(provider);
|
||||
const disposable = this._taskService.registerTaskProvider(provider, type);
|
||||
this._providers.set(handle, { disposable, provider });
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { MainThreadTelemetryShape, MainContext, IExtHostContext } from '../common/extHost.protocol';
|
||||
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
|
||||
import { ClassifiedEvent, StrictPropertyCheck, GDPRClassification } from 'vs/platform/telemetry/common/gdprTypings';
|
||||
|
||||
@extHostNamedCustomer(MainContext.MainThreadTelemetry)
|
||||
export class MainThreadTelemetry implements MainThreadTelemetryShape {
|
||||
@@ -28,4 +29,10 @@ export class MainThreadTelemetry implements MainThreadTelemetryShape {
|
||||
data[MainThreadTelemetry._name] = true;
|
||||
this._telemetryService.publicLog(eventName, data);
|
||||
}
|
||||
|
||||
$publicLog2<E extends ClassifiedEvent<T> = never, T extends GDPRClassification<T> = never>(eventName: string, data: StrictPropertyCheck<T, E>): void {
|
||||
this.$publicLog(eventName, data as any);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -3,30 +3,37 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
|
||||
import { ITerminalService, ITerminalInstance, IShellLaunchConfig, ITerminalProcessExtHostProxy, ITerminalProcessExtHostRequest, ITerminalDimensions, EXT_HOST_CREATION_DELAY } from 'vs/workbench/contrib/terminal/common/terminal';
|
||||
import { ExtHostContext, ExtHostTerminalServiceShape, MainThreadTerminalServiceShape, MainContext, IExtHostContext, ShellLaunchConfigDto } from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { IDisposable, DisposableStore } from 'vs/base/common/lifecycle';
|
||||
import { ITerminalService, ITerminalInstance, IShellLaunchConfig, ITerminalProcessExtHostProxy, ITerminalProcessExtHostRequest, ITerminalDimensions, EXT_HOST_CREATION_DELAY, IAvailableShellsRequest, IDefaultShellAndArgsRequest, ITerminalVirtualProcessRequest } from 'vs/workbench/contrib/terminal/common/terminal';
|
||||
import { ExtHostContext, ExtHostTerminalServiceShape, MainThreadTerminalServiceShape, MainContext, IExtHostContext, ShellLaunchConfigDto, TerminalLaunchConfig, ITerminalDimensionsDto } from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
|
||||
import { UriComponents, URI } from 'vs/base/common/uri';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { StopWatch } from 'vs/base/common/stopwatch';
|
||||
import { ITerminalInstanceService } from 'vs/workbench/contrib/terminal/browser/terminal';
|
||||
import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService';
|
||||
|
||||
@extHostNamedCustomer(MainContext.MainThreadTerminalService)
|
||||
export class MainThreadTerminalService implements MainThreadTerminalServiceShape {
|
||||
|
||||
private _proxy: ExtHostTerminalServiceShape;
|
||||
private _remoteAuthority: string | null;
|
||||
private _toDispose: IDisposable[] = [];
|
||||
private _terminalProcesses: { [id: number]: ITerminalProcessExtHostProxy } = {};
|
||||
private _terminalOnDidWriteDataListeners: { [id: number]: IDisposable } = {};
|
||||
private _terminalOnDidAcceptInputListeners: { [id: number]: IDisposable } = {};
|
||||
private readonly _toDispose = new DisposableStore();
|
||||
private readonly _terminalProcesses = new Map<number, Promise<ITerminalProcessExtHostProxy>>();
|
||||
private readonly _terminalProcessesReady = new Map<number, (proxy: ITerminalProcessExtHostProxy) => void>();
|
||||
private readonly _terminalOnDidWriteDataListeners = new Map<number, IDisposable>();
|
||||
private readonly _terminalOnDidAcceptInputListeners = new Map<number, IDisposable>();
|
||||
|
||||
constructor(
|
||||
extHostContext: IExtHostContext,
|
||||
@ITerminalService private readonly terminalService: ITerminalService
|
||||
@ITerminalService private readonly _terminalService: ITerminalService,
|
||||
@ITerminalInstanceService readonly terminalInstanceService: ITerminalInstanceService,
|
||||
@IRemoteAgentService readonly _remoteAgentService: IRemoteAgentService
|
||||
) {
|
||||
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostTerminalService);
|
||||
this._remoteAuthority = extHostContext.remoteAuthority;
|
||||
this._toDispose.push(terminalService.onInstanceCreated((instance) => {
|
||||
|
||||
// ITerminalService listeners
|
||||
this._toDispose.add(_terminalService.onInstanceCreated((instance) => {
|
||||
// Delay this message so the TerminalInstance constructor has a chance to finish and
|
||||
// return the ID normally to the extension host. The ID that is passed here will be used
|
||||
// to register non-extension API terminals in the extension host.
|
||||
@@ -35,45 +42,58 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape
|
||||
this._onInstanceDimensionsChanged(instance);
|
||||
}, EXT_HOST_CREATION_DELAY);
|
||||
}));
|
||||
this._toDispose.push(terminalService.onInstanceDisposed(instance => this._onTerminalDisposed(instance)));
|
||||
this._toDispose.push(terminalService.onInstanceProcessIdReady(instance => this._onTerminalProcessIdReady(instance)));
|
||||
this._toDispose.push(terminalService.onInstanceDimensionsChanged(instance => this._onInstanceDimensionsChanged(instance)));
|
||||
this._toDispose.push(terminalService.onInstanceRequestExtHostProcess(request => this._onTerminalRequestExtHostProcess(request)));
|
||||
this._toDispose.push(terminalService.onActiveInstanceChanged(instance => this._onActiveTerminalChanged(instance ? instance.id : null)));
|
||||
this._toDispose.push(terminalService.onInstanceTitleChanged(instance => this._onTitleChanged(instance.id, instance.title)));
|
||||
|
||||
this._toDispose.add(_terminalService.onInstanceDisposed(instance => this._onTerminalDisposed(instance)));
|
||||
this._toDispose.add(_terminalService.onInstanceProcessIdReady(instance => this._onTerminalProcessIdReady(instance)));
|
||||
this._toDispose.add(_terminalService.onInstanceDimensionsChanged(instance => this._onInstanceDimensionsChanged(instance)));
|
||||
this._toDispose.add(_terminalService.onInstanceMaximumDimensionsChanged(instance => this._onInstanceMaximumDimensionsChanged(instance)));
|
||||
this._toDispose.add(_terminalService.onInstanceRequestExtHostProcess(request => this._onTerminalRequestExtHostProcess(request)));
|
||||
this._toDispose.add(_terminalService.onInstanceRequestVirtualProcess(e => this._onTerminalRequestVirtualProcess(e)));
|
||||
this._toDispose.add(_terminalService.onActiveInstanceChanged(instance => this._onActiveTerminalChanged(instance ? instance.id : null)));
|
||||
this._toDispose.add(_terminalService.onInstanceTitleChanged(instance => this._onTitleChanged(instance.id, instance.title)));
|
||||
this._toDispose.add(_terminalService.configHelper.onWorkspacePermissionsChanged(isAllowed => this._onWorkspacePermissionsChanged(isAllowed)));
|
||||
this._toDispose.add(_terminalService.onRequestAvailableShells(e => this._onRequestAvailableShells(e)));
|
||||
|
||||
// ITerminalInstanceService listeners
|
||||
if (terminalInstanceService.onRequestDefaultShellAndArgs) {
|
||||
this._toDispose.add(terminalInstanceService.onRequestDefaultShellAndArgs(e => this._onRequestDefaultShellAndArgs(e)));
|
||||
}
|
||||
|
||||
// Set initial ext host state
|
||||
this.terminalService.terminalInstances.forEach(t => {
|
||||
this._terminalService.terminalInstances.forEach(t => {
|
||||
this._onTerminalOpened(t);
|
||||
t.processReady.then(() => this._onTerminalProcessIdReady(t));
|
||||
});
|
||||
const activeInstance = this.terminalService.getActiveInstance();
|
||||
const activeInstance = this._terminalService.getActiveInstance();
|
||||
if (activeInstance) {
|
||||
this._proxy.$acceptActiveTerminalChanged(activeInstance.id);
|
||||
}
|
||||
|
||||
this.terminalService.extHostReady(extHostContext.remoteAuthority);
|
||||
this._terminalService.extHostReady(extHostContext.remoteAuthority);
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
this._toDispose = dispose(this._toDispose);
|
||||
this._toDispose.dispose();
|
||||
|
||||
// TODO@Daniel: Should all the previously created terminals be disposed
|
||||
// when the extension host process goes down ?
|
||||
}
|
||||
|
||||
public $createTerminal(name?: string, shellPath?: string, shellArgs?: string[] | string, cwd?: string | UriComponents, env?: { [key: string]: string }, waitOnExit?: boolean, strictEnv?: boolean): Promise<{ id: number, name: string }> {
|
||||
public $createTerminal(launchConfig: TerminalLaunchConfig): Promise<{ id: number, name: string }> {
|
||||
const shellLaunchConfig: IShellLaunchConfig = {
|
||||
name,
|
||||
executable: shellPath,
|
||||
args: shellArgs,
|
||||
cwd: typeof cwd === 'string' ? cwd : URI.revive(cwd),
|
||||
waitOnExit,
|
||||
name: launchConfig.name,
|
||||
executable: launchConfig.shellPath,
|
||||
args: launchConfig.shellArgs,
|
||||
cwd: typeof launchConfig.cwd === 'string' ? launchConfig.cwd : URI.revive(launchConfig.cwd),
|
||||
waitOnExit: launchConfig.waitOnExit,
|
||||
ignoreConfigurationCwd: true,
|
||||
env,
|
||||
strictEnv
|
||||
env: launchConfig.env,
|
||||
strictEnv: launchConfig.strictEnv,
|
||||
hideFromUser: launchConfig.hideFromUser,
|
||||
isVirtualProcess: launchConfig.isVirtualProcess
|
||||
};
|
||||
const terminal = this.terminalService.createTerminal(shellLaunchConfig);
|
||||
const terminal = this._terminalService.createTerminal(shellLaunchConfig);
|
||||
this._terminalProcesses.set(terminal.id, new Promise<ITerminalProcessExtHostProxy>(r => this._terminalProcessesReady.set(terminal.id, r)));
|
||||
return Promise.resolve({
|
||||
id: terminal.id,
|
||||
name: terminal.title
|
||||
@@ -81,92 +101,94 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape
|
||||
}
|
||||
|
||||
public $createTerminalRenderer(name: string): Promise<number> {
|
||||
const instance = this.terminalService.createTerminalRenderer(name);
|
||||
const instance = this._terminalService.createTerminalRenderer(name);
|
||||
return Promise.resolve(instance.id);
|
||||
}
|
||||
|
||||
public $show(terminalId: number, preserveFocus: boolean): void {
|
||||
const terminalInstance = this.terminalService.getInstanceFromId(terminalId);
|
||||
const terminalInstance = this._terminalService.getInstanceFromId(terminalId);
|
||||
if (terminalInstance) {
|
||||
this.terminalService.setActiveInstance(terminalInstance);
|
||||
this.terminalService.showPanel(!preserveFocus);
|
||||
this._terminalService.setActiveInstance(terminalInstance);
|
||||
this._terminalService.showPanel(!preserveFocus);
|
||||
}
|
||||
}
|
||||
|
||||
public $hide(terminalId: number): void {
|
||||
const instance = this.terminalService.getActiveInstance();
|
||||
const instance = this._terminalService.getActiveInstance();
|
||||
if (instance && instance.id === terminalId) {
|
||||
this.terminalService.hidePanel();
|
||||
this._terminalService.hidePanel();
|
||||
}
|
||||
}
|
||||
|
||||
public $dispose(terminalId: number): void {
|
||||
const terminalInstance = this.terminalService.getInstanceFromId(terminalId);
|
||||
const terminalInstance = this._terminalService.getInstanceFromId(terminalId);
|
||||
if (terminalInstance) {
|
||||
terminalInstance.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
public $terminalRendererWrite(terminalId: number, text: string): void {
|
||||
const terminalInstance = this.terminalService.getInstanceFromId(terminalId);
|
||||
const terminalInstance = this._terminalService.getInstanceFromId(terminalId);
|
||||
if (terminalInstance && terminalInstance.shellLaunchConfig.isRendererOnly) {
|
||||
terminalInstance.write(text);
|
||||
}
|
||||
}
|
||||
|
||||
public $terminalRendererSetName(terminalId: number, name: string): void {
|
||||
const terminalInstance = this.terminalService.getInstanceFromId(terminalId);
|
||||
const terminalInstance = this._terminalService.getInstanceFromId(terminalId);
|
||||
if (terminalInstance && terminalInstance.shellLaunchConfig.isRendererOnly) {
|
||||
terminalInstance.setTitle(name, false);
|
||||
}
|
||||
}
|
||||
|
||||
public $terminalRendererSetDimensions(terminalId: number, dimensions: ITerminalDimensions): void {
|
||||
const terminalInstance = this.terminalService.getInstanceFromId(terminalId);
|
||||
const terminalInstance = this._terminalService.getInstanceFromId(terminalId);
|
||||
if (terminalInstance && terminalInstance.shellLaunchConfig.isRendererOnly) {
|
||||
terminalInstance.setDimensions(dimensions);
|
||||
}
|
||||
}
|
||||
|
||||
public $terminalRendererRegisterOnInputListener(terminalId: number): void {
|
||||
const terminalInstance = this.terminalService.getInstanceFromId(terminalId);
|
||||
const terminalInstance = this._terminalService.getInstanceFromId(terminalId);
|
||||
if (!terminalInstance) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Listener already registered
|
||||
if (this._terminalOnDidAcceptInputListeners.hasOwnProperty(terminalId)) {
|
||||
if (this._terminalOnDidAcceptInputListeners.has(terminalId)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Register
|
||||
this._terminalOnDidAcceptInputListeners[terminalId] = terminalInstance.onRendererInput(data => this._onTerminalRendererInput(terminalId, data));
|
||||
terminalInstance.addDisposable(this._terminalOnDidAcceptInputListeners[terminalId]);
|
||||
const listener = terminalInstance.onRendererInput(data => this._onTerminalRendererInput(terminalId, data));
|
||||
this._terminalOnDidAcceptInputListeners.set(terminalId, listener);
|
||||
terminalInstance.addDisposable(listener);
|
||||
}
|
||||
|
||||
public $sendText(terminalId: number, text: string, addNewLine: boolean): void {
|
||||
const terminalInstance = this.terminalService.getInstanceFromId(terminalId);
|
||||
const terminalInstance = this._terminalService.getInstanceFromId(terminalId);
|
||||
if (terminalInstance) {
|
||||
terminalInstance.sendText(text, addNewLine);
|
||||
}
|
||||
}
|
||||
|
||||
public $registerOnDataListener(terminalId: number): void {
|
||||
const terminalInstance = this.terminalService.getInstanceFromId(terminalId);
|
||||
const terminalInstance = this._terminalService.getInstanceFromId(terminalId);
|
||||
if (!terminalInstance) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Listener already registered
|
||||
if (this._terminalOnDidWriteDataListeners[terminalId]) {
|
||||
if (this._terminalOnDidWriteDataListeners.has(terminalId)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Register
|
||||
this._terminalOnDidWriteDataListeners[terminalId] = terminalInstance.onData(data => {
|
||||
const listener = terminalInstance.onData(data => {
|
||||
this._onTerminalData(terminalId, data);
|
||||
});
|
||||
terminalInstance.addDisposable(this._terminalOnDidWriteDataListeners[terminalId]);
|
||||
this._terminalOnDidWriteDataListeners.set(terminalId, listener);
|
||||
terminalInstance.addDisposable(listener);
|
||||
}
|
||||
|
||||
private _onActiveTerminalChanged(terminalId: number | null): void {
|
||||
@@ -181,6 +203,10 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape
|
||||
this._proxy.$acceptTerminalTitleChange(terminalId, name);
|
||||
}
|
||||
|
||||
private _onWorkspacePermissionsChanged(isAllowed: boolean): void {
|
||||
this._proxy.$acceptWorkspacePermissionsChanged(isAllowed);
|
||||
}
|
||||
|
||||
private _onTerminalRendererInput(terminalId: number, data: string): void {
|
||||
this._proxy.$acceptTerminalRendererInput(terminalId, data);
|
||||
}
|
||||
@@ -210,13 +236,24 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape
|
||||
this._proxy.$acceptTerminalDimensions(instance.id, instance.cols, instance.rows);
|
||||
}
|
||||
|
||||
private _onInstanceMaximumDimensionsChanged(instance: ITerminalInstance): void {
|
||||
this._proxy.$acceptTerminalMaximumDimensions(instance.id, instance.maxCols, instance.maxRows);
|
||||
}
|
||||
|
||||
private _onTerminalRequestExtHostProcess(request: ITerminalProcessExtHostRequest): void {
|
||||
// Only allow processes on remote ext hosts
|
||||
if (!this._remoteAuthority) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._terminalProcesses[request.proxy.terminalId] = request.proxy;
|
||||
const proxy = request.proxy;
|
||||
const ready = this._terminalProcessesReady.get(proxy.terminalId);
|
||||
if (ready) {
|
||||
ready(proxy);
|
||||
this._terminalProcessesReady.delete(proxy.terminalId);
|
||||
} else {
|
||||
this._terminalProcesses.set(proxy.terminalId, Promise.resolve(proxy));
|
||||
}
|
||||
const shellLaunchConfigDto: ShellLaunchConfigDto = {
|
||||
name: request.shellLaunchConfig.name,
|
||||
executable: request.shellLaunchConfig.executable,
|
||||
@@ -224,38 +261,66 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape
|
||||
cwd: request.shellLaunchConfig.cwd,
|
||||
env: request.shellLaunchConfig.env
|
||||
};
|
||||
this._proxy.$createProcess(request.proxy.terminalId, shellLaunchConfigDto, request.activeWorkspaceRootUri, request.cols, request.rows, request.isWorkspaceShellAllowed);
|
||||
request.proxy.onInput(data => this._proxy.$acceptProcessInput(request.proxy.terminalId, data));
|
||||
request.proxy.onResize(dimensions => this._proxy.$acceptProcessResize(request.proxy.terminalId, dimensions.cols, dimensions.rows));
|
||||
request.proxy.onShutdown(immediate => this._proxy.$acceptProcessShutdown(request.proxy.terminalId, immediate));
|
||||
request.proxy.onRequestCwd(() => this._proxy.$acceptProcessRequestCwd(request.proxy.terminalId));
|
||||
request.proxy.onRequestInitialCwd(() => this._proxy.$acceptProcessRequestInitialCwd(request.proxy.terminalId));
|
||||
request.proxy.onRequestLatency(() => this._onRequestLatency(request.proxy.terminalId));
|
||||
this._proxy.$createProcess(proxy.terminalId, shellLaunchConfigDto, request.activeWorkspaceRootUri, request.cols, request.rows, request.isWorkspaceShellAllowed);
|
||||
proxy.onInput(data => this._proxy.$acceptProcessInput(proxy.terminalId, data));
|
||||
proxy.onResize(dimensions => this._proxy.$acceptProcessResize(proxy.terminalId, dimensions.cols, dimensions.rows));
|
||||
proxy.onShutdown(immediate => this._proxy.$acceptProcessShutdown(proxy.terminalId, immediate));
|
||||
proxy.onRequestCwd(() => this._proxy.$acceptProcessRequestCwd(proxy.terminalId));
|
||||
proxy.onRequestInitialCwd(() => this._proxy.$acceptProcessRequestInitialCwd(proxy.terminalId));
|
||||
proxy.onRequestLatency(() => this._onRequestLatency(proxy.terminalId));
|
||||
}
|
||||
|
||||
private _onTerminalRequestVirtualProcess(request: ITerminalVirtualProcessRequest): void {
|
||||
const proxy = request.proxy;
|
||||
const ready = this._terminalProcessesReady.get(proxy.terminalId);
|
||||
if (!ready) {
|
||||
this._terminalProcesses.set(proxy.terminalId, Promise.resolve(proxy));
|
||||
} else {
|
||||
ready(proxy);
|
||||
this._terminalProcessesReady.delete(proxy.terminalId);
|
||||
}
|
||||
|
||||
// Note that onReisze is not being listened to here as it needs to fire when max dimensions
|
||||
// change, excluding the dimension override
|
||||
const initialDimensions: ITerminalDimensionsDto | undefined = request.cols && request.rows ? {
|
||||
columns: request.cols,
|
||||
rows: request.rows
|
||||
} : undefined;
|
||||
this._proxy.$startVirtualProcess(proxy.terminalId, initialDimensions);
|
||||
proxy.onInput(data => this._proxy.$acceptProcessInput(proxy.terminalId, data));
|
||||
proxy.onShutdown(immediate => this._proxy.$acceptProcessShutdown(proxy.terminalId, immediate));
|
||||
proxy.onRequestCwd(() => this._proxy.$acceptProcessRequestCwd(proxy.terminalId));
|
||||
proxy.onRequestInitialCwd(() => this._proxy.$acceptProcessRequestInitialCwd(proxy.terminalId));
|
||||
proxy.onRequestLatency(() => this._onRequestLatency(proxy.terminalId));
|
||||
}
|
||||
|
||||
public $sendProcessTitle(terminalId: number, title: string): void {
|
||||
this._terminalProcesses[terminalId].emitTitle(title);
|
||||
this._getTerminalProcess(terminalId).then(e => e.emitTitle(title));
|
||||
}
|
||||
|
||||
public $sendProcessData(terminalId: number, data: string): void {
|
||||
this._terminalProcesses[terminalId].emitData(data);
|
||||
this._getTerminalProcess(terminalId).then(e => e.emitData(data));
|
||||
}
|
||||
|
||||
public $sendProcessPid(terminalId: number, pid: number): void {
|
||||
this._terminalProcesses[terminalId].emitPid(pid);
|
||||
public $sendProcessReady(terminalId: number, pid: number, cwd: string): void {
|
||||
this._getTerminalProcess(terminalId).then(e => e.emitReady(pid, cwd));
|
||||
}
|
||||
|
||||
public $sendProcessExit(terminalId: number, exitCode: number): void {
|
||||
this._terminalProcesses[terminalId].emitExit(exitCode);
|
||||
delete this._terminalProcesses[terminalId];
|
||||
this._getTerminalProcess(terminalId).then(e => e.emitExit(exitCode));
|
||||
this._terminalProcesses.delete(terminalId);
|
||||
}
|
||||
|
||||
public $sendOverrideDimensions(terminalId: number, dimensions: ITerminalDimensions | undefined): void {
|
||||
this._getTerminalProcess(terminalId).then(e => e.emitOverrideDimensions(dimensions));
|
||||
}
|
||||
|
||||
public $sendProcessInitialCwd(terminalId: number, initialCwd: string): void {
|
||||
this._terminalProcesses[terminalId].emitInitialCwd(initialCwd);
|
||||
this._getTerminalProcess(terminalId).then(e => e.emitInitialCwd(initialCwd));
|
||||
}
|
||||
|
||||
public $sendProcessCwd(terminalId: number, cwd: string): void {
|
||||
this._terminalProcesses[terminalId].emitCwd(cwd);
|
||||
this._getTerminalProcess(terminalId).then(e => e.emitCwd(cwd));
|
||||
}
|
||||
|
||||
private async _onRequestLatency(terminalId: number): Promise<void> {
|
||||
@@ -267,6 +332,35 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape
|
||||
sw.stop();
|
||||
sum += sw.elapsed();
|
||||
}
|
||||
this._terminalProcesses[terminalId].emitLatency(sum / COUNT);
|
||||
this._getTerminalProcess(terminalId).then(e => e.emitLatency(sum / COUNT));
|
||||
}
|
||||
|
||||
private _isPrimaryExtHost(): boolean {
|
||||
// The "primary" ext host is the remote ext host if there is one, otherwise the local
|
||||
const conn = this._remoteAgentService.getConnection();
|
||||
if (conn) {
|
||||
return this._remoteAuthority === conn.remoteAuthority;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private _onRequestAvailableShells(request: IAvailableShellsRequest): void {
|
||||
if (this._isPrimaryExtHost()) {
|
||||
this._proxy.$requestAvailableShells().then(e => request(e));
|
||||
}
|
||||
}
|
||||
|
||||
private _onRequestDefaultShellAndArgs(request: IDefaultShellAndArgsRequest): void {
|
||||
if (this._isPrimaryExtHost()) {
|
||||
this._proxy.$requestDefaultShellAndArgs().then(e => request(e.shell, e.args));
|
||||
}
|
||||
}
|
||||
|
||||
private _getTerminalProcess(terminalId: number): Promise<ITerminalProcessExtHostProxy> {
|
||||
const terminal = this._terminalProcesses.get(terminalId);
|
||||
if (!terminal) {
|
||||
throw new Error(`Unknown terminal: ${terminalId}`);
|
||||
}
|
||||
return terminal;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -81,7 +81,10 @@ export class MainThreadTreeViews extends Disposable implements MainThreadTreeVie
|
||||
await treeView.refresh();
|
||||
}
|
||||
for (const parent of parentChain) {
|
||||
await treeView.expand(parent);
|
||||
const parentItem = dataProvider.getItem(parent.handle);
|
||||
if (parentItem) {
|
||||
await treeView.expand(parentItem);
|
||||
}
|
||||
}
|
||||
const item = dataProvider.getItem(itemIn.handle);
|
||||
if (item) {
|
||||
@@ -205,7 +208,7 @@ export class TreeViewDataProvider implements ITreeViewDataProvider {
|
||||
if (current) {
|
||||
const properties = distinct([...Object.keys(current), ...Object.keys(treeItem)]);
|
||||
for (const property of properties) {
|
||||
current[property] = treeItem[property];
|
||||
(<any>current)[property] = (<any>treeItem)[property];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
368
src/vs/workbench/api/browser/mainThreadWebview.ts
Normal file
368
src/vs/workbench/api/browser/mainThreadWebview.ts
Normal file
@@ -0,0 +1,368 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { onUnexpectedError } from 'vs/base/common/errors';
|
||||
import { Disposable, IDisposable } from 'vs/base/common/lifecycle';
|
||||
import * as map from 'vs/base/common/map';
|
||||
import { URI, UriComponents } from 'vs/base/common/uri';
|
||||
import * as modes from 'vs/editor/common/modes';
|
||||
import { localize } from 'vs/nls';
|
||||
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
|
||||
import { IOpenerService } from 'vs/platform/opener/common/opener';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { ExtHostContext, ExtHostWebviewsShape, IExtHostContext, MainContext, MainThreadWebviewsShape, WebviewPanelHandle, WebviewPanelShowOptions } from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { editorGroupToViewColumn, EditorViewColumn, viewColumnToEditorGroup } from 'vs/workbench/api/common/shared/editor';
|
||||
import { WebviewEditor } from 'vs/workbench/contrib/webview/browser/webviewEditor';
|
||||
import { WebviewEditorInput } from 'vs/workbench/contrib/webview/browser/webviewEditorInput';
|
||||
import { ICreateWebViewShowOptions, IWebviewEditorService, WebviewInputOptions } from 'vs/workbench/contrib/webview/browser/webviewEditorService';
|
||||
import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
|
||||
import { ACTIVE_GROUP, IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { extHostNamedCustomer } from '../common/extHostCustomers';
|
||||
import { IProductService } from 'vs/platform/product/common/product';
|
||||
|
||||
interface MainThreadWebviewState {
|
||||
readonly viewType: string;
|
||||
state: any;
|
||||
}
|
||||
|
||||
@extHostNamedCustomer(MainContext.MainThreadWebviews)
|
||||
export class MainThreadWebviews extends Disposable implements MainThreadWebviewsShape {
|
||||
|
||||
private static readonly standardSupportedLinkSchemes = new Set([
|
||||
'http',
|
||||
'https',
|
||||
'mailto',
|
||||
'vscode',
|
||||
'vscode-insider',
|
||||
]);
|
||||
|
||||
private static revivalPool = 0;
|
||||
|
||||
|
||||
private readonly _proxy: ExtHostWebviewsShape;
|
||||
private readonly _webviews = new Map<WebviewPanelHandle, WebviewEditorInput<MainThreadWebviewState>>();
|
||||
private readonly _revivers = new Map<string, IDisposable>();
|
||||
|
||||
private _activeWebview: WebviewPanelHandle | undefined = undefined;
|
||||
|
||||
constructor(
|
||||
context: IExtHostContext,
|
||||
@IExtensionService extensionService: IExtensionService,
|
||||
@IEditorGroupsService private readonly _editorGroupService: IEditorGroupsService,
|
||||
@IEditorService private readonly _editorService: IEditorService,
|
||||
@IWebviewEditorService private readonly _webviewEditorService: IWebviewEditorService,
|
||||
@IOpenerService private readonly _openerService: IOpenerService,
|
||||
@ITelemetryService private readonly _telemetryService: ITelemetryService,
|
||||
@IProductService private readonly _productService: IProductService,
|
||||
) {
|
||||
super();
|
||||
|
||||
this._proxy = context.getProxy(ExtHostContext.ExtHostWebviews);
|
||||
this._register(_editorService.onDidActiveEditorChange(this.onActiveEditorChanged, this));
|
||||
this._register(_editorService.onDidVisibleEditorsChange(this.onVisibleEditorsChanged, this));
|
||||
|
||||
// This reviver's only job is to activate webview extensions
|
||||
// This should trigger the real reviver to be registered from the extension host side.
|
||||
this._register(_webviewEditorService.registerReviver({
|
||||
canRevive: (webview: WebviewEditorInput<any>) => {
|
||||
const viewType = webview.state && webview.state.viewType;
|
||||
if (typeof viewType === 'string') {
|
||||
extensionService.activateByEvent(`onWebviewPanel:${viewType}`);
|
||||
}
|
||||
return false;
|
||||
},
|
||||
reviveWebview: () => { throw new Error('not implemented'); }
|
||||
}));
|
||||
}
|
||||
|
||||
public $createWebviewPanel(
|
||||
handle: WebviewPanelHandle,
|
||||
viewType: string,
|
||||
title: string,
|
||||
showOptions: { viewColumn?: EditorViewColumn, preserveFocus?: boolean },
|
||||
options: WebviewInputOptions,
|
||||
extensionId: ExtensionIdentifier,
|
||||
extensionLocation: UriComponents
|
||||
): void {
|
||||
const mainThreadShowOptions: ICreateWebViewShowOptions = Object.create(null);
|
||||
if (showOptions) {
|
||||
mainThreadShowOptions.preserveFocus = !!showOptions.preserveFocus;
|
||||
mainThreadShowOptions.group = viewColumnToEditorGroup(this._editorGroupService, showOptions.viewColumn);
|
||||
}
|
||||
|
||||
const webview = this._webviewEditorService.createWebview(handle, this.getInternalWebviewViewType(viewType), title, mainThreadShowOptions, reviveWebviewOptions(options), {
|
||||
location: URI.revive(extensionLocation),
|
||||
id: extensionId
|
||||
}, this.createWebviewEventDelegate(handle)) as WebviewEditorInput<MainThreadWebviewState>;
|
||||
webview.state = {
|
||||
viewType: viewType,
|
||||
state: undefined
|
||||
};
|
||||
|
||||
this._webviews.set(handle, webview);
|
||||
|
||||
/* __GDPR__
|
||||
"webviews:createWebviewPanel" : {
|
||||
"extensionId" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
|
||||
}
|
||||
*/
|
||||
this._telemetryService.publicLog('webviews:createWebviewPanel', { extensionId: extensionId.value });
|
||||
}
|
||||
|
||||
public $disposeWebview(handle: WebviewPanelHandle): void {
|
||||
const webview = this.getWebview(handle);
|
||||
webview.dispose();
|
||||
}
|
||||
|
||||
public $setTitle(handle: WebviewPanelHandle, value: string): void {
|
||||
const webview = this.getWebview(handle);
|
||||
webview.setName(value);
|
||||
}
|
||||
|
||||
public $setIconPath(handle: WebviewPanelHandle, value: { light: UriComponents, dark: UriComponents } | undefined): void {
|
||||
const webview = this.getWebview(handle);
|
||||
webview.iconPath = reviveWebviewIcon(value);
|
||||
}
|
||||
|
||||
public $setHtml(handle: WebviewPanelHandle, value: string): void {
|
||||
const webview = this.getWebview(handle);
|
||||
webview.html = value;
|
||||
}
|
||||
|
||||
public $setOptions(handle: WebviewPanelHandle, options: modes.IWebviewOptions): void {
|
||||
const webview = this.getWebview(handle);
|
||||
webview.setOptions(reviveWebviewOptions(options as any /*todo@mat */));
|
||||
}
|
||||
|
||||
public $reveal(handle: WebviewPanelHandle, showOptions: WebviewPanelShowOptions): void {
|
||||
const webview = this.getWebview(handle);
|
||||
if (webview.isDisposed()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const targetGroup = this._editorGroupService.getGroup(viewColumnToEditorGroup(this._editorGroupService, showOptions.viewColumn)) || this._editorGroupService.getGroup(webview.group || 0);
|
||||
if (targetGroup) {
|
||||
this._webviewEditorService.revealWebview(webview, targetGroup, !!showOptions.preserveFocus);
|
||||
}
|
||||
}
|
||||
|
||||
public async $postMessage(handle: WebviewPanelHandle, message: any): Promise<boolean> {
|
||||
const webview = this.getWebview(handle);
|
||||
const editors = this._editorService.visibleControls
|
||||
.filter(e => e instanceof WebviewEditor)
|
||||
.map(e => e as WebviewEditor)
|
||||
.filter(e => e.input!.matches(webview));
|
||||
|
||||
if (editors.length > 0) {
|
||||
editors[0].sendMessage(message);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (webview.webview) {
|
||||
webview.webview.sendMessage(message);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public $registerSerializer(viewType: string): void {
|
||||
if (this._revivers.has(viewType)) {
|
||||
throw new Error(`Reviver for ${viewType} already registered`);
|
||||
}
|
||||
|
||||
this._revivers.set(viewType, this._webviewEditorService.registerReviver({
|
||||
canRevive: (webview) => {
|
||||
return webview.state && webview.state.viewType === viewType;
|
||||
},
|
||||
reviveWebview: async (webview): Promise<void> => {
|
||||
const viewType = webview.state.viewType;
|
||||
const handle = 'revival-' + MainThreadWebviews.revivalPool++;
|
||||
this._webviews.set(handle, webview);
|
||||
webview._events = this.createWebviewEventDelegate(handle);
|
||||
let state = undefined;
|
||||
if (webview.state.state) {
|
||||
try {
|
||||
state = JSON.parse(webview.state.state);
|
||||
} catch {
|
||||
// noop
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
await this._proxy.$deserializeWebviewPanel(handle, viewType, webview.getTitle(), state, editorGroupToViewColumn(this._editorGroupService, webview.group || 0), webview.options);
|
||||
} catch (error) {
|
||||
onUnexpectedError(error);
|
||||
webview.html = MainThreadWebviews.getDeserializationFailedContents(viewType);
|
||||
}
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
public $unregisterSerializer(viewType: string): void {
|
||||
const reviver = this._revivers.get(viewType);
|
||||
if (!reviver) {
|
||||
throw new Error(`No reviver for ${viewType} registered`);
|
||||
}
|
||||
|
||||
reviver.dispose();
|
||||
this._revivers.delete(viewType);
|
||||
}
|
||||
|
||||
private getInternalWebviewViewType(viewType: string): string {
|
||||
return `mainThreadWebview-${viewType}`;
|
||||
}
|
||||
|
||||
private createWebviewEventDelegate(handle: WebviewPanelHandle) {
|
||||
return {
|
||||
onDidClickLink: (uri: URI) => this.onDidClickLink(handle, uri),
|
||||
onMessage: (message: any) => this._proxy.$onMessage(handle, message),
|
||||
onDispose: () => {
|
||||
this._proxy.$onDidDisposeWebviewPanel(handle).finally(() => {
|
||||
this._webviews.delete(handle);
|
||||
});
|
||||
},
|
||||
onDidUpdateWebviewState: (newState: any) => {
|
||||
const webview = this.tryGetWebview(handle);
|
||||
if (!webview || webview.isDisposed()) {
|
||||
return;
|
||||
}
|
||||
(webview as WebviewEditorInput<MainThreadWebviewState>).state.state = newState;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private onActiveEditorChanged() {
|
||||
const activeEditor = this._editorService.activeControl;
|
||||
let newActiveWebview: { input: WebviewEditorInput, handle: WebviewPanelHandle } | undefined = undefined;
|
||||
if (activeEditor && activeEditor.input instanceof WebviewEditorInput) {
|
||||
for (const handle of map.keys(this._webviews)) {
|
||||
const input = this._webviews.get(handle)!;
|
||||
if (input.matches(activeEditor.input)) {
|
||||
newActiveWebview = { input, handle };
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (newActiveWebview && newActiveWebview.handle === this._activeWebview) {
|
||||
// Webview itself unchanged but position may have changed
|
||||
this._proxy.$onDidChangeWebviewPanelViewState(newActiveWebview.handle, {
|
||||
active: true,
|
||||
visible: true,
|
||||
position: editorGroupToViewColumn(this._editorGroupService, newActiveWebview.input.group || 0)
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// Broadcast view state update for currently active
|
||||
if (typeof this._activeWebview !== 'undefined') {
|
||||
const oldActiveWebview = this._webviews.get(this._activeWebview);
|
||||
if (oldActiveWebview) {
|
||||
this._proxy.$onDidChangeWebviewPanelViewState(this._activeWebview, {
|
||||
active: false,
|
||||
visible: this._editorService.visibleControls.some(editor => !!editor.input && editor.input.matches(oldActiveWebview)),
|
||||
position: editorGroupToViewColumn(this._editorGroupService, oldActiveWebview.group || 0),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Then for newly active
|
||||
if (newActiveWebview) {
|
||||
this._proxy.$onDidChangeWebviewPanelViewState(newActiveWebview.handle, {
|
||||
active: true,
|
||||
visible: true,
|
||||
position: editorGroupToViewColumn(this._editorGroupService, activeEditor ? activeEditor.group : ACTIVE_GROUP),
|
||||
});
|
||||
this._activeWebview = newActiveWebview.handle;
|
||||
} else {
|
||||
this._activeWebview = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
private onVisibleEditorsChanged(): void {
|
||||
this._webviews.forEach((input, handle) => {
|
||||
for (const workbenchEditor of this._editorService.visibleControls) {
|
||||
if (workbenchEditor.input && workbenchEditor.input.matches(input)) {
|
||||
const editorPosition = editorGroupToViewColumn(this._editorGroupService, workbenchEditor.group!);
|
||||
|
||||
input.updateGroup(workbenchEditor.group!.id);
|
||||
this._proxy.$onDidChangeWebviewPanelViewState(handle, {
|
||||
active: handle === this._activeWebview,
|
||||
visible: true,
|
||||
position: editorPosition
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private onDidClickLink(handle: WebviewPanelHandle, link: URI): void {
|
||||
if (!link) {
|
||||
return;
|
||||
}
|
||||
|
||||
const webview = this.getWebview(handle);
|
||||
if (this.isSupportedLink(webview, link)) {
|
||||
this._openerService.open(link);
|
||||
}
|
||||
}
|
||||
|
||||
private isSupportedLink(webview: WebviewEditorInput, link: URI): boolean {
|
||||
if (MainThreadWebviews.standardSupportedLinkSchemes.has(link.scheme)) {
|
||||
return true;
|
||||
}
|
||||
if (this._productService.urlProtocol === link.scheme) {
|
||||
return true;
|
||||
}
|
||||
return !!webview.options.enableCommandUris && link.scheme === 'command';
|
||||
}
|
||||
|
||||
private getWebview(handle: WebviewPanelHandle): WebviewEditorInput {
|
||||
const webview = this.tryGetWebview(handle);
|
||||
if (!webview) {
|
||||
throw new Error('Unknown webview handle:' + handle);
|
||||
}
|
||||
return webview;
|
||||
}
|
||||
|
||||
private tryGetWebview(handle: WebviewPanelHandle): WebviewEditorInput | undefined {
|
||||
return this._webviews.get(handle);
|
||||
}
|
||||
|
||||
private static getDeserializationFailedContents(viewType: string) {
|
||||
return `<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<base href="https://code.visualstudio.com/raw/">
|
||||
<meta http-equiv="Content-type" content="text/html;charset=UTF-8">
|
||||
<meta http-equiv="Content-Security-Policy" content="default-src 'none'; img-src https: data:; media-src https:; script-src 'none'; style-src vscode-resource: https: 'unsafe-inline'; child-src 'none'; frame-src 'none';">
|
||||
</head>
|
||||
<body>${localize('errorMessage', "An error occurred while restoring view:{0}", viewType)}</body>
|
||||
</html>`;
|
||||
}
|
||||
}
|
||||
|
||||
function reviveWebviewOptions(options: WebviewInputOptions): WebviewInputOptions {
|
||||
return {
|
||||
...options,
|
||||
localResourceRoots: Array.isArray(options.localResourceRoots) ? options.localResourceRoots.map(r => URI.revive(r)) : undefined,
|
||||
};
|
||||
}
|
||||
|
||||
function reviveWebviewIcon(
|
||||
value: { light: UriComponents, dark: UriComponents } | undefined
|
||||
): { light: URI, dark: URI } | undefined {
|
||||
if (!value) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return {
|
||||
light: URI.revive(value.light),
|
||||
dark: URI.revive(value.dark)
|
||||
};
|
||||
}
|
||||
@@ -4,19 +4,20 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { Event } from 'vs/base/common/event';
|
||||
import { dispose, IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { DisposableStore } from 'vs/base/common/lifecycle';
|
||||
import { URI, UriComponents } from 'vs/base/common/uri';
|
||||
import { IWindowService, IWindowsService } from 'vs/platform/windows/common/windows';
|
||||
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
|
||||
import { ExtHostContext, ExtHostWindowShape, IExtHostContext, MainContext, MainThreadWindowShape, IOpenUriOptions } from '../common/extHost.protocol';
|
||||
import { ITunnelService, RemoteTunnel } from 'vs/platform/remote/common/tunnel';
|
||||
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
|
||||
import { extractLocalHostUriMetaDataForPortMapping } from 'vs/workbench/contrib/webview/common/portMapping';
|
||||
|
||||
@extHostNamedCustomer(MainContext.MainThreadWindow)
|
||||
export class MainThreadWindow implements MainThreadWindowShape {
|
||||
|
||||
private readonly proxy: ExtHostWindowShape;
|
||||
private disposables: IDisposable[] = [];
|
||||
private readonly disposables = new DisposableStore();
|
||||
private readonly _tunnels = new Map<number, Promise<RemoteTunnel>>();
|
||||
|
||||
constructor(
|
||||
@@ -33,7 +34,7 @@ export class MainThreadWindow implements MainThreadWindowShape {
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
this.disposables = dispose(this.disposables);
|
||||
this.disposables.dispose();
|
||||
|
||||
for (const tunnel of this._tunnels.values()) {
|
||||
tunnel.then(tunnel => tunnel.dispose());
|
||||
@@ -48,13 +49,11 @@ export class MainThreadWindow implements MainThreadWindowShape {
|
||||
async $openUri(uriComponent: UriComponents, options: IOpenUriOptions): Promise<boolean> {
|
||||
let uri = URI.revive(uriComponent);
|
||||
if (options.allowTunneling && !!this.environmentService.configuration.remoteAuthority) {
|
||||
if (uri.scheme === 'http' || uri.scheme === 'https') {
|
||||
const port = this.getLocalhostPort(uri);
|
||||
if (typeof port === 'number') {
|
||||
const tunnel = await this.getOrCreateTunnel(port);
|
||||
if (tunnel) {
|
||||
uri = uri.with({ authority: `localhost:${tunnel.tunnelLocalPort}` });
|
||||
}
|
||||
const portMappingRequest = extractLocalHostUriMetaDataForPortMapping(uri);
|
||||
if (portMappingRequest) {
|
||||
const tunnel = await this.getOrCreateTunnel(portMappingRequest.port);
|
||||
if (tunnel) {
|
||||
uri = uri.with({ authority: `127.0.0.1:${tunnel.tunnelLocalPort}` });
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -62,14 +61,6 @@ export class MainThreadWindow implements MainThreadWindowShape {
|
||||
return this.windowsService.openExternal(encodeURI(uri.toString(true)));
|
||||
}
|
||||
|
||||
private getLocalhostPort(uri: URI): number | undefined {
|
||||
const match = /^localhost:(\d+)$/.exec(uri.authority);
|
||||
if (match) {
|
||||
return +match[1];
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
private getOrCreateTunnel(remotePort: number): Promise<RemoteTunnel> | undefined {
|
||||
const existing = this._tunnels.get(remotePort);
|
||||
if (existing) {
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation';
|
||||
import { isPromiseCanceledError } from 'vs/base/common/errors';
|
||||
import { dispose, IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { DisposableStore } from 'vs/base/common/lifecycle';
|
||||
import { URI, UriComponents } from 'vs/base/common/uri';
|
||||
import { localize } from 'vs/nls';
|
||||
import { CommandsRegistry } from 'vs/platform/commands/common/commands';
|
||||
@@ -13,7 +13,6 @@ import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
|
||||
import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { ILabelService } from 'vs/platform/label/common/label';
|
||||
import { IFileMatch, IPatternInfo, ISearchProgressItem, ISearchService } from 'vs/workbench/services/search/common/search';
|
||||
import { IStatusbarService } from 'vs/platform/statusbar/common/statusbar';
|
||||
import { IWindowService } from 'vs/platform/windows/common/windows';
|
||||
import { IWorkspaceContextService, WorkbenchState, IWorkspace } from 'vs/platform/workspace/common/workspace';
|
||||
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
|
||||
@@ -24,11 +23,12 @@ import { IWorkspaceEditingService } from 'vs/workbench/services/workspace/common
|
||||
import { ExtHostContext, ExtHostWorkspaceShape, IExtHostContext, MainContext, MainThreadWorkspaceShape, IWorkspaceData, ITextSearchComplete } from '../common/extHost.protocol';
|
||||
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
|
||||
import { isEqualOrParent } from 'vs/base/common/resources';
|
||||
import { INotificationService } from 'vs/platform/notification/common/notification';
|
||||
|
||||
@extHostNamedCustomer(MainContext.MainThreadWorkspace)
|
||||
export class MainThreadWorkspace implements MainThreadWorkspaceShape {
|
||||
|
||||
private readonly _toDispose: IDisposable[] = [];
|
||||
private readonly _toDispose = new DisposableStore();
|
||||
private readonly _activeCancelTokens: { [id: number]: CancellationTokenSource } = Object.create(null);
|
||||
private readonly _proxy: ExtHostWorkspaceShape;
|
||||
private readonly _queryBuilder = this._instantiationService.createInstance(QueryBuilder);
|
||||
@@ -39,7 +39,7 @@ export class MainThreadWorkspace implements MainThreadWorkspaceShape {
|
||||
@IWorkspaceContextService private readonly _contextService: IWorkspaceContextService,
|
||||
@ITextFileService private readonly _textFileService: ITextFileService,
|
||||
@IWorkspaceEditingService private readonly _workspaceEditingService: IWorkspaceEditingService,
|
||||
@IStatusbarService private readonly _statusbarService: IStatusbarService,
|
||||
@INotificationService private readonly _notificationService: INotificationService,
|
||||
@IWindowService private readonly _windowService: IWindowService,
|
||||
@IInstantiationService private readonly _instantiationService: IInstantiationService,
|
||||
@ILabelService private readonly _labelService: ILabelService,
|
||||
@@ -52,7 +52,7 @@ export class MainThreadWorkspace implements MainThreadWorkspaceShape {
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
dispose(this._toDispose);
|
||||
this._toDispose.dispose();
|
||||
|
||||
for (let requestId in this._activeCancelTokens) {
|
||||
const tokenSource = this._activeCancelTokens[requestId];
|
||||
@@ -66,7 +66,7 @@ export class MainThreadWorkspace implements MainThreadWorkspaceShape {
|
||||
const workspaceFoldersToAdd = foldersToAdd.map(f => ({ uri: URI.revive(f.uri), name: f.name }));
|
||||
|
||||
// Indicate in status message
|
||||
this._statusbarService.setStatusMessage(this.getStatusMessage(extensionName, workspaceFoldersToAdd.length, deleteCount), 10 * 1000 /* 10s */);
|
||||
this._notificationService.status(this.getStatusMessage(extensionName, workspaceFoldersToAdd.length, deleteCount), { hideAfter: 10 * 1000 /* 10s */ });
|
||||
|
||||
return this._workspaceEditingService.updateFolders(index, deleteCount, workspaceFoldersToAdd, true);
|
||||
}
|
||||
@@ -179,10 +179,9 @@ export class MainThreadWorkspace implements MainThreadWorkspaceShape {
|
||||
return search;
|
||||
}
|
||||
|
||||
$checkExists(includes: string[], token: CancellationToken): Promise<boolean> {
|
||||
$checkExists(folders: UriComponents[], includes: string[], token: CancellationToken): Promise<boolean> {
|
||||
const queryBuilder = this._instantiationService.createInstance(QueryBuilder);
|
||||
const folders = this._contextService.getWorkspace().folders.map(folder => folder.uri);
|
||||
const query = queryBuilder.file(folders, {
|
||||
const query = queryBuilder.file(folders.map(folder => URI.revive(folder)), {
|
||||
_reason: 'checkExists',
|
||||
includePattern: includes.join(', '),
|
||||
expandPatterns: true,
|
||||
|
||||
@@ -36,7 +36,7 @@ import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet';
|
||||
import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
|
||||
import { IWorkbenchActionRegistry, Extensions as ActionExtensions } from 'vs/workbench/common/actions';
|
||||
import { SyncActionDescriptor } from 'vs/platform/actions/common/actions';
|
||||
import { createCSSRule } from 'vs/base/browser/dom';
|
||||
import { createCSSRule, asDomUri } from 'vs/base/browser/dom';
|
||||
|
||||
export interface IUserFriendlyViewsContainerDescriptor {
|
||||
id: string;
|
||||
@@ -321,13 +321,13 @@ class ViewsExtensionHandler implements IWorkbenchContribution {
|
||||
const registry = Registry.as<IWorkbenchActionRegistry>(ActionExtensions.WorkbenchActions);
|
||||
registry.registerWorkbenchAction(
|
||||
new SyncActionDescriptor(OpenCustomViewletAction, id, localize('showViewlet', "Show {0}", title)),
|
||||
'View: Show {0}',
|
||||
`View: Show ${title}`,
|
||||
localize('view', "View")
|
||||
);
|
||||
|
||||
// Generate CSS to show the icon in the activity bar
|
||||
const iconClass = `.monaco-workbench .activitybar .monaco-action-bar .action-label.${cssClass}`;
|
||||
createCSSRule(iconClass, `-webkit-mask: url('${icon}') no-repeat 50% 50%`);
|
||||
createCSSRule(iconClass, `-webkit-mask: url('${asDomUri(icon)}') no-repeat 50% 50%; -webkit-mask-size: 24px;`);
|
||||
}
|
||||
|
||||
return viewContainer;
|
||||
@@ -383,7 +383,7 @@ class ViewsExtensionHandler implements IWorkbenchContribution {
|
||||
when: ContextKeyExpr.deserialize(item.when),
|
||||
canToggleVisibility: true,
|
||||
collapsed: this.showCollapsed(container),
|
||||
treeView: this.instantiationService.createInstance(CustomTreeView, item.id, container),
|
||||
treeView: this.instantiationService.createInstance(CustomTreeView, item.id, item.name, container),
|
||||
order: ExtensionIdentifier.equals(extension.description.identifier, container.extensionId) ? index + 1 : undefined,
|
||||
extensionId: extension.description.identifier,
|
||||
originalContainerId: entry.key
|
||||
@@ -456,4 +456,4 @@ class ViewsExtensionHandler implements IWorkbenchContribution {
|
||||
}
|
||||
|
||||
const workbenchRegistry = Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench);
|
||||
workbenchRegistry.registerWorkbenchContribution(ViewsExtensionHandler, LifecyclePhase.Starting);
|
||||
workbenchRegistry.registerWorkbenchContribution(ViewsExtensionHandler, LifecyclePhase.Starting);
|
||||
|
||||
Reference in New Issue
Block a user