Merge from vscode 8e0f348413f4f616c23a88ae30030efa85811973 (#6381)
* Merge from vscode 8e0f348413f4f616c23a88ae30030efa85811973 * disable strict null check
@@ -14,47 +14,47 @@ import { ColorExtensionPoint } from 'vs/workbench/services/themes/common/colorEx
|
||||
import { LanguageConfigurationFileHandler } from 'vs/workbench/contrib/codeEditor/browser/languageConfigurationExtensionPoint';
|
||||
|
||||
// --- mainThread participants
|
||||
import '../browser/mainThreadClipboard';
|
||||
import '../browser/mainThreadCommands';
|
||||
import '../browser/mainThreadConfiguration';
|
||||
import '../browser/mainThreadConsole';
|
||||
// {{SQL CARBON EDIT}}
|
||||
// import '../browser/mainThreadDebugService';
|
||||
import '../browser/mainThreadDecorations';
|
||||
import '../browser/mainThreadDiagnostics';
|
||||
import '../browser/mainThreadDialogs';
|
||||
import '../browser/mainThreadDocumentContentProviders';
|
||||
import '../browser/mainThreadDocuments';
|
||||
import '../browser/mainThreadDocumentsAndEditors';
|
||||
import '../browser/mainThreadEditor';
|
||||
import '../browser/mainThreadEditors';
|
||||
import '../browser/mainThreadErrors';
|
||||
import '../browser/mainThreadExtensionService';
|
||||
import '../browser/mainThreadFileSystem';
|
||||
import '../browser/mainThreadFileSystemEventService';
|
||||
import '../browser/mainThreadHeapService';
|
||||
import '../browser/mainThreadKeytar';
|
||||
import '../browser/mainThreadLanguageFeatures';
|
||||
import '../browser/mainThreadLanguages';
|
||||
import '../browser/mainThreadLogService';
|
||||
import '../browser/mainThreadMessageService';
|
||||
import '../browser/mainThreadOutputService';
|
||||
import '../browser/mainThreadProgress';
|
||||
import '../browser/mainThreadQuickOpen';
|
||||
import '../browser/mainThreadSaveParticipant';
|
||||
import '../browser/mainThreadSCM';
|
||||
import '../browser/mainThreadSearch';
|
||||
import '../browser/mainThreadStatusBar';
|
||||
import '../browser/mainThreadStorage';
|
||||
import '../browser/mainThreadTelemetry';
|
||||
import '../browser/mainThreadTerminalService';
|
||||
import '../browser/mainThreadTreeViews';
|
||||
import '../browser/mainThreadUrls';
|
||||
import '../browser/mainThreadWindow';
|
||||
import '../browser/mainThreadWorkspace';
|
||||
import '../browser/mainThreadComments';
|
||||
import '../browser/mainThreadTask';
|
||||
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 {
|
||||
@@ -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
@@ -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
@@ -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];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,30 +2,31 @@
|
||||
* 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 { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';
|
||||
import * as modes from 'vs/editor/common/modes';
|
||||
import { localize } from 'vs/nls';
|
||||
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle';
|
||||
import { IOpenerService } from 'vs/platform/opener/common/opener';
|
||||
import product from 'vs/platform/product/node/product';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { ExtHostContext, ExtHostWebviewsShape, IExtHostContext, MainContext, MainThreadWebviewsShape, WebviewInsetHandle, WebviewPanelHandle, WebviewPanelShowOptions } from 'vs/workbench/api/common/extHost.protocol';
|
||||
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 { CodeInsetController } from 'vs/workbench/contrib/codeinset/electron-browser/codeInset.contribution';
|
||||
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 { WebviewElement } from 'vs/workbench/contrib/webview/electron-browser/webviewElement';
|
||||
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 {
|
||||
@@ -34,55 +35,47 @@ export class MainThreadWebviews extends Disposable implements MainThreadWebviews
|
||||
'http',
|
||||
'https',
|
||||
'mailto',
|
||||
product.urlProtocol,
|
||||
'vscode',
|
||||
'vscode-insiders'
|
||||
'vscode-insider',
|
||||
]);
|
||||
|
||||
private static revivalPool = 0;
|
||||
|
||||
|
||||
private readonly _proxy: ExtHostWebviewsShape;
|
||||
private readonly _webviews = new Map<WebviewPanelHandle, WebviewEditorInput>();
|
||||
private readonly _webviewsElements = new Map<WebviewInsetHandle, WebviewElement>();
|
||||
private readonly _webviews = new Map<WebviewPanelHandle, WebviewEditorInput<MainThreadWebviewState>>();
|
||||
private readonly _revivers = new Map<string, IDisposable>();
|
||||
|
||||
private _activeWebview: WebviewPanelHandle | undefined = undefined;
|
||||
|
||||
constructor(
|
||||
context: IExtHostContext,
|
||||
@ILifecycleService lifecycleService: ILifecycleService,
|
||||
@IExtensionService extensionService: IExtensionService,
|
||||
@IEditorGroupsService private readonly _editorGroupService: IEditorGroupsService,
|
||||
@IEditorService private readonly _editorService: IEditorService,
|
||||
@IWebviewEditorService private readonly _webviewService: IWebviewEditorService,
|
||||
@IWebviewEditorService private readonly _webviewEditorService: IWebviewEditorService,
|
||||
@IOpenerService private readonly _openerService: IOpenerService,
|
||||
@ITelemetryService private readonly _telemetryService: ITelemetryService,
|
||||
@IInstantiationService private readonly _instantiationService: IInstantiationService,
|
||||
@ICodeEditorService private readonly _codeEditorService: ICodeEditorService,
|
||||
@IProductService private readonly _productService: IProductService,
|
||||
) {
|
||||
super();
|
||||
|
||||
this._proxy = context.getProxy(ExtHostContext.ExtHostWebviews);
|
||||
_editorService.onDidActiveEditorChange(this.onActiveEditorChanged, this, this._toDispose);
|
||||
_editorService.onDidVisibleEditorsChange(this.onVisibleEditorsChanged, this, this._toDispose);
|
||||
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._toDispose.push(_webviewService.registerReviver({
|
||||
canRevive: (webview) => {
|
||||
const viewType = webview.state.viewType;
|
||||
if (viewType) {
|
||||
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'); }
|
||||
}));
|
||||
|
||||
lifecycleService.onBeforeShutdown(e => {
|
||||
e.veto(this._onBeforeShutdown());
|
||||
}, this, this._toDispose);
|
||||
}
|
||||
|
||||
public $createWebviewPanel(
|
||||
@@ -100,10 +93,10 @@ export class MainThreadWebviews extends Disposable implements MainThreadWebviews
|
||||
mainThreadShowOptions.group = viewColumnToEditorGroup(this._editorGroupService, showOptions.viewColumn);
|
||||
}
|
||||
|
||||
const webview = this._webviewService.createWebview(this.getInternalWebviewId(viewType), title, mainThreadShowOptions, reviveWebviewOptions(options), {
|
||||
const webview = this._webviewEditorService.createWebview(handle, this.getInternalWebviewViewType(viewType), title, mainThreadShowOptions, reviveWebviewOptions(options), {
|
||||
location: URI.revive(extensionLocation),
|
||||
id: extensionId
|
||||
}, this.createWebviewEventDelegate(handle));
|
||||
}, this.createWebviewEventDelegate(handle)) as WebviewEditorInput<MainThreadWebviewState>;
|
||||
webview.state = {
|
||||
viewType: viewType,
|
||||
state: undefined
|
||||
@@ -119,52 +112,6 @@ export class MainThreadWebviews extends Disposable implements MainThreadWebviews
|
||||
this._telemetryService.publicLog('webviews:createWebviewPanel', { extensionId: extensionId.value });
|
||||
}
|
||||
|
||||
$createWebviewCodeInset(
|
||||
handle: WebviewInsetHandle,
|
||||
symbolId: string,
|
||||
options: modes.IWebviewOptions,
|
||||
extensionId: ExtensionIdentifier,
|
||||
extensionLocation: UriComponents
|
||||
): void {
|
||||
// todo@joh main is for the lack of a code-inset service
|
||||
// which we maybe wanna have... this is how it now works
|
||||
// 1) create webview element
|
||||
// 2) find the code inset controller that request it
|
||||
// 3) let the controller adopt the widget
|
||||
// 4) continue to forward messages to the webview
|
||||
const webview = this._instantiationService.createInstance(
|
||||
WebviewElement,
|
||||
{
|
||||
extension: {
|
||||
location: URI.revive(extensionLocation),
|
||||
id: extensionId
|
||||
},
|
||||
enableFindWidget: false,
|
||||
},
|
||||
{
|
||||
allowScripts: options.enableScripts,
|
||||
}
|
||||
);
|
||||
|
||||
let found = false;
|
||||
for (const editor of this._codeEditorService.listCodeEditors()) {
|
||||
const ctrl = CodeInsetController.get(editor);
|
||||
if (ctrl && ctrl.acceptWebview(symbolId, webview)) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
webview.dispose();
|
||||
return;
|
||||
}
|
||||
// this will leak... the adopted webview will be disposed by the
|
||||
// code inset controller. we might need a dispose-event here so that
|
||||
// we can clean up things.
|
||||
this._webviewsElements.set(handle, webview);
|
||||
}
|
||||
|
||||
public $disposeWebview(handle: WebviewPanelHandle): void {
|
||||
const webview = this.getWebview(handle);
|
||||
webview.dispose();
|
||||
@@ -180,22 +127,14 @@ export class MainThreadWebviews extends Disposable implements MainThreadWebviews
|
||||
webview.iconPath = reviveWebviewIcon(value);
|
||||
}
|
||||
|
||||
public $setHtml(handle: WebviewPanelHandle | WebviewInsetHandle, value: string): void {
|
||||
if (typeof handle === 'number') {
|
||||
this.getWebviewElement(handle).html = value;
|
||||
} else {
|
||||
const webview = this.getWebview(handle);
|
||||
webview.html = value;
|
||||
}
|
||||
public $setHtml(handle: WebviewPanelHandle, value: string): void {
|
||||
const webview = this.getWebview(handle);
|
||||
webview.html = value;
|
||||
}
|
||||
|
||||
public $setOptions(handle: WebviewPanelHandle | WebviewInsetHandle, options: modes.IWebviewOptions): void {
|
||||
if (typeof handle === 'number') {
|
||||
this.getWebviewElement(handle).options = reviveWebviewOptions(options as any /*todo@mat */);
|
||||
} else {
|
||||
const webview = this.getWebview(handle);
|
||||
webview.setOptions(reviveWebviewOptions(options as any /*todo@mat */));
|
||||
}
|
||||
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 {
|
||||
@@ -206,33 +145,28 @@ export class MainThreadWebviews extends Disposable implements MainThreadWebviews
|
||||
|
||||
const targetGroup = this._editorGroupService.getGroup(viewColumnToEditorGroup(this._editorGroupService, showOptions.viewColumn)) || this._editorGroupService.getGroup(webview.group || 0);
|
||||
if (targetGroup) {
|
||||
this._webviewService.revealWebview(webview, targetGroup, !!showOptions.preserveFocus);
|
||||
this._webviewEditorService.revealWebview(webview, targetGroup, !!showOptions.preserveFocus);
|
||||
}
|
||||
}
|
||||
|
||||
public async $postMessage(handle: WebviewPanelHandle | WebviewInsetHandle, message: any): Promise<boolean> {
|
||||
if (typeof handle === 'number') {
|
||||
this.getWebviewElement(handle).sendMessage(message);
|
||||
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;
|
||||
} else {
|
||||
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;
|
||||
}
|
||||
|
||||
if (webview.webview) {
|
||||
webview.webview.sendMessage(message);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public $registerSerializer(viewType: string): void {
|
||||
@@ -240,7 +174,7 @@ export class MainThreadWebviews extends Disposable implements MainThreadWebviews
|
||||
throw new Error(`Reviver for ${viewType} already registered`);
|
||||
}
|
||||
|
||||
this._revivers.set(viewType, this._webviewService.registerReviver({
|
||||
this._revivers.set(viewType, this._webviewEditorService.registerReviver({
|
||||
canRevive: (webview) => {
|
||||
return webview.state && webview.state.viewType === viewType;
|
||||
},
|
||||
@@ -278,19 +212,10 @@ export class MainThreadWebviews extends Disposable implements MainThreadWebviews
|
||||
this._revivers.delete(viewType);
|
||||
}
|
||||
|
||||
private getInternalWebviewId(viewType: string): string {
|
||||
private getInternalWebviewViewType(viewType: string): string {
|
||||
return `mainThreadWebview-${viewType}`;
|
||||
}
|
||||
|
||||
private _onBeforeShutdown(): boolean {
|
||||
this._webviews.forEach((webview) => {
|
||||
if (!webview.isDisposed() && webview.state && this._revivers.has(webview.state.viewType)) {
|
||||
webview.state.state = webview.webviewState;
|
||||
}
|
||||
});
|
||||
return false; // Don't veto shutdown
|
||||
}
|
||||
|
||||
private createWebviewEventDelegate(handle: WebviewPanelHandle) {
|
||||
return {
|
||||
onDidClickLink: (uri: URI) => this.onDidClickLink(handle, uri),
|
||||
@@ -299,6 +224,13 @@ export class MainThreadWebviews extends Disposable implements MainThreadWebviews
|
||||
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;
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -384,23 +316,22 @@ export class MainThreadWebviews extends Disposable implements MainThreadWebviews
|
||||
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._webviews.get(handle);
|
||||
const webview = this.tryGetWebview(handle);
|
||||
if (!webview) {
|
||||
throw new Error('Unknown webview handle:' + handle);
|
||||
}
|
||||
return webview;
|
||||
}
|
||||
|
||||
private getWebviewElement(handle: number): WebviewElement {
|
||||
const webview = this._webviewsElements.get(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) {
|
||||
@@ -409,7 +340,7 @@ export class MainThreadWebviews extends Disposable implements MainThreadWebviews
|
||||
<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-core-resource: https: 'unsafe-inline'; child-src 'none'; frame-src 'none';">
|
||||
<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>`;
|
||||
@@ -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);
|
||||
|
||||
@@ -11,7 +11,7 @@ import { ITextEditorOptions } from 'vs/platform/editor/common/editor';
|
||||
import { EditorViewColumn } from 'vs/workbench/api/common/shared/editor';
|
||||
import { EditorGroupLayout } from 'vs/workbench/services/editor/common/editorGroupsService';
|
||||
import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IWindowsService, IOpenSettings, IURIToOpen } from 'vs/platform/windows/common/windows';
|
||||
import { IOpenSettings, IURIToOpen, IWindowService } from 'vs/platform/windows/common/windows';
|
||||
import { IDownloadService } from 'vs/platform/download/common/download';
|
||||
import { IWorkspacesService, hasWorkspaceFileExtension } from 'vs/platform/workspaces/common/workspaces';
|
||||
import { IRecent } from 'vs/platform/history/common/history';
|
||||
@@ -129,8 +129,8 @@ export class OpenAPICommand {
|
||||
CommandsRegistry.registerCommand(OpenAPICommand.ID, adjustHandler(OpenAPICommand.execute));
|
||||
|
||||
CommandsRegistry.registerCommand('_workbench.removeFromRecentlyOpened', function (accessor: ServicesAccessor, uri: URI) {
|
||||
const windowsService = accessor.get(IWindowsService);
|
||||
return windowsService.removeFromRecentlyOpened([uri]).then(() => undefined);
|
||||
const windowService = accessor.get(IWindowService);
|
||||
return windowService.removeFromRecentlyOpened([uri]);
|
||||
});
|
||||
|
||||
export class RemoveFromRecentlyOpenedAPICommand {
|
||||
@@ -160,7 +160,7 @@ interface RecentEntry {
|
||||
}
|
||||
|
||||
CommandsRegistry.registerCommand('_workbench.addToRecentlyOpened', async function (accessor: ServicesAccessor, recentEntry: RecentEntry) {
|
||||
const windowsService = accessor.get(IWindowsService);
|
||||
const windowService = accessor.get(IWindowService);
|
||||
const workspacesService = accessor.get(IWorkspacesService);
|
||||
let recent: IRecent | undefined = undefined;
|
||||
const uri = recentEntry.uri;
|
||||
@@ -173,7 +173,7 @@ CommandsRegistry.registerCommand('_workbench.addToRecentlyOpened', async functio
|
||||
} else {
|
||||
recent = { fileUri: uri, label };
|
||||
}
|
||||
return windowsService.addRecentlyOpened([recent]);
|
||||
return windowService.addRecentlyOpened([recent]);
|
||||
});
|
||||
|
||||
export class SetEditorLayoutAPICommand {
|
||||
|
||||
@@ -42,12 +42,12 @@ const configurationEntrySchema: IJSONSchema = {
|
||||
enum: ['application', 'machine', 'window', 'resource'],
|
||||
default: 'window',
|
||||
enumDescriptions: [
|
||||
nls.localize('scope.application.description', "Application specific configuration, which can be configured only in local user settings."),
|
||||
nls.localize('scope.machine.description', "Machine specific configuration, which can be configured only in local and remote user settings."),
|
||||
nls.localize('scope.window.description', "Window specific configuration, which can be configured in the user or workspace settings."),
|
||||
nls.localize('scope.resource.description', "Resource specific configuration, which can be configured in the user, workspace or folder settings.")
|
||||
nls.localize('scope.application.description', "Application specific configuration, which can be configured only in the user settings."),
|
||||
nls.localize('scope.machine.description', "Machine specific configuration, which can be configured only in the user settings when the extension is running locally, or only in the remote settings when the extension is running remotely."),
|
||||
nls.localize('scope.window.description', "Window specific configuration, which can be configured in the user, remote or workspace settings."),
|
||||
nls.localize('scope.resource.description', "Resource specific configuration, which can be configured in the user, remote, workspace or folder settings.")
|
||||
],
|
||||
description: nls.localize('scope.description', "Scope in which the configuration is applicable. Available scopes are `window` and `resource`.")
|
||||
description: nls.localize('scope.description', "Scope in which the configuration is applicable. Available scopes are `application`, `machine`, `window` and `resource`.")
|
||||
},
|
||||
enumDescriptions: {
|
||||
type: 'array',
|
||||
|
||||
@@ -3,50 +3,50 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { VSBuffer } from 'vs/base/common/buffer';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { IRemoteConsoleLog } from 'vs/base/common/console';
|
||||
import { SerializedError } from 'vs/base/common/errors';
|
||||
import { IRelativePattern } from 'vs/base/common/glob';
|
||||
import { IMarkdownString } from 'vs/base/common/htmlContent';
|
||||
import { IDisposable } from 'vs/base/common/lifecycle';
|
||||
import Severity from 'vs/base/common/severity';
|
||||
import { URI, UriComponents } from 'vs/base/common/uri';
|
||||
import { TextEditorCursorStyle, RenderLineNumbersType } from 'vs/editor/common/config/editorOptions';
|
||||
import { RenderLineNumbersType, TextEditorCursorStyle } from 'vs/editor/common/config/editorOptions';
|
||||
import { IPosition } from 'vs/editor/common/core/position';
|
||||
import { IRange } from 'vs/editor/common/core/range';
|
||||
import { ISelection, Selection } from 'vs/editor/common/core/selection';
|
||||
import * as editorCommon from 'vs/editor/common/editorCommon';
|
||||
import { ISingleEditOperation, EndOfLineSequence } from 'vs/editor/common/model';
|
||||
import { EndOfLineSequence, ISingleEditOperation } from 'vs/editor/common/model';
|
||||
import { IModelChangedEvent } from 'vs/editor/common/model/mirrorTextModel';
|
||||
import * as modes from 'vs/editor/common/modes';
|
||||
import { CharacterPair, CommentRule, EnterAction } from 'vs/editor/common/modes/languageConfiguration';
|
||||
import { ICommandHandlerDescription } from 'vs/platform/commands/common/commands';
|
||||
import { ConfigurationTarget, IConfigurationData, IConfigurationModel } from 'vs/platform/configuration/common/configuration';
|
||||
import { ConfigurationScope } from 'vs/platform/configuration/common/configurationRegistry';
|
||||
import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
||||
import * as files from 'vs/platform/files/common/files';
|
||||
import { ResourceLabelFormatter } from 'vs/platform/label/common/label';
|
||||
import { LogLevel } from 'vs/platform/log/common/log';
|
||||
import { IMarkerData } from 'vs/platform/markers/common/markers';
|
||||
import { IProgressOptions, IProgressStep } from 'vs/platform/progress/common/progress';
|
||||
import * as quickInput from 'vs/platform/quickinput/common/quickInput';
|
||||
import * as search from 'vs/workbench/services/search/common/search';
|
||||
import { RemoteAuthorityResolverErrorCode, ResolvedAuthority } from 'vs/platform/remote/common/remoteAuthorityResolver';
|
||||
import * as statusbar from 'vs/platform/statusbar/common/statusbar';
|
||||
import { ClassifiedEvent, GDPRClassification, StrictPropertyCheck } from 'vs/platform/telemetry/common/gdprTypings';
|
||||
import { ITelemetryInfo } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { ThemeColor } from 'vs/platform/theme/common/themeService';
|
||||
import { EditorViewColumn } from 'vs/workbench/api/common/shared/editor';
|
||||
import * as tasks from 'vs/workbench/api/common/shared/tasks';
|
||||
import { ITreeItem, IRevealOptions } from 'vs/workbench/common/views';
|
||||
import { IRevealOptions, ITreeItem } from 'vs/workbench/common/views';
|
||||
import * as callHierarchy from 'vs/workbench/contrib/callHierarchy/common/callHierarchy';
|
||||
import { IAdapterDescriptor, IConfig, ITerminalSettings } from 'vs/workbench/contrib/debug/common/debug';
|
||||
import { ITextQueryBuilderOptions } from 'vs/workbench/contrib/search/common/queryBuilder';
|
||||
import { ITerminalDimensions } from 'vs/workbench/contrib/terminal/common/terminal';
|
||||
import { ExtensionActivationError } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { IRPCProtocol, createExtHostContextProxyIdentifier as createExtId, createMainContextProxyIdentifier as createMainId } from 'vs/workbench/services/extensions/common/proxyIdentifier';
|
||||
import { IProgressOptions, IProgressStep } from 'vs/platform/progress/common/progress';
|
||||
import { createExtHostContextProxyIdentifier as createExtId, createMainContextProxyIdentifier as createMainId, IRPCProtocol } from 'vs/workbench/services/extensions/common/proxyIdentifier';
|
||||
import * as search from 'vs/workbench/services/search/common/search';
|
||||
import { SaveReason } from 'vs/workbench/services/textfile/common/textfiles';
|
||||
import { IMarkdownString } from 'vs/base/common/htmlContent';
|
||||
import { ResolvedAuthority, RemoteAuthorityResolverErrorCode } from 'vs/platform/remote/common/remoteAuthorityResolver';
|
||||
import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
||||
import * as codeInset from 'vs/workbench/contrib/codeinset/common/codeInset';
|
||||
import * as callHierarchy from 'vs/workbench/contrib/callHierarchy/common/callHierarchy';
|
||||
import { IRelativePattern } from 'vs/base/common/glob';
|
||||
import { IRemoteConsoleLog } from 'vs/base/common/console';
|
||||
import { VSBuffer } from 'vs/base/common/buffer';
|
||||
|
||||
// {{SQL CARBON EDIT}}
|
||||
import { ITreeItem as sqlITreeItem } from 'sql/workbench/common/views';
|
||||
@@ -62,6 +62,8 @@ export interface IEnvironment {
|
||||
extensionTestsLocationURI?: URI;
|
||||
globalStorageHome: URI;
|
||||
userHome: URI;
|
||||
webviewResourceRoot: string;
|
||||
webviewCspSource: string;
|
||||
}
|
||||
|
||||
export interface IStaticWorkspaceData {
|
||||
@@ -88,11 +90,11 @@ export interface IInitData {
|
||||
logLevel: LogLevel;
|
||||
logsLocation: URI;
|
||||
autoStart: boolean;
|
||||
remoteAuthority?: string | null;
|
||||
remote: { isRemote: boolean; authority: string | undefined; };
|
||||
}
|
||||
|
||||
export interface IConfigurationInitData extends IConfigurationData {
|
||||
configurationScopes: { [key: string]: ConfigurationScope };
|
||||
configurationScopes: [string, ConfigurationScope | undefined][];
|
||||
}
|
||||
|
||||
export interface IWorkspaceConfigurationChangeEventData {
|
||||
@@ -121,33 +123,18 @@ export interface MainThreadCommandsShape extends IDisposable {
|
||||
$getCommands(): Promise<string[]>;
|
||||
}
|
||||
|
||||
export interface CommentThreadTemplate {
|
||||
label: string;
|
||||
acceptInputCommand?: modes.Command;
|
||||
additionalCommands?: modes.Command[];
|
||||
deleteCommand?: modes.Command;
|
||||
}
|
||||
|
||||
export interface CommentProviderFeatures {
|
||||
startDraftLabel?: string;
|
||||
deleteDraftLabel?: string;
|
||||
finishDraftLabel?: string;
|
||||
reactionGroup?: modes.CommentReaction[];
|
||||
commentThreadTemplate?: CommentThreadTemplate;
|
||||
reactionHandler?: boolean;
|
||||
}
|
||||
|
||||
export interface MainThreadCommentsShape extends IDisposable {
|
||||
$registerCommentController(handle: number, id: string, label: string): void;
|
||||
$unregisterCommentController(handle: number): void;
|
||||
$updateCommentControllerFeatures(handle: number, features: CommentProviderFeatures): void;
|
||||
$createCommentThread(handle: number, commentThreadHandle: number, threadId: string, resource: UriComponents, range: IRange): modes.CommentThread2 | undefined;
|
||||
$updateCommentThread(handle: number, commentThreadHandle: number, threadId: string, resource: UriComponents, range: IRange, label: string, contextValue: string | undefined, comments: modes.Comment[], acceptInputCommand: modes.Command | undefined, additionalCommands: modes.Command[], deleteCommand: modes.Command | undefined, collapseState: modes.CommentThreadCollapsibleState): void;
|
||||
$createCommentThread(handle: number, commentThreadHandle: number, threadId: string, resource: UriComponents, range: IRange, extensionId: ExtensionIdentifier): modes.CommentThread | undefined;
|
||||
$updateCommentThread(handle: number, commentThreadHandle: number, threadId: string, resource: UriComponents, range: IRange, label: string, contextValue: string | undefined, comments: modes.Comment[], collapseState: modes.CommentThreadCollapsibleState): void;
|
||||
$deleteCommentThread(handle: number, commentThreadHandle: number): void;
|
||||
$setInputValue(handle: number, input: string): void;
|
||||
$registerDocumentCommentProvider(handle: number, features: CommentProviderFeatures): void;
|
||||
$unregisterDocumentCommentProvider(handle: number): void;
|
||||
$registerWorkspaceCommentProvider(handle: number, extensionId: ExtensionIdentifier): void;
|
||||
$unregisterWorkspaceCommentProvider(handle: number): void;
|
||||
$onDidCommentThreadsChange(handle: number, event: modes.CommentThreadChangedEvent): void;
|
||||
}
|
||||
|
||||
@@ -251,7 +238,7 @@ export interface MainThreadTextEditorsShape extends IDisposable {
|
||||
$trySetSelections(id: string, selections: ISelection[]): Promise<void>;
|
||||
$tryApplyEdits(id: string, modelVersionId: number, edits: ISingleEditOperation[], opts: IApplyEditsOptions): Promise<boolean>;
|
||||
$tryApplyWorkspaceEdit(workspaceEditDto: WorkspaceEditDto): Promise<boolean>;
|
||||
$tryInsertSnippet(id: string, template: string, selections: IRange[], opts: IUndoStopOptions): Promise<boolean>;
|
||||
$tryInsertSnippet(id: string, template: string, selections: readonly IRange[], opts: IUndoStopOptions): Promise<boolean>;
|
||||
$getDiffInformation(id: string): Promise<editorCommon.ILineChange[]>;
|
||||
}
|
||||
|
||||
@@ -336,7 +323,6 @@ export interface MainThreadLanguageFeaturesShape extends IDisposable {
|
||||
$unregister(handle: number): void;
|
||||
$registerDocumentSymbolProvider(handle: number, selector: ISerializedDocumentFilter[], label: string): void;
|
||||
$registerCodeLensSupport(handle: number, selector: ISerializedDocumentFilter[], eventHandle: number | undefined): void;
|
||||
$registerCodeInsetSupport(handle: number, selector: ISerializedDocumentFilter[], eventHandle: number | undefined): void;
|
||||
$emitCodeLensEvent(eventHandle: number, event?: any): void;
|
||||
$registerDefinitionSupport(handle: number, selector: ISerializedDocumentFilter[]): void;
|
||||
$registerDeclarationSupport(handle: number, selector: ISerializedDocumentFilter[]): void;
|
||||
@@ -351,7 +337,7 @@ export interface MainThreadLanguageFeaturesShape extends IDisposable {
|
||||
$registerOnTypeFormattingSupport(handle: number, selector: ISerializedDocumentFilter[], autoFormatTriggerCharacters: string[], extensionId: ExtensionIdentifier): void;
|
||||
$registerNavigateTypeSupport(handle: number): void;
|
||||
$registerRenameSupport(handle: number, selector: ISerializedDocumentFilter[], supportsResolveInitialValues: boolean): void;
|
||||
$registerSuggestSupport(handle: number, selector: ISerializedDocumentFilter[], triggerCharacters: string[], supportsResolveDetails: boolean): void;
|
||||
$registerSuggestSupport(handle: number, selector: ISerializedDocumentFilter[], triggerCharacters: string[], supportsResolveDetails: boolean, extensionId: ExtensionIdentifier): void;
|
||||
$registerSignatureHelpProvider(handle: number, selector: ISerializedDocumentFilter[], metadata: ISerializedSignatureHelpProviderMetadata): void;
|
||||
$registerDocumentLinkProvider(handle: number, selector: ISerializedDocumentFilter[], supportsResolve: boolean): void;
|
||||
$registerDocumentColorProvider(handle: number, selector: ISerializedDocumentFilter[]): void;
|
||||
@@ -392,8 +378,20 @@ export interface MainThreadProgressShape extends IDisposable {
|
||||
$progressEnd(handle: number): void;
|
||||
}
|
||||
|
||||
export interface TerminalLaunchConfig {
|
||||
name?: string;
|
||||
shellPath?: string;
|
||||
shellArgs?: string[] | string;
|
||||
cwd?: string | UriComponents;
|
||||
env?: { [key: string]: string | null };
|
||||
waitOnExit?: boolean;
|
||||
strictEnv?: boolean;
|
||||
hideFromUser?: boolean;
|
||||
isVirtualProcess?: boolean;
|
||||
}
|
||||
|
||||
export interface MainThreadTerminalServiceShape extends IDisposable {
|
||||
$createTerminal(name?: string, shellPath?: string, shellArgs?: string[] | string, cwd?: string | UriComponents, env?: { [key: string]: string | null }, waitOnExit?: boolean, strictEnv?: boolean): Promise<{ id: number, name: string }>;
|
||||
$createTerminal(config: TerminalLaunchConfig): Promise<{ id: number, name: string }>;
|
||||
$createTerminalRenderer(name: string): Promise<number>;
|
||||
$dispose(terminalId: number): void;
|
||||
$hide(terminalId: number): void;
|
||||
@@ -404,8 +402,9 @@ export interface MainThreadTerminalServiceShape extends IDisposable {
|
||||
// Process
|
||||
$sendProcessTitle(terminalId: number, title: string): void;
|
||||
$sendProcessData(terminalId: number, data: string): void;
|
||||
$sendProcessPid(terminalId: number, pid: number): void;
|
||||
$sendProcessReady(terminalId: number, pid: number, cwd: string): void;
|
||||
$sendProcessExit(terminalId: number, exitCode: number): void;
|
||||
$sendOverrideDimensions(terminalId: number, dimensions: ITerminalDimensions | undefined): void;
|
||||
$sendProcessInitialCwd(terminalId: number, cwd: string): void;
|
||||
$sendProcessCwd(terminalId: number, initialCwd: string): void;
|
||||
|
||||
@@ -428,6 +427,8 @@ export type TransferQuickInput = TransferQuickPick | TransferInputBox;
|
||||
|
||||
export interface BaseTransferQuickInput {
|
||||
|
||||
[key: string]: any;
|
||||
|
||||
id: number;
|
||||
|
||||
type?: 'quickPick' | 'inputBox';
|
||||
@@ -500,7 +501,7 @@ export interface MainThreadQuickOpenShape extends IDisposable {
|
||||
}
|
||||
|
||||
export interface MainThreadStatusBarShape extends IDisposable {
|
||||
$setEntry(id: number, extensionId: ExtensionIdentifier | undefined, text: string, tooltip: string, command: string, color: string | ThemeColor, alignment: statusbar.StatusbarAlignment, priority: number | undefined): void;
|
||||
$setEntry(id: number, statusId: string, statusName: string, text: string, tooltip: string, command: string, color: string | ThemeColor, alignment: statusbar.StatusbarAlignment, priority: number | undefined): void;
|
||||
$dispose(id: number): void;
|
||||
}
|
||||
|
||||
@@ -511,12 +512,25 @@ export interface MainThreadStorageShape extends IDisposable {
|
||||
|
||||
export interface MainThreadTelemetryShape extends IDisposable {
|
||||
$publicLog(eventName: string, data?: any): void;
|
||||
$publicLog2<E extends ClassifiedEvent<T> = never, T extends GDPRClassification<T> = never>(eventName: string, data?: StrictPropertyCheck<T, E>): void;
|
||||
}
|
||||
|
||||
export interface MainThreadEditorInsetsShape extends IDisposable {
|
||||
$createEditorInset(handle: number, id: string, uri: UriComponents, line: number, height: number, options: modes.IWebviewOptions, extensionId: ExtensionIdentifier, extensionLocation: UriComponents): Promise<void>;
|
||||
$disposeEditorInset(handle: number): void;
|
||||
|
||||
$setHtml(handle: number, value: string): void;
|
||||
$setOptions(handle: number, options: modes.IWebviewOptions): void;
|
||||
$postMessage(handle: number, value: any): Promise<boolean>;
|
||||
}
|
||||
|
||||
export interface ExtHostEditorInsetsShape {
|
||||
$onDidDispose(handle: number): void;
|
||||
$onDidReceiveMessage(handle: number, message: any): void;
|
||||
}
|
||||
|
||||
export type WebviewPanelHandle = string;
|
||||
|
||||
export type WebviewInsetHandle = number;
|
||||
|
||||
export interface WebviewPanelShowOptions {
|
||||
readonly viewColumn?: EditorViewColumn;
|
||||
readonly preserveFocus?: boolean;
|
||||
@@ -524,15 +538,14 @@ export interface WebviewPanelShowOptions {
|
||||
|
||||
export interface MainThreadWebviewsShape extends IDisposable {
|
||||
$createWebviewPanel(handle: WebviewPanelHandle, viewType: string, title: string, showOptions: WebviewPanelShowOptions, options: modes.IWebviewPanelOptions & modes.IWebviewOptions, extensionId: ExtensionIdentifier, extensionLocation: UriComponents): void;
|
||||
$createWebviewCodeInset(handle: WebviewInsetHandle, symbolId: string, options: modes.IWebviewOptions, extensionId: ExtensionIdentifier | undefined, extensionLocation: UriComponents | undefined): void;
|
||||
$disposeWebview(handle: WebviewPanelHandle): void;
|
||||
$reveal(handle: WebviewPanelHandle, showOptions: WebviewPanelShowOptions): void;
|
||||
$setTitle(handle: WebviewPanelHandle, value: string): void;
|
||||
$setIconPath(handle: WebviewPanelHandle, value: { light: UriComponents, dark: UriComponents } | undefined): void;
|
||||
|
||||
$setHtml(handle: WebviewPanelHandle | WebviewInsetHandle, value: string): void;
|
||||
$setOptions(handle: WebviewPanelHandle | WebviewInsetHandle, options: modes.IWebviewOptions): void;
|
||||
$postMessage(handle: WebviewPanelHandle | WebviewInsetHandle, value: any): Promise<boolean>;
|
||||
$setHtml(handle: WebviewPanelHandle, value: string): void;
|
||||
$setOptions(handle: WebviewPanelHandle, options: modes.IWebviewOptions): void;
|
||||
$postMessage(handle: WebviewPanelHandle, value: any): Promise<boolean>;
|
||||
|
||||
$registerSerializer(viewType: string): void;
|
||||
$unregisterSerializer(viewType: string): void;
|
||||
@@ -567,7 +580,7 @@ export interface ITextSearchComplete {
|
||||
export interface MainThreadWorkspaceShape extends IDisposable {
|
||||
$startFileSearch(includePattern: string | undefined, includeFolder: UriComponents | undefined, excludePatternOrDisregardExcludes: string | false | undefined, maxResults: number | undefined, token: CancellationToken): Promise<UriComponents[] | undefined>;
|
||||
$startTextSearch(query: search.IPatternInfo, options: ITextQueryBuilderOptions, requestId: number, token: CancellationToken): Promise<ITextSearchComplete>;
|
||||
$checkExists(includes: string[], token: CancellationToken): Promise<boolean>;
|
||||
$checkExists(folders: UriComponents[], includes: string[], token: CancellationToken): Promise<boolean>;
|
||||
$saveAll(includeUntitled?: boolean): Promise<boolean>;
|
||||
$updateWorkspaceFolders(extensionName: string, index: number, deleteCount: number, workspaceFoldersToAdd: { uri: UriComponents, name?: string }[]): Promise<void>;
|
||||
$resolveProxy(url: string): Promise<string | undefined>;
|
||||
@@ -581,9 +594,21 @@ export interface IFileChangeDto {
|
||||
export interface MainThreadFileSystemShape extends IDisposable {
|
||||
$registerFileSystemProvider(handle: number, scheme: string, capabilities: files.FileSystemProviderCapabilities): void;
|
||||
$unregisterProvider(handle: number): void;
|
||||
$onFileSystemChange(handle: number, resource: IFileChangeDto[]): void;
|
||||
|
||||
$stat(uri: UriComponents): Promise<files.IStat>;
|
||||
$readdir(resource: UriComponents): Promise<[string, files.FileType][]>;
|
||||
$readFile(resource: UriComponents): Promise<VSBuffer>;
|
||||
$writeFile(resource: UriComponents, content: VSBuffer): Promise<void>;
|
||||
$rename(resource: UriComponents, target: UriComponents, opts: files.FileOverwriteOptions): Promise<void>;
|
||||
$copy(resource: UriComponents, target: UriComponents, opts: files.FileOverwriteOptions): Promise<void>;
|
||||
$mkdir(resource: UriComponents): Promise<void>;
|
||||
$delete(resource: UriComponents, opts: files.FileDeleteOptions): Promise<void>;
|
||||
}
|
||||
|
||||
export interface MainThreadLabelServiceShape extends IDisposable {
|
||||
$registerResourceLabelFormatter(handle: number, formatter: ResourceLabelFormatter): void;
|
||||
$unregisterResourceLabelFormatter(handle: number): void;
|
||||
$onFileSystemChange(handle: number, resource: IFileChangeDto[]): void;
|
||||
}
|
||||
|
||||
export interface MainThreadSearchShape extends IDisposable {
|
||||
@@ -597,7 +622,7 @@ export interface MainThreadSearchShape extends IDisposable {
|
||||
|
||||
export interface MainThreadTaskShape extends IDisposable {
|
||||
$createTaskId(task: tasks.TaskDTO): Promise<string>;
|
||||
$registerTaskProvider(handle: number): Promise<void>;
|
||||
$registerTaskProvider(handle: number, type: string): Promise<void>;
|
||||
$unregisterTaskProvider(handle: number): Promise<void>;
|
||||
$fetchTasks(filter?: tasks.TaskFilterDTO): Promise<tasks.TaskDTO[]>;
|
||||
$executeTask(task: tasks.TaskHandleDTO | tasks.TaskDTO): Promise<tasks.TaskExecutionDTO>;
|
||||
@@ -813,6 +838,10 @@ export interface ExtHostFileSystemShape {
|
||||
$write(handle: number, fd: number, pos: number, data: VSBuffer): Promise<number>;
|
||||
}
|
||||
|
||||
export interface ExtHostLabelServiceShape {
|
||||
$registerResourceLabelFormatter(formatter: ResourceLabelFormatter): IDisposable;
|
||||
}
|
||||
|
||||
export interface ExtHostSearchShape {
|
||||
$provideFileSearchResults(handle: number, session: number, query: search.IRawQuery, token: CancellationToken): Promise<search.ISearchCompleteStats>;
|
||||
$provideTextSearchResults(handle: number, session: number, query: search.IRawTextQuery, token: CancellationToken): Promise<search.ISearchCompleteStats>;
|
||||
@@ -916,6 +945,20 @@ export interface SuggestResultDto {
|
||||
c?: boolean;
|
||||
}
|
||||
|
||||
export interface SignatureHelpDto {
|
||||
id: CacheId;
|
||||
signatures: modes.SignatureInformation[];
|
||||
activeSignature: number;
|
||||
activeParameter: number;
|
||||
}
|
||||
|
||||
export interface SignatureHelpContextDto {
|
||||
readonly triggerKind: modes.SignatureHelpTriggerKind;
|
||||
readonly triggerCharacter?: string;
|
||||
readonly isRetrigger: boolean;
|
||||
readonly activeSignatureHelp?: SignatureHelpDto;
|
||||
}
|
||||
|
||||
export interface LocationDto {
|
||||
uri: UriComponents;
|
||||
range: IRange;
|
||||
@@ -988,6 +1031,11 @@ export interface CodeActionDto {
|
||||
isPreferred?: boolean;
|
||||
}
|
||||
|
||||
export interface CodeActionListDto {
|
||||
cacheId: number;
|
||||
actions: ReadonlyArray<CodeActionDto>;
|
||||
}
|
||||
|
||||
export type CacheId = number;
|
||||
export type ChainedCacheId = [CacheId, CacheId];
|
||||
|
||||
@@ -1000,16 +1048,20 @@ export interface LinkDto {
|
||||
cacheId?: ChainedCacheId;
|
||||
range: IRange;
|
||||
url?: string | UriComponents;
|
||||
tooltip?: string;
|
||||
}
|
||||
|
||||
export interface CodeLensDto extends ObjectIdentifier {
|
||||
export interface CodeLensListDto {
|
||||
cacheId?: number;
|
||||
lenses: CodeLensDto[];
|
||||
}
|
||||
|
||||
export interface CodeLensDto {
|
||||
cacheId?: ChainedCacheId;
|
||||
range: IRange;
|
||||
id?: string;
|
||||
command?: CommandDto;
|
||||
}
|
||||
|
||||
export type CodeInsetDto = ObjectIdentifier & codeInset.ICodeInsetSymbol;
|
||||
|
||||
export interface CallHierarchyDto {
|
||||
_id: number;
|
||||
kind: modes.SymbolKind;
|
||||
@@ -1022,10 +1074,9 @@ export interface CallHierarchyDto {
|
||||
|
||||
export interface ExtHostLanguageFeaturesShape {
|
||||
$provideDocumentSymbols(handle: number, resource: UriComponents, token: CancellationToken): Promise<modes.DocumentSymbol[] | undefined>;
|
||||
$provideCodeLenses(handle: number, resource: UriComponents, token: CancellationToken): Promise<CodeLensDto[]>;
|
||||
$provideCodeLenses(handle: number, resource: UriComponents, token: CancellationToken): Promise<CodeLensListDto | undefined>;
|
||||
$resolveCodeLens(handle: number, symbol: CodeLensDto, token: CancellationToken): Promise<CodeLensDto | undefined>;
|
||||
$provideCodeInsets(handle: number, resource: UriComponents, token: CancellationToken): Promise<CodeInsetDto[] | undefined>;
|
||||
$resolveCodeInset(handle: number, resource: UriComponents, symbol: CodeInsetDto, token: CancellationToken): Promise<CodeInsetDto>;
|
||||
$releaseCodeLenses(handle: number, id: number): void;
|
||||
$provideDefinition(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Promise<DefinitionLinkDto[]>;
|
||||
$provideDeclaration(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Promise<DefinitionLinkDto[]>;
|
||||
$provideImplementation(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Promise<DefinitionLinkDto[]>;
|
||||
@@ -1033,7 +1084,8 @@ export interface ExtHostLanguageFeaturesShape {
|
||||
$provideHover(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Promise<modes.Hover | undefined>;
|
||||
$provideDocumentHighlights(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Promise<modes.DocumentHighlight[] | undefined>;
|
||||
$provideReferences(handle: number, resource: UriComponents, position: IPosition, context: modes.ReferenceContext, token: CancellationToken): Promise<LocationDto[] | undefined>;
|
||||
$provideCodeActions(handle: number, resource: UriComponents, rangeOrSelection: IRange | ISelection, context: modes.CodeActionContext, token: CancellationToken): Promise<CodeActionDto[] | undefined>;
|
||||
$provideCodeActions(handle: number, resource: UriComponents, rangeOrSelection: IRange | ISelection, context: modes.CodeActionContext, token: CancellationToken): Promise<CodeActionListDto | undefined>;
|
||||
$releaseCodeActions(handle: number, cacheId: number): void;
|
||||
$provideDocumentFormattingEdits(handle: number, resource: UriComponents, options: modes.FormattingOptions, token: CancellationToken): Promise<ISingleEditOperation[] | undefined>;
|
||||
$provideDocumentRangeFormattingEdits(handle: number, resource: UriComponents, range: IRange, options: modes.FormattingOptions, token: CancellationToken): Promise<ISingleEditOperation[] | undefined>;
|
||||
$provideOnTypeFormattingEdits(handle: number, resource: UriComponents, position: IPosition, ch: string, options: modes.FormattingOptions, token: CancellationToken): Promise<ISingleEditOperation[] | undefined>;
|
||||
@@ -1045,7 +1097,8 @@ export interface ExtHostLanguageFeaturesShape {
|
||||
$provideCompletionItems(handle: number, resource: UriComponents, position: IPosition, context: modes.CompletionContext, token: CancellationToken): Promise<SuggestResultDto | undefined>;
|
||||
$resolveCompletionItem(handle: number, resource: UriComponents, position: IPosition, id: ChainedCacheId, token: CancellationToken): Promise<SuggestDataDto | undefined>;
|
||||
$releaseCompletionItems(handle: number, id: number): void;
|
||||
$provideSignatureHelp(handle: number, resource: UriComponents, position: IPosition, context: modes.SignatureHelpContext, token: CancellationToken): Promise<modes.SignatureHelp | undefined>;
|
||||
$provideSignatureHelp(handle: number, resource: UriComponents, position: IPosition, context: modes.SignatureHelpContext, token: CancellationToken): Promise<SignatureHelpDto | undefined>;
|
||||
$releaseSignatureHelp(handle: number, id: number): void;
|
||||
$provideDocumentLinks(handle: number, resource: UriComponents, token: CancellationToken): Promise<LinksListDto | undefined>;
|
||||
$resolveDocumentLink(handle: number, id: ChainedCacheId, token: CancellationToken): Promise<LinkDto | undefined>;
|
||||
$releaseDocumentLinks(handle: number, id: number): void;
|
||||
@@ -1076,6 +1129,21 @@ export interface ShellLaunchConfigDto {
|
||||
env?: { [key: string]: string | null };
|
||||
}
|
||||
|
||||
export interface IShellDefinitionDto {
|
||||
label: string;
|
||||
path: string;
|
||||
}
|
||||
|
||||
export interface IShellAndArgsDto {
|
||||
shell: string;
|
||||
args: string[] | string | undefined;
|
||||
}
|
||||
|
||||
export interface ITerminalDimensionsDto {
|
||||
columns: number;
|
||||
rows: number;
|
||||
}
|
||||
|
||||
export interface ExtHostTerminalServiceShape {
|
||||
$acceptTerminalClosed(id: number): void;
|
||||
$acceptTerminalOpened(id: number, name: string): void;
|
||||
@@ -1085,13 +1153,18 @@ export interface ExtHostTerminalServiceShape {
|
||||
$acceptTerminalRendererInput(id: number, data: string): void;
|
||||
$acceptTerminalTitleChange(id: number, name: string): void;
|
||||
$acceptTerminalDimensions(id: number, cols: number, rows: number): void;
|
||||
$acceptTerminalMaximumDimensions(id: number, cols: number, rows: number): void;
|
||||
$createProcess(id: number, shellLaunchConfig: ShellLaunchConfigDto, activeWorkspaceRootUri: UriComponents, cols: number, rows: number, isWorkspaceShellAllowed: boolean): void;
|
||||
$startVirtualProcess(id: number, initialDimensions: ITerminalDimensionsDto | undefined): void;
|
||||
$acceptProcessInput(id: number, data: string): void;
|
||||
$acceptProcessResize(id: number, cols: number, rows: number): void;
|
||||
$acceptProcessShutdown(id: number, immediate: boolean): void;
|
||||
$acceptProcessRequestInitialCwd(id: number): void;
|
||||
$acceptProcessRequestCwd(id: number): void;
|
||||
$acceptProcessRequestLatency(id: number): number;
|
||||
$acceptWorkspacePermissionsChanged(isAllowed: boolean): void;
|
||||
$requestAvailableShells(): Promise<IShellDefinitionDto[]>;
|
||||
$requestDefaultShellAndArgs(): Promise<IShellAndArgsDto>;
|
||||
}
|
||||
|
||||
export interface ExtHostSCMShape {
|
||||
@@ -1104,6 +1177,7 @@ export interface ExtHostSCMShape {
|
||||
|
||||
export interface ExtHostTaskShape {
|
||||
$provideTasks(handle: number, validTypes: { [key: string]: boolean; }): Thenable<tasks.TaskSetDTO>;
|
||||
$resolveTask(handle: number, taskDTO: tasks.TaskDTO): Thenable<tasks.TaskDTO | undefined>;
|
||||
$onDidStartTask(execution: tasks.TaskExecutionDTO, terminalId: number): void;
|
||||
$onDidStartTaskProcess(value: tasks.TaskProcessStartedDTO): void;
|
||||
$onDidEndTaskProcess(value: tasks.TaskProcessEndedDTO): void;
|
||||
@@ -1209,25 +1283,12 @@ export interface ExtHostProgressShape {
|
||||
}
|
||||
|
||||
export interface ExtHostCommentsShape {
|
||||
$provideDocumentComments(handle: number, document: UriComponents): Promise<modes.CommentInfo | null>;
|
||||
$createNewCommentThread(handle: number, document: UriComponents, range: IRange, text: string): Promise<modes.CommentThread | null>;
|
||||
$createCommentThreadTemplate(commentControllerHandle: number, uriComponents: UriComponents, range: IRange): void;
|
||||
$onCommentWidgetInputChange(commentControllerHandle: number, document: UriComponents, range: IRange, input: string | undefined): Promise<number | undefined>;
|
||||
$updateCommentThreadTemplate(commentControllerHandle: number, threadHandle: number, range: IRange): Promise<void>;
|
||||
$deleteCommentThread(commentControllerHandle: number, commentThreadHandle: number): void;
|
||||
$provideCommentingRanges(commentControllerHandle: number, uriComponents: UriComponents, token: CancellationToken): Promise<IRange[] | undefined>;
|
||||
$checkStaticContribution(commentControllerHandle: number): Promise<boolean>;
|
||||
$provideReactionGroup(commentControllerHandle: number): Promise<modes.CommentReaction[] | undefined>;
|
||||
$toggleReaction(commentControllerHandle: number, threadHandle: number, uri: UriComponents, comment: modes.Comment, reaction: modes.CommentReaction): Promise<void>;
|
||||
$createNewCommentWidgetCallback(commentControllerHandle: number, uriComponents: UriComponents, range: IRange, token: CancellationToken): Promise<void>;
|
||||
$replyToCommentThread(handle: number, document: UriComponents, range: IRange, commentThread: modes.CommentThread, text: string): Promise<modes.CommentThread | null>;
|
||||
$editComment(handle: number, document: UriComponents, comment: modes.Comment, text: string): Promise<void>;
|
||||
$deleteComment(handle: number, document: UriComponents, comment: modes.Comment): Promise<void>;
|
||||
$startDraft(handle: number, document: UriComponents): Promise<void>;
|
||||
$deleteDraft(handle: number, document: UriComponents): Promise<void>;
|
||||
$finishDraft(handle: number, document: UriComponents): Promise<void>;
|
||||
$addReaction(handle: number, document: UriComponents, comment: modes.Comment, reaction: modes.CommentReaction): Promise<void>;
|
||||
$deleteReaction(handle: number, document: UriComponents, comment: modes.Comment, reaction: modes.CommentReaction): Promise<void>;
|
||||
$provideWorkspaceComments(handle: number): Promise<modes.CommentThread[] | null>;
|
||||
}
|
||||
|
||||
export interface ExtHostStorageShape {
|
||||
@@ -1249,6 +1310,7 @@ export const MainContext = {
|
||||
MainThreadDocuments: createMainId<MainThreadDocumentsShape>('MainThreadDocuments'),
|
||||
MainThreadDocumentContentProviders: createMainId<MainThreadDocumentContentProvidersShape>('MainThreadDocumentContentProviders'),
|
||||
MainThreadTextEditors: createMainId<MainThreadTextEditorsShape>('MainThreadTextEditors'),
|
||||
MainThreadEditorInsets: createMainId<MainThreadEditorInsetsShape>('MainThreadEditorInsets'),
|
||||
MainThreadErrors: createMainId<MainThreadErrorsShape>('MainThreadErrors'),
|
||||
MainThreadTreeViews: createMainId<MainThreadTreeViewsShape>('MainThreadTreeViews'),
|
||||
MainThreadKeytar: createMainId<MainThreadKeytarShape>('MainThreadKeytar'),
|
||||
@@ -1271,6 +1333,7 @@ export const MainContext = {
|
||||
MainThreadSearch: createMainId<MainThreadSearchShape>('MainThreadSearch'),
|
||||
MainThreadTask: createMainId<MainThreadTaskShape>('MainThreadTask'),
|
||||
MainThreadWindow: createMainId<MainThreadWindowShape>('MainThreadWindow'),
|
||||
MainThreadLabelService: createMainId<MainThreadLabelServiceShape>('MainThreadLabelService')
|
||||
};
|
||||
|
||||
export const ExtHostContext = {
|
||||
@@ -1287,7 +1350,6 @@ export const ExtHostContext = {
|
||||
ExtHostTreeViews: createExtId<ExtHostTreeViewsShape>('ExtHostTreeViews'),
|
||||
ExtHostFileSystem: createExtId<ExtHostFileSystemShape>('ExtHostFileSystem'),
|
||||
ExtHostFileSystemEventService: createExtId<ExtHostFileSystemEventServiceShape>('ExtHostFileSystemEventService'),
|
||||
ExtHostHeapService: createExtId<ExtHostHeapServiceShape>('ExtHostHeapMonitor'),
|
||||
ExtHostLanguageFeatures: createExtId<ExtHostLanguageFeaturesShape>('ExtHostLanguageFeatures'),
|
||||
ExtHostQuickOpen: createExtId<ExtHostQuickOpenShape>('ExtHostQuickOpen'),
|
||||
ExtHostExtensionService: createExtId<ExtHostExtensionServiceShape>('ExtHostExtensionService'),
|
||||
@@ -1299,9 +1361,11 @@ export const ExtHostContext = {
|
||||
ExtHostWorkspace: createExtId<ExtHostWorkspaceShape>('ExtHostWorkspace'),
|
||||
ExtHostWindow: createExtId<ExtHostWindowShape>('ExtHostWindow'),
|
||||
ExtHostWebviews: createExtId<ExtHostWebviewsShape>('ExtHostWebviews'),
|
||||
ExtHostEditorInsets: createExtId<ExtHostEditorInsetsShape>('ExtHostEditorInsets'),
|
||||
ExtHostProgress: createMainId<ExtHostProgressShape>('ExtHostProgress'),
|
||||
ExtHostComments: createMainId<ExtHostCommentsShape>('ExtHostComments'),
|
||||
ExtHostStorage: createMainId<ExtHostStorageShape>('ExtHostStorage'),
|
||||
ExtHostUrls: createExtId<ExtHostUrlsShape>('ExtHostUrls'),
|
||||
ExtHostOutputService: createMainId<ExtHostOutputServiceShape>('ExtHostOutputService'),
|
||||
ExtHosLabelService: createMainId<ExtHostLabelServiceShape>('ExtHostLabelService')
|
||||
};
|
||||
|
||||
@@ -18,6 +18,7 @@ import { CustomCodeAction } from 'vs/workbench/api/common/extHostLanguageFeature
|
||||
import { ICommandsExecutor, OpenFolderAPICommand, DiffAPICommand, OpenAPICommand, RemoveFromRecentlyOpenedAPICommand, SetEditorLayoutAPICommand, OpenIssueReporter } from './apiCommands';
|
||||
import { EditorGroupLayout } from 'vs/workbench/services/editor/common/editorGroupsService';
|
||||
import { isFalsyOrEmpty } from 'vs/base/common/arrays';
|
||||
import { IRange } from 'vs/editor/common/core/range';
|
||||
|
||||
export class ExtHostApiCommands {
|
||||
|
||||
@@ -143,7 +144,7 @@ export class ExtHostApiCommands {
|
||||
description: 'Execute CodeLens provider.',
|
||||
args: [
|
||||
{ name: 'uri', description: 'Uri of a text document', constraint: URI },
|
||||
{ name: 'itemResolveCount', description: '(optional) Number of lenses that should be resolved and returned. Will only retrun resolved lenses, will impact performance)', constraint: (value: any) => value === undefined || typeof value === 'number' }
|
||||
{ name: 'itemResolveCount', description: '(optional) Number of lenses that should be resolved and returned. Will only return resolved lenses, will impact performance)', constraint: (value: any) => value === undefined || typeof value === 'number' }
|
||||
],
|
||||
returns: 'A promise that resolves to an array of CodeLens-instances.'
|
||||
});
|
||||
@@ -223,7 +224,7 @@ export class ExtHostApiCommands {
|
||||
description: 'Open a folder or workspace in the current window or new window depending on the newWindow argument. Note that opening in the same window will shutdown the current extension host process and start a new one on the given folder/workspace unless the newWindow parameter is set to true.',
|
||||
args: [
|
||||
{ name: 'uri', description: '(optional) Uri of the folder or workspace file to open. If not provided, a native dialog will ask the user for the folder', constraint: (value: any) => value === undefined || value instanceof URI },
|
||||
{ name: 'options', description: '(optional) Options. Object with the following properties: `forceNewWindow `: Whether to open the folder/workspace in a new window or the same. Defaults to opening in the same window. `noRecentEntry`: Wheter the opened URI will appear in the \'Open Recent\' list. Defaults to true. Note, for backward compatibility, options can also be of type boolean, representing the `forceNewWindow` setting.', constraint: (value: any) => value === undefined || typeof value === 'object' || typeof value === 'boolean' }
|
||||
{ name: 'options', description: '(optional) Options. Object with the following properties: `forceNewWindow `: Whether to open the folder/workspace in a new window or the same. Defaults to opening in the same window. `noRecentEntry`: Whether the opened URI will appear in the \'Open Recent\' list. Defaults to true. Note, for backward compatibility, options can also be of type boolean, representing the `forceNewWindow` setting.', constraint: (value: any) => value === undefined || typeof value === 'object' || typeof value === 'boolean' }
|
||||
]
|
||||
});
|
||||
|
||||
@@ -414,15 +415,21 @@ export class ExtHostApiCommands {
|
||||
});
|
||||
}
|
||||
|
||||
private _executeSelectionRangeProvider(resource: URI, positions: types.Position[]): Promise<vscode.SelectionRange[][]> {
|
||||
private _executeSelectionRangeProvider(resource: URI, positions: types.Position[]): Promise<vscode.SelectionRange[]> {
|
||||
const pos = positions.map(typeConverters.Position.from);
|
||||
const args = {
|
||||
resource,
|
||||
position: pos[0],
|
||||
positions: pos
|
||||
};
|
||||
return this._commands.executeCommand<modes.SelectionRange[][]>('_executeSelectionRangeProvider', args).then(result => {
|
||||
return result.map(oneResult => oneResult.map(typeConverters.SelectionRange.to));
|
||||
return this._commands.executeCommand<IRange[][]>('_executeSelectionRangeProvider', args).then(result => {
|
||||
return result.map(ranges => {
|
||||
let node: types.SelectionRange | undefined;
|
||||
for (const range of ranges.reverse()) {
|
||||
node = new types.SelectionRange(typeConverters.Range.to(range), node);
|
||||
}
|
||||
return node!;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -473,7 +480,7 @@ export class ExtHostApiCommands {
|
||||
});
|
||||
}
|
||||
|
||||
private _executeCodeActionProvider(resource: URI, range: types.Range, kind?: string): Promise<(vscode.CodeAction | vscode.Command)[] | undefined> {
|
||||
private _executeCodeActionProvider(resource: URI, range: types.Range, kind?: string): Promise<(vscode.CodeAction | vscode.Command | undefined)[] | undefined> {
|
||||
const args = {
|
||||
resource,
|
||||
range: typeConverters.Range.from(range),
|
||||
@@ -504,7 +511,7 @@ export class ExtHostApiCommands {
|
||||
|
||||
private _executeCodeLensProvider(resource: URI, itemResolveCount: number): Promise<vscode.CodeLens[] | undefined> {
|
||||
const args = { resource, itemResolveCount };
|
||||
return this._commands.executeCommand<modes.ICodeLensSymbol[]>('_executeCodeLensProvider', args)
|
||||
return this._commands.executeCommand<modes.CodeLens[]>('_executeCodeLensProvider', args)
|
||||
.then(tryMapWith(item => {
|
||||
return new types.CodeLens(
|
||||
typeConverters.Range.to(item.range),
|
||||
|
||||
143
src/vs/workbench/api/common/extHostCodeInsets.ts
Normal file
@@ -0,0 +1,143 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { Emitter } from 'vs/base/common/event';
|
||||
import { DisposableStore } from 'vs/base/common/lifecycle';
|
||||
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
||||
import { ExtHostTextEditor } from 'vs/workbench/api/common/extHostTextEditor';
|
||||
import { ExtHostEditors } from 'vs/workbench/api/common/extHostTextEditors';
|
||||
import * as vscode from 'vscode';
|
||||
import { ExtHostEditorInsetsShape, MainThreadEditorInsetsShape } from './extHost.protocol';
|
||||
import { toWebviewResource, WebviewInitData } from 'vs/workbench/api/common/shared/webview';
|
||||
import { generateUuid } from 'vs/base/common/uuid';
|
||||
|
||||
export class ExtHostEditorInsets implements ExtHostEditorInsetsShape {
|
||||
|
||||
private _handlePool = 0;
|
||||
private _disposables = new DisposableStore();
|
||||
private _insets = new Map<number, { editor: vscode.TextEditor, inset: vscode.WebviewEditorInset, onDidReceiveMessage: Emitter<any> }>();
|
||||
|
||||
constructor(
|
||||
private readonly _proxy: MainThreadEditorInsetsShape,
|
||||
private readonly _editors: ExtHostEditors,
|
||||
private readonly _initData: WebviewInitData
|
||||
) {
|
||||
|
||||
// dispose editor inset whenever the hosting editor goes away
|
||||
this._disposables.add(_editors.onDidChangeVisibleTextEditors(() => {
|
||||
const visibleEditor = _editors.getVisibleTextEditors();
|
||||
this._insets.forEach(value => {
|
||||
if (visibleEditor.indexOf(value.editor) < 0) {
|
||||
value.inset.dispose(); // will remove from `this._insets`
|
||||
}
|
||||
});
|
||||
}));
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
this._insets.forEach(value => value.inset.dispose());
|
||||
this._disposables.dispose();
|
||||
}
|
||||
|
||||
createWebviewEditorInset(editor: vscode.TextEditor, line: number, height: number, options: vscode.WebviewOptions | undefined, extension: IExtensionDescription): vscode.WebviewEditorInset {
|
||||
|
||||
let apiEditor: ExtHostTextEditor | undefined;
|
||||
for (const candidate of this._editors.getVisibleTextEditors()) {
|
||||
if (candidate === editor) {
|
||||
apiEditor = <ExtHostTextEditor>candidate;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!apiEditor) {
|
||||
throw new Error('not a visible editor');
|
||||
}
|
||||
|
||||
const that = this;
|
||||
const handle = this._handlePool++;
|
||||
const onDidReceiveMessage = new Emitter<any>();
|
||||
const onDidDispose = new Emitter<void>();
|
||||
|
||||
const webview = new class implements vscode.Webview {
|
||||
|
||||
private readonly _uuid = generateUuid();
|
||||
private _html: string = '';
|
||||
private _options: vscode.WebviewOptions;
|
||||
|
||||
toWebviewResource(resource: vscode.Uri): vscode.Uri {
|
||||
return toWebviewResource(that._initData, this._uuid, resource);
|
||||
}
|
||||
|
||||
get cspSource(): string {
|
||||
return that._initData.webviewCspSource;
|
||||
}
|
||||
|
||||
set options(value: vscode.WebviewOptions) {
|
||||
this._options = value;
|
||||
that._proxy.$setOptions(handle, value);
|
||||
}
|
||||
|
||||
get options(): vscode.WebviewOptions {
|
||||
return this._options;
|
||||
}
|
||||
|
||||
set html(value: string) {
|
||||
this._html = value;
|
||||
that._proxy.$setHtml(handle, value);
|
||||
}
|
||||
|
||||
get html(): string {
|
||||
return this._html;
|
||||
}
|
||||
|
||||
get onDidReceiveMessage(): vscode.Event<any> {
|
||||
return onDidReceiveMessage.event;
|
||||
}
|
||||
|
||||
postMessage(message: any): Thenable<boolean> {
|
||||
return that._proxy.$postMessage(handle, message);
|
||||
}
|
||||
};
|
||||
|
||||
const inset = new class implements vscode.WebviewEditorInset {
|
||||
|
||||
readonly editor: vscode.TextEditor = editor;
|
||||
readonly line: number = line;
|
||||
readonly height: number = height;
|
||||
readonly webview: vscode.Webview = webview;
|
||||
readonly onDidDispose: vscode.Event<void> = onDidDispose.event;
|
||||
|
||||
dispose(): void {
|
||||
if (that._insets.has(handle)) {
|
||||
that._insets.delete(handle);
|
||||
that._proxy.$disposeEditorInset(handle);
|
||||
onDidDispose.fire();
|
||||
|
||||
// final cleanup
|
||||
onDidDispose.dispose();
|
||||
onDidReceiveMessage.dispose();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
this._proxy.$createEditorInset(handle, apiEditor.id, apiEditor.document.uri, line + 1, height, options || {}, extension.identifier, extension.extensionLocation);
|
||||
this._insets.set(handle, { editor, inset, onDidReceiveMessage });
|
||||
|
||||
return inset;
|
||||
}
|
||||
|
||||
$onDidDispose(handle: number): void {
|
||||
const value = this._insets.get(handle);
|
||||
if (value) {
|
||||
value.inset.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
$onDidReceiveMessage(handle: number, message: any): void {
|
||||
const value = this._insets.get(handle);
|
||||
if (value) {
|
||||
value.onDidReceiveMessage.fire(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9,7 +9,6 @@ import * as extHostTypes from 'vs/workbench/api/common/extHostTypes';
|
||||
import * as extHostTypeConverter from 'vs/workbench/api/common/extHostTypeConverters';
|
||||
import { cloneAndChange } from 'vs/base/common/objects';
|
||||
import { MainContext, MainThreadCommandsShape, ExtHostCommandsShape, ObjectIdentifier, IMainContext, CommandDto } from './extHost.protocol';
|
||||
import { ExtHostHeapService } from 'vs/workbench/api/common/extHostHeapService';
|
||||
import { isNonEmptyArray } from 'vs/base/common/arrays';
|
||||
import * as modes from 'vs/editor/common/modes';
|
||||
import * as vscode from 'vscode';
|
||||
@@ -18,6 +17,7 @@ import { revive } from 'vs/base/common/marshalling';
|
||||
import { Range } from 'vs/editor/common/core/range';
|
||||
import { Position } from 'vs/editor/common/core/position';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { DisposableStore, toDisposable } from 'vs/base/common/lifecycle';
|
||||
|
||||
interface CommandHandler {
|
||||
callback: Function;
|
||||
@@ -39,12 +39,11 @@ export class ExtHostCommands implements ExtHostCommandsShape {
|
||||
|
||||
constructor(
|
||||
mainContext: IMainContext,
|
||||
heapService: ExtHostHeapService,
|
||||
logService: ILogService
|
||||
) {
|
||||
this._proxy = mainContext.getProxy(MainContext.MainThreadCommands);
|
||||
this._logService = logService;
|
||||
this._converter = new CommandsConverter(this, heapService);
|
||||
this._converter = new CommandsConverter(this);
|
||||
this._argumentProcessors = [
|
||||
{
|
||||
processArgument(a) {
|
||||
@@ -200,21 +199,18 @@ export class ExtHostCommands implements ExtHostCommandsShape {
|
||||
export class CommandsConverter {
|
||||
|
||||
private readonly _delegatingCommandId: string;
|
||||
private _commands: ExtHostCommands;
|
||||
private _heap: ExtHostHeapService;
|
||||
private readonly _commands: ExtHostCommands;
|
||||
private readonly _cache = new Map<number, vscode.Command>();
|
||||
private _cachIdPool = 0;
|
||||
|
||||
// --- conversion between internal and api commands
|
||||
constructor(commands: ExtHostCommands, heap: ExtHostHeapService) {
|
||||
constructor(commands: ExtHostCommands) {
|
||||
this._delegatingCommandId = `_internal_command_delegation_${Date.now()}`;
|
||||
this._commands = commands;
|
||||
this._heap = heap;
|
||||
this._commands.registerCommand(true, this._delegatingCommandId, this._executeConvertedCommand, this);
|
||||
}
|
||||
|
||||
toInternal(command: vscode.Command): CommandDto;
|
||||
toInternal(command: undefined): undefined;
|
||||
toInternal(command: vscode.Command | undefined): CommandDto | undefined;
|
||||
toInternal(command: vscode.Command | undefined): CommandDto | undefined {
|
||||
toInternal(command: vscode.Command | undefined, disposables: DisposableStore): CommandDto | undefined {
|
||||
|
||||
if (!command) {
|
||||
return undefined;
|
||||
@@ -224,31 +220,31 @@ export class CommandsConverter {
|
||||
$ident: undefined,
|
||||
id: command.command,
|
||||
title: command.title,
|
||||
tooltip: command.tooltip
|
||||
};
|
||||
|
||||
if (command.command && isNonEmptyArray(command.arguments)) {
|
||||
// we have a contributed command with arguments. that
|
||||
// means we don't want to send the arguments around
|
||||
|
||||
const id = this._heap.keep(command);
|
||||
const id = ++this._cachIdPool;
|
||||
this._cache.set(id, command);
|
||||
disposables.add(toDisposable(() => this._cache.delete(id)));
|
||||
result.$ident = id;
|
||||
|
||||
result.id = this._delegatingCommandId;
|
||||
result.arguments = [id];
|
||||
}
|
||||
|
||||
if (command.tooltip) {
|
||||
result.tooltip = command.tooltip;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
fromInternal(command: modes.Command): vscode.Command {
|
||||
fromInternal(command: modes.Command): vscode.Command | undefined {
|
||||
|
||||
const id = ObjectIdentifier.of(command);
|
||||
if (typeof id === 'number') {
|
||||
return this._heap.get<vscode.Command>(id);
|
||||
return this._cache.get(id);
|
||||
|
||||
} else {
|
||||
return {
|
||||
@@ -260,7 +256,10 @@ export class CommandsConverter {
|
||||
}
|
||||
|
||||
private _executeConvertedCommand<R>(...args: any[]): Promise<R> {
|
||||
const actualCmd = this._heap.get<vscode.Command>(args[0]);
|
||||
const actualCmd = this._cache.get(args[0]);
|
||||
if (!actualCmd) {
|
||||
return Promise.reject('actual command NOT FOUND');
|
||||
}
|
||||
return this._commands.executeCommand(actualCmd.command, ...(actualCmd.arguments || []));
|
||||
}
|
||||
|
||||
|
||||
@@ -4,29 +4,25 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { asPromise } from 'vs/base/common/async';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { debounce } from 'vs/base/common/decorators';
|
||||
import { Emitter } from 'vs/base/common/event';
|
||||
import { DisposableStore, IDisposable, MutableDisposable } from 'vs/base/common/lifecycle';
|
||||
import { URI, UriComponents } from 'vs/base/common/uri';
|
||||
import { IRange } from 'vs/editor/common/core/range';
|
||||
import * as modes from 'vs/editor/common/modes';
|
||||
import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
||||
import { ExtHostDocuments } from 'vs/workbench/api/common/extHostDocuments';
|
||||
import * as extHostTypeConverter from 'vs/workbench/api/common/extHostTypeConverters';
|
||||
import * as types from 'vs/workbench/api/common/extHostTypes';
|
||||
import * as vscode from 'vscode';
|
||||
import { ExtHostCommentsShape, IMainContext, MainContext, MainThreadCommentsShape } from './extHost.protocol';
|
||||
import { CommandsConverter, ExtHostCommands } from './extHostCommands';
|
||||
import { IRange } from 'vs/editor/common/core/range';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
||||
import { Event, Emitter } from 'vs/base/common/event';
|
||||
import { debounce } from 'vs/base/common/decorators';
|
||||
|
||||
interface HandlerData<T> {
|
||||
|
||||
extensionId: ExtensionIdentifier;
|
||||
provider: T;
|
||||
}
|
||||
import { ExtHostCommands } from './extHostCommands';
|
||||
|
||||
type ProviderHandle = number;
|
||||
|
||||
export class ExtHostComments implements ExtHostCommentsShape {
|
||||
export class ExtHostComments implements ExtHostCommentsShape, IDisposable {
|
||||
|
||||
private static handlePool = 0;
|
||||
|
||||
private _proxy: MainThreadCommentsShape;
|
||||
@@ -35,17 +31,15 @@ export class ExtHostComments implements ExtHostCommentsShape {
|
||||
|
||||
private _commentControllersByExtension: Map<string, ExtHostCommentController[]> = new Map<string, ExtHostCommentController[]>();
|
||||
|
||||
private _documentProviders = new Map<number, HandlerData<vscode.DocumentCommentProvider>>();
|
||||
private _workspaceProviders = new Map<number, HandlerData<vscode.WorkspaceCommentProvider>>();
|
||||
|
||||
constructor(
|
||||
mainContext: IMainContext,
|
||||
private _commands: ExtHostCommands,
|
||||
commands: ExtHostCommands,
|
||||
private readonly _documents: ExtHostDocuments,
|
||||
) {
|
||||
this._proxy = mainContext.getProxy(MainContext.MainThreadComments);
|
||||
|
||||
_commands.registerArgumentProcessor({
|
||||
commands.registerArgumentProcessor({
|
||||
processArgument: arg => {
|
||||
if (arg && arg.$mid === 6) {
|
||||
const commentController = this._commentControllers.get(arg.handle);
|
||||
@@ -142,7 +136,7 @@ export class ExtHostComments implements ExtHostCommentsShape {
|
||||
|
||||
createCommentController(extension: IExtensionDescription, id: string, label: string): vscode.CommentController {
|
||||
const handle = ExtHostComments.handlePool++;
|
||||
const commentController = new ExtHostCommentController(extension, handle, this._commands.converter, this._proxy, id, label);
|
||||
const commentController = new ExtHostCommentController(extension, handle, this._proxy, id, label);
|
||||
this._commentControllers.set(commentController.handle, commentController);
|
||||
|
||||
const commentControllers = this._commentControllersByExtension.get(ExtensionIdentifier.toKey(extension.identifier)) || [];
|
||||
@@ -162,15 +156,14 @@ export class ExtHostComments implements ExtHostCommentsShape {
|
||||
commentController.$createCommentThreadTemplate(uriComponents, range);
|
||||
}
|
||||
|
||||
$onCommentWidgetInputChange(commentControllerHandle: number, uriComponents: UriComponents, range: IRange, input: string): Promise<number | undefined> {
|
||||
async $updateCommentThreadTemplate(commentControllerHandle: number, threadHandle: number, range: IRange) {
|
||||
const commentController = this._commentControllers.get(commentControllerHandle);
|
||||
|
||||
if (!commentController) {
|
||||
return Promise.resolve(undefined);
|
||||
return;
|
||||
}
|
||||
|
||||
commentController.$onCommentWidgetInputChange(uriComponents, range, input);
|
||||
return Promise.resolve(commentControllerHandle);
|
||||
commentController.$updateCommentThreadTemplate(threadHandle, range);
|
||||
}
|
||||
|
||||
$deleteCommentThread(commentControllerHandle: number, commentThreadHandle: number) {
|
||||
@@ -203,14 +196,14 @@ export class ExtHostComments implements ExtHostCommentsShape {
|
||||
|
||||
return asPromise(() => {
|
||||
return commentController!.reactionProvider!.availableReactions;
|
||||
}).then(reactions => reactions.map(reaction => convertToReaction2(commentController.reactionProvider, reaction)));
|
||||
}).then(reactions => reactions.map(reaction => convertToReaction(commentController.reactionProvider, reaction)));
|
||||
}
|
||||
|
||||
$toggleReaction(commentControllerHandle: number, threadHandle: number, uri: UriComponents, comment: modes.Comment, reaction: modes.CommentReaction): Promise<void> {
|
||||
const document = this._documents.getDocument(URI.revive(uri));
|
||||
const commentController = this._commentControllers.get(commentControllerHandle);
|
||||
|
||||
if (!commentController || !commentController.reactionProvider || !commentController.reactionProvider.toggleReaction) {
|
||||
if (!commentController || !((commentController.reactionProvider && commentController.reactionProvider.toggleReaction) || commentController.reactionHandler)) {
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
|
||||
@@ -219,238 +212,24 @@ export class ExtHostComments implements ExtHostCommentsShape {
|
||||
if (commentThread) {
|
||||
const vscodeComment = commentThread.getComment(comment.commentId);
|
||||
|
||||
if (commentController !== undefined && commentController.reactionProvider && commentController.reactionProvider.toggleReaction && vscodeComment) {
|
||||
return commentController.reactionProvider.toggleReaction(document, vscodeComment, convertFromReaction(reaction));
|
||||
if (commentController !== undefined && vscodeComment) {
|
||||
if (commentController.reactionHandler) {
|
||||
return commentController.reactionHandler(vscodeComment, convertFromReaction(reaction));
|
||||
}
|
||||
|
||||
if (commentController.reactionProvider && commentController.reactionProvider.toggleReaction) {
|
||||
return commentController.reactionProvider.toggleReaction(document, vscodeComment, convertFromReaction(reaction));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return Promise.resolve(undefined);
|
||||
});
|
||||
}
|
||||
|
||||
$createNewCommentWidgetCallback(commentControllerHandle: number, uriComponents: UriComponents, range: IRange, token: CancellationToken): Promise<void> {
|
||||
const commentController = this._commentControllers.get(commentControllerHandle);
|
||||
dispose() {
|
||||
|
||||
if (!commentController) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
if (!(commentController as any).emptyCommentThreadFactory) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
const document = this._documents.getDocument(URI.revive(uriComponents));
|
||||
return asPromise(() => {
|
||||
if ((commentController as any).emptyCommentThreadFactory) {
|
||||
return (commentController as any).emptyCommentThreadFactory!.createEmptyCommentThread(document, extHostTypeConverter.Range.to(range));
|
||||
}
|
||||
}).then(() => Promise.resolve());
|
||||
}
|
||||
|
||||
$checkStaticContribution(commentControllerHandle: number): Promise<boolean> {
|
||||
const commentController = this._commentControllers.get(commentControllerHandle);
|
||||
|
||||
if (!commentController) {
|
||||
return Promise.resolve(false);
|
||||
}
|
||||
|
||||
if (!(commentController as any).emptyCommentThreadFactory) {
|
||||
return Promise.resolve(true);
|
||||
}
|
||||
|
||||
return Promise.resolve(false);
|
||||
}
|
||||
|
||||
registerWorkspaceCommentProvider(
|
||||
extensionId: ExtensionIdentifier,
|
||||
provider: vscode.WorkspaceCommentProvider
|
||||
): vscode.Disposable {
|
||||
const handle = ExtHostComments.handlePool++;
|
||||
this._workspaceProviders.set(handle, {
|
||||
extensionId,
|
||||
provider
|
||||
});
|
||||
this._proxy.$registerWorkspaceCommentProvider(handle, extensionId);
|
||||
this.registerListeners(handle, extensionId, provider);
|
||||
|
||||
return {
|
||||
dispose: () => {
|
||||
this._proxy.$unregisterWorkspaceCommentProvider(handle);
|
||||
this._workspaceProviders.delete(handle);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
registerDocumentCommentProvider(
|
||||
extensionId: ExtensionIdentifier,
|
||||
provider: vscode.DocumentCommentProvider
|
||||
): vscode.Disposable {
|
||||
const handle = ExtHostComments.handlePool++;
|
||||
this._documentProviders.set(handle, {
|
||||
extensionId,
|
||||
provider
|
||||
});
|
||||
this._proxy.$registerDocumentCommentProvider(handle, {
|
||||
startDraftLabel: provider.startDraftLabel,
|
||||
deleteDraftLabel: provider.deleteDraftLabel,
|
||||
finishDraftLabel: provider.finishDraftLabel,
|
||||
reactionGroup: provider.reactionGroup ? provider.reactionGroup.map(reaction => convertToReaction(provider, reaction)) : undefined
|
||||
});
|
||||
this.registerListeners(handle, extensionId, provider);
|
||||
|
||||
return {
|
||||
dispose: () => {
|
||||
this._proxy.$unregisterDocumentCommentProvider(handle);
|
||||
this._documentProviders.delete(handle);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
$createNewCommentThread(handle: number, uri: UriComponents, range: IRange, text: string): Promise<modes.CommentThread | null> {
|
||||
const data = this._documents.getDocumentData(URI.revive(uri));
|
||||
const ran = <vscode.Range>extHostTypeConverter.Range.to(range);
|
||||
|
||||
if (!data || !data.document) {
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
|
||||
const handlerData = this.getDocumentProvider(handle);
|
||||
return asPromise(() => {
|
||||
return handlerData.provider.createNewCommentThread(data.document, ran, text, CancellationToken.None);
|
||||
}).then(commentThread => commentThread ? convertToCommentThread(handlerData.extensionId, handlerData.provider, commentThread, this._commands.converter) : null);
|
||||
}
|
||||
|
||||
$replyToCommentThread(handle: number, uri: UriComponents, range: IRange, thread: modes.CommentThread, text: string): Promise<modes.CommentThread | null> {
|
||||
const data = this._documents.getDocumentData(URI.revive(uri));
|
||||
const ran = <vscode.Range>extHostTypeConverter.Range.to(range);
|
||||
|
||||
if (!data || !data.document) {
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
|
||||
const handlerData = this.getDocumentProvider(handle);
|
||||
return asPromise(() => {
|
||||
return handlerData.provider.replyToCommentThread(data.document, ran, convertFromCommentThread(thread), text, CancellationToken.None);
|
||||
}).then(commentThread => commentThread ? convertToCommentThread(handlerData.extensionId, handlerData.provider, commentThread, this._commands.converter) : null);
|
||||
}
|
||||
|
||||
$editComment(handle: number, uri: UriComponents, comment: modes.Comment, text: string): Promise<void> {
|
||||
const document = this._documents.getDocument(URI.revive(uri));
|
||||
const handlerData = this.getDocumentProvider(handle);
|
||||
if (!handlerData.provider.editComment) {
|
||||
return Promise.reject(new Error('not implemented'));
|
||||
}
|
||||
return asPromise(() => {
|
||||
return handlerData.provider.editComment!(document, convertFromComment(comment), text, CancellationToken.None);
|
||||
});
|
||||
}
|
||||
|
||||
$deleteComment(handle: number, uri: UriComponents, comment: modes.Comment): Promise<void> {
|
||||
const document = this._documents.getDocument(URI.revive(uri));
|
||||
const handlerData = this.getDocumentProvider(handle);
|
||||
if (!handlerData.provider.deleteComment) {
|
||||
return Promise.reject(new Error('not implemented'));
|
||||
}
|
||||
return asPromise(() => {
|
||||
return handlerData.provider.deleteComment!(document, convertFromComment(comment), CancellationToken.None);
|
||||
});
|
||||
}
|
||||
|
||||
$startDraft(handle: number, uri: UriComponents): Promise<void> {
|
||||
const document = this._documents.getDocument(URI.revive(uri));
|
||||
|
||||
const handlerData = this.getDocumentProvider(handle);
|
||||
if (!handlerData.provider.startDraft) {
|
||||
return Promise.reject(new Error('not implemented'));
|
||||
}
|
||||
return asPromise(() => {
|
||||
return handlerData.provider.startDraft!(document, CancellationToken.None);
|
||||
});
|
||||
}
|
||||
|
||||
$deleteDraft(handle: number, uri: UriComponents): Promise<void> {
|
||||
const document = this._documents.getDocument(URI.revive(uri));
|
||||
const handlerData = this.getDocumentProvider(handle);
|
||||
if (!handlerData.provider.deleteDraft) {
|
||||
return Promise.reject(new Error('not implemented'));
|
||||
}
|
||||
return asPromise(() => {
|
||||
return handlerData.provider.deleteDraft!(document, CancellationToken.None);
|
||||
});
|
||||
}
|
||||
|
||||
$finishDraft(handle: number, uri: UriComponents): Promise<void> {
|
||||
const document = this._documents.getDocument(URI.revive(uri));
|
||||
const handlerData = this.getDocumentProvider(handle);
|
||||
if (!handlerData.provider.finishDraft) {
|
||||
return Promise.reject(new Error('not implemented'));
|
||||
}
|
||||
return asPromise(() => {
|
||||
return handlerData.provider.finishDraft!(document, CancellationToken.None);
|
||||
});
|
||||
}
|
||||
|
||||
$addReaction(handle: number, uri: UriComponents, comment: modes.Comment, reaction: modes.CommentReaction): Promise<void> {
|
||||
const document = this._documents.getDocument(URI.revive(uri));
|
||||
const handlerData = this.getDocumentProvider(handle);
|
||||
if (!handlerData.provider.addReaction) {
|
||||
return Promise.reject(new Error('not implemented'));
|
||||
}
|
||||
return asPromise(() => {
|
||||
return handlerData.provider.addReaction!(document, convertFromComment(comment), convertFromReaction(reaction));
|
||||
});
|
||||
}
|
||||
|
||||
$deleteReaction(handle: number, uri: UriComponents, comment: modes.Comment, reaction: modes.CommentReaction): Promise<void> {
|
||||
const document = this._documents.getDocument(URI.revive(uri));
|
||||
const handlerData = this.getDocumentProvider(handle);
|
||||
if (!handlerData.provider.deleteReaction) {
|
||||
return Promise.reject(new Error('not implemented'));
|
||||
}
|
||||
return asPromise(() => {
|
||||
return handlerData.provider.deleteReaction!(document, convertFromComment(comment), convertFromReaction(reaction));
|
||||
});
|
||||
}
|
||||
|
||||
$provideDocumentComments(handle: number, uri: UriComponents): Promise<modes.CommentInfo | null> {
|
||||
const document = this._documents.getDocument(URI.revive(uri));
|
||||
const handlerData = this.getDocumentProvider(handle);
|
||||
return asPromise(() => {
|
||||
return handlerData.provider.provideDocumentComments(document, CancellationToken.None);
|
||||
}).then(commentInfo => commentInfo ? convertCommentInfo(handle, handlerData.extensionId, handlerData.provider, commentInfo, this._commands.converter) : null);
|
||||
}
|
||||
|
||||
$provideWorkspaceComments(handle: number): Promise<modes.CommentThread[] | null> {
|
||||
const handlerData = this._workspaceProviders.get(handle);
|
||||
if (!handlerData) {
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
|
||||
return asPromise(() => {
|
||||
return handlerData.provider.provideWorkspaceComments(CancellationToken.None);
|
||||
}).then(comments =>
|
||||
comments.map(comment => convertToCommentThread(handlerData.extensionId, handlerData.provider, comment, this._commands.converter)
|
||||
));
|
||||
}
|
||||
|
||||
private registerListeners(handle: number, extensionId: ExtensionIdentifier, provider: vscode.DocumentCommentProvider | vscode.WorkspaceCommentProvider) {
|
||||
provider.onDidChangeCommentThreads(event => {
|
||||
|
||||
this._proxy.$onDidCommentThreadsChange(handle, {
|
||||
changed: event.changed.map(thread => convertToCommentThread(extensionId, provider, thread, this._commands.converter)),
|
||||
added: event.added.map(thread => convertToCommentThread(extensionId, provider, thread, this._commands.converter)),
|
||||
removed: event.removed.map(thread => convertToCommentThread(extensionId, provider, thread, this._commands.converter)),
|
||||
draftMode: !!(provider as vscode.DocumentCommentProvider).startDraft && !!(provider as vscode.DocumentCommentProvider).finishDraft ? (event.inDraftMode ? modes.DraftMode.InDraft : modes.DraftMode.NotInDraft) : modes.DraftMode.NotSupported
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private getDocumentProvider(handle: number): HandlerData<vscode.DocumentCommentProvider> {
|
||||
const provider = this._documentProviders.get(handle);
|
||||
if (!provider) {
|
||||
throw new Error('unknown provider');
|
||||
}
|
||||
return provider;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -524,36 +303,6 @@ export class ExtHostCommentThread implements vscode.CommentThread {
|
||||
this._onDidUpdateCommentThread.fire();
|
||||
}
|
||||
|
||||
private _acceptInputCommand: vscode.Command;
|
||||
get acceptInputCommand(): vscode.Command {
|
||||
return this._acceptInputCommand;
|
||||
}
|
||||
|
||||
set acceptInputCommand(acceptInputCommand: vscode.Command) {
|
||||
this._acceptInputCommand = acceptInputCommand;
|
||||
this._onDidUpdateCommentThread.fire();
|
||||
}
|
||||
|
||||
private _additionalCommands: vscode.Command[] = [];
|
||||
get additionalCommands(): vscode.Command[] {
|
||||
return this._additionalCommands;
|
||||
}
|
||||
|
||||
set additionalCommands(additionalCommands: vscode.Command[]) {
|
||||
this._additionalCommands = additionalCommands;
|
||||
this._onDidUpdateCommentThread.fire();
|
||||
}
|
||||
|
||||
private _deleteCommand?: vscode.Command;
|
||||
get deleteComand(): vscode.Command | undefined {
|
||||
return this._deleteCommand;
|
||||
}
|
||||
|
||||
set deleteCommand(deleteCommand: vscode.Command) {
|
||||
this._deleteCommand = deleteCommand;
|
||||
this._onDidUpdateCommentThread.fire();
|
||||
}
|
||||
|
||||
private _collapseState?: vscode.CommentThreadCollapsibleState;
|
||||
|
||||
get collapsibleState(): vscode.CommentThreadCollapsibleState {
|
||||
@@ -575,15 +324,19 @@ export class ExtHostCommentThread implements vscode.CommentThread {
|
||||
|
||||
private _commentsMap: Map<vscode.Comment, number> = new Map<vscode.Comment, number>();
|
||||
|
||||
private _acceptInputDisposables = new MutableDisposable<DisposableStore>();
|
||||
|
||||
constructor(
|
||||
private _proxy: MainThreadCommentsShape,
|
||||
private readonly _commandsConverter: CommandsConverter,
|
||||
private _commentController: ExtHostCommentController,
|
||||
private _id: string | undefined,
|
||||
private _uri: vscode.Uri,
|
||||
private _range: vscode.Range,
|
||||
private _comments: vscode.Comment[]
|
||||
private _comments: vscode.Comment[],
|
||||
extensionId: ExtensionIdentifier
|
||||
) {
|
||||
this._acceptInputDisposables.value = new DisposableStore();
|
||||
|
||||
if (this._id === undefined) {
|
||||
this._id = `${_commentController.id}.${this.handle}`;
|
||||
}
|
||||
@@ -593,7 +346,8 @@ export class ExtHostCommentThread implements vscode.CommentThread {
|
||||
this.handle,
|
||||
this._id,
|
||||
this._uri,
|
||||
extHostTypeConverter.Range.from(this._range)
|
||||
extHostTypeConverter.Range.from(this._range),
|
||||
extensionId
|
||||
);
|
||||
|
||||
this._localDisposables = [];
|
||||
@@ -607,15 +361,21 @@ export class ExtHostCommentThread implements vscode.CommentThread {
|
||||
this.comments = _comments;
|
||||
}
|
||||
|
||||
|
||||
@debounce(100)
|
||||
eventuallyUpdateCommentThread(): void {
|
||||
if (this._isDiposed) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this._acceptInputDisposables.value) {
|
||||
this._acceptInputDisposables.value = new DisposableStore();
|
||||
}
|
||||
|
||||
const commentThreadRange = extHostTypeConverter.Range.from(this._range);
|
||||
const label = this.label;
|
||||
const contextValue = this.contextValue;
|
||||
const comments = this._comments.map(cmt => { return convertToModeComment2(this, this._commentController, cmt, this._commandsConverter, this._commentsMap); });
|
||||
const acceptInputCommand = this._acceptInputCommand ? this._commandsConverter.toInternal(this._acceptInputCommand) : undefined;
|
||||
const additionalCommands = this._additionalCommands ? this._additionalCommands.map(x => this._commandsConverter.toInternal(x)) : [];
|
||||
const deleteCommand = this._deleteCommand ? this._commandsConverter.toInternal(this._deleteCommand) : undefined;
|
||||
const comments = this._comments.map(cmt => { return convertToModeComment(this, this._commentController, cmt, this._commentsMap); });
|
||||
const collapsibleState = convertToCollapsibleState(this._collapseState);
|
||||
|
||||
this._proxy.$updateCommentThread(
|
||||
@@ -627,9 +387,6 @@ export class ExtHostCommentThread implements vscode.CommentThread {
|
||||
label,
|
||||
contextValue,
|
||||
comments,
|
||||
acceptInputCommand,
|
||||
additionalCommands,
|
||||
deleteCommand,
|
||||
collapsibleState
|
||||
);
|
||||
}
|
||||
@@ -657,56 +414,18 @@ export class ExtHostCommentThread implements vscode.CommentThread {
|
||||
}
|
||||
|
||||
dispose() {
|
||||
this._isDiposed = true;
|
||||
this._acceptInputDisposables.dispose();
|
||||
this._localDisposables.forEach(disposable => disposable.dispose());
|
||||
this._proxy.$deleteCommentThread(
|
||||
this._commentController.handle,
|
||||
this.handle
|
||||
);
|
||||
this._isDiposed = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export class ExtHostCommentInputBox implements vscode.CommentInputBox {
|
||||
get resource(): vscode.Uri {
|
||||
return this._resource;
|
||||
}
|
||||
|
||||
get range(): vscode.Range {
|
||||
return this._range;
|
||||
}
|
||||
|
||||
get value(): string {
|
||||
return this._value;
|
||||
}
|
||||
|
||||
set value(newInput: string) {
|
||||
this._value = newInput;
|
||||
this._onDidChangeValue.fire(this._value);
|
||||
this._proxy.$setInputValue(this.commentControllerHandle, newInput);
|
||||
}
|
||||
|
||||
private _onDidChangeValue = new Emitter<string>();
|
||||
|
||||
get onDidChangeValue(): Event<string> {
|
||||
return this._onDidChangeValue.event;
|
||||
}
|
||||
|
||||
constructor(
|
||||
private _proxy: MainThreadCommentsShape,
|
||||
public commentControllerHandle: number,
|
||||
private _resource: vscode.Uri,
|
||||
private _range: vscode.Range,
|
||||
private _value: string
|
||||
) {
|
||||
}
|
||||
|
||||
setInput(resource: vscode.Uri, range: vscode.Range, input: string) {
|
||||
this._resource = resource;
|
||||
this._range = range;
|
||||
this._value = input;
|
||||
}
|
||||
}
|
||||
|
||||
type ReactionHandler = (comment: vscode.Comment, reaction: vscode.CommentReaction) => Promise<void>;
|
||||
|
||||
class ExtHostCommentController implements vscode.CommentController {
|
||||
get id(): string {
|
||||
return this._id;
|
||||
@@ -716,16 +435,12 @@ class ExtHostCommentController implements vscode.CommentController {
|
||||
return this._label;
|
||||
}
|
||||
|
||||
public inputBox: ExtHostCommentInputBox | undefined;
|
||||
|
||||
public activeCommentingRange?: vscode.Range;
|
||||
|
||||
public get handle(): number {
|
||||
return this._handle;
|
||||
}
|
||||
|
||||
private _threads: Map<number, ExtHostCommentThread> = new Map<number, ExtHostCommentThread>();
|
||||
commentingRangeProvider?: vscode.CommentingRangeProvider & { createEmptyCommentThread: (document: vscode.TextDocument, range: types.Range) => Promise<vscode.CommentThread>; };
|
||||
commentingRangeProvider?: vscode.CommentingRangeProvider;
|
||||
|
||||
private _commentReactionProvider?: vscode.CommentReactionProvider;
|
||||
|
||||
@@ -736,14 +451,25 @@ class ExtHostCommentController implements vscode.CommentController {
|
||||
set reactionProvider(provider: vscode.CommentReactionProvider | undefined) {
|
||||
this._commentReactionProvider = provider;
|
||||
if (provider) {
|
||||
this._proxy.$updateCommentControllerFeatures(this.handle, { reactionGroup: provider.availableReactions.map(reaction => convertToReaction2(provider, reaction)) });
|
||||
this._proxy.$updateCommentControllerFeatures(this.handle, { reactionGroup: provider.availableReactions.map(reaction => convertToReaction(provider, reaction)) });
|
||||
}
|
||||
}
|
||||
|
||||
private _reactionHandler?: ReactionHandler;
|
||||
|
||||
get reactionHandler(): ReactionHandler | undefined {
|
||||
return this._reactionHandler;
|
||||
}
|
||||
|
||||
set reactionHandler(handler: ReactionHandler | undefined) {
|
||||
this._reactionHandler = handler;
|
||||
|
||||
this._proxy.$updateCommentControllerFeatures(this.handle, { reactionHandler: !!handler });
|
||||
}
|
||||
|
||||
constructor(
|
||||
_extension: IExtensionDescription,
|
||||
private _extension: IExtensionDescription,
|
||||
private _handle: number,
|
||||
private readonly _commandsConverter: CommandsConverter,
|
||||
private _proxy: MainThreadCommentsShape,
|
||||
private _id: string,
|
||||
private _label: string
|
||||
@@ -752,27 +478,33 @@ class ExtHostCommentController implements vscode.CommentController {
|
||||
}
|
||||
|
||||
createCommentThread(resource: vscode.Uri, range: vscode.Range, comments: vscode.Comment[]): vscode.CommentThread;
|
||||
createCommentThread(id: string, resource: vscode.Uri, range: vscode.Range, comments: vscode.Comment[]): vscode.CommentThread;
|
||||
createCommentThread(arg0: vscode.Uri | string, arg1: vscode.Uri | vscode.Range, arg2: vscode.Range | vscode.Comment[], arg3?: vscode.Comment[]): vscode.CommentThread {
|
||||
if (typeof arg0 === 'string') {
|
||||
const commentThread = new ExtHostCommentThread(this._proxy, this._commandsConverter, this, arg0, arg1 as vscode.Uri, arg2 as vscode.Range, arg3 as vscode.Comment[]);
|
||||
const commentThread = new ExtHostCommentThread(this._proxy, this, arg0, arg1 as vscode.Uri, arg2 as vscode.Range, arg3 as vscode.Comment[], this._extension.identifier);
|
||||
this._threads.set(commentThread.handle, commentThread);
|
||||
return commentThread;
|
||||
} else {
|
||||
const commentThread = new ExtHostCommentThread(this._proxy, this._commandsConverter, this, undefined, arg0 as vscode.Uri, arg1 as vscode.Range, arg2 as vscode.Comment[]);
|
||||
const commentThread = new ExtHostCommentThread(this._proxy, this, undefined, arg0 as vscode.Uri, arg1 as vscode.Range, arg2 as vscode.Comment[], this._extension.identifier);
|
||||
this._threads.set(commentThread.handle, commentThread);
|
||||
return commentThread;
|
||||
}
|
||||
}
|
||||
|
||||
$createCommentThreadTemplate(uriComponents: UriComponents, range: IRange) {
|
||||
const commentThread = new ExtHostCommentThread(this._proxy, this._commandsConverter, this, undefined, URI.revive(uriComponents), extHostTypeConverter.Range.to(range), []);
|
||||
$createCommentThreadTemplate(uriComponents: UriComponents, range: IRange): ExtHostCommentThread {
|
||||
const commentThread = new ExtHostCommentThread(this._proxy, this, undefined, URI.revive(uriComponents), extHostTypeConverter.Range.to(range), [], this._extension.identifier);
|
||||
commentThread.collapsibleState = modes.CommentThreadCollapsibleState.Expanded;
|
||||
this._threads.set(commentThread.handle, commentThread);
|
||||
return commentThread;
|
||||
}
|
||||
|
||||
$deleteCommentThread(threadHandle: number) {
|
||||
$updateCommentThreadTemplate(threadHandle: number, range: IRange): void {
|
||||
let thread = this._threads.get(threadHandle);
|
||||
if (thread) {
|
||||
thread.range = extHostTypeConverter.Range.to(range);
|
||||
}
|
||||
}
|
||||
|
||||
$deleteCommentThread(threadHandle: number): void {
|
||||
let thread = this._threads.get(threadHandle);
|
||||
|
||||
if (thread) {
|
||||
@@ -782,15 +514,7 @@ class ExtHostCommentController implements vscode.CommentController {
|
||||
this._threads.delete(threadHandle);
|
||||
}
|
||||
|
||||
$onCommentWidgetInputChange(uriComponents: UriComponents, range: IRange, input: string) {
|
||||
if (!this.inputBox) {
|
||||
this.inputBox = new ExtHostCommentInputBox(this._proxy, this.handle, URI.revive(uriComponents), extHostTypeConverter.Range.to(range), input);
|
||||
} else {
|
||||
this.inputBox.setInput(URI.revive(uriComponents), extHostTypeConverter.Range.to(range), input);
|
||||
}
|
||||
}
|
||||
|
||||
getCommentThread(handle: number) {
|
||||
getCommentThread(handle: number): ExtHostCommentThread | undefined {
|
||||
return this._threads.get(handle);
|
||||
}
|
||||
|
||||
@@ -803,74 +527,7 @@ class ExtHostCommentController implements vscode.CommentController {
|
||||
}
|
||||
}
|
||||
|
||||
function convertCommentInfo(owner: number, extensionId: ExtensionIdentifier, provider: vscode.DocumentCommentProvider, vscodeCommentInfo: vscode.CommentInfo, commandsConverter: CommandsConverter): modes.CommentInfo {
|
||||
return {
|
||||
extensionId: extensionId.value,
|
||||
threads: vscodeCommentInfo.threads.map(x => convertToCommentThread(extensionId, provider, x, commandsConverter)),
|
||||
commentingRanges: vscodeCommentInfo.commentingRanges ? vscodeCommentInfo.commentingRanges.map(range => extHostTypeConverter.Range.from(range)) : [],
|
||||
draftMode: provider.startDraft && provider.finishDraft ? (vscodeCommentInfo.inDraftMode ? modes.DraftMode.InDraft : modes.DraftMode.NotInDraft) : modes.DraftMode.NotSupported
|
||||
};
|
||||
}
|
||||
|
||||
function convertToCommentThread(extensionId: ExtensionIdentifier, provider: vscode.DocumentCommentProvider | vscode.WorkspaceCommentProvider, vscodeCommentThread: vscode.CommentThread, commandsConverter: CommandsConverter): modes.CommentThread {
|
||||
return {
|
||||
extensionId: extensionId.value,
|
||||
threadId: vscodeCommentThread.id,
|
||||
resource: vscodeCommentThread.resource.toString(),
|
||||
range: extHostTypeConverter.Range.from(vscodeCommentThread.range),
|
||||
comments: vscodeCommentThread.comments.map(comment => convertToComment(provider, comment as vscode.Comment, commandsConverter)),
|
||||
collapsibleState: vscodeCommentThread.collapsibleState
|
||||
};
|
||||
}
|
||||
|
||||
function convertFromCommentThread(commentThread: modes.CommentThread): vscode.CommentThread {
|
||||
return {
|
||||
id: commentThread.threadId!,
|
||||
threadId: commentThread.threadId!,
|
||||
uri: URI.parse(commentThread.resource!),
|
||||
resource: URI.parse(commentThread.resource!),
|
||||
range: extHostTypeConverter.Range.to(commentThread.range),
|
||||
comments: commentThread.comments ? commentThread.comments.map(convertFromComment) : [],
|
||||
collapsibleState: commentThread.collapsibleState,
|
||||
dispose: () => { }
|
||||
} as vscode.CommentThread;
|
||||
}
|
||||
|
||||
function convertFromComment(comment: modes.Comment): vscode.Comment {
|
||||
let userIconPath: URI | undefined;
|
||||
if (comment.userIconPath) {
|
||||
try {
|
||||
userIconPath = URI.parse(comment.userIconPath);
|
||||
} catch (e) {
|
||||
// Ignore
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
id: comment.commentId,
|
||||
commentId: comment.commentId,
|
||||
body: extHostTypeConverter.MarkdownString.to(comment.body),
|
||||
author: {
|
||||
name: comment.userName,
|
||||
iconPath: userIconPath
|
||||
},
|
||||
userName: comment.userName,
|
||||
userIconPath: userIconPath,
|
||||
canEdit: comment.canEdit,
|
||||
canDelete: comment.canDelete,
|
||||
isDraft: comment.isDraft,
|
||||
commentReactions: comment.commentReactions ? comment.commentReactions.map(reaction => {
|
||||
return {
|
||||
label: reaction.label,
|
||||
count: reaction.count,
|
||||
hasReacted: reaction.hasReacted
|
||||
};
|
||||
}) : undefined,
|
||||
mode: comment.mode ? comment.mode : modes.CommentMode.Preview
|
||||
};
|
||||
}
|
||||
|
||||
function convertToModeComment2(thread: ExtHostCommentThread, commentController: ExtHostCommentController, vscodeComment: vscode.Comment, commandsConverter: CommandsConverter, commentsMap: Map<vscode.Comment, number>): modes.Comment {
|
||||
function convertToModeComment(thread: ExtHostCommentThread, commentController: ExtHostCommentController, vscodeComment: vscode.Comment, commentsMap: Map<vscode.Comment, number>): modes.Comment {
|
||||
let commentUniqueId = commentsMap.get(vscodeComment)!;
|
||||
if (!commentUniqueId) {
|
||||
commentUniqueId = ++thread.commentHandle;
|
||||
@@ -880,54 +537,19 @@ function convertToModeComment2(thread: ExtHostCommentThread, commentController:
|
||||
const iconPath = vscodeComment.author && vscodeComment.author.iconPath ? vscodeComment.author.iconPath.toString() : undefined;
|
||||
|
||||
return {
|
||||
commentId: vscodeComment.id || vscodeComment.commentId,
|
||||
commentId: vscodeComment.commentId,
|
||||
mode: vscodeComment.mode,
|
||||
contextValue: vscodeComment.contextValue,
|
||||
uniqueIdInThread: commentUniqueId,
|
||||
body: extHostTypeConverter.MarkdownString.from(vscodeComment.body),
|
||||
userName: vscodeComment.author ? vscodeComment.author.name : vscodeComment.userName,
|
||||
userName: vscodeComment.author.name,
|
||||
userIconPath: iconPath,
|
||||
isDraft: vscodeComment.isDraft,
|
||||
selectCommand: vscodeComment.selectCommand ? commandsConverter.toInternal(vscodeComment.selectCommand) : undefined,
|
||||
editCommand: vscodeComment.editCommand ? commandsConverter.toInternal(vscodeComment.editCommand) : undefined,
|
||||
deleteCommand: vscodeComment.deleteCommand ? commandsConverter.toInternal(vscodeComment.deleteCommand) : undefined,
|
||||
label: vscodeComment.label,
|
||||
commentReactions: vscodeComment.commentReactions ? vscodeComment.commentReactions.map(reaction => convertToReaction2(commentController.reactionProvider, reaction)) : undefined
|
||||
commentReactions: vscodeComment.reactions ? vscodeComment.reactions.map(reaction => convertToReaction(commentController.reactionProvider, reaction)) : undefined
|
||||
};
|
||||
}
|
||||
|
||||
function convertToComment(provider: vscode.DocumentCommentProvider | vscode.WorkspaceCommentProvider, vscodeComment: vscode.Comment, commandsConverter: CommandsConverter): modes.Comment {
|
||||
const canEdit = !!(provider as vscode.DocumentCommentProvider).editComment && vscodeComment.canEdit;
|
||||
const canDelete = !!(provider as vscode.DocumentCommentProvider).deleteComment && vscodeComment.canDelete;
|
||||
const iconPath = vscodeComment.userIconPath ? vscodeComment.userIconPath.toString() : vscodeComment.gravatar;
|
||||
|
||||
return {
|
||||
commentId: vscodeComment.commentId,
|
||||
body: extHostTypeConverter.MarkdownString.from(vscodeComment.body),
|
||||
userName: vscodeComment.userName,
|
||||
userIconPath: iconPath,
|
||||
canEdit: canEdit,
|
||||
canDelete: canDelete,
|
||||
selectCommand: vscodeComment.command ? commandsConverter.toInternal(vscodeComment.command) : undefined,
|
||||
isDraft: vscodeComment.isDraft,
|
||||
commentReactions: vscodeComment.commentReactions ? vscodeComment.commentReactions.map(reaction => convertToReaction(provider, reaction)) : undefined
|
||||
};
|
||||
}
|
||||
|
||||
function convertToReaction(provider: vscode.DocumentCommentProvider | vscode.WorkspaceCommentProvider, reaction: vscode.CommentReaction): modes.CommentReaction {
|
||||
const providerCanDeleteReaction = !!(provider as vscode.DocumentCommentProvider).deleteReaction;
|
||||
const providerCanAddReaction = !!(provider as vscode.DocumentCommentProvider).addReaction;
|
||||
|
||||
return {
|
||||
label: reaction.label,
|
||||
iconPath: reaction.iconPath ? extHostTypeConverter.pathOrURIToURI(reaction.iconPath) : undefined,
|
||||
count: reaction.count,
|
||||
hasReacted: reaction.hasReacted,
|
||||
canEdit: (reaction.hasReacted && providerCanDeleteReaction) || (!reaction.hasReacted && providerCanAddReaction)
|
||||
};
|
||||
}
|
||||
|
||||
function convertToReaction2(provider: vscode.CommentReactionProvider | undefined, reaction: vscode.CommentReaction): modes.CommentReaction {
|
||||
function convertToReaction(provider: vscode.CommentReactionProvider | undefined, reaction: vscode.CommentReaction): modes.CommentReaction {
|
||||
return {
|
||||
label: reaction.label,
|
||||
iconPath: reaction.iconPath ? extHostTypeConverter.pathOrURIToURI(reaction.iconPath) : undefined,
|
||||
@@ -939,9 +561,11 @@ function convertToReaction2(provider: vscode.CommentReactionProvider | undefined
|
||||
|
||||
function convertFromReaction(reaction: modes.CommentReaction): vscode.CommentReaction {
|
||||
return {
|
||||
label: reaction.label,
|
||||
count: reaction.count,
|
||||
hasReacted: reaction.hasReacted
|
||||
label: reaction.label || '',
|
||||
count: reaction.count || 0,
|
||||
iconPath: reaction.iconPath ? URI.revive(reaction.iconPath) : '',
|
||||
hasReacted: reaction.hasReacted,
|
||||
authorHasReacted: reaction.hasReacted || false
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -71,14 +71,14 @@ export class ExtHostConfigProvider {
|
||||
private readonly _onDidChangeConfiguration = new Emitter<vscode.ConfigurationChangeEvent>();
|
||||
private readonly _proxy: MainThreadConfigurationShape;
|
||||
private readonly _extHostWorkspace: ExtHostWorkspace;
|
||||
private _configurationScopes: { [key: string]: ConfigurationScope };
|
||||
private _configurationScopes: Map<string, ConfigurationScope | undefined>;
|
||||
private _configuration: Configuration;
|
||||
|
||||
constructor(proxy: MainThreadConfigurationShape, extHostWorkspace: ExtHostWorkspace, data: IConfigurationInitData) {
|
||||
this._proxy = proxy;
|
||||
this._extHostWorkspace = extHostWorkspace;
|
||||
this._configuration = ExtHostConfigProvider.parse(data);
|
||||
this._configurationScopes = data.configurationScopes;
|
||||
this._configurationScopes = this._toMap(data.configurationScopes);
|
||||
}
|
||||
|
||||
get onDidChangeConfiguration(): Event<vscode.ConfigurationChangeEvent> {
|
||||
@@ -87,7 +87,7 @@ export class ExtHostConfigProvider {
|
||||
|
||||
$acceptConfigurationChanged(data: IConfigurationInitData, eventData: IWorkspaceConfigurationChangeEventData) {
|
||||
this._configuration = ExtHostConfigProvider.parse(data);
|
||||
this._configurationScopes = data.configurationScopes;
|
||||
this._configurationScopes = this._toMap(data.configurationScopes);
|
||||
this._onDidChangeConfiguration.fire(this._toConfigurationChangeEvent(eventData));
|
||||
}
|
||||
|
||||
@@ -225,7 +225,7 @@ export class ExtHostConfigProvider {
|
||||
}
|
||||
|
||||
private _validateConfigurationAccess(key: string, resource: URI | undefined, extensionId?: ExtensionIdentifier): void {
|
||||
const scope = OVERRIDE_PROPERTY_PATTERN.test(key) ? ConfigurationScope.RESOURCE : this._configurationScopes[key];
|
||||
const scope = OVERRIDE_PROPERTY_PATTERN.test(key) ? ConfigurationScope.RESOURCE : this._configurationScopes.get(key);
|
||||
const extensionIdText = extensionId ? `[${extensionId.value}] ` : '';
|
||||
if (ConfigurationScope.RESOURCE === scope) {
|
||||
if (resource === undefined) {
|
||||
@@ -255,6 +255,10 @@ export class ExtHostConfigProvider {
|
||||
});
|
||||
}
|
||||
|
||||
private _toMap(scopes: [string, ConfigurationScope | undefined][]): Map<string, ConfigurationScope | undefined> {
|
||||
return scopes.reduce((result, scope) => { result.set(scope[0], scope[1]); return result; }, new Map<string, ConfigurationScope | undefined>());
|
||||
}
|
||||
|
||||
private static parse(data: IConfigurationData): Configuration {
|
||||
const defaultConfiguration = ExtHostConfigProvider.parseConfigurationModel(data.defaults);
|
||||
const userConfiguration = ExtHostConfigProvider.parseConfigurationModel(data.user);
|
||||
|
||||
@@ -47,9 +47,9 @@ export class DiagnosticCollection implements vscode.DiagnosticCollection {
|
||||
return this._name;
|
||||
}
|
||||
|
||||
set(uri: vscode.Uri, diagnostics: vscode.Diagnostic[]): void;
|
||||
set(entries: [vscode.Uri, vscode.Diagnostic[]][]): void;
|
||||
set(first: vscode.Uri | [vscode.Uri, vscode.Diagnostic[]][], diagnostics?: vscode.Diagnostic[]) {
|
||||
set(uri: vscode.Uri, diagnostics: ReadonlyArray<vscode.Diagnostic>): void;
|
||||
set(entries: ReadonlyArray<[vscode.Uri, ReadonlyArray<vscode.Diagnostic>]>): void;
|
||||
set(first: vscode.Uri | ReadonlyArray<[vscode.Uri, ReadonlyArray<vscode.Diagnostic>]>, diagnostics?: ReadonlyArray<vscode.Diagnostic>) {
|
||||
|
||||
if (!first) {
|
||||
// this set-call is a clear-call
|
||||
@@ -167,7 +167,7 @@ export class DiagnosticCollection implements vscode.DiagnosticCollection {
|
||||
this._proxy.$clear(this._owner);
|
||||
}
|
||||
|
||||
forEach(callback: (uri: URI, diagnostics: vscode.Diagnostic[], collection: DiagnosticCollection) => any, thisArg?: any): void {
|
||||
forEach(callback: (uri: URI, diagnostics: ReadonlyArray<vscode.Diagnostic>, collection: DiagnosticCollection) => any, thisArg?: any): void {
|
||||
this._checkDisposed();
|
||||
this._data.forEach((value, key) => {
|
||||
const uri = URI.parse(key);
|
||||
@@ -175,11 +175,11 @@ export class DiagnosticCollection implements vscode.DiagnosticCollection {
|
||||
});
|
||||
}
|
||||
|
||||
get(uri: URI): vscode.Diagnostic[] {
|
||||
get(uri: URI): ReadonlyArray<vscode.Diagnostic> {
|
||||
this._checkDisposed();
|
||||
const result = this._data.get(uri.toString());
|
||||
if (Array.isArray(result)) {
|
||||
return <vscode.Diagnostic[]>Object.freeze(result.slice(0));
|
||||
return <ReadonlyArray<vscode.Diagnostic>>Object.freeze(result.slice(0));
|
||||
}
|
||||
return [];
|
||||
}
|
||||
@@ -278,10 +278,10 @@ export class ExtHostDiagnostics implements ExtHostDiagnosticsShape {
|
||||
return result;
|
||||
}
|
||||
|
||||
getDiagnostics(resource: vscode.Uri): vscode.Diagnostic[];
|
||||
getDiagnostics(): [vscode.Uri, vscode.Diagnostic[]][];
|
||||
getDiagnostics(resource?: vscode.Uri): vscode.Diagnostic[] | [vscode.Uri, vscode.Diagnostic[]][];
|
||||
getDiagnostics(resource?: vscode.Uri): vscode.Diagnostic[] | [vscode.Uri, vscode.Diagnostic[]][] {
|
||||
getDiagnostics(resource: vscode.Uri): ReadonlyArray<vscode.Diagnostic>;
|
||||
getDiagnostics(): ReadonlyArray<[vscode.Uri, ReadonlyArray<vscode.Diagnostic>]>;
|
||||
getDiagnostics(resource?: vscode.Uri): ReadonlyArray<vscode.Diagnostic> | ReadonlyArray<[vscode.Uri, ReadonlyArray<vscode.Diagnostic>]>;
|
||||
getDiagnostics(resource?: vscode.Uri): ReadonlyArray<vscode.Diagnostic> | ReadonlyArray<[vscode.Uri, ReadonlyArray<vscode.Diagnostic>]> {
|
||||
if (resource) {
|
||||
return this._getDiagnostics(resource);
|
||||
} else {
|
||||
@@ -302,7 +302,7 @@ export class ExtHostDiagnostics implements ExtHostDiagnosticsShape {
|
||||
}
|
||||
}
|
||||
|
||||
private _getDiagnostics(resource: vscode.Uri): vscode.Diagnostic[] {
|
||||
private _getDiagnostics(resource: vscode.Uri): ReadonlyArray<vscode.Diagnostic> {
|
||||
let res: vscode.Diagnostic[] = [];
|
||||
this._collections.forEach(collection => {
|
||||
if (collection.has(resource)) {
|
||||
|
||||
@@ -29,14 +29,10 @@ export class ExtHostDocumentContentProvider implements ExtHostDocumentContentPro
|
||||
this._proxy = mainContext.getProxy(MainContext.MainThreadDocumentContentProviders);
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
// todo@joh
|
||||
}
|
||||
|
||||
registerTextDocumentContentProvider(scheme: string, provider: vscode.TextDocumentContentProvider): vscode.Disposable {
|
||||
// todo@remote
|
||||
// check with scheme from fs-providers!
|
||||
if (scheme === Schemas.file || scheme === Schemas.untitled) {
|
||||
if (Object.keys(Schemas).indexOf(scheme) >= 0) {
|
||||
throw new Error(`scheme '${scheme}' already registered`);
|
||||
}
|
||||
|
||||
|
||||
@@ -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 { URI, UriComponents } from 'vs/base/common/uri';
|
||||
import { IModelChangedEvent } from 'vs/editor/common/model/mirrorTextModel';
|
||||
import { ExtHostDocumentsShape, IMainContext, MainContext, MainThreadDocumentsShape } from 'vs/workbench/api/common/extHost.protocol';
|
||||
@@ -25,7 +25,7 @@ export class ExtHostDocuments implements ExtHostDocumentsShape {
|
||||
readonly onDidChangeDocument: Event<vscode.TextDocumentChangeEvent> = this._onDidChangeDocument.event;
|
||||
readonly onDidSaveDocument: Event<vscode.TextDocument> = this._onDidSaveDocument.event;
|
||||
|
||||
private _toDispose: IDisposable[];
|
||||
private readonly _toDispose = new DisposableStore();
|
||||
private _proxy: MainThreadDocumentsShape;
|
||||
private _documentsAndEditors: ExtHostDocumentsAndEditors;
|
||||
private _documentLoader = new Map<string, Promise<ExtHostDocumentData>>();
|
||||
@@ -34,22 +34,20 @@ export class ExtHostDocuments implements ExtHostDocumentsShape {
|
||||
this._proxy = mainContext.getProxy(MainContext.MainThreadDocuments);
|
||||
this._documentsAndEditors = documentsAndEditors;
|
||||
|
||||
this._toDispose = [
|
||||
this._documentsAndEditors.onDidRemoveDocuments(documents => {
|
||||
for (const data of documents) {
|
||||
this._onDidRemoveDocument.fire(data.document);
|
||||
}
|
||||
}),
|
||||
this._documentsAndEditors.onDidAddDocuments(documents => {
|
||||
for (const data of documents) {
|
||||
this._onDidAddDocument.fire(data.document);
|
||||
}
|
||||
})
|
||||
];
|
||||
this._documentsAndEditors.onDidRemoveDocuments(documents => {
|
||||
for (const data of documents) {
|
||||
this._onDidRemoveDocument.fire(data.document);
|
||||
}
|
||||
}, undefined, this._toDispose);
|
||||
this._documentsAndEditors.onDidAddDocuments(documents => {
|
||||
for (const data of documents) {
|
||||
this._onDidAddDocument.fire(data.document);
|
||||
}
|
||||
}, undefined, this._toDispose);
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
dispose(this._toDispose);
|
||||
this._toDispose.dispose();
|
||||
}
|
||||
|
||||
public getAllDocumentData(): ExtHostDocumentData[] {
|
||||
|
||||
@@ -12,8 +12,9 @@ import { ExtensionActivationError, MissingDependencyError } from 'vs/workbench/s
|
||||
const NO_OP_VOID_PROMISE = Promise.resolve<void>(undefined);
|
||||
|
||||
export interface IExtensionMemento {
|
||||
get<T>(key: string): T | undefined;
|
||||
get<T>(key: string, defaultValue: T): T;
|
||||
update(key: string, value: any): Promise<boolean>;
|
||||
update(key: string, value: any): Promise<void>;
|
||||
}
|
||||
|
||||
export interface IExtensionContext {
|
||||
@@ -43,14 +44,13 @@ export interface IExtensionAPI {
|
||||
// _extensionAPIBrand: any;
|
||||
}
|
||||
|
||||
/* __GDPR__FRAGMENT__
|
||||
"ExtensionActivationTimes" : {
|
||||
"startup": { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth", "isMeasurement": true },
|
||||
"codeLoadingTime" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth", "isMeasurement": true },
|
||||
"activateCallTime" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth", "isMeasurement": true },
|
||||
"activateResolvedTime" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth", "isMeasurement": true }
|
||||
}
|
||||
*/
|
||||
export type ExtensionActivationTimesFragment = {
|
||||
startup?: { classification: 'SystemMetaData', purpose: 'PerformanceAndHealth', isMeasurement: true };
|
||||
codeLoadingTime?: { classification: 'SystemMetaData', purpose: 'PerformanceAndHealth', isMeasurement: true };
|
||||
activateCallTime?: { classification: 'SystemMetaData', purpose: 'PerformanceAndHealth', isMeasurement: true };
|
||||
activateResolvedTime?: { classification: 'SystemMetaData', purpose: 'PerformanceAndHealth', isMeasurement: true };
|
||||
};
|
||||
|
||||
export class ExtensionActivationTimes {
|
||||
|
||||
public static readonly NONE = new ExtensionActivationTimes(false, -1, -1, -1);
|
||||
|
||||
@@ -8,11 +8,10 @@ import { MainContext, IMainContext, ExtHostFileSystemShape, MainThreadFileSystem
|
||||
import * as vscode from 'vscode';
|
||||
import * as files from 'vs/platform/files/common/files';
|
||||
import { IDisposable, toDisposable, dispose } from 'vs/base/common/lifecycle';
|
||||
import { FileChangeType } from 'vs/workbench/api/common/extHostTypes';
|
||||
import { FileChangeType, FileSystemError } from 'vs/workbench/api/common/extHostTypes';
|
||||
import * as typeConverter from 'vs/workbench/api/common/extHostTypeConverters';
|
||||
import { ExtHostLanguageFeatures } from 'vs/workbench/api/common/extHostLanguageFeatures';
|
||||
import { Schemas } from 'vs/base/common/network';
|
||||
import { ResourceLabelFormatter } from 'vs/platform/label/common/label';
|
||||
import { State, StateMachine, LinkComputer, Edge } from 'vs/editor/common/modes/linkComputer';
|
||||
import { commonPrefixLength } from 'vs/base/common/strings';
|
||||
import { CharCode } from 'vs/base/common/charCode';
|
||||
@@ -104,6 +103,50 @@ class FsLinkProvider {
|
||||
}
|
||||
}
|
||||
|
||||
class ConsumerFileSystem implements vscode.FileSystem {
|
||||
|
||||
constructor(private _proxy: MainThreadFileSystemShape) { }
|
||||
|
||||
stat(uri: vscode.Uri): Promise<vscode.FileStat> {
|
||||
return this._proxy.$stat(uri).catch(ConsumerFileSystem._handleError);
|
||||
}
|
||||
readDirectory(uri: vscode.Uri): Promise<[string, vscode.FileType][]> {
|
||||
return this._proxy.$readdir(uri).catch(ConsumerFileSystem._handleError);
|
||||
}
|
||||
createDirectory(uri: vscode.Uri): Promise<void> {
|
||||
return this._proxy.$mkdir(uri).catch(ConsumerFileSystem._handleError);
|
||||
}
|
||||
async readFile(uri: vscode.Uri): Promise<Uint8Array> {
|
||||
return this._proxy.$readFile(uri).then(buff => buff.buffer).catch(ConsumerFileSystem._handleError);
|
||||
}
|
||||
writeFile(uri: vscode.Uri, content: Uint8Array): Promise<void> {
|
||||
return this._proxy.$writeFile(uri, VSBuffer.wrap(content)).catch(ConsumerFileSystem._handleError);
|
||||
}
|
||||
delete(uri: vscode.Uri, options?: { recursive?: boolean; useTrash?: boolean; }): Promise<void> {
|
||||
return this._proxy.$delete(uri, { ...{ recursive: false, useTrash: false }, ...options }).catch(ConsumerFileSystem._handleError);
|
||||
}
|
||||
rename(oldUri: vscode.Uri, newUri: vscode.Uri, options?: { overwrite?: boolean; }): Promise<void> {
|
||||
return this._proxy.$rename(oldUri, newUri, { ...{ overwrite: false }, ...options }).catch(ConsumerFileSystem._handleError);
|
||||
}
|
||||
copy(source: vscode.Uri, destination: vscode.Uri, options?: { overwrite?: boolean }): Promise<void> {
|
||||
return this._proxy.$copy(source, destination, { ...{ overwrite: false }, ...options }).catch(ConsumerFileSystem._handleError);
|
||||
}
|
||||
private static _handleError(err: any): never {
|
||||
// generic error
|
||||
if (!(err instanceof Error)) {
|
||||
throw new FileSystemError(String(err));
|
||||
}
|
||||
|
||||
// no provider (unknown scheme) error
|
||||
if (err.name === 'ENOPRO') {
|
||||
throw FileSystemError.Unavailable(err.message);
|
||||
}
|
||||
|
||||
// file system error
|
||||
throw new FileSystemError(err.message, err.name as files.FileSystemProviderErrorCode);
|
||||
}
|
||||
}
|
||||
|
||||
export class ExtHostFileSystem implements ExtHostFileSystemShape {
|
||||
|
||||
private readonly _proxy: MainThreadFileSystemShape;
|
||||
@@ -113,21 +156,16 @@ export class ExtHostFileSystem implements ExtHostFileSystemShape {
|
||||
private readonly _watches = new Map<number, IDisposable>();
|
||||
|
||||
private _linkProviderRegistration: IDisposable;
|
||||
// Used as a handle both for file system providers and resource label formatters (being lazy)
|
||||
private _handlePool: number = 0;
|
||||
|
||||
readonly fileSystem: vscode.FileSystem;
|
||||
|
||||
constructor(mainContext: IMainContext, private _extHostLanguageFeatures: ExtHostLanguageFeatures) {
|
||||
this._proxy = mainContext.getProxy(MainContext.MainThreadFileSystem);
|
||||
this._usedSchemes.add(Schemas.file);
|
||||
this._usedSchemes.add(Schemas.untitled);
|
||||
this._usedSchemes.add(Schemas.vscode);
|
||||
this._usedSchemes.add(Schemas.inMemory);
|
||||
this._usedSchemes.add(Schemas.internal);
|
||||
this._usedSchemes.add(Schemas.http);
|
||||
this._usedSchemes.add(Schemas.https);
|
||||
this._usedSchemes.add(Schemas.mailto);
|
||||
this._usedSchemes.add(Schemas.data);
|
||||
this._usedSchemes.add(Schemas.command);
|
||||
this.fileSystem = new ConsumerFileSystem(this._proxy);
|
||||
|
||||
// register used schemes
|
||||
Object.keys(Schemas).forEach(scheme => this._usedSchemes.add(scheme));
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
@@ -154,23 +192,23 @@ export class ExtHostFileSystem implements ExtHostFileSystemShape {
|
||||
this._usedSchemes.add(scheme);
|
||||
this._fsProvider.set(handle, provider);
|
||||
|
||||
let capabilites = files.FileSystemProviderCapabilities.FileReadWrite;
|
||||
let capabilities = files.FileSystemProviderCapabilities.FileReadWrite;
|
||||
if (options.isCaseSensitive) {
|
||||
capabilites += files.FileSystemProviderCapabilities.PathCaseSensitive;
|
||||
capabilities += files.FileSystemProviderCapabilities.PathCaseSensitive;
|
||||
}
|
||||
if (options.isReadonly) {
|
||||
capabilites += files.FileSystemProviderCapabilities.Readonly;
|
||||
capabilities += files.FileSystemProviderCapabilities.Readonly;
|
||||
}
|
||||
if (typeof provider.copy === 'function') {
|
||||
capabilites += files.FileSystemProviderCapabilities.FileFolderCopy;
|
||||
capabilities += files.FileSystemProviderCapabilities.FileFolderCopy;
|
||||
}
|
||||
if (typeof provider.open === 'function' && typeof provider.close === 'function'
|
||||
&& typeof provider.read === 'function' && typeof provider.write === 'function'
|
||||
) {
|
||||
capabilites += files.FileSystemProviderCapabilities.FileOpenReadWriteClose;
|
||||
capabilities += files.FileSystemProviderCapabilities.FileOpenReadWriteClose;
|
||||
}
|
||||
|
||||
this._proxy.$registerFileSystemProvider(handle, scheme, capabilites);
|
||||
this._proxy.$registerFileSystemProvider(handle, scheme, capabilities);
|
||||
|
||||
const subscription = provider.onDidChangeFile(event => {
|
||||
const mapped: IFileChangeDto[] = [];
|
||||
@@ -208,46 +246,37 @@ export class ExtHostFileSystem implements ExtHostFileSystemShape {
|
||||
});
|
||||
}
|
||||
|
||||
registerResourceLabelFormatter(formatter: ResourceLabelFormatter): IDisposable {
|
||||
const handle = this._handlePool++;
|
||||
this._proxy.$registerResourceLabelFormatter(handle, formatter);
|
||||
|
||||
return toDisposable(() => {
|
||||
this._proxy.$unregisterResourceLabelFormatter(handle);
|
||||
});
|
||||
}
|
||||
|
||||
private static _asIStat(stat: vscode.FileStat): files.IStat {
|
||||
const { type, ctime, mtime, size } = stat;
|
||||
return { type, ctime, mtime, size };
|
||||
}
|
||||
|
||||
$stat(handle: number, resource: UriComponents): Promise<files.IStat> {
|
||||
return Promise.resolve(this.getProvider(handle).stat(URI.revive(resource))).then(ExtHostFileSystem._asIStat);
|
||||
return Promise.resolve(this._getFsProvider(handle).stat(URI.revive(resource))).then(ExtHostFileSystem._asIStat);
|
||||
}
|
||||
|
||||
$readdir(handle: number, resource: UriComponents): Promise<[string, files.FileType][]> {
|
||||
return Promise.resolve(this.getProvider(handle).readDirectory(URI.revive(resource)));
|
||||
return Promise.resolve(this._getFsProvider(handle).readDirectory(URI.revive(resource)));
|
||||
}
|
||||
|
||||
$readFile(handle: number, resource: UriComponents): Promise<VSBuffer> {
|
||||
return Promise.resolve(this.getProvider(handle).readFile(URI.revive(resource))).then(data => VSBuffer.wrap(data));
|
||||
return Promise.resolve(this._getFsProvider(handle).readFile(URI.revive(resource))).then(data => VSBuffer.wrap(data));
|
||||
}
|
||||
|
||||
$writeFile(handle: number, resource: UriComponents, content: VSBuffer, opts: files.FileWriteOptions): Promise<void> {
|
||||
return Promise.resolve(this.getProvider(handle).writeFile(URI.revive(resource), content.buffer, opts));
|
||||
return Promise.resolve(this._getFsProvider(handle).writeFile(URI.revive(resource), content.buffer, opts));
|
||||
}
|
||||
|
||||
$delete(handle: number, resource: UriComponents, opts: files.FileDeleteOptions): Promise<void> {
|
||||
return Promise.resolve(this.getProvider(handle).delete(URI.revive(resource), opts));
|
||||
return Promise.resolve(this._getFsProvider(handle).delete(URI.revive(resource), opts));
|
||||
}
|
||||
|
||||
$rename(handle: number, oldUri: UriComponents, newUri: UriComponents, opts: files.FileOverwriteOptions): Promise<void> {
|
||||
return Promise.resolve(this.getProvider(handle).rename(URI.revive(oldUri), URI.revive(newUri), opts));
|
||||
return Promise.resolve(this._getFsProvider(handle).rename(URI.revive(oldUri), URI.revive(newUri), opts));
|
||||
}
|
||||
|
||||
$copy(handle: number, oldUri: UriComponents, newUri: UriComponents, opts: files.FileOverwriteOptions): Promise<void> {
|
||||
const provider = this.getProvider(handle);
|
||||
const provider = this._getFsProvider(handle);
|
||||
if (!provider.copy) {
|
||||
throw new Error('FileSystemProvider does not implement "copy"');
|
||||
}
|
||||
@@ -255,11 +284,11 @@ export class ExtHostFileSystem implements ExtHostFileSystemShape {
|
||||
}
|
||||
|
||||
$mkdir(handle: number, resource: UriComponents): Promise<void> {
|
||||
return Promise.resolve(this.getProvider(handle).createDirectory(URI.revive(resource)));
|
||||
return Promise.resolve(this._getFsProvider(handle).createDirectory(URI.revive(resource)));
|
||||
}
|
||||
|
||||
$watch(handle: number, session: number, resource: UriComponents, opts: files.IWatchOptions): void {
|
||||
const subscription = this.getProvider(handle).watch(URI.revive(resource), opts);
|
||||
const subscription = this._getFsProvider(handle).watch(URI.revive(resource), opts);
|
||||
this._watches.set(session, subscription);
|
||||
}
|
||||
|
||||
@@ -272,7 +301,7 @@ export class ExtHostFileSystem implements ExtHostFileSystemShape {
|
||||
}
|
||||
|
||||
$open(handle: number, resource: UriComponents, opts: files.FileOpenOptions): Promise<number> {
|
||||
const provider = this.getProvider(handle);
|
||||
const provider = this._getFsProvider(handle);
|
||||
if (!provider.open) {
|
||||
throw new Error('FileSystemProvider does not implement "open"');
|
||||
}
|
||||
@@ -280,7 +309,7 @@ export class ExtHostFileSystem implements ExtHostFileSystemShape {
|
||||
}
|
||||
|
||||
$close(handle: number, fd: number): Promise<void> {
|
||||
const provider = this.getProvider(handle);
|
||||
const provider = this._getFsProvider(handle);
|
||||
if (!provider.close) {
|
||||
throw new Error('FileSystemProvider does not implement "close"');
|
||||
}
|
||||
@@ -288,7 +317,7 @@ export class ExtHostFileSystem implements ExtHostFileSystemShape {
|
||||
}
|
||||
|
||||
$read(handle: number, fd: number, pos: number, length: number): Promise<VSBuffer> {
|
||||
const provider = this.getProvider(handle);
|
||||
const provider = this._getFsProvider(handle);
|
||||
if (!provider.read) {
|
||||
throw new Error('FileSystemProvider does not implement "read"');
|
||||
}
|
||||
@@ -299,14 +328,14 @@ export class ExtHostFileSystem implements ExtHostFileSystemShape {
|
||||
}
|
||||
|
||||
$write(handle: number, fd: number, pos: number, data: VSBuffer): Promise<number> {
|
||||
const provider = this.getProvider(handle);
|
||||
const provider = this._getFsProvider(handle);
|
||||
if (!provider.write) {
|
||||
throw new Error('FileSystemProvider does not implement "write"');
|
||||
}
|
||||
return Promise.resolve(provider.write(fd, pos, data.buffer, 0, data.byteLength));
|
||||
}
|
||||
|
||||
private getProvider(handle: number): vscode.FileSystemProvider {
|
||||
private _getFsProvider(handle: number): vscode.FileSystemProvider {
|
||||
const provider = this._fsProvider.get(handle);
|
||||
if (!provider) {
|
||||
const err = new Error();
|
||||
|
||||
@@ -1,33 +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 { ExtHostHeapServiceShape } from './extHost.protocol';
|
||||
|
||||
export class ExtHostHeapService implements ExtHostHeapServiceShape {
|
||||
|
||||
private static _idPool = 0;
|
||||
|
||||
private _data = new Map<number, any>();
|
||||
|
||||
keep(obj: any): number {
|
||||
const id = ExtHostHeapService._idPool++;
|
||||
this._data.set(id, obj);
|
||||
return id;
|
||||
}
|
||||
|
||||
delete(id: number): boolean {
|
||||
return this._data.delete(id);
|
||||
}
|
||||
|
||||
get<T>(id: number): T {
|
||||
return this._data.get(id);
|
||||
}
|
||||
|
||||
$onGarbageCollection(ids: number[]): void {
|
||||
for (const id of ids) {
|
||||
this.delete(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
27
src/vs/workbench/api/common/extHostLabelService.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { ResourceLabelFormatter } from 'vs/platform/label/common/label';
|
||||
import { IDisposable, toDisposable } from 'vs/base/common/lifecycle';
|
||||
import { MainThreadLabelServiceShape, ExtHostLabelServiceShape, MainContext, IMainContext } from 'vs/workbench/api/common/extHost.protocol';
|
||||
|
||||
export class ExtHostLabelService implements ExtHostLabelServiceShape {
|
||||
|
||||
private readonly _proxy: MainThreadLabelServiceShape;
|
||||
private _handlePool: number = 0;
|
||||
|
||||
constructor(mainContext: IMainContext) {
|
||||
this._proxy = mainContext.getProxy(MainContext.MainThreadLabelService);
|
||||
}
|
||||
|
||||
$registerResourceLabelFormatter(formatter: ResourceLabelFormatter): IDisposable {
|
||||
const handle = this._handlePool++;
|
||||
this._proxy.$registerResourceLabelFormatter(handle, formatter);
|
||||
|
||||
return toDisposable(() => {
|
||||
this._proxy.$unregisterResourceLabelFormatter(handle);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -10,12 +10,11 @@ import * as typeConvert from 'vs/workbench/api/common/extHostTypeConverters';
|
||||
import { Range, Disposable, CompletionList, SnippetString, CodeActionKind, SymbolInformation, DocumentSymbol } from 'vs/workbench/api/common/extHostTypes';
|
||||
import { ISingleEditOperation } from 'vs/editor/common/model';
|
||||
import * as modes from 'vs/editor/common/modes';
|
||||
import { ExtHostHeapService } from 'vs/workbench/api/common/extHostHeapService';
|
||||
import { ExtHostDocuments } from 'vs/workbench/api/common/extHostDocuments';
|
||||
import { ExtHostCommands, CommandsConverter } from 'vs/workbench/api/common/extHostCommands';
|
||||
import { ExtHostDiagnostics } from 'vs/workbench/api/common/extHostDiagnostics';
|
||||
import { asPromise } from 'vs/base/common/async';
|
||||
import { MainContext, MainThreadLanguageFeaturesShape, ExtHostLanguageFeaturesShape, ObjectIdentifier, IRawColorInfo, IMainContext, IdObject, ISerializedRegExp, ISerializedIndentationRule, ISerializedOnEnterRule, ISerializedLanguageConfiguration, WorkspaceSymbolDto, SuggestResultDto, WorkspaceSymbolsDto, CodeActionDto, ISerializedDocumentFilter, WorkspaceEditDto, ISerializedSignatureHelpProviderMetadata, LinkDto, CodeLensDto, MainThreadWebviewsShape, CodeInsetDto, SuggestDataDto, LinksListDto, ChainedCacheId } from './extHost.protocol';
|
||||
import { MainContext, MainThreadLanguageFeaturesShape, ExtHostLanguageFeaturesShape, IRawColorInfo, IMainContext, IdObject, ISerializedRegExp, ISerializedIndentationRule, ISerializedOnEnterRule, ISerializedLanguageConfiguration, WorkspaceSymbolDto, SuggestResultDto, WorkspaceSymbolsDto, CodeActionDto, ISerializedDocumentFilter, WorkspaceEditDto, ISerializedSignatureHelpProviderMetadata, LinkDto, CodeLensDto, SuggestDataDto, LinksListDto, ChainedCacheId, CodeLensListDto, CodeActionListDto, SignatureHelpDto, SignatureHelpContextDto } from './extHost.protocol';
|
||||
import { regExpLeadsToEndlessLoop, regExpFlags } from 'vs/base/common/strings';
|
||||
import { IPosition } from 'vs/editor/common/core/position';
|
||||
import { IRange, Range as EditorRange } from 'vs/editor/common/core/range';
|
||||
@@ -25,11 +24,10 @@ import { ISelection, Selection } from 'vs/editor/common/core/selection';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
||||
import { ExtHostWebview } from 'vs/workbench/api/common/extHostWebview';
|
||||
import * as codeInset from 'vs/workbench/contrib/codeinset/common/codeInset';
|
||||
import { generateUuid } from 'vs/base/common/uuid';
|
||||
import * as callHierarchy from 'vs/workbench/contrib/callHierarchy/common/callHierarchy';
|
||||
import { LRUCache } from 'vs/base/common/map';
|
||||
import { IURITransformer } from 'vs/base/common/uriIpc';
|
||||
import { DisposableStore, dispose } from 'vs/base/common/lifecycle';
|
||||
|
||||
// --- adapter
|
||||
|
||||
@@ -104,34 +102,48 @@ class CodeLensAdapter {
|
||||
|
||||
private static _badCmd: vscode.Command = { command: 'missing', title: '!!MISSING: command!!' };
|
||||
|
||||
private readonly _cache = new Cache<vscode.CodeLens>('CodeLens');
|
||||
private readonly _disposables = new Map<number, DisposableStore>();
|
||||
|
||||
constructor(
|
||||
private readonly _documents: ExtHostDocuments,
|
||||
private readonly _commands: CommandsConverter,
|
||||
private readonly _heapService: ExtHostHeapService,
|
||||
private readonly _provider: vscode.CodeLensProvider
|
||||
) { }
|
||||
|
||||
provideCodeLenses(resource: URI, token: CancellationToken): Promise<CodeLensDto[]> {
|
||||
provideCodeLenses(resource: URI, token: CancellationToken): Promise<CodeLensListDto | undefined> {
|
||||
const doc = this._documents.getDocument(resource);
|
||||
|
||||
return asPromise(() => this._provider.provideCodeLenses(doc, token)).then(lenses => {
|
||||
const result: CodeLensDto[] = [];
|
||||
if (isNonEmptyArray(lenses)) {
|
||||
for (const lens of lenses) {
|
||||
const id = this._heapService.keep(lens);
|
||||
result.push(ObjectIdentifier.mixin({
|
||||
range: typeConvert.Range.from(lens.range),
|
||||
command: this._commands.toInternal(lens.command)
|
||||
}, id));
|
||||
}
|
||||
|
||||
if (!lenses || token.isCancellationRequested) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const cacheId = this._cache.add(lenses);
|
||||
const disposables = new DisposableStore();
|
||||
this._disposables.set(cacheId, disposables);
|
||||
|
||||
const result: CodeLensListDto = {
|
||||
cacheId,
|
||||
lenses: [],
|
||||
};
|
||||
|
||||
for (let i = 0; i < lenses.length; i++) {
|
||||
result.lenses.push({
|
||||
cacheId: [cacheId, i],
|
||||
range: typeConvert.Range.from(lenses[i].range),
|
||||
command: this._commands.toInternal(lenses[i].command, disposables)
|
||||
});
|
||||
}
|
||||
|
||||
return result;
|
||||
});
|
||||
}
|
||||
|
||||
resolveCodeLens(symbol: CodeLensDto, token: CancellationToken): Promise<CodeLensDto | undefined> {
|
||||
|
||||
const lens = this._heapService.get<vscode.CodeLens>(ObjectIdentifier.of(symbol));
|
||||
const lens = symbol.cacheId && this._cache.get(...symbol.cacheId);
|
||||
if (!lens) {
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
@@ -144,51 +156,26 @@ class CodeLensAdapter {
|
||||
}
|
||||
|
||||
return resolve.then(newLens => {
|
||||
newLens = newLens || lens;
|
||||
symbol.command = this._commands.toInternal(newLens.command || CodeLensAdapter._badCmd);
|
||||
return symbol;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
class CodeInsetAdapter {
|
||||
|
||||
constructor(
|
||||
private readonly _documents: ExtHostDocuments,
|
||||
private readonly _heapService: ExtHostHeapService,
|
||||
private readonly _provider: vscode.CodeInsetProvider
|
||||
) { }
|
||||
|
||||
provideCodeInsets(resource: URI, token: CancellationToken): Promise<CodeInsetDto[] | undefined> {
|
||||
const doc = this._documents.getDocument(resource);
|
||||
return asPromise(() => this._provider.provideCodeInsets(doc, token)).then(insets => {
|
||||
if (Array.isArray(insets)) {
|
||||
return insets.map(inset => {
|
||||
const $ident = this._heapService.keep(inset);
|
||||
const id = generateUuid();
|
||||
return {
|
||||
$ident,
|
||||
id,
|
||||
range: typeConvert.Range.from(inset.range),
|
||||
height: inset.height
|
||||
};
|
||||
});
|
||||
if (token.isCancellationRequested) {
|
||||
return undefined;
|
||||
}
|
||||
return undefined;
|
||||
|
||||
const disposables = symbol.cacheId && this._disposables.get(symbol.cacheId[0]);
|
||||
if (!disposables) {
|
||||
// We've already been disposed of
|
||||
return undefined;
|
||||
}
|
||||
|
||||
newLens = newLens || lens;
|
||||
symbol.command = this._commands.toInternal(newLens.command || CodeLensAdapter._badCmd, disposables);
|
||||
return symbol;
|
||||
});
|
||||
}
|
||||
|
||||
resolveCodeInset(symbol: CodeInsetDto, webview: vscode.Webview, token: CancellationToken): Promise<CodeInsetDto> {
|
||||
|
||||
const inset = this._heapService.get<vscode.CodeInset>(ObjectIdentifier.of(symbol));
|
||||
if (!inset) {
|
||||
return Promise.resolve(symbol);
|
||||
}
|
||||
|
||||
return asPromise(() => this._provider.resolveCodeInset(inset, webview, token)).then(newInset => {
|
||||
newInset = newInset || inset;
|
||||
return symbol;
|
||||
});
|
||||
releaseCodeLenses(cachedId: number): void {
|
||||
dispose(this._disposables.get(cachedId));
|
||||
this._disposables.delete(cachedId);
|
||||
this._cache.delete(cachedId);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -328,6 +315,9 @@ export interface CustomCodeAction extends CodeActionDto {
|
||||
class CodeActionAdapter {
|
||||
private static readonly _maxCodeActionsPerFile: number = 1000;
|
||||
|
||||
private readonly _cache = new Cache<vscode.CodeAction | vscode.Command>('CodeAction');
|
||||
private readonly _disposables = new Map<number, DisposableStore>();
|
||||
|
||||
constructor(
|
||||
private readonly _documents: ExtHostDocuments,
|
||||
private readonly _commands: CommandsConverter,
|
||||
@@ -337,7 +327,7 @@ class CodeActionAdapter {
|
||||
private readonly _extensionId: ExtensionIdentifier
|
||||
) { }
|
||||
|
||||
provideCodeActions(resource: URI, rangeOrSelection: IRange | ISelection, context: modes.CodeActionContext, token: CancellationToken): Promise<CodeActionDto[] | undefined> {
|
||||
provideCodeActions(resource: URI, rangeOrSelection: IRange | ISelection, context: modes.CodeActionContext, token: CancellationToken): Promise<CodeActionListDto | undefined> {
|
||||
|
||||
const doc = this._documents.getDocument(resource);
|
||||
const ran = Selection.isISelection(rangeOrSelection)
|
||||
@@ -360,34 +350,39 @@ class CodeActionAdapter {
|
||||
};
|
||||
|
||||
return asPromise(() => this._provider.provideCodeActions(doc, ran, codeActionContext, token)).then(commandsOrActions => {
|
||||
if (!isNonEmptyArray(commandsOrActions)) {
|
||||
if (!isNonEmptyArray(commandsOrActions) || token.isCancellationRequested) {
|
||||
return undefined;
|
||||
}
|
||||
const result: CustomCodeAction[] = [];
|
||||
|
||||
const cacheId = this._cache.add(commandsOrActions);
|
||||
const disposables = new DisposableStore();
|
||||
this._disposables.set(cacheId, disposables);
|
||||
|
||||
const actions: CustomCodeAction[] = [];
|
||||
for (const candidate of commandsOrActions) {
|
||||
if (!candidate) {
|
||||
continue;
|
||||
}
|
||||
if (CodeActionAdapter._isCommand(candidate)) {
|
||||
// old school: synthetic code action
|
||||
result.push({
|
||||
actions.push({
|
||||
_isSynthetic: true,
|
||||
title: candidate.title,
|
||||
command: this._commands.toInternal(candidate),
|
||||
command: this._commands.toInternal(candidate, disposables),
|
||||
});
|
||||
} else {
|
||||
if (codeActionContext.only) {
|
||||
if (!candidate.kind) {
|
||||
this._logService.warn(`${this._extensionId.value} - Code actions of kind '${codeActionContext.only.value} 'requested but returned code action does not have a 'kind'. Code action will be dropped. Please set 'CodeAction.kind'.`);
|
||||
} else if (!codeActionContext.only.contains(candidate.kind)) {
|
||||
this._logService.warn(`${this._extensionId.value} -Code actions of kind '${codeActionContext.only.value} 'requested but returned code action is of kind '${candidate.kind.value}'. Code action will be dropped. Please check 'CodeActionContext.only' to only return requested code actions.`);
|
||||
this._logService.warn(`${this._extensionId.value} - Code actions of kind '${codeActionContext.only.value} 'requested but returned code action is of kind '${candidate.kind.value}'. Code action will be dropped. Please check 'CodeActionContext.only' to only return requested code actions.`);
|
||||
}
|
||||
}
|
||||
|
||||
// new school: convert code action
|
||||
result.push({
|
||||
actions.push({
|
||||
title: candidate.title,
|
||||
command: candidate.command && this._commands.toInternal(candidate.command),
|
||||
command: candidate.command && this._commands.toInternal(candidate.command, disposables),
|
||||
diagnostics: candidate.diagnostics && candidate.diagnostics.map(typeConvert.Diagnostic.from),
|
||||
edit: candidate.edit && typeConvert.WorkspaceEdit.from(candidate.edit),
|
||||
kind: candidate.kind && candidate.kind.value,
|
||||
@@ -396,10 +391,16 @@ class CodeActionAdapter {
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
return <CodeActionListDto>{ cacheId, actions };
|
||||
});
|
||||
}
|
||||
|
||||
public releaseCodeActions(cachedId: number): void {
|
||||
dispose(this._disposables.get(cachedId));
|
||||
this._disposables.delete(cachedId);
|
||||
this._cache.delete(cachedId);
|
||||
}
|
||||
|
||||
private static _isCommand(thing: any): thing is vscode.Command {
|
||||
return typeof (<vscode.Command>thing).command === 'string' && typeof (<vscode.Command>thing).title === 'string';
|
||||
}
|
||||
@@ -623,7 +624,8 @@ class SuggestAdapter {
|
||||
private _commands: CommandsConverter;
|
||||
private _provider: vscode.CompletionItemProvider;
|
||||
|
||||
private _cache = new Cache<vscode.CompletionItem>();
|
||||
private _cache = new Cache<vscode.CompletionItem>('CompletionItem');
|
||||
private _disposables = new Map<number, DisposableStore>();
|
||||
|
||||
constructor(documents: ExtHostDocuments, commands: CommandsConverter, provider: vscode.CompletionItemProvider) {
|
||||
this._documents = documents;
|
||||
@@ -643,13 +645,18 @@ class SuggestAdapter {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
let list = Array.isArray(value) ? new CompletionList(value) : value;
|
||||
let pid: number | undefined;
|
||||
if (token.isCancellationRequested) {
|
||||
// cancelled -> return without further ado, esp no caching
|
||||
// of results as they will leak
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const list = Array.isArray(value) ? new CompletionList(value) : value;
|
||||
|
||||
// keep result for providers that support resolving
|
||||
if (SuggestAdapter.supportsResolving(this._provider)) {
|
||||
pid = this._cache.add(list.items);
|
||||
}
|
||||
const pid: number = SuggestAdapter.supportsResolving(this._provider) ? this._cache.add(list.items) : this._cache.add([]);
|
||||
const disposables = new DisposableStore();
|
||||
this._disposables.set(pid, disposables);
|
||||
|
||||
// the default text edit range
|
||||
const wordRangeBeforePos = (doc.getWordRangeAtPosition(pos) as Range || new Range(pos, pos))
|
||||
@@ -663,7 +670,7 @@ class SuggestAdapter {
|
||||
};
|
||||
|
||||
for (let i = 0; i < list.items.length; i++) {
|
||||
const suggestion = this._convertCompletionItem(list.items[i], pos, pid && [pid, i] || undefined);
|
||||
const suggestion = this._convertCompletionItem(list.items[i], pos, [pid, i]);
|
||||
// check for bad completion item
|
||||
// for the converter did warn
|
||||
if (suggestion) {
|
||||
@@ -698,15 +705,22 @@ class SuggestAdapter {
|
||||
}
|
||||
|
||||
releaseCompletionItems(id: number): any {
|
||||
dispose(this._disposables.get(id));
|
||||
this._disposables.delete(id);
|
||||
this._cache.delete(id);
|
||||
}
|
||||
|
||||
private _convertCompletionItem(item: vscode.CompletionItem, position: vscode.Position, id: ChainedCacheId | undefined): SuggestDataDto | undefined {
|
||||
private _convertCompletionItem(item: vscode.CompletionItem, position: vscode.Position, id: ChainedCacheId): SuggestDataDto | undefined {
|
||||
if (typeof item.label !== 'string' || item.label.length === 0) {
|
||||
console.warn('INVALID text edit -> must have at least a label');
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const disposables = this._disposables.get(id[0]);
|
||||
if (!disposables) {
|
||||
throw Error('DisposableStore is missing...');
|
||||
}
|
||||
|
||||
const result: SuggestDataDto = {
|
||||
//
|
||||
x: id,
|
||||
@@ -721,7 +735,7 @@ class SuggestAdapter {
|
||||
i: item.keepWhitespace ? modes.CompletionItemInsertTextRule.KeepWhitespace : 0,
|
||||
k: item.commitCharacters,
|
||||
l: item.additionalTextEdits && item.additionalTextEdits.map(typeConvert.TextEdit.from),
|
||||
m: this._commands.toInternal(item.command),
|
||||
m: this._commands.toInternal(item.command, disposables),
|
||||
};
|
||||
|
||||
// 'insertText'-logic
|
||||
@@ -756,31 +770,32 @@ class SuggestAdapter {
|
||||
|
||||
class SignatureHelpAdapter {
|
||||
|
||||
private readonly _cache = new Cache<vscode.SignatureHelp>('SignatureHelp');
|
||||
|
||||
constructor(
|
||||
private readonly _documents: ExtHostDocuments,
|
||||
private readonly _provider: vscode.SignatureHelpProvider,
|
||||
private readonly _heap: ExtHostHeapService,
|
||||
) { }
|
||||
|
||||
provideSignatureHelp(resource: URI, position: IPosition, context: modes.SignatureHelpContext, token: CancellationToken): Promise<modes.SignatureHelp | undefined> {
|
||||
provideSignatureHelp(resource: URI, position: IPosition, context: SignatureHelpContextDto, token: CancellationToken): Promise<SignatureHelpDto | undefined> {
|
||||
const doc = this._documents.getDocument(resource);
|
||||
const pos = typeConvert.Position.to(position);
|
||||
const vscodeContext = this.reviveContext(context);
|
||||
|
||||
return asPromise(() => this._provider.provideSignatureHelp(doc, pos, token, vscodeContext)).then(value => {
|
||||
if (value) {
|
||||
const id = this._heap.keep(value);
|
||||
return ObjectIdentifier.mixin(typeConvert.SignatureHelp.from(value), id);
|
||||
const id = this._cache.add([value]);
|
||||
return { ...typeConvert.SignatureHelp.from(value), id };
|
||||
}
|
||||
return undefined;
|
||||
});
|
||||
}
|
||||
|
||||
private reviveContext(context: modes.SignatureHelpContext): vscode.SignatureHelpContext {
|
||||
private reviveContext(context: SignatureHelpContextDto): vscode.SignatureHelpContext {
|
||||
let activeSignatureHelp: vscode.SignatureHelp | undefined = undefined;
|
||||
if (context.activeSignatureHelp) {
|
||||
const revivedSignatureHelp = typeConvert.SignatureHelp.to(context.activeSignatureHelp);
|
||||
const saved = this._heap.get<vscode.SignatureHelp>(ObjectIdentifier.of(context.activeSignatureHelp));
|
||||
const saved = this._cache.get(context.activeSignatureHelp.id, 0);
|
||||
if (saved) {
|
||||
activeSignatureHelp = saved;
|
||||
activeSignatureHelp.activeSignature = revivedSignatureHelp.activeSignature;
|
||||
@@ -791,16 +806,26 @@ class SignatureHelpAdapter {
|
||||
}
|
||||
return { ...context, activeSignatureHelp };
|
||||
}
|
||||
|
||||
releaseSignatureHelp(id: number): any {
|
||||
this._cache.delete(id);
|
||||
}
|
||||
}
|
||||
|
||||
class Cache<T> {
|
||||
private static readonly enableDebugLogging = false;
|
||||
|
||||
private _data = new Map<number, T[]>();
|
||||
private readonly _data = new Map<number, readonly T[]>();
|
||||
private _idPool = 1;
|
||||
|
||||
add(item: T[]): number {
|
||||
constructor(
|
||||
private readonly id: string
|
||||
) { }
|
||||
|
||||
add(item: readonly T[]): number {
|
||||
const id = this._idPool++;
|
||||
this._data.set(id, item);
|
||||
this.logDebugInfo();
|
||||
return id;
|
||||
}
|
||||
|
||||
@@ -810,12 +835,20 @@ class Cache<T> {
|
||||
|
||||
delete(id: number) {
|
||||
this._data.delete(id);
|
||||
this.logDebugInfo();
|
||||
}
|
||||
|
||||
private logDebugInfo() {
|
||||
if (!Cache.enableDebugLogging) {
|
||||
return;
|
||||
}
|
||||
console.log(`${this.id} cache size — ${this._data.size}`);
|
||||
}
|
||||
}
|
||||
|
||||
class LinkProviderAdapter {
|
||||
|
||||
private _cache = new Cache<vscode.DocumentLink>();
|
||||
private _cache = new Cache<vscode.DocumentLink>('DocumentLink');
|
||||
|
||||
constructor(
|
||||
private readonly _documents: ExtHostDocuments,
|
||||
@@ -831,6 +864,12 @@ class LinkProviderAdapter {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
if (token.isCancellationRequested) {
|
||||
// cancelled -> return without further ado, esp no caching
|
||||
// of results as they will leak
|
||||
return undefined;
|
||||
}
|
||||
|
||||
if (typeof this._provider.resolveDocumentLink !== 'function') {
|
||||
// no resolve -> no caching
|
||||
return { links: links.map(typeConvert.DocumentLink.from) };
|
||||
@@ -877,7 +916,7 @@ class ColorProviderAdapter {
|
||||
provideColors(resource: URI, token: CancellationToken): Promise<IRawColorInfo[]> {
|
||||
const doc = this._documents.getDocument(resource);
|
||||
return asPromise(() => this._provider.provideDocumentColors(doc, token)).then(colors => {
|
||||
if (!Array.isArray(colors)) {
|
||||
if (!Array.isArray<vscode.ColorInformation>(colors)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
@@ -1027,7 +1066,7 @@ type Adapter = DocumentSymbolAdapter | CodeLensAdapter | DefinitionAdapter | Hov
|
||||
| DocumentHighlightAdapter | ReferenceAdapter | CodeActionAdapter | DocumentFormattingAdapter
|
||||
| RangeFormattingAdapter | OnTypeFormattingAdapter | NavigateTypeAdapter | RenameAdapter
|
||||
| SuggestAdapter | SignatureHelpAdapter | LinkProviderAdapter | ImplementationAdapter | TypeDefinitionAdapter
|
||||
| ColorProviderAdapter | FoldingProviderAdapter | CodeInsetAdapter | DeclarationAdapter | SelectionRangeAdapter | CallHierarchyAdapter;
|
||||
| ColorProviderAdapter | FoldingProviderAdapter | DeclarationAdapter | SelectionRangeAdapter | CallHierarchyAdapter;
|
||||
|
||||
class AdapterData {
|
||||
constructor(
|
||||
@@ -1036,41 +1075,32 @@ class AdapterData {
|
||||
) { }
|
||||
}
|
||||
|
||||
export interface ISchemeTransformer {
|
||||
transformOutgoing(scheme: string): string;
|
||||
}
|
||||
|
||||
export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape {
|
||||
|
||||
private static _handlePool: number = 0;
|
||||
|
||||
private readonly _schemeTransformer: ISchemeTransformer | null;
|
||||
private readonly _uriTransformer: IURITransformer | null;
|
||||
private _proxy: MainThreadLanguageFeaturesShape;
|
||||
private _documents: ExtHostDocuments;
|
||||
private _commands: ExtHostCommands;
|
||||
private _heapService: ExtHostHeapService;
|
||||
private _diagnostics: ExtHostDiagnostics;
|
||||
private _adapter = new Map<number, AdapterData>();
|
||||
private readonly _logService: ILogService;
|
||||
private _webviewProxy: MainThreadWebviewsShape;
|
||||
|
||||
constructor(
|
||||
mainContext: IMainContext,
|
||||
schemeTransformer: ISchemeTransformer | null,
|
||||
uriTransformer: IURITransformer | null,
|
||||
documents: ExtHostDocuments,
|
||||
commands: ExtHostCommands,
|
||||
heapMonitor: ExtHostHeapService,
|
||||
diagnostics: ExtHostDiagnostics,
|
||||
logService: ILogService
|
||||
) {
|
||||
this._schemeTransformer = schemeTransformer;
|
||||
this._uriTransformer = uriTransformer;
|
||||
this._proxy = mainContext.getProxy(MainContext.MainThreadLanguageFeatures);
|
||||
this._documents = documents;
|
||||
this._commands = commands;
|
||||
this._heapService = heapMonitor;
|
||||
this._diagnostics = diagnostics;
|
||||
this._logService = logService;
|
||||
this._webviewProxy = mainContext.getProxy(MainContext.MainThreadWebviews);
|
||||
}
|
||||
|
||||
private _transformDocumentSelector(selector: vscode.DocumentSelector): Array<ISerializedDocumentFilter> {
|
||||
@@ -1099,8 +1129,8 @@ export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape {
|
||||
}
|
||||
|
||||
private _transformScheme(scheme: string | undefined): string | undefined {
|
||||
if (this._schemeTransformer && typeof scheme === 'string') {
|
||||
return this._schemeTransformer.transformOutgoing(scheme);
|
||||
if (this._uriTransformer && typeof scheme === 'string') {
|
||||
return this._uriTransformer.transformOutgoingScheme(scheme);
|
||||
}
|
||||
return scheme;
|
||||
}
|
||||
@@ -1173,7 +1203,7 @@ export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape {
|
||||
const handle = this._nextHandle();
|
||||
const eventHandle = typeof provider.onDidChangeCodeLenses === 'function' ? this._nextHandle() : undefined;
|
||||
|
||||
this._adapter.set(handle, new AdapterData(new CodeLensAdapter(this._documents, this._commands.converter, this._heapService, provider), extension));
|
||||
this._adapter.set(handle, new AdapterData(new CodeLensAdapter(this._documents, this._commands.converter, provider), extension));
|
||||
this._proxy.$registerCodeLensSupport(handle, this._transformDocumentSelector(selector), eventHandle);
|
||||
let result = this._createDisposable(handle);
|
||||
|
||||
@@ -1185,43 +1215,16 @@ export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape {
|
||||
return result;
|
||||
}
|
||||
|
||||
$provideCodeLenses(handle: number, resource: UriComponents, token: CancellationToken): Promise<modes.ICodeLensSymbol[]> {
|
||||
return this._withAdapter(handle, CodeLensAdapter, adapter => adapter.provideCodeLenses(URI.revive(resource), token), []);
|
||||
$provideCodeLenses(handle: number, resource: UriComponents, token: CancellationToken): Promise<CodeLensListDto | undefined> {
|
||||
return this._withAdapter(handle, CodeLensAdapter, adapter => adapter.provideCodeLenses(URI.revive(resource), token), undefined);
|
||||
}
|
||||
|
||||
$resolveCodeLens(handle: number, symbol: modes.ICodeLensSymbol, token: CancellationToken): Promise<modes.ICodeLensSymbol | undefined> {
|
||||
$resolveCodeLens(handle: number, symbol: CodeLensDto, token: CancellationToken): Promise<CodeLensDto | undefined> {
|
||||
return this._withAdapter(handle, CodeLensAdapter, adapter => adapter.resolveCodeLens(symbol, token), undefined);
|
||||
}
|
||||
|
||||
// --- code insets
|
||||
|
||||
registerCodeInsetProvider(extension: IExtensionDescription, selector: vscode.DocumentSelector, provider: vscode.CodeInsetProvider): vscode.Disposable {
|
||||
const handle = this._nextHandle();
|
||||
const eventHandle = typeof provider.onDidChangeCodeInsets === 'function' ? this._nextHandle() : undefined;
|
||||
|
||||
this._adapter.set(handle, new AdapterData(new CodeInsetAdapter(this._documents, this._heapService, provider), extension));
|
||||
this._proxy.$registerCodeInsetSupport(handle, this._transformDocumentSelector(selector), eventHandle);
|
||||
let result = this._createDisposable(handle);
|
||||
|
||||
if (eventHandle !== undefined && provider.onDidChangeCodeInsets) {
|
||||
const subscription = provider.onDidChangeCodeInsets(_ => this._proxy.$emitCodeLensEvent(eventHandle));
|
||||
result = Disposable.from(result, subscription);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
$provideCodeInsets(handle: number, resource: UriComponents, token: CancellationToken): Promise<codeInset.ICodeInsetSymbol[] | undefined> {
|
||||
return this._withAdapter(handle, CodeInsetAdapter, adapter => adapter.provideCodeInsets(URI.revive(resource), token), undefined);
|
||||
}
|
||||
|
||||
$resolveCodeInset(handle: number, _resource: UriComponents, symbol: codeInset.ICodeInsetSymbol, token: CancellationToken): Promise<codeInset.ICodeInsetSymbol> {
|
||||
const webviewHandle = Math.random();
|
||||
const webview = new ExtHostWebview(webviewHandle, this._webviewProxy, { enableScripts: true });
|
||||
return this._withAdapter(handle, CodeInsetAdapter, async (adapter, extension) => {
|
||||
await this._webviewProxy.$createWebviewCodeInset(webviewHandle, symbol.id, { enableCommandUris: true, enableScripts: true }, extension ? extension.identifier : undefined, extension ? extension.extensionLocation : undefined);
|
||||
return adapter.resolveCodeInset(symbol, webview, token);
|
||||
}, symbol);
|
||||
$releaseCodeLenses(handle: number, cacheId: number): void {
|
||||
this._withAdapter(handle, CodeLensAdapter, adapter => Promise.resolve(adapter.releaseCodeLenses(cacheId)), undefined);
|
||||
}
|
||||
|
||||
// --- declaration
|
||||
@@ -1311,10 +1314,14 @@ export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape {
|
||||
}
|
||||
|
||||
|
||||
$provideCodeActions(handle: number, resource: UriComponents, rangeOrSelection: IRange | ISelection, context: modes.CodeActionContext, token: CancellationToken): Promise<CodeActionDto[] | undefined> {
|
||||
$provideCodeActions(handle: number, resource: UriComponents, rangeOrSelection: IRange | ISelection, context: modes.CodeActionContext, token: CancellationToken): Promise<CodeActionListDto | undefined> {
|
||||
return this._withAdapter(handle, CodeActionAdapter, adapter => adapter.provideCodeActions(URI.revive(resource), rangeOrSelection, context, token), undefined);
|
||||
}
|
||||
|
||||
$releaseCodeActions(handle: number, cacheId: number): void {
|
||||
this._withAdapter(handle, CodeActionAdapter, adapter => Promise.resolve(adapter.releaseCodeActions(cacheId)), undefined);
|
||||
}
|
||||
|
||||
// --- formatting
|
||||
|
||||
registerDocumentFormattingEditProvider(extension: IExtensionDescription, selector: vscode.DocumentSelector, provider: vscode.DocumentFormattingEditProvider): vscode.Disposable {
|
||||
@@ -1387,7 +1394,7 @@ export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape {
|
||||
|
||||
registerCompletionItemProvider(extension: IExtensionDescription, selector: vscode.DocumentSelector, provider: vscode.CompletionItemProvider, triggerCharacters: string[]): vscode.Disposable {
|
||||
const handle = this._addNewAdapter(new SuggestAdapter(this._documents, this._commands.converter, provider), extension);
|
||||
this._proxy.$registerSuggestSupport(handle, this._transformDocumentSelector(selector), triggerCharacters, SuggestAdapter.supportsResolving(provider));
|
||||
this._proxy.$registerSuggestSupport(handle, this._transformDocumentSelector(selector), triggerCharacters, SuggestAdapter.supportsResolving(provider), extension.identifier);
|
||||
return this._createDisposable(handle);
|
||||
}
|
||||
|
||||
@@ -1410,15 +1417,19 @@ export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape {
|
||||
? { triggerCharacters: metadataOrTriggerChars, retriggerCharacters: [] }
|
||||
: metadataOrTriggerChars;
|
||||
|
||||
const handle = this._addNewAdapter(new SignatureHelpAdapter(this._documents, provider, this._heapService), extension);
|
||||
const handle = this._addNewAdapter(new SignatureHelpAdapter(this._documents, provider), extension);
|
||||
this._proxy.$registerSignatureHelpProvider(handle, this._transformDocumentSelector(selector), metadata);
|
||||
return this._createDisposable(handle);
|
||||
}
|
||||
|
||||
$provideSignatureHelp(handle: number, resource: UriComponents, position: IPosition, context: modes.SignatureHelpContext, token: CancellationToken): Promise<modes.SignatureHelp | undefined> {
|
||||
$provideSignatureHelp(handle: number, resource: UriComponents, position: IPosition, context: SignatureHelpContextDto, token: CancellationToken): Promise<SignatureHelpDto | undefined> {
|
||||
return this._withAdapter(handle, SignatureHelpAdapter, adapter => adapter.provideSignatureHelp(URI.revive(resource), position, context, token), undefined);
|
||||
}
|
||||
|
||||
$releaseSignatureHelp(handle: number, id: number): void {
|
||||
this._withAdapter(handle, SignatureHelpAdapter, adapter => adapter.releaseSignatureHelp(id), undefined);
|
||||
}
|
||||
|
||||
// --- links
|
||||
|
||||
registerDocumentLinkProvider(extension: IExtensionDescription | undefined, selector: vscode.DocumentSelector, provider: vscode.DocumentLinkProvider): vscode.Disposable {
|
||||
|
||||
@@ -38,7 +38,9 @@ export class ExtensionMemento implements IExtensionMemento {
|
||||
return this._init;
|
||||
}
|
||||
|
||||
get<T>(key: string, defaultValue: T): T {
|
||||
get<T>(key: string): T | undefined;
|
||||
get<T>(key: string, defaultValue: T): T;
|
||||
get<T>(key: string, defaultValue?: T): T {
|
||||
let value = this._value[key];
|
||||
if (typeof value === 'undefined') {
|
||||
value = defaultValue;
|
||||
@@ -46,11 +48,9 @@ export class ExtensionMemento implements IExtensionMemento {
|
||||
return value;
|
||||
}
|
||||
|
||||
update(key: string, value: any): Promise<boolean> {
|
||||
update(key: string, value: any): Promise<void> {
|
||||
this._value[key] = value;
|
||||
return this._storage
|
||||
.setValue(this._shared, this._id, this._value)
|
||||
.then(() => true);
|
||||
return this._storage.setValue(this._shared, this._id, this._value);
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
|
||||
@@ -458,14 +458,14 @@ function getLightIconUri(iconPath: QuickInputButton['iconPath']) {
|
||||
|| iconPath instanceof URI) {
|
||||
return getIconUri(iconPath);
|
||||
}
|
||||
return getIconUri(iconPath['light']);
|
||||
return getIconUri((iconPath as any).light);
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function getDarkIconUri(iconPath: QuickInputButton['iconPath']) {
|
||||
if (iconPath && !(iconPath instanceof ThemeIcon) && iconPath['dark']) {
|
||||
return getIconUri(iconPath['dark']);
|
||||
if (iconPath && !(iconPath instanceof ThemeIcon) && (iconPath as any).dark) {
|
||||
return getIconUri((iconPath as any).dark);
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
import { URI, UriComponents } from 'vs/base/common/uri';
|
||||
import { Event, Emitter } from 'vs/base/common/event';
|
||||
import { debounce } from 'vs/base/common/decorators';
|
||||
import { dispose, IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { dispose, IDisposable, DisposableStore, MutableDisposable } from 'vs/base/common/lifecycle';
|
||||
import { asPromise } from 'vs/base/common/async';
|
||||
import { ExtHostCommands } from 'vs/workbench/api/common/extHostCommands';
|
||||
import { MainContext, MainThreadSCMShape, SCMRawResource, SCMRawResourceSplice, SCMRawResourceSplices, IMainContext, ExtHostSCMShape, CommandDto } from './extHost.protocol';
|
||||
@@ -415,6 +415,7 @@ class ExtHostSourceControl implements vscode.SourceControl {
|
||||
this._proxy.$updateSourceControl(this.handle, { commitTemplate });
|
||||
}
|
||||
|
||||
private _acceptInputDisposables = new MutableDisposable<DisposableStore>();
|
||||
private _acceptInputCommand: vscode.Command | undefined = undefined;
|
||||
|
||||
get acceptInputCommand(): vscode.Command | undefined {
|
||||
@@ -422,12 +423,15 @@ class ExtHostSourceControl implements vscode.SourceControl {
|
||||
}
|
||||
|
||||
set acceptInputCommand(acceptInputCommand: vscode.Command | undefined) {
|
||||
this._acceptInputDisposables.value = new DisposableStore();
|
||||
|
||||
this._acceptInputCommand = acceptInputCommand;
|
||||
|
||||
const internal = this._commands.converter.toInternal(acceptInputCommand);
|
||||
const internal = this._commands.converter.toInternal(acceptInputCommand, this._acceptInputDisposables.value);
|
||||
this._proxy.$updateSourceControl(this.handle, { acceptInputCommand: internal });
|
||||
}
|
||||
|
||||
private _statusBarDisposables = new MutableDisposable<DisposableStore>();
|
||||
private _statusBarCommands: vscode.Command[] | undefined = undefined;
|
||||
|
||||
get statusBarCommands(): vscode.Command[] | undefined {
|
||||
@@ -439,9 +443,11 @@ class ExtHostSourceControl implements vscode.SourceControl {
|
||||
return;
|
||||
}
|
||||
|
||||
this._statusBarDisposables.value = new DisposableStore();
|
||||
|
||||
this._statusBarCommands = statusBarCommands;
|
||||
|
||||
const internal = (statusBarCommands || []).map(c => this._commands.converter.toInternal(c)) as CommandDto[];
|
||||
const internal = (statusBarCommands || []).map(c => this._commands.converter.toInternal(c, this._statusBarDisposables.value!)) as CommandDto[];
|
||||
this._proxy.$updateSourceControl(this.handle, { statusBarCommands: internal });
|
||||
}
|
||||
|
||||
@@ -519,6 +525,9 @@ class ExtHostSourceControl implements vscode.SourceControl {
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
this._acceptInputDisposables.dispose();
|
||||
this._statusBarDisposables.dispose();
|
||||
|
||||
this._groups.forEach(group => group.dispose());
|
||||
this._proxy.$unregisterSourceControl(this.handle);
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ import { StatusbarAlignment as MainThreadStatusBarAlignment } from 'vs/platform/
|
||||
import { StatusBarAlignment as ExtHostStatusBarAlignment, Disposable, ThemeColor } from './extHostTypes';
|
||||
import { StatusBarItem, StatusBarAlignment } from 'vscode';
|
||||
import { MainContext, MainThreadStatusBarShape, IMainContext } from './extHost.protocol';
|
||||
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
|
||||
import { localize } from 'vs/nls';
|
||||
|
||||
export class ExtHostStatusBarEntry implements StatusBarItem {
|
||||
private static ID_GEN = 0;
|
||||
@@ -18,6 +18,9 @@ export class ExtHostStatusBarEntry implements StatusBarItem {
|
||||
private _disposed: boolean;
|
||||
private _visible: boolean;
|
||||
|
||||
private _statusId: string;
|
||||
private _statusName: string;
|
||||
|
||||
private _text: string;
|
||||
private _tooltip: string;
|
||||
private _color: string | ThemeColor;
|
||||
@@ -26,14 +29,13 @@ export class ExtHostStatusBarEntry implements StatusBarItem {
|
||||
private _timeoutHandle: any;
|
||||
private _proxy: MainThreadStatusBarShape;
|
||||
|
||||
private _extensionId?: ExtensionIdentifier;
|
||||
|
||||
constructor(proxy: MainThreadStatusBarShape, extensionId: ExtensionIdentifier | undefined, alignment: ExtHostStatusBarAlignment = ExtHostStatusBarAlignment.Left, priority?: number) {
|
||||
constructor(proxy: MainThreadStatusBarShape, id: string, name: string, alignment: ExtHostStatusBarAlignment = ExtHostStatusBarAlignment.Left, priority?: number) {
|
||||
this._id = ExtHostStatusBarEntry.ID_GEN++;
|
||||
this._proxy = proxy;
|
||||
this._statusId = id;
|
||||
this._statusName = name;
|
||||
this._alignment = alignment;
|
||||
this._priority = priority;
|
||||
this._extensionId = extensionId;
|
||||
}
|
||||
|
||||
public get id(): number {
|
||||
@@ -107,7 +109,7 @@ export class ExtHostStatusBarEntry implements StatusBarItem {
|
||||
this._timeoutHandle = undefined;
|
||||
|
||||
// Set to status bar
|
||||
this._proxy.$setEntry(this.id, this._extensionId, this.text, this.tooltip, this.command, this.color,
|
||||
this._proxy.$setEntry(this.id, this._statusId, this._statusName, this.text, this.tooltip, this.command, this.color,
|
||||
this._alignment === ExtHostStatusBarAlignment.Left ? MainThreadStatusBarAlignment.LEFT : MainThreadStatusBarAlignment.RIGHT,
|
||||
this._priority);
|
||||
}, 0);
|
||||
@@ -125,7 +127,7 @@ class StatusBarMessage {
|
||||
private _messages: { message: string }[] = [];
|
||||
|
||||
constructor(statusBar: ExtHostStatusBar) {
|
||||
this._item = statusBar.createStatusBarEntry(undefined, ExtHostStatusBarAlignment.Left, Number.MIN_VALUE);
|
||||
this._item = statusBar.createStatusBarEntry('status.extensionMessage', localize('status.extensionMessage', "Extension Status"), ExtHostStatusBarAlignment.Left, Number.MIN_VALUE);
|
||||
}
|
||||
|
||||
dispose() {
|
||||
@@ -167,8 +169,8 @@ export class ExtHostStatusBar {
|
||||
this._statusMessage = new StatusBarMessage(this);
|
||||
}
|
||||
|
||||
createStatusBarEntry(extensionId: ExtensionIdentifier | undefined, alignment?: ExtHostStatusBarAlignment, priority?: number): StatusBarItem {
|
||||
return new ExtHostStatusBarEntry(this._proxy, extensionId, alignment, priority);
|
||||
createStatusBarEntry(id: string, name: string, alignment?: ExtHostStatusBarAlignment, priority?: number): StatusBarItem {
|
||||
return new ExtHostStatusBarEntry(this._proxy, id, name, alignment, priority);
|
||||
}
|
||||
|
||||
setStatusBarMessage(text: string, timeoutOrThenable?: number | Thenable<any>): Disposable {
|
||||
|
||||
@@ -613,7 +613,7 @@ export class ExtHostTextEditor implements vscode.TextEditor {
|
||||
});
|
||||
}
|
||||
|
||||
insertSnippet(snippet: SnippetString, where?: Position | Position[] | Range | Range[], options: { undoStopBefore: boolean; undoStopAfter: boolean; } = { undoStopBefore: true, undoStopAfter: true }): Promise<boolean> {
|
||||
insertSnippet(snippet: SnippetString, where?: Position | readonly Position[] | Range | readonly Range[], options: { undoStopBefore: boolean; undoStopAfter: boolean; } = { undoStopBefore: true, undoStopAfter: true }): Promise<boolean> {
|
||||
if (this._disposed) {
|
||||
return Promise.reject(new Error('TextEditor#insertSnippet not possible on closed editors'));
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ import * as vscode from 'vscode';
|
||||
import { basename } from 'vs/base/common/resources';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { Emitter, Event } from 'vs/base/common/event';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { Disposable, DisposableStore, IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { ExtHostTreeViewsShape, MainThreadTreeViewsShape } from './extHost.protocol';
|
||||
import { ITreeItem, TreeViewItemHandleArg, ITreeItemLabel, IRevealOptions } from 'vs/workbench/common/views';
|
||||
import { ExtHostCommands, CommandsConverter } from 'vs/workbench/api/common/extHostCommands';
|
||||
@@ -142,8 +142,7 @@ export class ExtHostTreeViews implements ExtHostTreeViewsShape {
|
||||
type Root = null | undefined;
|
||||
type TreeData<T> = { message: boolean, element: T | Root | false };
|
||||
|
||||
// {{SQL CARBON EDIT}}
|
||||
export interface TreeNode {
|
||||
export interface TreeNode extends IDisposable { // {{SQL CARBON EDIT}} export interface
|
||||
item: ITreeItem;
|
||||
parent: TreeNode | Root;
|
||||
children?: TreeNode[];
|
||||
@@ -435,6 +434,7 @@ export class ExtHostTreeView<T> extends Disposable {
|
||||
if (extTreeItem) {
|
||||
const newNode = this.createTreeNode(extElement, extTreeItem, existing.parent);
|
||||
this.updateNodeCache(extElement, newNode, existing, existing.parent);
|
||||
existing.dispose();
|
||||
return newNode;
|
||||
}
|
||||
return null;
|
||||
@@ -454,18 +454,8 @@ export class ExtHostTreeView<T> extends Disposable {
|
||||
return node;
|
||||
}
|
||||
|
||||
// {{SQL CARBON EDIT}}
|
||||
protected createTreeNode(element: T, extensionTreeItem: vscode.TreeItem, parent: TreeNode | Root): TreeNode {
|
||||
return {
|
||||
item: this.createTreeItem(element, extensionTreeItem, parent),
|
||||
parent,
|
||||
children: undefined
|
||||
};
|
||||
}
|
||||
|
||||
// {{SQL CARBON EDIT}}
|
||||
protected createTreeItem(element: T, extensionTreeItem: azdata.TreeItem, parent: TreeNode | Root): ITreeItem {
|
||||
|
||||
protected createTreeNode(element: T, extensionTreeItem: azdata.TreeItem, parent: TreeNode | Root): TreeNode { // {{SQL CARBON EDIT}} change to protected, change to azdata.TreeItem
|
||||
const disposable = new DisposableStore();
|
||||
const handle = this.createHandle(element, extensionTreeItem, parent);
|
||||
const icon = this.getLightIconPath(extensionTreeItem);
|
||||
const item = {
|
||||
@@ -475,7 +465,7 @@ export class ExtHostTreeView<T> extends Disposable {
|
||||
description: extensionTreeItem.description,
|
||||
resourceUri: extensionTreeItem.resourceUri,
|
||||
tooltip: typeof extensionTreeItem.tooltip === 'string' ? extensionTreeItem.tooltip : undefined,
|
||||
command: extensionTreeItem.command ? this.commands.toInternal(extensionTreeItem.command) : undefined,
|
||||
command: extensionTreeItem.command ? this.commands.toInternal(extensionTreeItem.command, disposable) : undefined,
|
||||
contextValue: extensionTreeItem.contextValue,
|
||||
icon,
|
||||
iconDark: this.getDarkIconPath(extensionTreeItem) || icon,
|
||||
@@ -487,7 +477,12 @@ export class ExtHostTreeView<T> extends Disposable {
|
||||
type: extensionTreeItem.type
|
||||
};
|
||||
|
||||
return item;
|
||||
return {
|
||||
item,
|
||||
parent,
|
||||
children: undefined,
|
||||
dispose(): void { disposable.dispose(); }
|
||||
};
|
||||
}
|
||||
|
||||
private createHandle(element: T, { id, label, resourceUri }: vscode.TreeItem, parent: TreeNode | Root, returnFirst?: boolean): TreeItemHandle {
|
||||
@@ -524,14 +519,14 @@ export class ExtHostTreeView<T> extends Disposable {
|
||||
|| extensionTreeItem.iconPath instanceof URI) {
|
||||
return this.getIconPath(extensionTreeItem.iconPath);
|
||||
}
|
||||
return this.getIconPath(extensionTreeItem.iconPath['light']);
|
||||
return this.getIconPath((<{ light: string | URI; dark: string | URI }>extensionTreeItem.iconPath).light);
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
private getDarkIconPath(extensionTreeItem: vscode.TreeItem): URI | undefined {
|
||||
if (extensionTreeItem.iconPath && !(extensionTreeItem.iconPath instanceof ThemeIcon) && extensionTreeItem.iconPath['dark']) {
|
||||
return this.getIconPath(extensionTreeItem.iconPath['dark']);
|
||||
if (extensionTreeItem.iconPath && !(extensionTreeItem.iconPath instanceof ThemeIcon) && (<{ light: string | URI; dark: string | URI }>extensionTreeItem.iconPath).dark) {
|
||||
return this.getIconPath((<{ light: string | URI; dark: string | URI }>extensionTreeItem.iconPath).dark);
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
@@ -614,6 +609,7 @@ export class ExtHostTreeView<T> extends Disposable {
|
||||
}
|
||||
this.nodes.delete(element);
|
||||
this.elements.delete(node.item.handle);
|
||||
node.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -621,6 +617,7 @@ export class ExtHostTreeView<T> extends Disposable {
|
||||
protected clearAll(): void {
|
||||
this.roots = null;
|
||||
this.elements.clear();
|
||||
this.nodes.forEach(node => node.dispose());
|
||||
this.nodes.clear();
|
||||
}
|
||||
|
||||
|
||||
@@ -237,8 +237,7 @@ export namespace MarkdownString {
|
||||
const resUris: { [href: string]: UriComponents } = Object.create(null);
|
||||
res.uris = resUris;
|
||||
|
||||
const renderer = new marked.Renderer();
|
||||
renderer.image = renderer.link = (href: string): string => {
|
||||
const collectUri = (href: string): string => {
|
||||
try {
|
||||
let uri = URI.parse(href, true);
|
||||
uri = uri.with({ query: _uriMassage(uri.query, resUris) });
|
||||
@@ -248,6 +247,10 @@ export namespace MarkdownString {
|
||||
}
|
||||
return '';
|
||||
};
|
||||
const renderer = new marked.Renderer();
|
||||
renderer.link = collectUri;
|
||||
renderer.image = href => collectUri(htmlContent.parseHrefAndDimensions(href).href);
|
||||
|
||||
marked(res.value, { renderer });
|
||||
|
||||
return res;
|
||||
@@ -808,7 +811,8 @@ export namespace DocumentLink {
|
||||
export function from(link: vscode.DocumentLink): modes.ILink {
|
||||
return {
|
||||
range: Range.from(link.range),
|
||||
url: link.target
|
||||
url: link.target,
|
||||
tooltip: link.tooltip
|
||||
};
|
||||
}
|
||||
|
||||
@@ -858,10 +862,7 @@ export namespace Color {
|
||||
|
||||
export namespace SelectionRange {
|
||||
export function from(obj: vscode.SelectionRange): modes.SelectionRange {
|
||||
return {
|
||||
kind: '',
|
||||
range: Range.from(obj.range)
|
||||
};
|
||||
return { range: Range.from(obj.range) };
|
||||
}
|
||||
|
||||
export function to(obj: modes.SelectionRange): vscode.SelectionRange {
|
||||
|
||||
@@ -1440,6 +1440,8 @@ export class DocumentLink {
|
||||
|
||||
target?: URI;
|
||||
|
||||
tooltip?: string;
|
||||
|
||||
constructor(range: Range, target: URI | undefined) {
|
||||
if (target && !(target instanceof URI)) {
|
||||
throw illegalArgument('target');
|
||||
@@ -1770,6 +1772,24 @@ export class CustomExecution implements vscode.CustomExecution {
|
||||
}
|
||||
}
|
||||
|
||||
export class CustomExecution2 implements vscode.CustomExecution2 {
|
||||
private _callback: () => Thenable<vscode.TerminalVirtualProcess>;
|
||||
constructor(callback: () => Thenable<vscode.TerminalVirtualProcess>) {
|
||||
this._callback = callback;
|
||||
}
|
||||
public computeId(): string {
|
||||
return 'customExecution' + generateUuid();
|
||||
}
|
||||
|
||||
public set callback(value: () => Thenable<vscode.TerminalVirtualProcess>) {
|
||||
this._callback = value;
|
||||
}
|
||||
|
||||
public get callback(): (() => Thenable<vscode.TerminalVirtualProcess>) {
|
||||
return this._callback;
|
||||
}
|
||||
}
|
||||
|
||||
@es5ClassCompat
|
||||
export class Task implements vscode.Task2 {
|
||||
|
||||
@@ -1783,7 +1803,7 @@ export class Task implements vscode.Task2 {
|
||||
private _definition: vscode.TaskDefinition;
|
||||
private _scope: vscode.TaskScope.Global | vscode.TaskScope.Workspace | vscode.WorkspaceFolder | undefined;
|
||||
private _name: string;
|
||||
private _execution: ProcessExecution | ShellExecution | CustomExecution | undefined;
|
||||
private _execution: ProcessExecution | ShellExecution | CustomExecution | CustomExecution2 | undefined;
|
||||
private _problemMatchers: string[];
|
||||
private _hasDefinedMatchers: boolean;
|
||||
private _isBackground: boolean;
|
||||
@@ -1792,8 +1812,8 @@ export class Task implements vscode.Task2 {
|
||||
private _presentationOptions: vscode.TaskPresentationOptions;
|
||||
private _runOptions: vscode.RunOptions;
|
||||
|
||||
constructor(definition: vscode.TaskDefinition, name: string, source: string, execution?: ProcessExecution | ShellExecution | CustomExecution, problemMatchers?: string | string[]);
|
||||
constructor(definition: vscode.TaskDefinition, scope: vscode.TaskScope.Global | vscode.TaskScope.Workspace | vscode.WorkspaceFolder, name: string, source: string, execution?: ProcessExecution | ShellExecution | CustomExecution, problemMatchers?: string | string[]);
|
||||
constructor(definition: vscode.TaskDefinition, name: string, source: string, execution?: ProcessExecution | ShellExecution | CustomExecution | CustomExecution2, problemMatchers?: string | string[]);
|
||||
constructor(definition: vscode.TaskDefinition, scope: vscode.TaskScope.Global | vscode.TaskScope.Workspace | vscode.WorkspaceFolder, name: string, source: string, execution?: ProcessExecution | ShellExecution | CustomExecution | CustomExecution2, problemMatchers?: string | string[]);
|
||||
constructor(definition: vscode.TaskDefinition, arg2: string | (vscode.TaskScope.Global | vscode.TaskScope.Workspace) | vscode.WorkspaceFolder, arg3: any, arg4?: any, arg5?: any, arg6?: any) {
|
||||
this.definition = definition;
|
||||
let problemMatchers: string | string[];
|
||||
@@ -1905,18 +1925,18 @@ export class Task implements vscode.Task2 {
|
||||
}
|
||||
|
||||
get execution(): ProcessExecution | ShellExecution | undefined {
|
||||
return (this._execution instanceof CustomExecution) ? undefined : this._execution;
|
||||
return ((this._execution instanceof CustomExecution) || (this._execution instanceof CustomExecution2)) ? undefined : this._execution;
|
||||
}
|
||||
|
||||
set execution(value: ProcessExecution | ShellExecution | undefined) {
|
||||
this.execution2 = value;
|
||||
}
|
||||
|
||||
get execution2(): ProcessExecution | ShellExecution | CustomExecution | undefined {
|
||||
get execution2(): ProcessExecution | ShellExecution | CustomExecution | CustomExecution2 | undefined {
|
||||
return this._execution;
|
||||
}
|
||||
|
||||
set execution2(value: ProcessExecution | ShellExecution | CustomExecution | undefined) {
|
||||
set execution2(value: ProcessExecution | ShellExecution | CustomExecution | CustomExecution2 | undefined) {
|
||||
if (value === null) {
|
||||
value = undefined;
|
||||
}
|
||||
@@ -2317,3 +2337,8 @@ export enum ExtensionExecutionContext {
|
||||
Local = 1,
|
||||
Remote = 2
|
||||
}
|
||||
|
||||
export enum ExtensionKind {
|
||||
UI = 1,
|
||||
Workspace = 2
|
||||
}
|
||||
|
||||
@@ -8,37 +8,41 @@ import { URI } from 'vs/base/common/uri';
|
||||
import * as typeConverters from 'vs/workbench/api/common/extHostTypeConverters';
|
||||
import { EditorViewColumn } from 'vs/workbench/api/common/shared/editor';
|
||||
import * as vscode from 'vscode';
|
||||
import { ExtHostWebviewsShape, IMainContext, MainContext, MainThreadWebviewsShape, WebviewPanelHandle, WebviewPanelViewState, WebviewInsetHandle } from './extHost.protocol';
|
||||
import { ExtHostWebviewsShape, IMainContext, MainContext, MainThreadWebviewsShape, WebviewPanelHandle, WebviewPanelViewState } from './extHost.protocol';
|
||||
import { Disposable } from './extHostTypes';
|
||||
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
||||
import * as modes from 'vs/editor/common/modes';
|
||||
import { WebviewInitData, toWebviewResource } from 'vs/workbench/api/common/shared/webview';
|
||||
import { generateUuid } from 'vs/base/common/uuid';
|
||||
|
||||
type IconPath = URI | { light: URI, dark: URI };
|
||||
|
||||
export class ExtHostWebview implements vscode.Webview {
|
||||
private readonly _handle: WebviewPanelHandle | WebviewInsetHandle;
|
||||
private readonly _proxy: MainThreadWebviewsShape;
|
||||
private _html: string;
|
||||
private _options: vscode.WebviewOptions;
|
||||
private _isDisposed: boolean = false;
|
||||
|
||||
public readonly _onMessageEmitter = new Emitter<any>();
|
||||
public readonly onDidReceiveMessage: Event<any> = this._onMessageEmitter.event;
|
||||
|
||||
constructor(
|
||||
handle: WebviewPanelHandle | WebviewInsetHandle,
|
||||
proxy: MainThreadWebviewsShape,
|
||||
options: vscode.WebviewOptions
|
||||
) {
|
||||
this._handle = handle;
|
||||
this._proxy = proxy;
|
||||
this._options = options;
|
||||
}
|
||||
private readonly _handle: WebviewPanelHandle,
|
||||
private readonly _proxy: MainThreadWebviewsShape,
|
||||
private _options: vscode.WebviewOptions,
|
||||
private readonly _initData: WebviewInitData
|
||||
) { }
|
||||
|
||||
public dispose() {
|
||||
this._onMessageEmitter.dispose();
|
||||
}
|
||||
|
||||
public toWebviewResource(resource: vscode.Uri): vscode.Uri {
|
||||
return toWebviewResource(this._initData, this._handle, resource);
|
||||
}
|
||||
|
||||
public get cspSource(): string {
|
||||
return this._initData.webviewCspSource.replace('{{uuid}}', this._handle);
|
||||
}
|
||||
|
||||
public get html(): string {
|
||||
this.assertNotDisposed();
|
||||
return this._html;
|
||||
@@ -228,10 +232,9 @@ export class ExtHostWebviewPanel implements vscode.WebviewPanel {
|
||||
}
|
||||
|
||||
export class ExtHostWebviews implements ExtHostWebviewsShape {
|
||||
private static webviewHandlePool = 1;
|
||||
|
||||
private static newHandle(): WebviewPanelHandle {
|
||||
return ExtHostWebviews.webviewHandlePool++ + '';
|
||||
return generateUuid();
|
||||
}
|
||||
|
||||
private readonly _proxy: MainThreadWebviewsShape;
|
||||
@@ -239,7 +242,8 @@ export class ExtHostWebviews implements ExtHostWebviewsShape {
|
||||
private readonly _serializers = new Map<string, vscode.WebviewPanelSerializer>();
|
||||
|
||||
constructor(
|
||||
mainContext: IMainContext
|
||||
mainContext: IMainContext,
|
||||
private readonly initData: WebviewInitData
|
||||
) {
|
||||
this._proxy = mainContext.getProxy(MainContext.MainThreadWebviews);
|
||||
}
|
||||
@@ -260,7 +264,7 @@ export class ExtHostWebviews implements ExtHostWebviewsShape {
|
||||
const handle = ExtHostWebviews.newHandle();
|
||||
this._proxy.$createWebviewPanel(handle, viewType, title, webviewShowOptions, convertWebviewOptions(options), extension.identifier, extension.extensionLocation);
|
||||
|
||||
const webview = new ExtHostWebview(handle, this._proxy, options);
|
||||
const webview = new ExtHostWebview(handle, this._proxy, options, this.initData);
|
||||
const panel = new ExtHostWebviewPanel(handle, this._proxy, viewType, title, viewColumn, options, webview);
|
||||
this._webviewPanels.set(handle, panel);
|
||||
return panel;
|
||||
@@ -333,7 +337,7 @@ export class ExtHostWebviews implements ExtHostWebviewsShape {
|
||||
return Promise.reject(new Error(`No serializer found for '${viewType}'`));
|
||||
}
|
||||
|
||||
const webview = new ExtHostWebview(webviewHandle, this._proxy, options);
|
||||
const webview = new ExtHostWebview(webviewHandle, this._proxy, options, this.initData);
|
||||
const revivedPanel = new ExtHostWebviewPanel(webviewHandle, this._proxy, viewType, title, typeof position === 'number' && position >= 0 ? typeConverters.ViewColumn.to(position) : undefined, options, webview);
|
||||
this._webviewPanels.set(webviewHandle, revivedPanel);
|
||||
return Promise.resolve(serializer.deserializeWebviewPanel(revivedPanel, state));
|
||||
|
||||
@@ -9,7 +9,6 @@ import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { Emitter, Event } from 'vs/base/common/event';
|
||||
import { TernarySearchTree } from 'vs/base/common/map';
|
||||
import { Counter } from 'vs/base/common/numbers';
|
||||
import { isLinux } from 'vs/base/common/platform';
|
||||
import { basenameOrAuthority, dirname, isEqual, relativePath, basename } from 'vs/base/common/resources';
|
||||
import { compare } from 'vs/base/common/strings';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
@@ -34,7 +33,7 @@ export interface IExtHostWorkspaceProvider {
|
||||
}
|
||||
|
||||
function isFolderEqual(folderA: URI, folderB: URI): boolean {
|
||||
return isEqual(folderA, folderB, !isLinux);
|
||||
return isEqual(folderA, folderB);
|
||||
}
|
||||
|
||||
function compareWorkspaceFolderByUri(a: vscode.WorkspaceFolder, b: vscode.WorkspaceFolder): number {
|
||||
|
||||
@@ -21,7 +21,6 @@ namespace schema {
|
||||
export interface IUserFriendlyMenuItem {
|
||||
command: string;
|
||||
alt?: string;
|
||||
precondition?: string;
|
||||
when?: string;
|
||||
group?: string;
|
||||
}
|
||||
@@ -84,10 +83,6 @@ namespace schema {
|
||||
collector.error(localize('optstring', "property `{0}` can be omitted or must be of type `string`", 'alt'));
|
||||
return false;
|
||||
}
|
||||
if (item.precondition && typeof item.precondition !== 'string') {
|
||||
collector.error(localize('optstring', "property `{0}` can be omitted or must be of type `string`", 'precondition'));
|
||||
return false;
|
||||
}
|
||||
if (item.when && typeof item.when !== 'string') {
|
||||
collector.error(localize('optstring', "property `{0}` can be omitted or must be of type `string`", 'when'));
|
||||
return false;
|
||||
@@ -112,10 +107,6 @@ namespace schema {
|
||||
description: localize('vscode.extension.contributes.menuItem.alt', 'Identifier of an alternative command to execute. The command must be declared in the \'commands\'-section'),
|
||||
type: 'string'
|
||||
},
|
||||
precondition: {
|
||||
description: localize('vscode.extension.contributes.menuItem.precondition', 'Condition which must be true to enable this item'),
|
||||
type: 'string'
|
||||
},
|
||||
when: {
|
||||
description: localize('vscode.extension.contributes.menuItem.when', 'Condition which must be true to show this item'),
|
||||
type: 'string'
|
||||
@@ -206,8 +197,8 @@ namespace schema {
|
||||
type: 'array',
|
||||
items: menuItem
|
||||
},
|
||||
'comments/commentThread/actions': {
|
||||
description: localize('commentThread.actions', "The contributed comment thread actions"),
|
||||
'comments/commentThread/context': {
|
||||
description: localize('commentThread.actions', "The contributed comment thread context menu, rendered as buttons below the comment editor"),
|
||||
type: 'array',
|
||||
items: menuItem
|
||||
},
|
||||
@@ -216,8 +207,8 @@ namespace schema {
|
||||
type: 'array',
|
||||
items: menuItem
|
||||
},
|
||||
'comments/comment/actions': {
|
||||
description: localize('comment.actions', "The contributed comment actions"),
|
||||
'comments/comment/context': {
|
||||
description: localize('comment.actions', "The contributed comment context menu, rendered as buttons below the comment editor"),
|
||||
type: 'array',
|
||||
items: menuItem
|
||||
},
|
||||
@@ -229,6 +220,7 @@ namespace schema {
|
||||
export interface IUserFriendlyCommand {
|
||||
command: string;
|
||||
title: string | ILocalizedString;
|
||||
enablement?: string;
|
||||
category?: string | ILocalizedString;
|
||||
icon?: IUserFriendlyIcon;
|
||||
}
|
||||
@@ -247,6 +239,10 @@ namespace schema {
|
||||
if (!isValidLocalizedString(command.title, collector, 'title')) {
|
||||
return false;
|
||||
}
|
||||
if (command.enablement && typeof command.enablement !== 'string') {
|
||||
collector.error(localize('optstring', "property `{0}` can be omitted or must be of type `string`", 'precondition'));
|
||||
return false;
|
||||
}
|
||||
if (command.category && !isValidLocalizedString(command.category, collector, 'category')) {
|
||||
return false;
|
||||
}
|
||||
@@ -300,6 +296,10 @@ namespace schema {
|
||||
description: localize('vscode.extension.contributes.commandType.category', '(Optional) Category string by the command is grouped in the UI'),
|
||||
type: 'string'
|
||||
},
|
||||
enablement: {
|
||||
description: localize('vscode.extension.contributes.commandType.precondition', '(Optional) Condition which must be true to enable the command'),
|
||||
type: 'string'
|
||||
},
|
||||
icon: {
|
||||
description: localize('vscode.extension.contributes.commandType.icon', '(Optional) Icon which is used to represent the command in the UI. Either a file path or a themable configuration'),
|
||||
anyOf: [{
|
||||
@@ -336,10 +336,12 @@ namespace schema {
|
||||
|
||||
let _commandRegistrations: IDisposable[] = [];
|
||||
|
||||
ExtensionsRegistry.registerExtensionPoint<schema.IUserFriendlyCommand | schema.IUserFriendlyCommand[]>({
|
||||
export const commandsExtensionPoint = ExtensionsRegistry.registerExtensionPoint<schema.IUserFriendlyCommand | schema.IUserFriendlyCommand[]>({
|
||||
extensionPoint: 'commands',
|
||||
jsonSchema: schema.commandsContribution
|
||||
}).setHandler(extensions => {
|
||||
});
|
||||
|
||||
commandsExtensionPoint.setHandler(extensions => {
|
||||
|
||||
function handleCommand(userFriendlyCommand: schema.IUserFriendlyCommand, extension: IExtensionPointUser<any>, disposables: IDisposable[]) {
|
||||
|
||||
@@ -347,7 +349,7 @@ ExtensionsRegistry.registerExtensionPoint<schema.IUserFriendlyCommand | schema.I
|
||||
return;
|
||||
}
|
||||
|
||||
const { icon, category, title, command } = userFriendlyCommand;
|
||||
const { icon, enablement, category, title, command } = userFriendlyCommand;
|
||||
|
||||
let absoluteIcon: { dark: URI; light?: URI; } | undefined;
|
||||
if (icon) {
|
||||
@@ -364,7 +366,13 @@ ExtensionsRegistry.registerExtensionPoint<schema.IUserFriendlyCommand | schema.I
|
||||
if (MenuRegistry.getCommand(command)) {
|
||||
extension.collector.info(localize('dup', "Command `{0}` appears multiple times in the `commands` section.", userFriendlyCommand.command));
|
||||
}
|
||||
const registration = MenuRegistry.addCommand({ id: command, title, category, iconLocation: absoluteIcon });
|
||||
const registration = MenuRegistry.addCommand({
|
||||
id: command,
|
||||
title,
|
||||
category,
|
||||
precondition: ContextKeyExpr.deserialize(enablement),
|
||||
iconLocation: absoluteIcon
|
||||
});
|
||||
disposables.push(registration);
|
||||
}
|
||||
|
||||
@@ -439,14 +447,6 @@ ExtensionsRegistry.registerExtensionPoint<{ [loc: string]: schema.IUserFriendlyM
|
||||
}
|
||||
}
|
||||
|
||||
if (item.precondition) {
|
||||
command.precondition = ContextKeyExpr.deserialize(item.precondition);
|
||||
}
|
||||
|
||||
if (alt && item.precondition) {
|
||||
alt.precondition = command.precondition;
|
||||
}
|
||||
|
||||
const registration = MenuRegistry.appendMenuItem(menu, {
|
||||
command,
|
||||
alt,
|
||||
|
||||
@@ -70,6 +70,10 @@ export interface CustomExecutionDTO {
|
||||
customExecution: 'customExecution';
|
||||
}
|
||||
|
||||
export interface CustomExecution2DTO {
|
||||
customExecution: 'customExecution2';
|
||||
}
|
||||
|
||||
export interface TaskSourceDTO {
|
||||
label: string;
|
||||
extensionId?: string;
|
||||
@@ -84,7 +88,7 @@ export interface TaskHandleDTO {
|
||||
export interface TaskDTO {
|
||||
_id: string;
|
||||
name?: string;
|
||||
execution: ProcessExecutionDTO | ShellExecutionDTO | CustomExecutionDTO | undefined;
|
||||
execution: ProcessExecutionDTO | ShellExecutionDTO | CustomExecutionDTO | CustomExecution2DTO | undefined;
|
||||
definition: TaskDefinitionDTO;
|
||||
isBackground?: boolean;
|
||||
source: TaskSourceDTO;
|
||||
|
||||
24
src/vs/workbench/api/common/shared/webview.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import * as vscode from 'vscode';
|
||||
|
||||
export interface WebviewInitData {
|
||||
readonly webviewResourceRoot: string;
|
||||
readonly webviewCspSource: string;
|
||||
}
|
||||
|
||||
export function toWebviewResource(
|
||||
initData: WebviewInitData,
|
||||
uuid: string,
|
||||
resource: vscode.Uri
|
||||
): vscode.Uri {
|
||||
const uri = initData.webviewResourceRoot
|
||||
.replace('{{resource}}', resource.toString().replace(/^\S+?:/, ''))
|
||||
.replace('{{uuid}}', uuid);
|
||||
|
||||
return URI.parse(uri);
|
||||
}
|
||||
@@ -3,6 +3,7 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as nls from 'vs/nls';
|
||||
import { CancellationTokenSource } from 'vs/base/common/cancellation';
|
||||
import * as errors from 'vs/base/common/errors';
|
||||
import { Emitter, Event } from 'vs/base/common/event';
|
||||
@@ -35,8 +36,7 @@ import { ExtensionActivatedByAPI } from 'vs/workbench/api/common/extHostExtensio
|
||||
import { ExtHostExtensionService } from 'vs/workbench/api/node/extHostExtensionService';
|
||||
import { ExtHostFileSystem } from 'vs/workbench/api/common/extHostFileSystem';
|
||||
import { ExtHostFileSystemEventService } from 'vs/workbench/api/common/extHostFileSystemEventService';
|
||||
import { ExtHostHeapService } from 'vs/workbench/api/common/extHostHeapService';
|
||||
import { ExtHostLanguageFeatures, ISchemeTransformer } from 'vs/workbench/api/common/extHostLanguageFeatures';
|
||||
import { ExtHostLanguageFeatures } from 'vs/workbench/api/common/extHostLanguageFeatures';
|
||||
import { ExtHostLanguages } from 'vs/workbench/api/common/extHostLanguages';
|
||||
import { ExtHostLogService } from 'vs/workbench/api/common/extHostLogService';
|
||||
import { ExtHostMessageService } from 'vs/workbench/api/common/extHostMessageService';
|
||||
@@ -68,6 +68,12 @@ import { CLIServer } from 'vs/workbench/api/node/extHostCLIServer';
|
||||
import { withNullAsUndefined } from 'vs/base/common/types';
|
||||
import { values } from 'vs/base/common/collections';
|
||||
import { Schemas } from 'vs/base/common/network';
|
||||
import { IURITransformer } from 'vs/base/common/uriIpc';
|
||||
import { ExtHostEditorInsets } from 'vs/workbench/api/common/extHostCodeInsets';
|
||||
import { ExtHostLabelService } from 'vs/workbench/api/common/extHostLabelService';
|
||||
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
|
||||
import { InstantiationService } from 'vs/platform/instantiation/common/instantiationService';
|
||||
import { getSingletonServiceDescriptors } from 'vs/platform/instantiation/common/extensions';
|
||||
|
||||
export interface IExtensionApiFactory {
|
||||
(extension: IExtensionDescription, registry: ExtensionDescriptionRegistry, configProvider: ExtHostConfigProvider): typeof vscode;
|
||||
@@ -92,46 +98,50 @@ export function createApiFactory(
|
||||
extensionService: ExtHostExtensionService,
|
||||
extHostLogService: ExtHostLogService,
|
||||
extHostStorage: ExtHostStorage,
|
||||
schemeTransformer: ISchemeTransformer | null,
|
||||
outputChannelName: string
|
||||
uriTransformer: IURITransformer | null
|
||||
): IExtensionApiFactory {
|
||||
|
||||
// bootstrap services
|
||||
const services = new ServiceCollection(...getSingletonServiceDescriptors());
|
||||
const instaService = new InstantiationService(services);
|
||||
|
||||
// Addressable instances
|
||||
rpcProtocol.set(ExtHostContext.ExtHostLogService, extHostLogService);
|
||||
const extHostHeapService = rpcProtocol.set(ExtHostContext.ExtHostHeapService, new ExtHostHeapService());
|
||||
const extHostDecorations = rpcProtocol.set(ExtHostContext.ExtHostDecorations, new ExtHostDecorations(rpcProtocol));
|
||||
const extHostWebviews = rpcProtocol.set(ExtHostContext.ExtHostWebviews, new ExtHostWebviews(rpcProtocol));
|
||||
const extHostWebviews = rpcProtocol.set(ExtHostContext.ExtHostWebviews, new ExtHostWebviews(rpcProtocol, initData.environment));
|
||||
const extHostUrls = rpcProtocol.set(ExtHostContext.ExtHostUrls, new ExtHostUrls(rpcProtocol));
|
||||
const extHostDocumentsAndEditors = rpcProtocol.set(ExtHostContext.ExtHostDocumentsAndEditors, new ExtHostDocumentsAndEditors(rpcProtocol));
|
||||
const extHostDocuments = rpcProtocol.set(ExtHostContext.ExtHostDocuments, new ExtHostDocuments(rpcProtocol, extHostDocumentsAndEditors));
|
||||
const extHostDocumentContentProviders = rpcProtocol.set(ExtHostContext.ExtHostDocumentContentProviders, new ExtHostDocumentContentProvider(rpcProtocol, extHostDocumentsAndEditors, extHostLogService));
|
||||
const extHostDocumentSaveParticipant = rpcProtocol.set(ExtHostContext.ExtHostDocumentSaveParticipant, new ExtHostDocumentSaveParticipant(extHostLogService, extHostDocuments, rpcProtocol.getProxy(MainContext.MainThreadTextEditors)));
|
||||
const extHostEditors = rpcProtocol.set(ExtHostContext.ExtHostEditors, new ExtHostEditors(rpcProtocol, extHostDocumentsAndEditors));
|
||||
const extHostCommands = rpcProtocol.set(ExtHostContext.ExtHostCommands, new ExtHostCommands(rpcProtocol, extHostHeapService, extHostLogService));
|
||||
const extHostCommands = rpcProtocol.set(ExtHostContext.ExtHostCommands, new ExtHostCommands(rpcProtocol, extHostLogService));
|
||||
const extHostTreeViews = rpcProtocol.set(ExtHostContext.ExtHostTreeViews, new ExtHostTreeViews(rpcProtocol.getProxy(MainContext.MainThreadTreeViews), extHostCommands, extHostLogService));
|
||||
rpcProtocol.set(ExtHostContext.ExtHostWorkspace, extHostWorkspace);
|
||||
rpcProtocol.set(ExtHostContext.ExtHostConfiguration, extHostConfiguration);
|
||||
const extHostEditorInsets = rpcProtocol.set(ExtHostContext.ExtHostEditorInsets, new ExtHostEditorInsets(rpcProtocol.getProxy(MainContext.MainThreadEditorInsets), extHostEditors, initData.environment));
|
||||
const extHostDiagnostics = rpcProtocol.set(ExtHostContext.ExtHostDiagnostics, new ExtHostDiagnostics(rpcProtocol));
|
||||
const extHostLanguageFeatures = rpcProtocol.set(ExtHostContext.ExtHostLanguageFeatures, new ExtHostLanguageFeatures(rpcProtocol, schemeTransformer, extHostDocuments, extHostCommands, extHostHeapService, extHostDiagnostics, extHostLogService));
|
||||
const extHostLanguageFeatures = rpcProtocol.set(ExtHostContext.ExtHostLanguageFeatures, new ExtHostLanguageFeatures(rpcProtocol, uriTransformer, extHostDocuments, extHostCommands, extHostDiagnostics, extHostLogService));
|
||||
const extHostFileSystem = rpcProtocol.set(ExtHostContext.ExtHostFileSystem, new ExtHostFileSystem(rpcProtocol, extHostLanguageFeatures));
|
||||
const extHostFileSystemEvent = rpcProtocol.set(ExtHostContext.ExtHostFileSystemEventService, new ExtHostFileSystemEventService(rpcProtocol, extHostDocumentsAndEditors));
|
||||
const extHostQuickOpen = rpcProtocol.set(ExtHostContext.ExtHostQuickOpen, new ExtHostQuickOpen(rpcProtocol, extHostWorkspace, extHostCommands));
|
||||
const extHostTerminalService = rpcProtocol.set(ExtHostContext.ExtHostTerminalService, new ExtHostTerminalService(rpcProtocol, extHostConfiguration, extHostWorkspace, extHostDocumentsAndEditors, extHostLogService));
|
||||
// {{SQL CARBON EDIT}}
|
||||
// const extHostDebugService = rpcProtocol.set(ExtHostContext.ExtHostDebugService, new ExtHostDebugService(rpcProtocol, extHostWorkspace, extensionService, extHostDocumentsAndEditors, extHostConfiguration, extHostTerminalService, extHostCommands));
|
||||
// const extHostDebugService = rpcProtocol.set(ExtHostContext.ExtHostDebugService, instaService.createInstance(ExtHostDebugService, rpcProtocol, extHostWorkspace, extensionService, extHostDocumentsAndEditors, extHostConfiguration, extHostTerminalService, extHostCommands)); {{SQL CARBON EDIT}} remove debug service
|
||||
const extHostSCM = rpcProtocol.set(ExtHostContext.ExtHostSCM, new ExtHostSCM(rpcProtocol, extHostCommands, extHostLogService));
|
||||
const extHostComment = rpcProtocol.set(ExtHostContext.ExtHostComments, new ExtHostComments(rpcProtocol, extHostCommands, extHostDocuments));
|
||||
const extHostSearch = rpcProtocol.set(ExtHostContext.ExtHostSearch, new ExtHostSearch(rpcProtocol, schemeTransformer, extHostLogService));
|
||||
const extHostSearch = rpcProtocol.set(ExtHostContext.ExtHostSearch, new ExtHostSearch(rpcProtocol, uriTransformer, extHostLogService));
|
||||
const extHostTask = rpcProtocol.set(ExtHostContext.ExtHostTask, new ExtHostTask(rpcProtocol, extHostWorkspace, extHostDocumentsAndEditors, extHostConfiguration, extHostTerminalService));
|
||||
const extHostWindow = rpcProtocol.set(ExtHostContext.ExtHostWindow, new ExtHostWindow(rpcProtocol));
|
||||
rpcProtocol.set(ExtHostContext.ExtHostExtensionService, extensionService);
|
||||
const extHostProgress = rpcProtocol.set(ExtHostContext.ExtHostProgress, new ExtHostProgress(rpcProtocol.getProxy(MainContext.MainThreadProgress)));
|
||||
const extHostOutputService = rpcProtocol.set(ExtHostContext.ExtHostOutputService, new ExtHostOutputService(LogOutputChannelFactory, initData.logsLocation, rpcProtocol));
|
||||
rpcProtocol.set(ExtHostContext.ExtHostStorage, extHostStorage);
|
||||
if (initData.remoteAuthority) {
|
||||
const extHostLabelService = rpcProtocol.set(ExtHostContext.ExtHosLabelService, new ExtHostLabelService(rpcProtocol));
|
||||
|
||||
if (initData.remote.isRemote && initData.remote.authority) {
|
||||
extHostTask.registerTaskSystem(Schemas.vscodeRemote, {
|
||||
scheme: Schemas.vscodeRemote,
|
||||
authority: initData.remoteAuthority,
|
||||
authority: initData.remote.authority,
|
||||
platform: process.platform
|
||||
});
|
||||
|
||||
@@ -143,7 +153,8 @@ export function createApiFactory(
|
||||
|
||||
// Check that no named customers are missing
|
||||
// {{SQL CARBON EDIT}} filter out the services we don't expose
|
||||
const expected: ProxyIdentifier<any>[] = values(ExtHostContext).filter(v => v !== ExtHostContext.ExtHostDebugService);
|
||||
const filtered: ProxyIdentifier<any>[] = [ExtHostContext.ExtHostDebugService, ExtHostContext.ExtHostTask];
|
||||
const expected: ProxyIdentifier<any>[] = values(ExtHostContext).filter(v => !filtered.includes(v));
|
||||
rpcProtocol.assertRegistered(expected);
|
||||
|
||||
// Other instances
|
||||
@@ -154,6 +165,7 @@ export function createApiFactory(
|
||||
const extHostLanguages = new ExtHostLanguages(rpcProtocol, extHostDocuments);
|
||||
|
||||
// Register an output channel for exthost log
|
||||
const outputChannelName = initData.remote.isRemote ? nls.localize('remote extension host Log', "Remote Extension Host") : nls.localize('extension host Log', "Extension Host");
|
||||
extHostOutputService.createOutputChannelFromLogFile(outputChannelName, extHostLogService.logFile);
|
||||
|
||||
// Register API-ish commands
|
||||
@@ -163,7 +175,7 @@ export function createApiFactory(
|
||||
|
||||
// Check document selectors for being overly generic. Technically this isn't a problem but
|
||||
// in practice many extensions say they support `fooLang` but need fs-access to do so. Those
|
||||
// extension should specify then the `file`-scheme, e.g `{ scheme: 'fooLang', language: 'fooLang' }`
|
||||
// extension should specify then the `file`-scheme, e.g. `{ scheme: 'fooLang', language: 'fooLang' }`
|
||||
// We only inform once, it is not a warning because we just want to raise awareness and because
|
||||
// we cannot say if the extension is doing it right or wrong...
|
||||
const checkSelector = (function () {
|
||||
@@ -239,7 +251,7 @@ export function createApiFactory(
|
||||
};
|
||||
|
||||
// namespace: env
|
||||
const env: typeof vscode.env = Object.freeze({
|
||||
const env: typeof vscode.env = {
|
||||
get machineId() { return initData.telemetryInfo.machineId; },
|
||||
get sessionId() { return initData.telemetryInfo.sessionId; },
|
||||
get language() { return initData.environment.appLanguage; },
|
||||
@@ -257,22 +269,44 @@ export function createApiFactory(
|
||||
get clipboard(): vscode.Clipboard {
|
||||
return extHostClipboard;
|
||||
},
|
||||
get shell() {
|
||||
return extHostTerminalService.getDefaultShell(configProvider);
|
||||
},
|
||||
openExternal(uri: URI) {
|
||||
return extHostWindow.openUri(uri, { allowTunneling: !!initData.remoteAuthority });
|
||||
return extHostWindow.openUri(uri, { allowTunneling: !!initData.remote.isRemote });
|
||||
},
|
||||
get remoteName() {
|
||||
if (!initData.remote.authority) {
|
||||
return undefined;
|
||||
}
|
||||
const pos = initData.remote.authority.indexOf('+');
|
||||
if (pos < 0) {
|
||||
// funky? bad authority?
|
||||
return initData.remote.authority;
|
||||
}
|
||||
return initData.remote.authority.substr(0, pos);
|
||||
}
|
||||
});
|
||||
};
|
||||
if (!initData.environment.extensionTestsLocationURI) {
|
||||
// allow to patch env-function when running tests
|
||||
Object.freeze(env);
|
||||
}
|
||||
|
||||
const extensionKind = initData.remote.isRemote
|
||||
? extHostTypes.ExtensionKind.Workspace
|
||||
: extHostTypes.ExtensionKind.UI;
|
||||
|
||||
// namespace: extensions
|
||||
const extensions: typeof vscode.extensions = {
|
||||
getExtension(extensionId: string): Extension<any> | undefined {
|
||||
const desc = extensionRegistry.getExtensionDescription(extensionId);
|
||||
if (desc) {
|
||||
return new Extension(extensionService, desc);
|
||||
return new Extension(extensionService, desc, extensionKind);
|
||||
}
|
||||
return undefined;
|
||||
},
|
||||
get all(): Extension<any>[] {
|
||||
return extensionRegistry.getAllExtensionDescriptions().map((desc) => new Extension(extensionService, desc));
|
||||
return extensionRegistry.getAllExtensionDescriptions().map((desc) => new Extension(extensionService, desc, extensionKind));
|
||||
},
|
||||
get onDidChange() {
|
||||
return extensionRegistry.onDidChange;
|
||||
@@ -305,10 +339,6 @@ export function createApiFactory(
|
||||
registerCodeLensProvider(selector: vscode.DocumentSelector, provider: vscode.CodeLensProvider): vscode.Disposable {
|
||||
return extHostLanguageFeatures.registerCodeLensProvider(extension, checkSelector(selector), provider);
|
||||
},
|
||||
registerCodeInsetProvider(selector: vscode.DocumentSelector, provider: vscode.CodeInsetProvider): vscode.Disposable {
|
||||
checkProposedApiEnabled(extension);
|
||||
return extHostLanguageFeatures.registerCodeInsetProvider(extension, checkSelector(selector), provider);
|
||||
},
|
||||
registerDefinitionProvider(selector: vscode.DocumentSelector, provider: vscode.DefinitionProvider): vscode.Disposable {
|
||||
return extHostLanguageFeatures.registerDefinitionProvider(extension, checkSelector(selector), provider);
|
||||
},
|
||||
@@ -469,8 +499,24 @@ export function createApiFactory(
|
||||
showSaveDialog(options) {
|
||||
return extHostDialogs.showSaveDialog(options);
|
||||
},
|
||||
createStatusBarItem(position?: vscode.StatusBarAlignment, priority?: number): vscode.StatusBarItem {
|
||||
return extHostStatusBar.createStatusBarEntry(extension.identifier, <number>position, priority);
|
||||
createStatusBarItem(alignmentOrOptions?: vscode.StatusBarAlignment | vscode.window.StatusBarItemOptions, priority?: number): vscode.StatusBarItem {
|
||||
let id: string;
|
||||
let name: string;
|
||||
let alignment: number | undefined;
|
||||
|
||||
if (alignmentOrOptions && typeof alignmentOrOptions !== 'number') {
|
||||
id = alignmentOrOptions.id;
|
||||
name = alignmentOrOptions.name;
|
||||
alignment = alignmentOrOptions.alignment;
|
||||
priority = alignmentOrOptions.priority;
|
||||
} else {
|
||||
id = extension.identifier.value;
|
||||
name = nls.localize('extensionLabel', "{0} (Extension)", extension.displayName || extension.name);
|
||||
alignment = alignmentOrOptions as number; // {{SQL CARBON EDIT}} strict-null-check
|
||||
priority = priority;
|
||||
}
|
||||
|
||||
return extHostStatusBar.createStatusBarEntry(id, name, alignment, priority);
|
||||
},
|
||||
setStatusBarMessage(text: string, timeoutOrThenable?: number | Thenable<any>): vscode.Disposable {
|
||||
return extHostStatusBar.setStatusBarMessage(text, timeoutOrThenable);
|
||||
@@ -488,9 +534,18 @@ export function createApiFactory(
|
||||
createWebviewPanel(viewType: string, title: string, showOptions: vscode.ViewColumn | { viewColumn: vscode.ViewColumn, preserveFocus?: boolean }, options: vscode.WebviewPanelOptions & vscode.WebviewOptions): vscode.WebviewPanel {
|
||||
return extHostWebviews.createWebviewPanel(extension, viewType, title, showOptions, options);
|
||||
},
|
||||
createTerminal(nameOrOptions?: vscode.TerminalOptions | string, shellPath?: string, shellArgs?: string[] | string): vscode.Terminal {
|
||||
createWebviewTextEditorInset(editor: vscode.TextEditor, line: number, height: number, options: vscode.WebviewOptions): vscode.WebviewEditorInset {
|
||||
checkProposedApiEnabled(extension);
|
||||
return extHostEditorInsets.createWebviewEditorInset(editor, line, height, options, extension);
|
||||
},
|
||||
createTerminal(nameOrOptions?: vscode.TerminalOptions | vscode.TerminalVirtualProcessOptions | string, shellPath?: string, shellArgs?: string[] | string): vscode.Terminal {
|
||||
if (typeof nameOrOptions === 'object') {
|
||||
return extHostTerminalService.createTerminalFromOptions(<vscode.TerminalOptions>nameOrOptions);
|
||||
if ('virtualProcess' in nameOrOptions) {
|
||||
return extHostTerminalService.createVirtualProcessTerminal(nameOrOptions);
|
||||
} else {
|
||||
nameOrOptions.hideFromUser = nameOrOptions.hideFromUser || (nameOrOptions.runInBackground && extension.enableProposedApi);
|
||||
return extHostTerminalService.createTerminalFromOptions(nameOrOptions);
|
||||
}
|
||||
}
|
||||
return extHostTerminalService.createTerminal(<string>nameOrOptions, shellPath, shellArgs);
|
||||
},
|
||||
@@ -634,28 +689,25 @@ export function createApiFactory(
|
||||
return extHostDocumentContentProviders.registerTextDocumentContentProvider(scheme, provider);
|
||||
},
|
||||
registerTaskProvider: (type: string, provider: vscode.TaskProvider) => {
|
||||
return extHostTask.registerTaskProvider(extension, provider);
|
||||
return extHostTask.registerTaskProvider(extension, type, provider);
|
||||
},
|
||||
registerFileSystemProvider(scheme, provider, options) {
|
||||
return extHostFileSystem.registerFileSystemProvider(scheme, provider, options);
|
||||
},
|
||||
get fs() {
|
||||
return extHostFileSystem.fileSystem;
|
||||
},
|
||||
registerFileSearchProvider: proposedApiFunction(extension, (scheme: string, provider: vscode.FileSearchProvider) => {
|
||||
return extHostSearch.registerFileSearchProvider(scheme, provider);
|
||||
}),
|
||||
registerTextSearchProvider: proposedApiFunction(extension, (scheme: string, provider: vscode.TextSearchProvider) => {
|
||||
return extHostSearch.registerTextSearchProvider(scheme, provider);
|
||||
}),
|
||||
registerDocumentCommentProvider: proposedApiFunction(extension, (provider: vscode.DocumentCommentProvider) => {
|
||||
return extHostComment.registerDocumentCommentProvider(extension.identifier, provider);
|
||||
}),
|
||||
registerWorkspaceCommentProvider: proposedApiFunction(extension, (provider: vscode.WorkspaceCommentProvider) => {
|
||||
return extHostComment.registerWorkspaceCommentProvider(extension.identifier, provider);
|
||||
}),
|
||||
registerRemoteAuthorityResolver: proposedApiFunction(extension, (authorityPrefix: string, resolver: vscode.RemoteAuthorityResolver) => {
|
||||
return extensionService.registerRemoteAuthorityResolver(authorityPrefix, resolver);
|
||||
}),
|
||||
registerResourceLabelFormatter: proposedApiFunction(extension, (formatter: vscode.ResourceLabelFormatter) => {
|
||||
return extHostFileSystem.registerResourceLabelFormatter(formatter);
|
||||
return extHostLabelService.$registerResourceLabelFormatter(formatter);
|
||||
}),
|
||||
onDidRenameFile: proposedApiFunction(extension, (listener: (e: vscode.FileRenameEvent) => any, thisArg?: any, disposables?: vscode.Disposable[]) => {
|
||||
return extHostFileSystemEvent.onDidRenameFile(listener, thisArg, disposables);
|
||||
@@ -675,7 +727,7 @@ export function createApiFactory(
|
||||
}
|
||||
};
|
||||
|
||||
const comment: typeof vscode.comment = {
|
||||
const comment: typeof vscode.comments = {
|
||||
createCommentController(id: string, label: string) {
|
||||
return extHostComment.createCommentController(extension, id, label);
|
||||
}
|
||||
@@ -732,7 +784,7 @@ export function createApiFactory(
|
||||
|
||||
const tasks: typeof vscode.tasks = {
|
||||
registerTaskProvider: (type: string, provider: vscode.TaskProvider) => {
|
||||
return extHostTask.registerTaskProvider(extension, provider);
|
||||
return extHostTask.registerTaskProvider(extension, type, provider);
|
||||
},
|
||||
fetchTasks: (filter?: vscode.TaskFilter): Thenable<vscode.Task[]> => {
|
||||
return extHostTask.fetchTasks(filter);
|
||||
@@ -805,7 +857,9 @@ export function createApiFactory(
|
||||
EndOfLine: extHostTypes.EndOfLine,
|
||||
EventEmitter: Emitter,
|
||||
ExtensionExecutionContext: extHostTypes.ExtensionExecutionContext,
|
||||
ExtensionKind: extHostTypes.ExtensionKind,
|
||||
CustomExecution: extHostTypes.CustomExecution,
|
||||
CustomExecution2: extHostTypes.CustomExecution2,
|
||||
FileChangeType: extHostTypes.FileChangeType,
|
||||
FileSystemError: extHostTypes.FileSystemError,
|
||||
FileType: files.FileType,
|
||||
@@ -872,16 +926,18 @@ class Extension<T> implements vscode.Extension<T> {
|
||||
private _extensionService: ExtHostExtensionService;
|
||||
private _identifier: ExtensionIdentifier;
|
||||
|
||||
public id: string;
|
||||
public extensionPath: string;
|
||||
public packageJSON: IExtensionDescription;
|
||||
readonly id: string;
|
||||
readonly extensionPath: string;
|
||||
readonly packageJSON: IExtensionDescription;
|
||||
readonly extensionKind: vscode.ExtensionKind;
|
||||
|
||||
constructor(extensionService: ExtHostExtensionService, description: IExtensionDescription) {
|
||||
constructor(extensionService: ExtHostExtensionService, description: IExtensionDescription, kind: extHostTypes.ExtensionKind) {
|
||||
this._extensionService = extensionService;
|
||||
this._identifier = description.identifier;
|
||||
this.id = description.identifier.value;
|
||||
this.extensionPath = path.normalize(originalFSPath(description.extensionLocation));
|
||||
this.packageJSON = description;
|
||||
this.extensionKind = kind;
|
||||
}
|
||||
|
||||
get isActive(): boolean {
|
||||
|
||||
@@ -81,7 +81,7 @@ export class CLIServer {
|
||||
break;
|
||||
default:
|
||||
res.writeHead(404);
|
||||
res.write(`Unkown message type: ${data.type}`, err => {
|
||||
res.write(`Unknown message type: ${data.type}`, err => {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ import { IExtHostWorkspaceProvider } from 'vs/workbench/api/common/extHostWorksp
|
||||
import { ExtHostExtensionService } from 'vs/workbench/api/node/extHostExtensionService';
|
||||
import { ExtHostDocumentsAndEditors } from 'vs/workbench/api/common/extHostDocumentsAndEditors';
|
||||
import { ITerminalSettings, IDebuggerContribution, IConfig, IDebugAdapter, IDebugAdapterServer, IDebugAdapterExecutable, IAdapterDescriptor } from 'vs/workbench/contrib/debug/common/debug';
|
||||
import { getTerminalLauncher, hasChildProcesses, prepareCommand } from 'vs/workbench/contrib/debug/node/terminals';
|
||||
import { hasChildProcesses, prepareCommand, runInExternalTerminal } from 'vs/workbench/contrib/debug/node/terminals';
|
||||
import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace';
|
||||
import { AbstractVariableResolverService } from 'vs/workbench/services/configurationResolver/common/variableResolver';
|
||||
import { ExtHostConfiguration, ExtHostConfigProvider } from '../common/extHostConfiguration';
|
||||
@@ -357,10 +357,7 @@ export class ExtHostDebugService implements ExtHostDebugServiceShape {
|
||||
|
||||
} else if (args.kind === 'external') {
|
||||
|
||||
const terminalLauncher = getTerminalLauncher();
|
||||
if (terminalLauncher) {
|
||||
return terminalLauncher.runInTerminal(args, config);
|
||||
}
|
||||
runInExternalTerminal(args, config);
|
||||
}
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ import * as path from 'vs/base/common/path';
|
||||
import { createApiFactory, initializeExtensionApi, ISqlExtensionApiFactory } from 'sql/workbench/api/node/sqlExtHost.api.impl';
|
||||
import { originalFSPath } from 'vs/base/common/resources';
|
||||
import { Barrier } from 'vs/base/common/async';
|
||||
import { dispose, toDisposable } from 'vs/base/common/lifecycle';
|
||||
import { dispose, toDisposable, DisposableStore } from 'vs/base/common/lifecycle';
|
||||
import { TernarySearchTree } from 'vs/base/common/map';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
@@ -18,7 +18,7 @@ import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { NodeModuleRequireInterceptor, VSCodeNodeModuleFactory, KeytarNodeModuleFactory, OpenNodeModuleFactory } from 'vs/workbench/api/node/extHostRequireInterceptor';
|
||||
import { ExtHostExtensionServiceShape, IEnvironment, IInitData, IMainContext, MainContext, MainThreadExtensionServiceShape, MainThreadTelemetryShape, MainThreadWorkspaceShape, IResolveAuthorityResult } from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { ExtHostConfiguration } from 'vs/workbench/api/common/extHostConfiguration';
|
||||
import { ActivatedExtension, EmptyExtension, ExtensionActivatedByAPI, ExtensionActivatedByEvent, ExtensionActivationReason, ExtensionActivationTimes, ExtensionActivationTimesBuilder, ExtensionsActivator, IExtensionAPI, IExtensionContext, IExtensionModule, HostExtension } from 'vs/workbench/api/common/extHostExtensionActivator';
|
||||
import { ActivatedExtension, EmptyExtension, ExtensionActivatedByAPI, ExtensionActivatedByEvent, ExtensionActivationReason, ExtensionActivationTimes, ExtensionActivationTimesBuilder, ExtensionsActivator, IExtensionAPI, IExtensionContext, IExtensionModule, HostExtension, ExtensionActivationTimesFragment } from 'vs/workbench/api/common/extHostExtensionActivator';
|
||||
import { ExtHostLogService } from 'vs/workbench/api/common/extHostLogService';
|
||||
import { ExtHostStorage } from 'vs/workbench/api/common/extHostStorage';
|
||||
import { ExtHostWorkspace } from 'vs/workbench/api/common/extHostWorkspace';
|
||||
@@ -29,25 +29,40 @@ import { CancellationTokenSource } from 'vs/base/common/cancellation';
|
||||
import * as errors from 'vs/base/common/errors';
|
||||
import * as vscode from 'vscode';
|
||||
import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
||||
import { IWorkspace } from 'vs/platform/workspace/common/workspace';
|
||||
import { Schemas } from 'vs/base/common/network';
|
||||
import { withNullAsUndefined } from 'vs/base/common/types';
|
||||
import { VSBuffer } from 'vs/base/common/buffer';
|
||||
import { ISchemeTransformer } from 'vs/workbench/api/common/extHostLanguageFeatures';
|
||||
import { ExtensionMemento } from 'vs/workbench/api/common/extHostMemento';
|
||||
import { ExtensionStoragePaths } from 'vs/workbench/api/node/extHostStoragePaths';
|
||||
import { RemoteAuthorityResolverError, ExtensionExecutionContext } from 'vs/workbench/api/common/extHostTypes';
|
||||
import { IURITransformer } from 'vs/base/common/uriIpc';
|
||||
|
||||
interface ITestRunner {
|
||||
/** Old test runner API, as exported from `vscode/lib/testrunner` */
|
||||
run(testsRoot: string, clb: (error: Error, failures?: number) => void): void;
|
||||
}
|
||||
|
||||
interface INewTestRunner {
|
||||
/** New test runner API, as explained in the extension test doc */
|
||||
run(): Promise<void>;
|
||||
}
|
||||
|
||||
export interface IHostUtils {
|
||||
exit(code?: number): void;
|
||||
exists(path: string): Promise<boolean>;
|
||||
realpath(path: string): Promise<string>;
|
||||
}
|
||||
|
||||
type TelemetryActivationEventFragment = {
|
||||
id: { classification: 'PublicNonPersonalData', purpose: 'FeatureInsight' };
|
||||
name: { classification: 'PublicNonPersonalData', purpose: 'FeatureInsight' };
|
||||
extensionVersion: { classification: 'PublicNonPersonalData', purpose: 'FeatureInsight' };
|
||||
publisherDisplayName: { classification: 'SystemMetaData', purpose: 'FeatureInsight' };
|
||||
activationEvents: { classification: 'SystemMetaData', purpose: 'FeatureInsight' };
|
||||
isBuiltin: { classification: 'SystemMetaData', purpose: 'FeatureInsight', isMeasurement: true };
|
||||
reason: { classification: 'SystemMetaData', purpose: 'FeatureInsight' };
|
||||
};
|
||||
|
||||
export class ExtHostExtensionService implements ExtHostExtensionServiceShape {
|
||||
|
||||
private static readonly WORKSPACE_CONTAINS_TIMEOUT = 7000;
|
||||
@@ -78,6 +93,8 @@ export class ExtHostExtensionService implements ExtHostExtensionServiceShape {
|
||||
|
||||
private _started: boolean;
|
||||
|
||||
private readonly _disposables: DisposableStore;
|
||||
|
||||
constructor(
|
||||
hostUtils: IHostUtils,
|
||||
initData: IInitData,
|
||||
@@ -86,8 +103,7 @@ export class ExtHostExtensionService implements ExtHostExtensionServiceShape {
|
||||
extHostConfiguration: ExtHostConfiguration,
|
||||
environment: IEnvironment,
|
||||
extHostLogService: ExtHostLogService,
|
||||
schemeTransformer: ISchemeTransformer | null,
|
||||
outputChannelName: string
|
||||
uriTransformer: IURITransformer | null
|
||||
) {
|
||||
this._hostUtils = hostUtils;
|
||||
this._initData = initData;
|
||||
@@ -96,6 +112,7 @@ export class ExtHostExtensionService implements ExtHostExtensionServiceShape {
|
||||
this._extHostConfiguration = extHostConfiguration;
|
||||
this._environment = environment;
|
||||
this._extHostLogService = extHostLogService;
|
||||
this._disposables = new DisposableStore();
|
||||
|
||||
this._mainThreadWorkspaceProxy = this._extHostContext.getProxy(MainContext.MainThreadWorkspace);
|
||||
this._mainThreadTelemetryProxy = this._extHostContext.getProxy(MainContext.MainThreadTelemetry);
|
||||
@@ -137,8 +154,7 @@ export class ExtHostExtensionService implements ExtHostExtensionServiceShape {
|
||||
this,
|
||||
this._extHostLogService,
|
||||
this._storage,
|
||||
schemeTransformer,
|
||||
outputChannelName
|
||||
uriTransformer
|
||||
);
|
||||
|
||||
this._resolvers = Object.create(null);
|
||||
@@ -160,7 +176,7 @@ export class ExtHostExtensionService implements ExtHostExtensionServiceShape {
|
||||
// NodeModuleRequireInterceptor.INSTANCE.register(new VSCodeNodeModuleFactory(this._extensionApiFactory, extensionPaths, this._registry, configProvider));
|
||||
await initializeExtensionApi(this, this._extensionApiFactory, this._registry, configProvider);
|
||||
NodeModuleRequireInterceptor.INSTANCE.register(new KeytarNodeModuleFactory(this._extHostContext.getProxy(MainContext.MainThreadKeytar), this._environment));
|
||||
if (this._initData.remoteAuthority) {
|
||||
if (this._initData.remote.isRemote) {
|
||||
NodeModuleRequireInterceptor.INSTANCE.register(new OpenNodeModuleFactory(
|
||||
this._extHostContext.getProxy(MainContext.MainThreadWindow),
|
||||
this._extHostContext.getProxy(MainContext.MainThreadTelemetry),
|
||||
@@ -314,23 +330,32 @@ export class ExtHostExtensionService implements ExtHostExtensionServiceShape {
|
||||
"outcome" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
|
||||
}
|
||||
*/
|
||||
this._mainThreadTelemetryProxy.$publicLog('extensionActivationTimes', {
|
||||
type ExtensionActivationTimesClassification = {
|
||||
outcome: { classification: 'SystemMetaData', purpose: 'FeatureInsight' };
|
||||
} & TelemetryActivationEventFragment & ExtensionActivationTimesFragment;
|
||||
|
||||
type ExtensionActivationTimesEvent = {
|
||||
outcome: string
|
||||
} & ActivationTimesEvent & TelemetryActivationEvent;
|
||||
|
||||
type ActivationTimesEvent = {
|
||||
startup?: boolean;
|
||||
codeLoadingTime?: number;
|
||||
activateCallTime?: number;
|
||||
activateResolvedTime?: number;
|
||||
};
|
||||
|
||||
this._mainThreadTelemetryProxy.$publicLog2<ExtensionActivationTimesEvent, ExtensionActivationTimesClassification>('extensionActivationTimes', {
|
||||
...event,
|
||||
...(activationTimes || {}),
|
||||
outcome,
|
||||
outcome
|
||||
});
|
||||
}
|
||||
|
||||
private _doActivateExtension(extensionDescription: IExtensionDescription, reason: ExtensionActivationReason): Promise<ActivatedExtension> {
|
||||
const event = getTelemetryActivationEvent(extensionDescription, reason);
|
||||
/* __GDPR__
|
||||
"activatePlugin" : {
|
||||
"${include}": [
|
||||
"${TelemetryActivationEvent}"
|
||||
]
|
||||
}
|
||||
*/
|
||||
this._mainThreadTelemetryProxy.$publicLog('activatePlugin', event);
|
||||
type ActivatePluginClassification = {} & TelemetryActivationEventFragment;
|
||||
this._mainThreadTelemetryProxy.$publicLog2<TelemetryActivationEvent, ActivatePluginClassification>('activatePlugin', event);
|
||||
if (!extensionDescription.main) {
|
||||
// Treat the extension as being empty => NOT AN ERROR CASE
|
||||
return Promise.resolve(new EmptyExtension(ExtensionActivationTimes.NONE));
|
||||
@@ -347,7 +372,7 @@ export class ExtHostExtensionService implements ExtHostExtensionServiceShape {
|
||||
});
|
||||
}
|
||||
|
||||
private _loadExtensionContext(extensionDescription: IExtensionDescription): Promise<IExtensionContext> {
|
||||
private _loadExtensionContext(extensionDescription: IExtensionDescription): Promise<vscode.ExtensionContext> {
|
||||
|
||||
const globalState = new ExtensionMemento(extensionDescription.identifier.value, true, this._storage);
|
||||
const workspaceState = new ExtensionMemento(extensionDescription.identifier.value, false, this._storage);
|
||||
@@ -368,7 +393,7 @@ export class ExtHostExtensionService implements ExtHostExtensionServiceShape {
|
||||
globalStoragePath: this._storagePath.globalValue(extensionDescription),
|
||||
asAbsolutePath: (relativePath: string) => { return path.join(extensionDescription.extensionLocation.fsPath, relativePath); },
|
||||
logPath: that._extHostLogService.getLogDirectory(extensionDescription.identifier),
|
||||
executionContext: this._initData.remoteAuthority ? ExtensionExecutionContext.Remote : ExtensionExecutionContext.Local
|
||||
executionContext: this._initData.remote.isRemote ? ExtensionExecutionContext.Remote : ExtensionExecutionContext.Local,
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -428,27 +453,33 @@ export class ExtHostExtensionService implements ExtHostExtensionServiceShape {
|
||||
console.error(err);
|
||||
});
|
||||
|
||||
return this._handleWorkspaceContainsEagerExtensions(this._extHostWorkspace.workspace);
|
||||
this._disposables.add(this._extHostWorkspace.onDidChangeWorkspace((e) => this._handleWorkspaceContainsEagerExtensions(e.added)));
|
||||
const folders = this._extHostWorkspace.workspace ? this._extHostWorkspace.workspace.folders : [];
|
||||
return this._handleWorkspaceContainsEagerExtensions(folders);
|
||||
}
|
||||
|
||||
private _handleWorkspaceContainsEagerExtensions(workspace: IWorkspace | undefined): Promise<void> {
|
||||
if (!workspace || workspace.folders.length === 0) {
|
||||
private _handleWorkspaceContainsEagerExtensions(folders: ReadonlyArray<vscode.WorkspaceFolder>): Promise<void> {
|
||||
if (folders.length === 0) {
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
|
||||
return Promise.all(
|
||||
this._registry.getAllExtensionDescriptions().map((desc) => {
|
||||
return this._handleWorkspaceContainsEagerExtension(workspace, desc);
|
||||
return this._handleWorkspaceContainsEagerExtension(folders, desc);
|
||||
})
|
||||
).then(() => { });
|
||||
}
|
||||
|
||||
private _handleWorkspaceContainsEagerExtension(workspace: IWorkspace, desc: IExtensionDescription): Promise<void> {
|
||||
private _handleWorkspaceContainsEagerExtension(folders: ReadonlyArray<vscode.WorkspaceFolder>, desc: IExtensionDescription): Promise<void> {
|
||||
const activationEvents = desc.activationEvents;
|
||||
if (!activationEvents) {
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
|
||||
if (this.isActivated(desc.identifier)) {
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
|
||||
const fileNames: string[] = [];
|
||||
const globPatterns: string[] = [];
|
||||
|
||||
@@ -467,16 +498,16 @@ export class ExtHostExtensionService implements ExtHostExtensionServiceShape {
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
|
||||
const fileNamePromise = Promise.all(fileNames.map((fileName) => this._activateIfFileName(workspace, desc.identifier, fileName))).then(() => { });
|
||||
const globPatternPromise = this._activateIfGlobPatterns(desc.identifier, globPatterns);
|
||||
const fileNamePromise = Promise.all(fileNames.map((fileName) => this._activateIfFileName(folders, desc.identifier, fileName))).then(() => { });
|
||||
const globPatternPromise = this._activateIfGlobPatterns(folders, desc.identifier, globPatterns);
|
||||
|
||||
return Promise.all([fileNamePromise, globPatternPromise]).then(() => { });
|
||||
}
|
||||
|
||||
private async _activateIfFileName(workspace: IWorkspace, extensionId: ExtensionIdentifier, fileName: string): Promise<void> {
|
||||
private async _activateIfFileName(folders: ReadonlyArray<vscode.WorkspaceFolder>, extensionId: ExtensionIdentifier, fileName: string): Promise<void> {
|
||||
|
||||
// find exact path
|
||||
for (const { uri } of workspace.folders) {
|
||||
for (const { uri } of folders) {
|
||||
if (await this._hostUtils.exists(path.join(URI.revive(uri).fsPath, fileName))) {
|
||||
// the file was found
|
||||
return (
|
||||
@@ -489,7 +520,7 @@ export class ExtHostExtensionService implements ExtHostExtensionServiceShape {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
private async _activateIfGlobPatterns(extensionId: ExtensionIdentifier, globPatterns: string[]): Promise<void> {
|
||||
private async _activateIfGlobPatterns(folders: ReadonlyArray<vscode.WorkspaceFolder>, extensionId: ExtensionIdentifier, globPatterns: string[]): Promise<void> {
|
||||
this._extHostLogService.trace(`extensionHostMain#activateIfGlobPatterns: fileSearch, extension: ${extensionId.value}, entryPoint: workspaceContains`);
|
||||
|
||||
if (globPatterns.length === 0) {
|
||||
@@ -497,7 +528,7 @@ export class ExtHostExtensionService implements ExtHostExtensionServiceShape {
|
||||
}
|
||||
|
||||
const tokenSource = new CancellationTokenSource();
|
||||
const searchP = this._mainThreadWorkspaceProxy.$checkExists(globPatterns, tokenSource.token);
|
||||
const searchP = this._mainThreadWorkspaceProxy.$checkExists(folders.map(folder => folder.uri), globPatterns, tokenSource.token);
|
||||
|
||||
const timer = setTimeout(async () => {
|
||||
tokenSource.cancel();
|
||||
@@ -545,7 +576,7 @@ export class ExtHostExtensionService implements ExtHostExtensionServiceShape {
|
||||
const extensionTestsPath = originalFSPath(extensionTestsLocationURI);
|
||||
|
||||
// Require the test runner via node require from the provided path
|
||||
let testRunner: ITestRunner | undefined;
|
||||
let testRunner: ITestRunner | INewTestRunner | undefined;
|
||||
let requireError: Error | undefined;
|
||||
try {
|
||||
testRunner = <any>require.__$__nodeRequire(extensionTestsPath);
|
||||
@@ -553,10 +584,10 @@ export class ExtHostExtensionService implements ExtHostExtensionServiceShape {
|
||||
requireError = error;
|
||||
}
|
||||
|
||||
// Execute the runner if it follows our spec
|
||||
// Execute the runner if it follows the old `run` spec
|
||||
if (testRunner && typeof testRunner.run === 'function') {
|
||||
return new Promise<void>((c, e) => {
|
||||
testRunner!.run(extensionTestsPath, (error, failures) => {
|
||||
const oldTestRunnerCallback = (error: Error, failures: number | undefined) => {
|
||||
if (error) {
|
||||
e(error.toString());
|
||||
} else {
|
||||
@@ -565,7 +596,22 @@ export class ExtHostExtensionService implements ExtHostExtensionServiceShape {
|
||||
|
||||
// after tests have run, we shutdown the host
|
||||
this._gracefulExit(error || (typeof failures === 'number' && failures > 0) ? 1 /* ERROR */ : 0 /* OK */);
|
||||
});
|
||||
};
|
||||
|
||||
const runResult = testRunner!.run(extensionTestsPath, oldTestRunnerCallback);
|
||||
|
||||
// Using the new API `run(): Promise<void>`
|
||||
if (runResult && runResult.then) {
|
||||
runResult
|
||||
.then(() => {
|
||||
c();
|
||||
this._gracefulExit(0);
|
||||
})
|
||||
.catch((err: Error) => {
|
||||
e(err.toString());
|
||||
this._gracefulExit(1);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -582,7 +628,7 @@ export class ExtHostExtensionService implements ExtHostExtensionServiceShape {
|
||||
// messages to the main process, we delay the exit() by some time
|
||||
setTimeout(() => {
|
||||
// If extension tests are running, give the exit code to the renderer
|
||||
if (this._initData.remoteAuthority && !!this._initData.environment.extensionTestsLocationURI) {
|
||||
if (this._initData.remote.isRemote && !!this._initData.environment.extensionTestsLocationURI) {
|
||||
this._mainThreadExtensionsProxy.$onExtensionHostExit(code);
|
||||
return;
|
||||
}
|
||||
@@ -735,22 +781,20 @@ function loadCommonJSModule<T>(logService: ILogService, modulePath: string, acti
|
||||
return Promise.resolve(r);
|
||||
}
|
||||
|
||||
function getTelemetryActivationEvent(extensionDescription: IExtensionDescription, reason: ExtensionActivationReason): any {
|
||||
type TelemetryActivationEvent = {
|
||||
id: string;
|
||||
name: string;
|
||||
extensionVersion: string;
|
||||
publisherDisplayName: string;
|
||||
activationEvents: string | null;
|
||||
isBuiltin: boolean;
|
||||
reason: string;
|
||||
};
|
||||
|
||||
function getTelemetryActivationEvent(extensionDescription: IExtensionDescription, reason: ExtensionActivationReason): TelemetryActivationEvent {
|
||||
const reasonStr = reason instanceof ExtensionActivatedByEvent ? reason.activationEvent :
|
||||
reason instanceof ExtensionActivatedByAPI ? 'api' :
|
||||
'';
|
||||
|
||||
/* __GDPR__FRAGMENT__
|
||||
"TelemetryActivationEvent" : {
|
||||
"id": { "classification": "PublicNonPersonalData", "purpose": "FeatureInsight" },
|
||||
"name": { "classification": "PublicNonPersonalData", "purpose": "FeatureInsight" },
|
||||
"extensionVersion": { "classification": "PublicNonPersonalData", "purpose": "FeatureInsight" },
|
||||
"publisherDisplayName": { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
|
||||
"activationEvents": { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
|
||||
"isBuiltin": { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
|
||||
"reason": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
|
||||
}
|
||||
*/
|
||||
const event = {
|
||||
id: extensionDescription.identifier.value,
|
||||
name: extensionDescription.name,
|
||||
|
||||
@@ -51,7 +51,7 @@ export const LogOutputChannelFactory = new class implements IOutputChannelFactor
|
||||
try {
|
||||
const outputDirPath = join(logsLocation.fsPath, `output_logging_${toLocalISOString(new Date()).replace(/-|:|\.\d+Z$/g, '')}`);
|
||||
const outputDir = await dirExists(outputDirPath).then(exists => exists ? exists : mkdirp(outputDirPath).then(() => true)).then(() => outputDirPath);
|
||||
const fileName = `${this._namePool++}-${name}`;
|
||||
const fileName = `${this._namePool++}-${name.replace(/[\\/:\*\?"<>\|]/g, '')}`;
|
||||
const file = URI.file(join(outputDir, `${fileName}.log`));
|
||||
const appender = new OutputAppender(fileName, file.fsPath);
|
||||
return new ExtHostOutputChannelBackedByFile(name, appender, proxy);
|
||||
|
||||
@@ -16,10 +16,7 @@ import { OutputChannel } from 'vs/workbench/services/search/node/ripgrepSearchUt
|
||||
import { TextSearchManager } from 'vs/workbench/services/search/node/textSearchManager';
|
||||
import * as vscode from 'vscode';
|
||||
import { ExtHostSearchShape, IMainContext, MainContext, MainThreadSearchShape } from '../common/extHost.protocol';
|
||||
|
||||
export interface ISchemeTransformer {
|
||||
transformOutgoing(scheme: string): string;
|
||||
}
|
||||
import { IURITransformer } from 'vs/base/common/uriIpc';
|
||||
|
||||
export class ExtHostSearch implements ExtHostSearchShape {
|
||||
|
||||
@@ -35,14 +32,14 @@ export class ExtHostSearch implements ExtHostSearchShape {
|
||||
|
||||
private _fileSearchManager: FileSearchManager;
|
||||
|
||||
constructor(mainContext: IMainContext, private _schemeTransformer: ISchemeTransformer | null, private _logService: ILogService, private _pfs = pfs) {
|
||||
constructor(mainContext: IMainContext, private _uriTransformer: IURITransformer | null, private _logService: ILogService, private _pfs = pfs) {
|
||||
this._proxy = mainContext.getProxy(MainContext.MainThreadSearch);
|
||||
this._fileSearchManager = new FileSearchManager();
|
||||
}
|
||||
|
||||
private _transformScheme(scheme: string): string {
|
||||
if (this._schemeTransformer) {
|
||||
return this._schemeTransformer.transformOutgoing(scheme);
|
||||
if (this._uriTransformer) {
|
||||
return this._uriTransformer.transformOutgoingScheme(scheme);
|
||||
}
|
||||
return scheme;
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ import {
|
||||
ProcessExecutionOptionsDTO, ProcessExecutionDTO,
|
||||
ShellExecutionOptionsDTO, ShellExecutionDTO,
|
||||
CustomExecutionDTO,
|
||||
CustomExecution2DTO,
|
||||
TaskDTO, TaskHandleDTO, TaskFilterDTO, TaskProcessStartedDTO, TaskProcessEndedDTO, TaskSystemInfoDTO, TaskSetDTO
|
||||
} from '../common/shared/tasks';
|
||||
// {{SQL CARBON EDIT}}
|
||||
@@ -31,7 +32,7 @@ import { ExtHostConfiguration } from 'vs/workbench/api/common/extHostConfigurati
|
||||
import { ExtHostTerminalService, ExtHostTerminal } from 'vs/workbench/api/node/extHostTerminalService';
|
||||
import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace';
|
||||
import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation';
|
||||
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
|
||||
import { IDisposable, DisposableStore } from 'vs/base/common/lifecycle';
|
||||
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
||||
|
||||
namespace TaskDefinitionDTO {
|
||||
@@ -80,7 +81,7 @@ namespace ProcessExecutionOptionsDTO {
|
||||
}
|
||||
|
||||
namespace ProcessExecutionDTO {
|
||||
export function is(value: ShellExecutionDTO | ProcessExecutionDTO | CustomExecutionDTO | undefined): value is ProcessExecutionDTO {
|
||||
export function is(value: ShellExecutionDTO | ProcessExecutionDTO | CustomExecutionDTO | CustomExecution2DTO | undefined): value is ProcessExecutionDTO {
|
||||
if (value) {
|
||||
const candidate = value as ProcessExecutionDTO;
|
||||
return candidate && !!candidate.process;
|
||||
@@ -125,7 +126,7 @@ namespace ShellExecutionOptionsDTO {
|
||||
}
|
||||
|
||||
namespace ShellExecutionDTO {
|
||||
export function is(value: ShellExecutionDTO | ProcessExecutionDTO | CustomExecutionDTO | undefined): value is ShellExecutionDTO {
|
||||
export function is(value: ShellExecutionDTO | ProcessExecutionDTO | CustomExecutionDTO | CustomExecution2DTO | undefined): value is ShellExecutionDTO {
|
||||
if (value) {
|
||||
const candidate = value as ShellExecutionDTO;
|
||||
return candidate && (!!candidate.commandLine || !!candidate.command);
|
||||
@@ -163,7 +164,7 @@ namespace ShellExecutionDTO {
|
||||
}
|
||||
|
||||
namespace CustomExecutionDTO {
|
||||
export function is(value: ShellExecutionDTO | ProcessExecutionDTO | CustomExecutionDTO | undefined): value is CustomExecutionDTO {
|
||||
export function is(value: ShellExecutionDTO | ProcessExecutionDTO | CustomExecutionDTO | CustomExecution2DTO | undefined): value is CustomExecutionDTO {
|
||||
if (value) {
|
||||
let candidate = value as CustomExecutionDTO;
|
||||
return candidate && candidate.customExecution === 'customExecution';
|
||||
@@ -179,6 +180,23 @@ namespace CustomExecutionDTO {
|
||||
}
|
||||
}
|
||||
|
||||
namespace CustomExecution2DTO {
|
||||
export function is(value: ShellExecutionDTO | ProcessExecutionDTO | CustomExecutionDTO | CustomExecution2DTO | undefined): value is CustomExecution2DTO {
|
||||
if (value) {
|
||||
let candidate = value as CustomExecution2DTO;
|
||||
return candidate && candidate.customExecution === 'customExecution2';
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
export function from(value: vscode.CustomExecution2): CustomExecution2DTO {
|
||||
return {
|
||||
customExecution: 'customExecution2'
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
namespace TaskHandleDTO {
|
||||
export function from(value: types.Task): TaskHandleDTO {
|
||||
let folder: UriComponents | undefined;
|
||||
@@ -212,14 +230,17 @@ namespace TaskDTO {
|
||||
if (value === undefined || value === null) {
|
||||
return undefined;
|
||||
}
|
||||
let execution: ShellExecutionDTO | ProcessExecutionDTO | CustomExecutionDTO | undefined;
|
||||
let execution: ShellExecutionDTO | ProcessExecutionDTO | CustomExecutionDTO | CustomExecution2DTO | undefined;
|
||||
if (value.execution instanceof types.ProcessExecution) {
|
||||
execution = ProcessExecutionDTO.from(value.execution);
|
||||
} else if (value.execution instanceof types.ShellExecution) {
|
||||
execution = ShellExecutionDTO.from(value.execution);
|
||||
} else if ((<vscode.Task2>value).execution2 && (<vscode.Task2>value).execution2 instanceof types.CustomExecution) {
|
||||
execution = CustomExecutionDTO.from(<types.CustomExecution>(<vscode.Task2>value).execution2);
|
||||
} else if ((<vscode.Task2>value).execution2 && (<vscode.Task2>value).execution2 instanceof types.CustomExecution2) {
|
||||
execution = CustomExecution2DTO.from(<types.CustomExecution2>(<vscode.Task2>value).execution2);
|
||||
}
|
||||
|
||||
const definition: TaskDefinitionDTO | undefined = TaskDefinitionDTO.from(value.definition);
|
||||
let scope: number | UriComponents;
|
||||
if (value.scope) {
|
||||
@@ -348,6 +369,7 @@ namespace TaskExecutionDTO {
|
||||
}
|
||||
|
||||
interface HandlerData {
|
||||
type: string;
|
||||
provider: vscode.TaskProvider;
|
||||
extension: IExtensionDescription;
|
||||
}
|
||||
@@ -356,7 +378,7 @@ class CustomExecutionData implements IDisposable {
|
||||
private static waitForDimensionsTimeoutInMs: number = 5000;
|
||||
private _cancellationSource?: CancellationTokenSource;
|
||||
private readonly _onTaskExecutionComplete: Emitter<CustomExecutionData> = new Emitter<CustomExecutionData>();
|
||||
private readonly _disposables: IDisposable[] = [];
|
||||
private readonly _disposables = new DisposableStore();
|
||||
private terminal?: vscode.Terminal;
|
||||
private terminalId?: number;
|
||||
public result: number | undefined;
|
||||
@@ -368,7 +390,7 @@ class CustomExecutionData implements IDisposable {
|
||||
|
||||
public dispose(): void {
|
||||
this._cancellationSource = undefined;
|
||||
dispose(this._disposables);
|
||||
this._disposables.dispose();
|
||||
}
|
||||
|
||||
public get onTaskExecutionComplete(): Event<CustomExecutionData> {
|
||||
@@ -405,7 +427,7 @@ class CustomExecutionData implements IDisposable {
|
||||
const callbackTerminals: vscode.Terminal[] = this.terminalService.terminals.filter((terminal) => terminal._id === terminalId);
|
||||
|
||||
if (!callbackTerminals || callbackTerminals.length === 0) {
|
||||
this._disposables.push(this.terminalService.onDidOpenTerminal(this.onDidOpenTerminal.bind(this)));
|
||||
this._disposables.add(this.terminalService.onDidOpenTerminal(this.onDidOpenTerminal.bind(this)));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -441,9 +463,9 @@ class CustomExecutionData implements IDisposable {
|
||||
}
|
||||
|
||||
this._cancellationSource = new CancellationTokenSource();
|
||||
this._disposables.push(this._cancellationSource);
|
||||
this._disposables.add(this._cancellationSource);
|
||||
|
||||
this._disposables.push(this.terminalService.onDidCloseTerminal(this.onDidCloseTerminal.bind(this)));
|
||||
this._disposables.add(this.terminalService.onDidCloseTerminal(this.onDidCloseTerminal.bind(this)));
|
||||
|
||||
// Regardless of how the task completes, we are done with this custom execution task.
|
||||
this.customExecution.callback(terminalRenderer, this._cancellationSource.token).then(
|
||||
@@ -468,6 +490,8 @@ export class ExtHostTask implements ExtHostTaskShape {
|
||||
private _taskExecutions: Map<string, TaskExecutionImpl>;
|
||||
private _providedCustomExecutions: Map<string, CustomExecutionData>;
|
||||
private _activeCustomExecutions: Map<string, CustomExecutionData>;
|
||||
private _providedCustomExecutions2: Map<string, vscode.CustomExecution2>;
|
||||
private _activeCustomExecutions2: Map<string, vscode.CustomExecution2>;
|
||||
|
||||
private readonly _onDidExecuteTask: Emitter<vscode.TaskStartEvent> = new Emitter<vscode.TaskStartEvent>();
|
||||
private readonly _onDidTerminateTask: Emitter<vscode.TaskEndEvent> = new Emitter<vscode.TaskEndEvent>();
|
||||
@@ -491,15 +515,17 @@ export class ExtHostTask implements ExtHostTaskShape {
|
||||
this._taskExecutions = new Map<string, TaskExecutionImpl>();
|
||||
this._providedCustomExecutions = new Map<string, CustomExecutionData>();
|
||||
this._activeCustomExecutions = new Map<string, CustomExecutionData>();
|
||||
this._providedCustomExecutions2 = new Map<string, vscode.CustomExecution2>();
|
||||
this._activeCustomExecutions2 = new Map<string, vscode.CustomExecution2>();
|
||||
}
|
||||
|
||||
public registerTaskProvider(extension: IExtensionDescription, provider: vscode.TaskProvider): vscode.Disposable {
|
||||
public registerTaskProvider(extension: IExtensionDescription, type: string, provider: vscode.TaskProvider): vscode.Disposable {
|
||||
if (!provider) {
|
||||
return new types.Disposable(() => { });
|
||||
}
|
||||
const handle = this.nextHandle();
|
||||
this._handlers.set(handle, { provider, extension });
|
||||
this._proxy.$registerTaskProvider(handle);
|
||||
this._handlers.set(handle, { type, provider, extension });
|
||||
this._proxy.$registerTaskProvider(handle, type);
|
||||
return new types.Disposable(() => {
|
||||
this._handlers.delete(handle);
|
||||
this._proxy.$unregisterTaskProvider(handle);
|
||||
@@ -555,6 +581,19 @@ export class ExtHostTask implements ExtHostTaskShape {
|
||||
}
|
||||
|
||||
public async $onDidStartTask(execution: TaskExecutionDTO, terminalId: number): Promise<void> {
|
||||
const execution2: vscode.CustomExecution2 | undefined = this._providedCustomExecutions2.get(execution.id);
|
||||
if (execution2) {
|
||||
if (this._activeCustomExecutions2.get(execution.id) !== undefined) {
|
||||
throw new Error('We should not be trying to start the same custom task executions twice.');
|
||||
}
|
||||
|
||||
// Clone the custom execution to keep the original untouched. This is important for multiple runs of the same task.
|
||||
this._activeCustomExecutions2.set(execution.id, execution2);
|
||||
this._terminalService.performTerminalIdAction(terminalId, async terminal => {
|
||||
this._terminalService.attachVirtualProcessToTerminal(terminalId, await execution2.callback());
|
||||
});
|
||||
}
|
||||
|
||||
// Once a terminal is spun up for the custom execution task this event will be fired.
|
||||
// At that point, we need to actually start the callback, but
|
||||
// only if it hasn't already begun.
|
||||
@@ -630,6 +669,7 @@ export class ExtHostTask implements ExtHostTaskShape {
|
||||
// since we obviously cannot send callback functions through the proxy.
|
||||
// So, clear out any existing ones.
|
||||
this._providedCustomExecutions.clear();
|
||||
this._providedCustomExecutions2.clear();
|
||||
|
||||
// Set up a list of task ID promises that we can wait on
|
||||
// before returning the provided tasks. The ensures that
|
||||
@@ -653,15 +693,13 @@ export class ExtHostTask implements ExtHostTaskShape {
|
||||
taskDTOs.push(taskDTO);
|
||||
|
||||
if (CustomExecutionDTO.is(taskDTO.execution)) {
|
||||
taskIdPromises.push(new Promise((resolve) => {
|
||||
// The ID is calculated on the main thread task side, so, let's call into it here.
|
||||
// We need the task id's pre-computed for custom task executions because when OnDidStartTask
|
||||
// is invoked, we have to be able to map it back to our data.
|
||||
this._proxy.$createTaskId(taskDTO).then((taskId) => {
|
||||
this._providedCustomExecutions.set(taskId, new CustomExecutionData(<vscode.CustomExecution>(<vscode.Task2>task).execution2, this._terminalService));
|
||||
resolve();
|
||||
});
|
||||
}));
|
||||
// The ID is calculated on the main thread task side, so, let's call into it here.
|
||||
// We need the task id's pre-computed for custom task executions because when OnDidStartTask
|
||||
// is invoked, we have to be able to map it back to our data.
|
||||
taskIdPromises.push(this.addCustomExecution(taskDTO, <vscode.Task2>task));
|
||||
} else if (CustomExecution2DTO.is(taskDTO.execution)) {
|
||||
taskIdPromises.push(this.addCustomExecution2(taskDTO, <vscode.Task2>task));
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -682,6 +720,43 @@ export class ExtHostTask implements ExtHostTaskShape {
|
||||
}
|
||||
|
||||
// {{SQL CARBON EDIT}} disable debug related method
|
||||
public async $resolveTask(handle: number, taskDTO: TaskDTO): Promise<TaskDTO | undefined> {
|
||||
/*const handler = this._handlers.get(handle);
|
||||
if (!handler) {
|
||||
return Promise.reject(new Error('no handler found'));
|
||||
}
|
||||
|
||||
if (taskDTO.definition.type !== handler.type) {
|
||||
throw new Error(`Unexpected: Task of type [${taskDTO.definition.type}] cannot be resolved by provider of type [${handler.type}].`);
|
||||
}
|
||||
|
||||
const task = await TaskDTO.to(taskDTO, this._workspaceProvider);
|
||||
if (!task) {
|
||||
throw new Error('Unexpected: Task cannot be resolved.');
|
||||
}
|
||||
|
||||
const resolvedTask = await handler.provider.resolveTask(task, CancellationToken.None);
|
||||
if (!resolvedTask) {
|
||||
return;
|
||||
}
|
||||
|
||||
const resolvedTaskDTO: TaskDTO | undefined = TaskDTO.from(resolvedTask, handler.extension);
|
||||
if (!resolvedTaskDTO) {
|
||||
throw new Error('Unexpected: Task cannot be resolved.');
|
||||
}
|
||||
|
||||
if (CustomExecutionDTO.is(resolvedTaskDTO.execution)) {
|
||||
await this.addCustomExecution(taskDTO, <vscode.Task2>task);
|
||||
}
|
||||
|
||||
if (CustomExecution2DTO.is(resolvedTaskDTO.execution)) {
|
||||
await this.addCustomExecution2(taskDTO, <vscode.Task2>task);
|
||||
}
|
||||
|
||||
return resolvedTaskDTO;*/
|
||||
return undefined;
|
||||
}
|
||||
|
||||
public async $resolveVariables(uriComponents: UriComponents, toResolve: { process?: { name: string; cwd?: string; path?: string }, variables: string[] }): Promise<{ process?: string, variables: { [key: string]: string; } }> {
|
||||
/*const configProvider = await this._configurationService.getConfigProvider();
|
||||
const uri: URI = URI.revive(uriComponents);
|
||||
@@ -714,7 +789,7 @@ export class ExtHostTask implements ExtHostTaskShape {
|
||||
paths[i] = resolver.resolve(ws, paths[i]);
|
||||
}
|
||||
}
|
||||
result.process = win32.findExecutable(
|
||||
result.process = await win32.findExecutable(
|
||||
resolver.resolve(ws, toResolve.process.name),
|
||||
toResolve.process.cwd !== undefined ? resolver.resolve(ws, toResolve.process.cwd) : undefined,
|
||||
paths
|
||||
@@ -728,6 +803,16 @@ export class ExtHostTask implements ExtHostTaskShape {
|
||||
return this._handleCounter++;
|
||||
}
|
||||
|
||||
private async addCustomExecution(taskDTO: TaskDTO, task: vscode.Task2): Promise<void> {
|
||||
const taskId = await this._proxy.$createTaskId(taskDTO);
|
||||
this._providedCustomExecutions.set(taskId, new CustomExecutionData(<vscode.CustomExecution>(<vscode.Task2>task).execution2, this._terminalService));
|
||||
}
|
||||
|
||||
private async addCustomExecution2(taskDTO: TaskDTO, task: vscode.Task2): Promise<void> {
|
||||
const taskId = await this._proxy.$createTaskId(taskDTO);
|
||||
this._providedCustomExecutions2.set(taskId, <vscode.CustomExecution2>(<vscode.Task2>task).execution2);
|
||||
}
|
||||
|
||||
private async getTaskExecution(execution: TaskExecutionDTO | string, task?: vscode.Task): Promise<TaskExecutionImpl> {
|
||||
if (typeof execution === 'string') {
|
||||
const taskExecution = this._taskExecutions.get(execution);
|
||||
@@ -757,5 +842,9 @@ export class ExtHostTask implements ExtHostTaskShape {
|
||||
this._proxy.$customExecutionComplete(execution.id, extensionCallback.result);
|
||||
extensionCallback.dispose();
|
||||
}
|
||||
const extensionCallback2: vscode.CustomExecution2 | undefined = this._activeCustomExecutions2.get(execution.id);
|
||||
if (extensionCallback2) {
|
||||
this._activeCustomExecutions2.delete(execution.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,10 +10,10 @@ import { URI, UriComponents } from 'vs/base/common/uri';
|
||||
import * as platform from 'vs/base/common/platform';
|
||||
import * as terminalEnvironment from 'vs/workbench/contrib/terminal/common/terminalEnvironment';
|
||||
import { Event, Emitter } from 'vs/base/common/event';
|
||||
import { ExtHostTerminalServiceShape, MainContext, MainThreadTerminalServiceShape, IMainContext, ShellLaunchConfigDto } from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { ExtHostConfiguration } from 'vs/workbench/api/common/extHostConfiguration';
|
||||
import { ExtHostTerminalServiceShape, MainContext, MainThreadTerminalServiceShape, IMainContext, ShellLaunchConfigDto, IShellDefinitionDto, IShellAndArgsDto, ITerminalDimensionsDto } from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { ExtHostConfiguration, ExtHostConfigProvider } from 'vs/workbench/api/common/extHostConfiguration';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { EXT_HOST_CREATION_DELAY, IShellLaunchConfig, ITerminalEnvironment } from 'vs/workbench/contrib/terminal/common/terminal';
|
||||
import { EXT_HOST_CREATION_DELAY, IShellLaunchConfig, ITerminalEnvironment, ITerminalChildProcess, ITerminalDimensions } from 'vs/workbench/contrib/terminal/common/terminal';
|
||||
import { TerminalProcess } from 'vs/workbench/contrib/terminal/node/terminalProcess';
|
||||
import { timeout } from 'vs/base/common/async';
|
||||
import { ExtHostWorkspace } from 'vs/workbench/api/common/extHostWorkspace';
|
||||
@@ -21,7 +21,9 @@ import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace';
|
||||
// {{SQL CARBON EDIT}}
|
||||
// import { ExtHostVariableResolverService } from 'vs/workbench/api/node/extHostDebugService';
|
||||
import { ExtHostDocumentsAndEditors } from 'vs/workbench/api/common/extHostDocumentsAndEditors';
|
||||
import { getDefaultShell } from 'vs/workbench/contrib/terminal/node/terminal';
|
||||
import { getSystemShell, detectAvailableShells } from 'vs/workbench/contrib/terminal/node/terminal';
|
||||
import { getMainProcessParentEnv } from 'vs/workbench/contrib/terminal/node/terminalEnvironment';
|
||||
import { IDisposable } from 'vs/base/common/lifecycle';
|
||||
|
||||
const RENDERER_NO_PROCESS_ID = -1;
|
||||
|
||||
@@ -115,9 +117,17 @@ export class ExtHostTerminal extends BaseExtHostTerminal implements vscode.Termi
|
||||
cwd?: string | URI,
|
||||
env?: { [key: string]: string | null },
|
||||
waitOnExit?: boolean,
|
||||
strictEnv?: boolean
|
||||
strictEnv?: boolean,
|
||||
hideFromUser?: boolean
|
||||
): void {
|
||||
this._proxy.$createTerminal(this._name, shellPath, shellArgs, cwd, env, waitOnExit, strictEnv).then(terminal => {
|
||||
this._proxy.$createTerminal({ name: this._name, shellPath, shellArgs, cwd, env, waitOnExit, strictEnv, hideFromUser }).then(terminal => {
|
||||
this._name = terminal.name;
|
||||
this._runQueuedRequests(terminal.id);
|
||||
});
|
||||
}
|
||||
|
||||
public createVirtualProcess(): Promise<void> {
|
||||
return this._proxy.$createTerminal({ name: this._name, isVirtualProcess: true }).then(terminal => {
|
||||
this._name = terminal.name;
|
||||
this._runQueuedRequests(terminal.id);
|
||||
});
|
||||
@@ -176,7 +186,7 @@ export class ExtHostTerminal extends BaseExtHostTerminal implements vscode.Termi
|
||||
this._pidPromiseComplete(processId);
|
||||
this._pidPromiseComplete = null;
|
||||
} else {
|
||||
// Recreate the promise if this is the nth processId set (eg. reused task terminals)
|
||||
// Recreate the promise if this is the nth processId set (e.g. reused task terminals)
|
||||
this._pidPromise.then(pid => {
|
||||
if (pid !== processId) {
|
||||
this._pidPromise = Promise.resolve(processId);
|
||||
@@ -274,10 +284,13 @@ export class ExtHostTerminalService implements ExtHostTerminalServiceShape {
|
||||
private _proxy: MainThreadTerminalServiceShape;
|
||||
private _activeTerminal: ExtHostTerminal | undefined;
|
||||
private _terminals: ExtHostTerminal[] = [];
|
||||
private _terminalProcesses: { [id: number]: TerminalProcess } = {};
|
||||
private _terminalProcesses: { [id: number]: ITerminalChildProcess } = {};
|
||||
private _terminalRenderers: ExtHostTerminalRenderer[] = [];
|
||||
private _getTerminalPromises: { [id: number]: Promise<ExtHostTerminal> } = {};
|
||||
|
||||
// TODO: Pull this from main side
|
||||
private _isWorkspaceShellAllowed: boolean = false;
|
||||
|
||||
public get activeTerminal(): ExtHostTerminal | undefined { return this._activeTerminal; }
|
||||
public get terminals(): ExtHostTerminal[] { return this._terminals; }
|
||||
|
||||
@@ -309,11 +322,28 @@ export class ExtHostTerminalService implements ExtHostTerminalServiceShape {
|
||||
|
||||
public createTerminalFromOptions(options: vscode.TerminalOptions): vscode.Terminal {
|
||||
const terminal = new ExtHostTerminal(this._proxy, options.name);
|
||||
terminal.create(options.shellPath, options.shellArgs, options.cwd, options.env, /*options.waitOnExit*/ undefined, options.strictEnv);
|
||||
terminal.create(options.shellPath, options.shellArgs, options.cwd, options.env, /*options.waitOnExit*/ undefined, options.strictEnv, options.hideFromUser);
|
||||
this._terminals.push(terminal);
|
||||
return terminal;
|
||||
}
|
||||
|
||||
public createVirtualProcessTerminal(options: vscode.TerminalVirtualProcessOptions): vscode.Terminal {
|
||||
const terminal = new ExtHostTerminal(this._proxy, options.name);
|
||||
const p = new ExtHostVirtualProcess(options.virtualProcess);
|
||||
terminal.createVirtualProcess().then(() => this._setupExtHostProcessListeners(terminal._id, p));
|
||||
this._terminals.push(terminal);
|
||||
return terminal;
|
||||
}
|
||||
|
||||
public attachVirtualProcessToTerminal(id: number, virtualProcess: vscode.TerminalVirtualProcess) {
|
||||
const terminal = this._getTerminalById(id);
|
||||
if (!terminal) {
|
||||
throw new Error(`Cannot resolve terminal with id ${id} for virtual process`);
|
||||
}
|
||||
const p = new ExtHostVirtualProcess(virtualProcess);
|
||||
this._setupExtHostProcessListeners(id, p);
|
||||
}
|
||||
|
||||
public createTerminalRenderer(name: string): vscode.TerminalRenderer {
|
||||
const terminal = new ExtHostTerminal(this._proxy, name);
|
||||
terminal._setProcessId(undefined);
|
||||
@@ -325,6 +355,32 @@ export class ExtHostTerminalService implements ExtHostTerminalServiceShape {
|
||||
return renderer;
|
||||
}
|
||||
|
||||
public getDefaultShell(configProvider: ExtHostConfigProvider): string {
|
||||
const fetchSetting = (key: string) => {
|
||||
const setting = configProvider
|
||||
.getConfiguration(key.substr(0, key.lastIndexOf('.')))
|
||||
.inspect<string | string[]>(key.substr(key.lastIndexOf('.') + 1));
|
||||
return this._apiInspectConfigToPlain<string | string[]>(setting);
|
||||
};
|
||||
return terminalEnvironment.getDefaultShell(
|
||||
fetchSetting,
|
||||
this._isWorkspaceShellAllowed,
|
||||
getSystemShell(platform.platform),
|
||||
process.env.hasOwnProperty('PROCESSOR_ARCHITEW6432'),
|
||||
process.env.windir
|
||||
);
|
||||
}
|
||||
|
||||
private _getDefaultShellArgs(configProvider: ExtHostConfigProvider): string[] | string | undefined {
|
||||
const fetchSetting = (key: string) => {
|
||||
const setting = configProvider
|
||||
.getConfiguration(key.substr(0, key.lastIndexOf('.')))
|
||||
.inspect<string | string[]>(key.substr(key.lastIndexOf('.') + 1));
|
||||
return this._apiInspectConfigToPlain<string | string[]>(setting);
|
||||
};
|
||||
return terminalEnvironment.getDefaultShellArgs(fetchSetting, this._isWorkspaceShellAllowed);
|
||||
}
|
||||
|
||||
public async resolveTerminalRenderer(id: number): Promise<vscode.TerminalRenderer> {
|
||||
// Check to see if the extension host already knows about this terminal.
|
||||
for (const terminalRenderer of this._terminalRenderers) {
|
||||
@@ -352,7 +408,7 @@ export class ExtHostTerminalService implements ExtHostTerminalServiceShape {
|
||||
}
|
||||
return;
|
||||
}
|
||||
this._performTerminalIdAction(id, terminal => {
|
||||
this.performTerminalIdAction(id, terminal => {
|
||||
if (terminal) {
|
||||
this._activeTerminal = terminal;
|
||||
if (original !== this._activeTerminal) {
|
||||
@@ -380,14 +436,26 @@ export class ExtHostTerminalService implements ExtHostTerminalServiceShape {
|
||||
});
|
||||
}
|
||||
}
|
||||
// When a terminal's dimensions change, a renderer's _maximum_ dimensions change
|
||||
const renderer = this._getTerminalRendererById(id);
|
||||
if (renderer) {
|
||||
renderer._setMaximumDimensions(cols, rows);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public $acceptTerminalMaximumDimensions(id: number, cols: number, rows: number): void {
|
||||
if (this._terminalProcesses[id]) {
|
||||
// Virtual processes only - when virtual process resize fires it means that the
|
||||
// terminal's maximum dimensions changed
|
||||
this._terminalProcesses[id].resize(cols, rows);
|
||||
} else {
|
||||
// Terminal renderer
|
||||
this._getTerminalByIdEventually(id).then(() => {
|
||||
// When a terminal's dimensions change, a renderer's _maximum_ dimensions change
|
||||
const renderer = this._getTerminalRendererById(id);
|
||||
if (renderer) {
|
||||
renderer._setMaximumDimensions(cols, rows);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public $acceptTerminalRendererInput(id: number, data: string): void {
|
||||
const renderer = this._getTerminalRendererById(id);
|
||||
if (renderer) {
|
||||
@@ -425,10 +493,10 @@ export class ExtHostTerminalService implements ExtHostTerminalServiceShape {
|
||||
}
|
||||
|
||||
public $acceptTerminalProcessId(id: number, processId: number): void {
|
||||
this._performTerminalIdAction(id, terminal => terminal._setProcessId(processId));
|
||||
this.performTerminalIdAction(id, terminal => terminal._setProcessId(processId));
|
||||
}
|
||||
|
||||
private _performTerminalIdAction(id: number, callback: (terminal: ExtHostTerminal) => void): void {
|
||||
public performTerminalIdAction(id: number, callback: (terminal: ExtHostTerminal) => void): void {
|
||||
let terminal = this._getTerminalById(id);
|
||||
if (terminal) {
|
||||
callback(terminal);
|
||||
@@ -439,7 +507,7 @@ export class ExtHostTerminalService implements ExtHostTerminalServiceShape {
|
||||
if (terminal) {
|
||||
callback(terminal);
|
||||
}
|
||||
}, EXT_HOST_CREATION_DELAY);
|
||||
}, EXT_HOST_CREATION_DELAY * 2);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -453,6 +521,12 @@ export class ExtHostTerminalService implements ExtHostTerminalServiceShape {
|
||||
};
|
||||
}
|
||||
|
||||
private async _getNonInheritedEnv(): Promise<platform.IProcessEnvironment> {
|
||||
const env = await getMainProcessParentEnv();
|
||||
env.VSCODE_IPC_HOOK_CLI = process.env['VSCODE_IPC_HOOK_CLI']!;
|
||||
return env;
|
||||
}
|
||||
|
||||
public async $createProcess(id: number, shellLaunchConfigDto: ShellLaunchConfigDto, activeWorkspaceRootUriComponents: UriComponents, cols: number, rows: number, isWorkspaceShellAllowed: boolean): Promise<void> {
|
||||
const shellLaunchConfig: IShellLaunchConfig = {
|
||||
name: shellLaunchConfigDto.name,
|
||||
@@ -466,13 +540,8 @@ export class ExtHostTerminalService implements ExtHostTerminalServiceShape {
|
||||
const platformKey = platform.isWindows ? 'windows' : (platform.isMacintosh ? 'osx' : 'linux');
|
||||
const configProvider = await this._extHostConfiguration.getConfigProvider();
|
||||
if (!shellLaunchConfig.executable) {
|
||||
const fetchSetting = (key: string) => {
|
||||
const setting = configProvider
|
||||
.getConfiguration(key.substr(0, key.lastIndexOf('.')))
|
||||
.inspect<string | string[]>(key.substr(key.lastIndexOf('.') + 1));
|
||||
return this._apiInspectConfigToPlain<string | string[]>(setting);
|
||||
};
|
||||
terminalEnvironment.mergeDefaultShellPathAndArgs(shellLaunchConfig, fetchSetting, isWorkspaceShellAllowed || false, getDefaultShell(platform.platform));
|
||||
shellLaunchConfig.executable = this.getDefaultShell(configProvider);
|
||||
shellLaunchConfig.args = this._getDefaultShellArgs(configProvider);
|
||||
}
|
||||
|
||||
// Get the initial cwd
|
||||
@@ -495,6 +564,7 @@ export class ExtHostTerminalService implements ExtHostTerminalServiceShape {
|
||||
// {{SQL CARBON EDIT}}
|
||||
// const variableResolver = workspaceFolders ? new ExtHostVariableResolverService(workspaceFolders, this._extHostDocumentsAndEditors, configProvider) : undefined;
|
||||
const variableResolver = undefined;
|
||||
const baseEnv = terminalConfig.get<boolean>('inheritEnv', true) ? process.env as platform.IProcessEnvironment : await this._getNonInheritedEnv();
|
||||
const env = terminalEnvironment.createTerminalEnvironment(
|
||||
shellLaunchConfig,
|
||||
lastActiveWorkspace,
|
||||
@@ -502,16 +572,30 @@ export class ExtHostTerminalService implements ExtHostTerminalServiceShape {
|
||||
variableResolver,
|
||||
isWorkspaceShellAllowed,
|
||||
pkg.version,
|
||||
terminalConfig.get<boolean>('setLocaleVariables', false)
|
||||
terminalConfig.get<boolean>('setLocaleVariables', false),
|
||||
baseEnv
|
||||
);
|
||||
|
||||
// Fork the process and listen for messages
|
||||
this._logService.debug(`Terminal process launching on ext host`, shellLaunchConfig, initialCwd, cols, rows, env);
|
||||
const p = new TerminalProcess(shellLaunchConfig, initialCwd, cols, rows, env, terminalConfig.get('windowsEnableConpty') as boolean, this._logService);
|
||||
p.onProcessIdReady(pid => this._proxy.$sendProcessPid(id, pid));
|
||||
// TODO: Support conpty on remote, it doesn't seem to work for some reason?
|
||||
// TODO: When conpty is enabled, only enable it when accessibilityMode is off
|
||||
const enableConpty = false; //terminalConfig.get('windowsEnableConpty') as boolean;
|
||||
this._setupExtHostProcessListeners(id, new TerminalProcess(shellLaunchConfig, initialCwd, cols, rows, env, enableConpty, this._logService));
|
||||
}
|
||||
|
||||
public $startVirtualProcess(id: number, initialDimensions: ITerminalDimensionsDto | undefined): void {
|
||||
(this._terminalProcesses[id] as ExtHostVirtualProcess).startSendingEvents(initialDimensions);
|
||||
}
|
||||
|
||||
private _setupExtHostProcessListeners(id: number, p: ITerminalChildProcess): void {
|
||||
p.onProcessReady((e: { pid: number, cwd: string }) => this._proxy.$sendProcessReady(id, e.pid, e.cwd));
|
||||
p.onProcessTitleChanged(title => this._proxy.$sendProcessTitle(id, title));
|
||||
p.onProcessData(data => this._proxy.$sendProcessData(id, data));
|
||||
p.onProcessExit(exitCode => this._onProcessExit(id, exitCode));
|
||||
if (p.onProcessOverrideDimensions) {
|
||||
p.onProcessOverrideDimensions(e => this._proxy.$sendOverrideDimensions(id, e));
|
||||
}
|
||||
this._terminalProcesses[id] = p;
|
||||
}
|
||||
|
||||
@@ -546,10 +630,19 @@ export class ExtHostTerminalService implements ExtHostTerminalServiceShape {
|
||||
return id;
|
||||
}
|
||||
|
||||
private _onProcessExit(id: number, exitCode: number): void {
|
||||
// Remove listeners
|
||||
this._terminalProcesses[id].dispose();
|
||||
public $requestAvailableShells(): Promise<IShellDefinitionDto[]> {
|
||||
return detectAvailableShells();
|
||||
}
|
||||
|
||||
public async $requestDefaultShellAndArgs(): Promise<IShellAndArgsDto> {
|
||||
const configProvider = await this._extHostConfiguration.getConfigProvider();
|
||||
return Promise.resolve({
|
||||
shell: this.getDefaultShell(configProvider),
|
||||
args: this._getDefaultShellArgs(configProvider)
|
||||
});
|
||||
}
|
||||
|
||||
private _onProcessExit(id: number, exitCode: number): void {
|
||||
// Remove process reference
|
||||
delete this._terminalProcesses[id];
|
||||
|
||||
@@ -611,6 +704,10 @@ export class ExtHostTerminalService implements ExtHostTerminalServiceShape {
|
||||
});
|
||||
return index;
|
||||
}
|
||||
|
||||
public $acceptWorkspacePermissionsChanged(isAllowed: boolean): void {
|
||||
this._isWorkspaceShellAllowed = isAllowed;
|
||||
}
|
||||
}
|
||||
|
||||
class ApiRequest {
|
||||
@@ -626,3 +723,90 @@ class ApiRequest {
|
||||
this._callback.apply(proxy, [id].concat(this._args));
|
||||
}
|
||||
}
|
||||
|
||||
class ExtHostVirtualProcess implements ITerminalChildProcess {
|
||||
private _queuedEvents: (IQueuedEvent<string> | IQueuedEvent<number> | IQueuedEvent<{ pid: number, cwd: string }> | IQueuedEvent<ITerminalDimensions | undefined>)[] = [];
|
||||
private _queueDisposables: IDisposable[] | undefined;
|
||||
|
||||
private readonly _onProcessData = new Emitter<string>();
|
||||
public readonly onProcessData: Event<string> = this._onProcessData.event;
|
||||
private readonly _onProcessExit = new Emitter<number>();
|
||||
public readonly onProcessExit: Event<number> = this._onProcessExit.event;
|
||||
private readonly _onProcessReady = new Emitter<{ pid: number, cwd: string }>();
|
||||
public get onProcessReady(): Event<{ pid: number, cwd: string }> { return this._onProcessReady.event; }
|
||||
private readonly _onProcessTitleChanged = new Emitter<string>();
|
||||
public readonly onProcessTitleChanged: Event<string> = this._onProcessTitleChanged.event;
|
||||
private readonly _onProcessOverrideDimensions = new Emitter<ITerminalDimensions | undefined>();
|
||||
public get onProcessOverrideDimensions(): Event<ITerminalDimensions | undefined> { return this._onProcessOverrideDimensions.event; }
|
||||
|
||||
constructor(
|
||||
private readonly _virtualProcess: vscode.TerminalVirtualProcess
|
||||
) {
|
||||
this._queueDisposables = [];
|
||||
this._queueDisposables.push(this._virtualProcess.onDidWrite(e => this._queuedEvents.push({ emitter: this._onProcessData, data: e })));
|
||||
if (this._virtualProcess.onDidExit) {
|
||||
this._queueDisposables.push(this._virtualProcess.onDidExit(e => this._queuedEvents.push({ emitter: this._onProcessExit, data: e })));
|
||||
}
|
||||
if (this._virtualProcess.onDidOverrideDimensions) {
|
||||
this._queueDisposables.push(this._virtualProcess.onDidOverrideDimensions(e => this._queuedEvents.push({ emitter: this._onProcessOverrideDimensions, data: e ? { cols: e.columns, rows: e.rows } : undefined })));
|
||||
}
|
||||
}
|
||||
|
||||
shutdown(): void {
|
||||
if (this._virtualProcess.shutdown) {
|
||||
this._virtualProcess.shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
input(data: string): void {
|
||||
if (this._virtualProcess.handleInput) {
|
||||
this._virtualProcess.handleInput(data);
|
||||
}
|
||||
}
|
||||
|
||||
resize(cols: number, rows: number): void {
|
||||
if (this._virtualProcess.setDimensions) {
|
||||
this._virtualProcess.setDimensions({ columns: cols, rows });
|
||||
}
|
||||
}
|
||||
|
||||
getInitialCwd(): Promise<string> {
|
||||
return Promise.resolve('');
|
||||
}
|
||||
|
||||
getCwd(): Promise<string> {
|
||||
return Promise.resolve('');
|
||||
}
|
||||
|
||||
getLatency(): Promise<number> {
|
||||
return Promise.resolve(0);
|
||||
}
|
||||
|
||||
startSendingEvents(initialDimensions: ITerminalDimensionsDto | undefined): void {
|
||||
// Flush all buffered events
|
||||
this._queuedEvents.forEach(e => (<any>e.emitter.fire)(e.data));
|
||||
this._queuedEvents = [];
|
||||
this._queueDisposables = undefined;
|
||||
|
||||
// Attach the real listeners
|
||||
this._virtualProcess.onDidWrite(e => this._onProcessData.fire(e));
|
||||
if (this._virtualProcess.onDidExit) {
|
||||
this._virtualProcess.onDidExit(e => {
|
||||
// Ensure only positive exit codes are returned
|
||||
this._onProcessExit.fire(e >= 0 ? e : 1);
|
||||
});
|
||||
}
|
||||
if (this._virtualProcess.onDidOverrideDimensions) {
|
||||
this._virtualProcess.onDidOverrideDimensions(e => this._onProcessOverrideDimensions.fire(e ? { cols: e.columns, rows: e.rows } : undefined)); // {{SQL CARBON EDIT}} strict-null-check
|
||||
}
|
||||
|
||||
if (this._virtualProcess.start) {
|
||||
this._virtualProcess.start(initialDimensions);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
interface IQueuedEvent<T> {
|
||||
emitter: Emitter<T>;
|
||||
data: T;
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ export class ActionBarContributor {
|
||||
/**
|
||||
* Returns an array of primary actions in the given context.
|
||||
*/
|
||||
getActions(context: unknown): IAction[] {
|
||||
getActions(context: unknown): ReadonlyArray<IAction> {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
@@ -66,7 +66,7 @@ export class ContributableActionProvider implements IActionProvider {
|
||||
return false;
|
||||
}
|
||||
|
||||
getActions(tree: ITree, element: unknown): IAction[] {
|
||||
getActions(tree: ITree, element: unknown): ReadonlyArray<IAction> {
|
||||
const actions: IAction[] = [];
|
||||
const context = this.toContext(tree, element);
|
||||
|
||||
@@ -155,7 +155,7 @@ export interface IActionBarRegistry {
|
||||
|
||||
class ActionBarRegistry implements IActionBarRegistry {
|
||||
private readonly actionBarContributorConstructors: { scope: string; ctor: IConstructorSignature0<ActionBarContributor>; }[] = [];
|
||||
private readonly actionBarContributorInstances: { [scope: string]: ActionBarContributor[] } = Object.create(null);
|
||||
private readonly actionBarContributorInstances: Map<string, ActionBarContributor[]> = new Map();
|
||||
private instantiationService: IInstantiationService;
|
||||
|
||||
start(accessor: ServicesAccessor): void {
|
||||
@@ -169,15 +169,16 @@ class ActionBarRegistry implements IActionBarRegistry {
|
||||
|
||||
private createActionBarContributor(scope: string, ctor: IConstructorSignature0<ActionBarContributor>): void {
|
||||
const instance = this.instantiationService.createInstance(ctor);
|
||||
let target = this.actionBarContributorInstances[scope];
|
||||
let target = this.actionBarContributorInstances.get(scope);
|
||||
if (!target) {
|
||||
target = this.actionBarContributorInstances[scope] = [];
|
||||
target = [];
|
||||
this.actionBarContributorInstances.set(scope, target);
|
||||
}
|
||||
target.push(instance);
|
||||
}
|
||||
|
||||
private getContributors(scope: string): ActionBarContributor[] {
|
||||
return this.actionBarContributorInstances[scope] || [];
|
||||
return this.actionBarContributorInstances.get(scope) || [];
|
||||
}
|
||||
|
||||
registerActionBarContributor(scope: string, ctor: IConstructorSignature0<ActionBarContributor>): void {
|
||||
|
||||
222
src/vs/workbench/browser/actions/developerActions.ts
Normal file
@@ -0,0 +1,222 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { Action } from 'vs/base/common/actions';
|
||||
import { IWindowService } from 'vs/platform/windows/common/windows';
|
||||
import * as nls from 'vs/nls';
|
||||
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
||||
import { domEvent } from 'vs/base/browser/event';
|
||||
import { Event } from 'vs/base/common/event';
|
||||
import { IDisposable, toDisposable, dispose, Disposable, DisposableStore } from 'vs/base/common/lifecycle';
|
||||
import { getDomNodePagePosition, createStyleSheet, createCSSRule, append, $ } from 'vs/base/browser/dom';
|
||||
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { Context } from 'vs/platform/contextkey/browser/contextKeyService';
|
||||
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
|
||||
import { timeout } from 'vs/base/common/async';
|
||||
import { IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService';
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { SyncActionDescriptor } from 'vs/platform/actions/common/actions';
|
||||
import { IWorkbenchActionRegistry, Extensions } from 'vs/workbench/common/actions';
|
||||
import { IStorageService } from 'vs/platform/storage/common/storage';
|
||||
|
||||
export class InspectContextKeysAction extends Action {
|
||||
|
||||
static readonly ID = 'workbench.action.inspectContextKeys';
|
||||
static LABEL = nls.localize('inspect context keys', "Inspect Context Keys");
|
||||
|
||||
constructor(
|
||||
id: string,
|
||||
label: string,
|
||||
@IContextKeyService private readonly contextKeyService: IContextKeyService,
|
||||
@IWindowService private readonly windowService: IWindowService,
|
||||
) {
|
||||
super(id, label);
|
||||
}
|
||||
|
||||
run(): Promise<void> {
|
||||
const disposables = new DisposableStore();
|
||||
|
||||
const stylesheet = createStyleSheet();
|
||||
disposables.add(toDisposable(() => {
|
||||
if (stylesheet.parentNode) {
|
||||
stylesheet.parentNode.removeChild(stylesheet);
|
||||
}
|
||||
}));
|
||||
createCSSRule('*', 'cursor: crosshair !important;', stylesheet);
|
||||
|
||||
const hoverFeedback = document.createElement('div');
|
||||
document.body.appendChild(hoverFeedback);
|
||||
disposables.add(toDisposable(() => document.body.removeChild(hoverFeedback)));
|
||||
|
||||
hoverFeedback.style.position = 'absolute';
|
||||
hoverFeedback.style.pointerEvents = 'none';
|
||||
hoverFeedback.style.backgroundColor = 'rgba(255, 0, 0, 0.5)';
|
||||
hoverFeedback.style.zIndex = '1000';
|
||||
|
||||
const onMouseMove = domEvent(document.body, 'mousemove', true);
|
||||
disposables.add(onMouseMove(e => {
|
||||
const target = e.target as HTMLElement;
|
||||
const position = getDomNodePagePosition(target);
|
||||
|
||||
hoverFeedback.style.top = `${position.top}px`;
|
||||
hoverFeedback.style.left = `${position.left}px`;
|
||||
hoverFeedback.style.width = `${position.width}px`;
|
||||
hoverFeedback.style.height = `${position.height}px`;
|
||||
}));
|
||||
|
||||
const onMouseDown = Event.once(domEvent(document.body, 'mousedown', true));
|
||||
onMouseDown(e => { e.preventDefault(); e.stopPropagation(); }, null, disposables);
|
||||
|
||||
const onMouseUp = Event.once(domEvent(document.body, 'mouseup', true));
|
||||
onMouseUp(e => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
||||
const context = this.contextKeyService.getContext(e.target as HTMLElement) as Context;
|
||||
console.log(context.collectAllValues());
|
||||
this.windowService.openDevTools();
|
||||
|
||||
dispose(disposables);
|
||||
}, null, disposables);
|
||||
|
||||
return Promise.resolve();
|
||||
}
|
||||
}
|
||||
|
||||
export class ToggleScreencastModeAction extends Action {
|
||||
|
||||
static readonly ID = 'workbench.action.toggleScreencastMode';
|
||||
static LABEL = nls.localize('toggle screencast mode', "Toggle Screencast Mode");
|
||||
|
||||
static disposable: IDisposable | undefined;
|
||||
|
||||
constructor(
|
||||
id: string,
|
||||
label: string,
|
||||
@IKeybindingService private readonly keybindingService: IKeybindingService,
|
||||
@IWorkbenchLayoutService private readonly layoutService: IWorkbenchLayoutService
|
||||
) {
|
||||
super(id, label);
|
||||
}
|
||||
|
||||
async run(): Promise<void> {
|
||||
if (ToggleScreencastModeAction.disposable) {
|
||||
ToggleScreencastModeAction.disposable.dispose();
|
||||
ToggleScreencastModeAction.disposable = undefined;
|
||||
return;
|
||||
}
|
||||
|
||||
const container = this.layoutService.getWorkbenchElement();
|
||||
|
||||
const mouseMarker = append(container, $('div'));
|
||||
mouseMarker.style.position = 'absolute';
|
||||
mouseMarker.style.border = '2px solid red';
|
||||
mouseMarker.style.borderRadius = '20px';
|
||||
mouseMarker.style.width = '20px';
|
||||
mouseMarker.style.height = '20px';
|
||||
mouseMarker.style.top = '0';
|
||||
mouseMarker.style.left = '0';
|
||||
mouseMarker.style.zIndex = '100000';
|
||||
mouseMarker.style.content = ' ';
|
||||
mouseMarker.style.pointerEvents = 'none';
|
||||
mouseMarker.style.display = 'none';
|
||||
|
||||
const onMouseDown = domEvent(container, 'mousedown', true);
|
||||
const onMouseUp = domEvent(container, 'mouseup', true);
|
||||
const onMouseMove = domEvent(container, 'mousemove', true);
|
||||
|
||||
const mouseListener = onMouseDown(e => {
|
||||
mouseMarker.style.top = `${e.clientY - 10}px`;
|
||||
mouseMarker.style.left = `${e.clientX - 10}px`;
|
||||
mouseMarker.style.display = 'block';
|
||||
|
||||
const mouseMoveListener = onMouseMove(e => {
|
||||
mouseMarker.style.top = `${e.clientY - 10}px`;
|
||||
mouseMarker.style.left = `${e.clientX - 10}px`;
|
||||
});
|
||||
|
||||
Event.once(onMouseUp)(() => {
|
||||
mouseMarker.style.display = 'none';
|
||||
mouseMoveListener.dispose();
|
||||
});
|
||||
});
|
||||
|
||||
const keyboardMarker = append(container, $('div'));
|
||||
keyboardMarker.style.position = 'absolute';
|
||||
keyboardMarker.style.backgroundColor = 'rgba(0, 0, 0 ,0.5)';
|
||||
keyboardMarker.style.width = '100%';
|
||||
keyboardMarker.style.height = '100px';
|
||||
keyboardMarker.style.bottom = '20%';
|
||||
keyboardMarker.style.left = '0';
|
||||
keyboardMarker.style.zIndex = '100000';
|
||||
keyboardMarker.style.pointerEvents = 'none';
|
||||
keyboardMarker.style.color = 'white';
|
||||
keyboardMarker.style.lineHeight = '100px';
|
||||
keyboardMarker.style.textAlign = 'center';
|
||||
keyboardMarker.style.fontSize = '56px';
|
||||
keyboardMarker.style.display = 'none';
|
||||
|
||||
const onKeyDown = domEvent(container, 'keydown', true);
|
||||
let keyboardTimeout: IDisposable = Disposable.None;
|
||||
|
||||
const keyboardListener = onKeyDown(e => {
|
||||
keyboardTimeout.dispose();
|
||||
|
||||
const event = new StandardKeyboardEvent(e);
|
||||
const keybinding = this.keybindingService.resolveKeyboardEvent(event);
|
||||
const label = keybinding.getLabel();
|
||||
|
||||
if (!event.ctrlKey && !event.altKey && !event.metaKey && !event.shiftKey && this.keybindingService.mightProducePrintableCharacter(event) && label) {
|
||||
keyboardMarker.textContent += ' ' + label;
|
||||
} else {
|
||||
keyboardMarker.textContent = label;
|
||||
}
|
||||
|
||||
keyboardMarker.style.display = 'block';
|
||||
|
||||
const promise = timeout(800);
|
||||
keyboardTimeout = toDisposable(() => promise.cancel());
|
||||
|
||||
promise.then(() => {
|
||||
keyboardMarker.textContent = '';
|
||||
keyboardMarker.style.display = 'none';
|
||||
});
|
||||
});
|
||||
|
||||
ToggleScreencastModeAction.disposable = toDisposable(() => {
|
||||
mouseListener.dispose();
|
||||
keyboardListener.dispose();
|
||||
mouseMarker.remove();
|
||||
keyboardMarker.remove();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export class LogStorageAction extends Action {
|
||||
|
||||
static readonly ID = 'workbench.action.logStorage';
|
||||
static LABEL = nls.localize({ key: 'logStorage', comment: ['A developer only action to log the contents of the storage for the current window.'] }, "Log Storage Database Contents");
|
||||
|
||||
constructor(
|
||||
id: string,
|
||||
label: string,
|
||||
@IStorageService private readonly storageService: IStorageService,
|
||||
@IWindowService private readonly windowService: IWindowService
|
||||
) {
|
||||
super(id, label);
|
||||
}
|
||||
|
||||
run(): Promise<void> {
|
||||
this.storageService.logStorage();
|
||||
|
||||
return this.windowService.openDevTools();
|
||||
}
|
||||
}
|
||||
|
||||
const developerCategory = nls.localize('developer', "Developer");
|
||||
const registry = Registry.as<IWorkbenchActionRegistry>(Extensions.WorkbenchActions);
|
||||
registry.registerWorkbenchAction(new SyncActionDescriptor(InspectContextKeysAction, InspectContextKeysAction.ID, InspectContextKeysAction.LABEL), 'Developer: Inspect Context Keys', developerCategory);
|
||||
registry.registerWorkbenchAction(new SyncActionDescriptor(ToggleScreencastModeAction, ToggleScreencastModeAction.ID, ToggleScreencastModeAction.LABEL), 'Developer: Toggle Screencast Mode', developerCategory);
|
||||
registry.registerWorkbenchAction(new SyncActionDescriptor(LogStorageAction, LogStorageAction.ID, LogStorageAction.LABEL), 'Developer: Log Storage Database Contents', developerCategory);
|
||||
@@ -16,13 +16,14 @@ import { CommandsRegistry } from 'vs/platform/commands/common/commands';
|
||||
import { IEditorGroupsService, GroupOrientation } from 'vs/workbench/services/editor/common/editorGroupsService';
|
||||
import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { KeyMod, KeyCode, KeyChord } from 'vs/base/common/keyCodes';
|
||||
import { dispose, IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { DisposableStore } from 'vs/base/common/lifecycle';
|
||||
import { MenuBarVisibility } from 'vs/platform/windows/common/windows';
|
||||
import { isWindows, isLinux } from 'vs/base/common/platform';
|
||||
import { IsMacContext } from 'vs/workbench/browser/contextkeys';
|
||||
import { isWindows, isLinux, isWeb } from 'vs/base/common/platform';
|
||||
import { IsMacNativeContext } from 'vs/workbench/browser/contextkeys';
|
||||
import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
|
||||
import { InEditorZenModeContext } from 'vs/workbench/common/editor';
|
||||
import { InEditorZenModeContext, IsCenteredLayoutContext } from 'vs/workbench/common/editor';
|
||||
import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { SideBarVisibleContext } from 'vs/workbench/common/viewlet';
|
||||
|
||||
const registry = Registry.as<IWorkbenchActionRegistry>(Extensions.WorkbenchActions);
|
||||
const viewCategory = nls.localize('view', "View");
|
||||
@@ -61,7 +62,8 @@ MenuRegistry.appendMenuItem(MenuId.MenubarAppearanceMenu, {
|
||||
group: '2_workbench_layout',
|
||||
command: {
|
||||
id: ToggleActivityBarVisibilityAction.ID,
|
||||
title: nls.localize({ key: 'miToggleActivityBar', comment: ['&& denotes a mnemonic'] }, "Toggle &&Activity Bar")
|
||||
title: nls.localize({ key: 'miShowActivityBar', comment: ['&& denotes a mnemonic'] }, "Show &&Activity Bar"),
|
||||
toggled: ContextKeyExpr.equals('config.workbench.activityBar.visible', true)
|
||||
},
|
||||
order: 4
|
||||
});
|
||||
@@ -95,7 +97,8 @@ MenuRegistry.appendMenuItem(MenuId.MenubarAppearanceMenu, {
|
||||
group: '1_toggle_view',
|
||||
command: {
|
||||
id: ToggleCenteredLayout.ID,
|
||||
title: nls.localize('miToggleCenteredLayout', "Toggle Centered Layout")
|
||||
title: nls.localize('miToggleCenteredLayout', "Centered Layout"),
|
||||
toggled: IsCenteredLayoutContext
|
||||
},
|
||||
order: 3
|
||||
});
|
||||
@@ -107,7 +110,7 @@ export class ToggleEditorLayoutAction extends Action {
|
||||
static readonly ID = 'workbench.action.toggleEditorGroupLayout';
|
||||
static readonly LABEL = nls.localize('flipLayout', "Toggle Vertical/Horizontal Editor Layout");
|
||||
|
||||
private toDispose: IDisposable[];
|
||||
private readonly toDispose = this._register(new DisposableStore());
|
||||
|
||||
constructor(
|
||||
id: string,
|
||||
@@ -116,8 +119,6 @@ export class ToggleEditorLayoutAction extends Action {
|
||||
) {
|
||||
super(id, label);
|
||||
|
||||
this.toDispose = [];
|
||||
|
||||
this.class = 'flip-editor-layout';
|
||||
this.updateEnablement();
|
||||
|
||||
@@ -125,8 +126,8 @@ export class ToggleEditorLayoutAction extends Action {
|
||||
}
|
||||
|
||||
private registerListeners(): void {
|
||||
this.toDispose.push(this.editorGroupService.onDidAddGroup(() => this.updateEnablement()));
|
||||
this.toDispose.push(this.editorGroupService.onDidRemoveGroup(() => this.updateEnablement()));
|
||||
this.toDispose.add(this.editorGroupService.onDidAddGroup(() => this.updateEnablement()));
|
||||
this.toDispose.add(this.editorGroupService.onDidRemoveGroup(() => this.updateEnablement()));
|
||||
}
|
||||
|
||||
private updateEnablement(): void {
|
||||
@@ -139,12 +140,6 @@ export class ToggleEditorLayoutAction extends Action {
|
||||
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
this.toDispose = dispose(this.toDispose);
|
||||
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
CommandsRegistry.registerCommand('_workbench.editor.setGroupOrientation', function (accessor: ServicesAccessor, args: [GroupOrientation]) {
|
||||
@@ -157,7 +152,7 @@ CommandsRegistry.registerCommand('_workbench.editor.setGroupOrientation', functi
|
||||
});
|
||||
|
||||
const group = viewCategory;
|
||||
registry.registerWorkbenchAction(new SyncActionDescriptor(ToggleEditorLayoutAction, ToggleEditorLayoutAction.ID, ToggleEditorLayoutAction.LABEL, { primary: KeyMod.Shift | KeyMod.Alt | KeyCode.KEY_0, mac: { primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.KEY_0 } }), 'View: Flip Editor Group Layout', group);
|
||||
registry.registerWorkbenchAction(new SyncActionDescriptor(ToggleEditorLayoutAction, ToggleEditorLayoutAction.ID, ToggleEditorLayoutAction.LABEL, { primary: KeyMod.Shift | KeyMod.Alt | KeyCode.KEY_0, mac: { primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.KEY_0 } }), 'View: Toggle Vertical/Horizontal Editor Layout', group);
|
||||
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarLayoutMenu, {
|
||||
group: 'z_flip',
|
||||
@@ -203,11 +198,22 @@ export class ToggleSidebarPositionAction extends Action {
|
||||
registry.registerWorkbenchAction(new SyncActionDescriptor(ToggleSidebarPositionAction, ToggleSidebarPositionAction.ID, ToggleSidebarPositionAction.LABEL), 'View: Toggle Side Bar Position', viewCategory);
|
||||
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarAppearanceMenu, {
|
||||
group: '2_workbench_layout',
|
||||
group: '3_workbench_layout_move',
|
||||
command: {
|
||||
id: ToggleSidebarPositionAction.ID,
|
||||
title: nls.localize({ key: 'miMoveSidebarLeftRight', comment: ['&& denotes a mnemonic'] }, "&&Move Side Bar Left/Right")
|
||||
title: nls.localize({ key: 'miMoveSidebarRight', comment: ['&& denotes a mnemonic'] }, "&&Move Side Bar Right")
|
||||
},
|
||||
when: ContextKeyExpr.notEquals('config.workbench.sideBar.location', 'right'),
|
||||
order: 2
|
||||
});
|
||||
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarAppearanceMenu, {
|
||||
group: '3_workbench_layout_move',
|
||||
command: {
|
||||
id: ToggleSidebarPositionAction.ID,
|
||||
title: nls.localize({ key: 'miMoveSidebarLeft', comment: ['&& denotes a mnemonic'] }, "&&Move Side Bar Left")
|
||||
},
|
||||
when: ContextKeyExpr.equals('config.workbench.sideBar.location', 'right'),
|
||||
order: 2
|
||||
});
|
||||
|
||||
@@ -262,18 +268,26 @@ export class ToggleSidebarVisibilityAction extends Action {
|
||||
|
||||
registry.registerWorkbenchAction(new SyncActionDescriptor(ToggleSidebarVisibilityAction, ToggleSidebarVisibilityAction.ID, ToggleSidebarVisibilityAction.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.KEY_B }), 'View: Toggle Side Bar Visibility', viewCategory);
|
||||
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarViewMenu, {
|
||||
group: '2_appearance',
|
||||
title: nls.localize({ key: 'miAppearance', comment: ['&& denotes a mnemonic'] }, "&&Appearance"),
|
||||
submenu: MenuId.MenubarAppearanceMenu,
|
||||
order: 1
|
||||
});
|
||||
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarAppearanceMenu, {
|
||||
group: '2_workbench_layout',
|
||||
command: {
|
||||
id: ToggleSidebarVisibilityAction.ID,
|
||||
title: nls.localize({ key: 'miToggleSidebar', comment: ['&& denotes a mnemonic'] }, "&&Toggle Side Bar")
|
||||
title: nls.localize({ key: 'miShowSidebar', comment: ['&& denotes a mnemonic'] }, "Show &&Side Bar"),
|
||||
toggled: SideBarVisibleContext
|
||||
},
|
||||
order: 1
|
||||
});
|
||||
|
||||
// --- Toggle Statusbar Visibility
|
||||
|
||||
class ToggleStatusbarVisibilityAction extends Action {
|
||||
export class ToggleStatusbarVisibilityAction extends Action {
|
||||
|
||||
static readonly ID = 'workbench.action.toggleStatusbarVisibility';
|
||||
static readonly LABEL = nls.localize('toggleStatusbar', "Toggle Status Bar Visibility");
|
||||
@@ -305,7 +319,8 @@ MenuRegistry.appendMenuItem(MenuId.MenubarAppearanceMenu, {
|
||||
group: '2_workbench_layout',
|
||||
command: {
|
||||
id: ToggleStatusbarVisibilityAction.ID,
|
||||
title: nls.localize({ key: 'miToggleStatusbar', comment: ['&& denotes a mnemonic'] }, "&&Toggle Status Bar")
|
||||
title: nls.localize({ key: 'miShowStatusbar', comment: ['&& denotes a mnemonic'] }, "Show S&&tatus Bar"),
|
||||
toggled: ContextKeyExpr.equals('config.workbench.statusBar.visible', true)
|
||||
},
|
||||
order: 3
|
||||
});
|
||||
@@ -370,7 +385,8 @@ MenuRegistry.appendMenuItem(MenuId.MenubarAppearanceMenu, {
|
||||
group: '1_toggle_view',
|
||||
command: {
|
||||
id: ToggleZenMode.ID,
|
||||
title: nls.localize('miToggleZenMode', "Toggle Zen Mode")
|
||||
title: nls.localize('miToggleZenMode', "Zen Mode"),
|
||||
toggled: InEditorZenModeContext
|
||||
},
|
||||
order: 2
|
||||
});
|
||||
@@ -422,18 +438,19 @@ export class ToggleMenuBarAction extends Action {
|
||||
}
|
||||
}
|
||||
|
||||
if (isWindows || isLinux) {
|
||||
if (isWindows || isLinux || isWeb) {
|
||||
registry.registerWorkbenchAction(new SyncActionDescriptor(ToggleMenuBarAction, ToggleMenuBarAction.ID, ToggleMenuBarAction.LABEL), 'View: Toggle Menu Bar', viewCategory);
|
||||
}
|
||||
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarAppearanceMenu, {
|
||||
group: '1_toggle_view',
|
||||
group: '2_workbench_layout',
|
||||
command: {
|
||||
id: ToggleMenuBarAction.ID,
|
||||
title: nls.localize({ key: 'miToggleMenuBar', comment: ['&& denotes a mnemonic'] }, "Toggle Menu &&Bar")
|
||||
title: nls.localize({ key: 'miShowMenuBar', comment: ['&& denotes a mnemonic'] }, "Show Menu &&Bar"),
|
||||
toggled: ContextKeyExpr.and(IsMacNativeContext.toNegated(), ContextKeyExpr.notEquals('config.window.menuBarVisibility', 'hidden'), ContextKeyExpr.notEquals('config.window.menuBarVisibility', 'toggle'))
|
||||
},
|
||||
when: IsMacContext.toNegated(),
|
||||
order: 4
|
||||
when: IsMacNativeContext.toNegated(),
|
||||
order: 0
|
||||
});
|
||||
|
||||
// --- Resize View
|
||||
|
||||
@@ -603,7 +603,17 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({
|
||||
const focus = list.getFocus();
|
||||
|
||||
if (focus.length > 0) {
|
||||
list.toggleCollapsed(focus[0]);
|
||||
let toggleCollapsed = true;
|
||||
|
||||
if (list.expandOnlyOnTwistieClick === true) {
|
||||
toggleCollapsed = false;
|
||||
} else if (typeof list.expandOnlyOnTwistieClick !== 'boolean' && list.expandOnlyOnTwistieClick(focus[0])) {
|
||||
toggleCollapsed = false;
|
||||
}
|
||||
|
||||
if (toggleCollapsed) {
|
||||
list.toggleCollapsed(focus[0]);
|
||||
}
|
||||
}
|
||||
|
||||
list.setSelection(focus, fakeKeyboardEvent);
|
||||
|
||||
@@ -4,10 +4,22 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
.vs .monaco-workbench .flip-editor-layout {
|
||||
background-image: url('editor-layout.svg');
|
||||
background-image: url('layout-light.svg');
|
||||
}
|
||||
|
||||
.vs-dark .monaco-workbench .flip-editor-layout,
|
||||
.hc-black .monaco-workbench .flip-editor-layout {
|
||||
background-image: url('editor-layout-inverse.svg') !important;
|
||||
.vs-dark .monaco-workbench .flip-editor-layout {
|
||||
background-image: url('layout-dark.svg');
|
||||
}
|
||||
|
||||
.hc-black .monaco-workbench .flip-editor-layout {
|
||||
background-image: url('layout-hc.svg');
|
||||
}
|
||||
|
||||
.vs .action-remove-from-recently-opened {
|
||||
background: url("remove-light.svg") center center no-repeat;
|
||||
}
|
||||
|
||||
.vs-dark .action-remove-from-recently-opened,
|
||||
.hc-black .action-remove-from-recently-opened {
|
||||
background: url("remove-dark.svg") center center no-repeat;
|
||||
}
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><style>.icon-canvas-transparent{opacity:0;fill:#2d2d30}.icon-vs-out{fill:#2d2d30}.icon-vs-bg{fill:#c5c5c5}.icon-vs-fg{fill:#2b282e}</style><path class="icon-canvas-transparent" d="M16 16H0V0h16v16z" id="canvas"/><path class="icon-vs-out" d="M0 16V0h11v6h5v10H0z" id="outline" style="display: none;"/><path class="icon-vs-fg" d="M4 14H2V4h7v3H4v7zm10 0H5v-4h9v4z" id="iconFg" style="display: none;"/><path class="icon-vs-bg" d="M10 7V1H1v14h14V7h-5zm-6 7H2V4h7v3H4v7zm10 0H5v-4h9v4z" id="iconBg"/></svg>
|
||||
|
Before Width: | Height: | Size: 562 B |
@@ -1 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><style>.icon-canvas-transparent{opacity:0;fill:#f6f6f6}.icon-vs-out{fill:#f6f6f6}.icon-vs-bg{fill:#424242}.icon-vs-fg{fill:#f0eff1}</style><path class="icon-canvas-transparent" d="M16 16H0V0h16v16z" id="canvas"/><path class="icon-vs-out" d="M0 16V0h11v6h5v10H0z" id="outline" style="display: none;"/><path class="icon-vs-fg" d="M4 14H2V4h7v3H4v7zm10 0H5v-4h9v4z" id="iconFg" style="display: none;"/><path class="icon-vs-bg" d="M10 7V1H1v14h14V7h-5zm-6 7H2V4h7v3H4v7zm10 0H5v-4h9v4z" id="iconBg"/></svg>
|
||||
|
Before Width: | Height: | Size: 562 B |
3
src/vs/workbench/browser/actions/media/layout-dark.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M15 6.49999L14.5302 5.99999H7V1.4698L6.5302 1H1.4698L1 1.4698V9.53019L1.4698 9.99999H4V14.5302L4.4698 15H14.5302L15 14.5302V6.49999ZM2 8.99999V3H6V8.99999H2ZM14 14H5V9.99999H6.5302L7 9.53019V8.01341H14V14Z" fill="#C5C5C5"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 336 B |
3
src/vs/workbench/browser/actions/media/layout-hc.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M15 6.49999L14.5302 5.99999H7V1.4698L6.5302 1H1.4698L1 1.4698V9.53019L1.4698 9.99999H4V14.5302L4.4698 15H14.5302L15 14.5302V6.49999ZM2 8.99999V3H6V8.99999H2ZM14 14H5V9.99999H6.5302L7 9.53019V8.01341H14V14Z" fill="white"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 334 B |
3
src/vs/workbench/browser/actions/media/layout-light.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M15 6.49999L14.5302 5.99999H7V1.4698L6.5302 1H1.4698L1 1.4698V9.53019L1.4698 9.99999H4V14.5302L4.4698 15H14.5302L15 14.5302V6.49999ZM2 8.99999V3H6V8.99999H2ZM14 14H5V9.99999H6.5302L7 9.53019V8.01341H14V14Z" fill="#424242"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 336 B |
3
src/vs/workbench/browser/actions/media/remove-dark.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M7.99998 8.70711L11.6464 12.3536L12.3535 11.6464L8.70708 8L12.3535 4.35355L11.6464 3.64645L7.99998 7.29289L4.35353 3.64645L3.64642 4.35355L7.29287 8L3.64642 11.6464L4.35353 12.3536L7.99998 8.70711Z" fill="#C5C5C5"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 368 B |
3
src/vs/workbench/browser/actions/media/remove-light.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M7.99998 8.70711L11.6464 12.3536L12.3535 11.6465L8.70708 8.00001L12.3535 4.35356L11.6464 3.64645L7.99998 7.2929L4.35353 3.64645L3.64642 4.35356L7.29287 8.00001L3.64642 11.6465L4.35353 12.3536L7.99998 8.70711Z" fill="#424242"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 379 B |
300
src/vs/workbench/browser/actions/windowActions.ts
Normal file
@@ -0,0 +1,300 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import 'vs/css!./media/actions';
|
||||
|
||||
import * as nls from 'vs/nls';
|
||||
import { Action } from 'vs/base/common/actions';
|
||||
import { IWindowService, IURIToOpen } from 'vs/platform/windows/common/windows';
|
||||
import { SyncActionDescriptor, MenuRegistry, MenuId } from 'vs/platform/actions/common/actions';
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { KeyCode, KeyMod } from 'vs/base/common/keyCodes';
|
||||
import { IsFullscreenContext, IsDevelopmentContext } from 'vs/workbench/browser/contextkeys';
|
||||
import { IWorkbenchActionRegistry, Extensions } from 'vs/workbench/common/actions';
|
||||
import { IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService';
|
||||
import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
|
||||
import { IQuickInputButton, IQuickInputService, IQuickPickSeparator } from 'vs/platform/quickinput/common/quickInput';
|
||||
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
|
||||
import { ILabelService } from 'vs/platform/label/common/label';
|
||||
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
||||
import { IModelService } from 'vs/editor/common/services/modelService';
|
||||
import { IModeService } from 'vs/editor/common/services/modeService';
|
||||
import { IRecentWorkspace, IRecentFolder, IRecentFile, IRecent, isRecentFolder, isRecentWorkspace } from 'vs/platform/history/common/history';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { getIconClasses } from 'vs/editor/common/services/getIconClasses';
|
||||
import { FileKind } from 'vs/platform/files/common/files';
|
||||
import { splitName } from 'vs/base/common/labels';
|
||||
import { IKeyMods } from 'vs/base/parts/quickopen/common/quickOpen';
|
||||
import { isMacintosh } from 'vs/base/common/platform';
|
||||
import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { inQuickOpenContext, getQuickNavigateHandler } from 'vs/workbench/browser/parts/quickopen/quickopen';
|
||||
|
||||
export const inRecentFilesPickerContextKey = 'inRecentFilesPicker';
|
||||
|
||||
abstract class BaseOpenRecentAction extends Action {
|
||||
|
||||
private removeFromRecentlyOpened: IQuickInputButton = {
|
||||
iconClass: 'action-remove-from-recently-opened',
|
||||
tooltip: nls.localize('remove', "Remove from Recently Opened")
|
||||
};
|
||||
|
||||
constructor(
|
||||
id: string,
|
||||
label: string,
|
||||
private windowService: IWindowService,
|
||||
private quickInputService: IQuickInputService,
|
||||
private contextService: IWorkspaceContextService,
|
||||
private labelService: ILabelService,
|
||||
private keybindingService: IKeybindingService,
|
||||
private modelService: IModelService,
|
||||
private modeService: IModeService,
|
||||
) {
|
||||
super(id, label);
|
||||
}
|
||||
|
||||
protected abstract isQuickNavigate(): boolean;
|
||||
|
||||
async run(): Promise<void> {
|
||||
const { workspaces, files } = await this.windowService.getRecentlyOpened();
|
||||
|
||||
this.openRecent(workspaces, files);
|
||||
}
|
||||
|
||||
private async openRecent(recentWorkspaces: Array<IRecentWorkspace | IRecentFolder>, recentFiles: IRecentFile[]): Promise<void> {
|
||||
|
||||
const toPick = (recent: IRecent, labelService: ILabelService, buttons: IQuickInputButton[] | undefined) => {
|
||||
let uriToOpen: IURIToOpen | undefined;
|
||||
let iconClasses: string[];
|
||||
let fullLabel: string | undefined;
|
||||
let resource: URI | undefined;
|
||||
|
||||
// Folder
|
||||
if (isRecentFolder(recent)) {
|
||||
resource = recent.folderUri;
|
||||
iconClasses = getIconClasses(this.modelService, this.modeService, resource, FileKind.FOLDER);
|
||||
uriToOpen = { folderUri: resource };
|
||||
fullLabel = recent.label || labelService.getWorkspaceLabel(resource, { verbose: true });
|
||||
}
|
||||
|
||||
// Workspace
|
||||
else if (isRecentWorkspace(recent)) {
|
||||
resource = recent.workspace.configPath;
|
||||
iconClasses = getIconClasses(this.modelService, this.modeService, resource, FileKind.ROOT_FOLDER);
|
||||
uriToOpen = { workspaceUri: resource };
|
||||
fullLabel = recent.label || labelService.getWorkspaceLabel(recent.workspace, { verbose: true });
|
||||
}
|
||||
|
||||
// File
|
||||
else {
|
||||
resource = recent.fileUri;
|
||||
iconClasses = getIconClasses(this.modelService, this.modeService, resource, FileKind.FILE);
|
||||
uriToOpen = { fileUri: resource };
|
||||
fullLabel = recent.label || labelService.getUriLabel(resource);
|
||||
}
|
||||
|
||||
const { name, parentPath } = splitName(fullLabel);
|
||||
|
||||
return {
|
||||
iconClasses,
|
||||
label: name,
|
||||
description: parentPath,
|
||||
buttons,
|
||||
uriToOpen,
|
||||
resource
|
||||
};
|
||||
};
|
||||
|
||||
const workspacePicks = recentWorkspaces.map(workspace => toPick(workspace, this.labelService, !this.isQuickNavigate() ? [this.removeFromRecentlyOpened] : undefined));
|
||||
const filePicks = recentFiles.map(p => toPick(p, this.labelService, !this.isQuickNavigate() ? [this.removeFromRecentlyOpened] : undefined));
|
||||
|
||||
// focus second entry if the first recent workspace is the current workspace
|
||||
const firstEntry = recentWorkspaces[0];
|
||||
let autoFocusSecondEntry: boolean = firstEntry && this.contextService.isCurrentWorkspace(isRecentWorkspace(firstEntry) ? firstEntry.workspace : firstEntry.folderUri);
|
||||
|
||||
let keyMods: IKeyMods | undefined;
|
||||
|
||||
const workspaceSeparator: IQuickPickSeparator = { type: 'separator', label: nls.localize('workspaces', "workspaces") };
|
||||
const fileSeparator: IQuickPickSeparator = { type: 'separator', label: nls.localize('files', "files") };
|
||||
const picks = [workspaceSeparator, ...workspacePicks, fileSeparator, ...filePicks];
|
||||
|
||||
const pick = await this.quickInputService.pick(picks, {
|
||||
contextKey: inRecentFilesPickerContextKey,
|
||||
activeItem: [...workspacePicks, ...filePicks][autoFocusSecondEntry ? 1 : 0],
|
||||
placeHolder: isMacintosh ? nls.localize('openRecentPlaceHolderMac', "Select to open (hold Cmd-key to open in new window)") : nls.localize('openRecentPlaceHolder', "Select to open (hold Ctrl-key to open in new window)"),
|
||||
matchOnDescription: true,
|
||||
onKeyMods: mods => keyMods = mods,
|
||||
quickNavigate: this.isQuickNavigate() ? { keybindings: this.keybindingService.lookupKeybindings(this.id) } : undefined,
|
||||
onDidTriggerItemButton: async context => {
|
||||
await this.windowService.removeFromRecentlyOpened([context.item.resource]);
|
||||
context.removeItem();
|
||||
}
|
||||
});
|
||||
|
||||
if (pick) {
|
||||
return this.windowService.openWindow([pick.uriToOpen], { forceNewWindow: keyMods && keyMods.ctrlCmd });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class OpenRecentAction extends BaseOpenRecentAction {
|
||||
|
||||
static readonly ID = 'workbench.action.openRecent';
|
||||
static readonly LABEL = nls.localize('openRecent', "Open Recent...");
|
||||
|
||||
constructor(
|
||||
id: string,
|
||||
label: string,
|
||||
@IWindowService windowService: IWindowService,
|
||||
@IQuickInputService quickInputService: IQuickInputService,
|
||||
@IWorkspaceContextService contextService: IWorkspaceContextService,
|
||||
@IKeybindingService keybindingService: IKeybindingService,
|
||||
@IModelService modelService: IModelService,
|
||||
@IModeService modeService: IModeService,
|
||||
@ILabelService labelService: ILabelService
|
||||
) {
|
||||
super(id, label, windowService, quickInputService, contextService, labelService, keybindingService, modelService, modeService);
|
||||
}
|
||||
|
||||
protected isQuickNavigate(): boolean {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
export class QuickOpenRecentAction extends BaseOpenRecentAction {
|
||||
|
||||
static readonly ID = 'workbench.action.quickOpenRecent';
|
||||
static readonly LABEL = nls.localize('quickOpenRecent', "Quick Open Recent...");
|
||||
|
||||
constructor(
|
||||
id: string,
|
||||
label: string,
|
||||
@IWindowService windowService: IWindowService,
|
||||
@IQuickInputService quickInputService: IQuickInputService,
|
||||
@IWorkspaceContextService contextService: IWorkspaceContextService,
|
||||
@IKeybindingService keybindingService: IKeybindingService,
|
||||
@IModelService modelService: IModelService,
|
||||
@IModeService modeService: IModeService,
|
||||
@ILabelService labelService: ILabelService
|
||||
) {
|
||||
super(id, label, windowService, quickInputService, contextService, labelService, keybindingService, modelService, modeService);
|
||||
}
|
||||
|
||||
protected isQuickNavigate(): boolean {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
export class ToggleFullScreenAction extends Action {
|
||||
|
||||
static readonly ID = 'workbench.action.toggleFullScreen';
|
||||
static LABEL = nls.localize('toggleFullScreen', "Toggle Full Screen");
|
||||
|
||||
constructor(
|
||||
id: string,
|
||||
label: string,
|
||||
@IWindowService private readonly windowService: IWindowService,
|
||||
@IWorkbenchLayoutService private readonly layoutService: IWorkbenchLayoutService) {
|
||||
super(id, label);
|
||||
}
|
||||
|
||||
run(): Promise<void> {
|
||||
const container = this.layoutService.getWorkbenchElement();
|
||||
|
||||
return this.windowService.toggleFullScreen(container);
|
||||
}
|
||||
}
|
||||
|
||||
export class ReloadWindowAction extends Action {
|
||||
|
||||
static readonly ID = 'workbench.action.reloadWindow';
|
||||
static LABEL = nls.localize('reloadWindow', "Reload Window");
|
||||
|
||||
constructor(
|
||||
id: string,
|
||||
label: string,
|
||||
@IWindowService private readonly windowService: IWindowService
|
||||
) {
|
||||
super(id, label);
|
||||
}
|
||||
|
||||
async run(): Promise<boolean> {
|
||||
await this.windowService.reloadWindow();
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
const registry = Registry.as<IWorkbenchActionRegistry>(Extensions.WorkbenchActions);
|
||||
|
||||
// --- Actions Registration
|
||||
|
||||
const fileCategory = nls.localize('file', "File");
|
||||
registry.registerWorkbenchAction(new SyncActionDescriptor(QuickOpenRecentAction, QuickOpenRecentAction.ID, QuickOpenRecentAction.LABEL), 'File: Quick Open Recent...', fileCategory);
|
||||
registry.registerWorkbenchAction(new SyncActionDescriptor(OpenRecentAction, OpenRecentAction.ID, OpenRecentAction.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.KEY_R, mac: { primary: KeyMod.WinCtrl | KeyCode.KEY_R } }), 'File: Open Recent...', fileCategory);
|
||||
|
||||
const viewCategory = nls.localize('view', "View");
|
||||
registry.registerWorkbenchAction(new SyncActionDescriptor(ToggleFullScreenAction, ToggleFullScreenAction.ID, ToggleFullScreenAction.LABEL, { primary: KeyCode.F11, mac: { primary: KeyMod.CtrlCmd | KeyMod.WinCtrl | KeyCode.KEY_F } }), 'View: Toggle Full Screen', viewCategory);
|
||||
|
||||
const developerCategory = nls.localize('developer', "Developer");
|
||||
registry.registerWorkbenchAction(new SyncActionDescriptor(ReloadWindowAction, ReloadWindowAction.ID, ReloadWindowAction.LABEL), 'Developer: Reload Window', developerCategory);
|
||||
|
||||
// --- Commands/Keybindings Registration
|
||||
|
||||
const recentFilesPickerContext = ContextKeyExpr.and(inQuickOpenContext, ContextKeyExpr.has(inRecentFilesPickerContextKey));
|
||||
|
||||
const quickOpenNavigateNextInRecentFilesPickerId = 'workbench.action.quickOpenNavigateNextInRecentFilesPicker';
|
||||
KeybindingsRegistry.registerCommandAndKeybindingRule({
|
||||
id: quickOpenNavigateNextInRecentFilesPickerId,
|
||||
weight: KeybindingWeight.WorkbenchContrib + 50,
|
||||
handler: getQuickNavigateHandler(quickOpenNavigateNextInRecentFilesPickerId, true),
|
||||
when: recentFilesPickerContext,
|
||||
primary: KeyMod.CtrlCmd | KeyCode.KEY_R,
|
||||
mac: { primary: KeyMod.WinCtrl | KeyCode.KEY_R }
|
||||
});
|
||||
|
||||
const quickOpenNavigatePreviousInRecentFilesPicker = 'workbench.action.quickOpenNavigatePreviousInRecentFilesPicker';
|
||||
KeybindingsRegistry.registerCommandAndKeybindingRule({
|
||||
id: quickOpenNavigatePreviousInRecentFilesPicker,
|
||||
weight: KeybindingWeight.WorkbenchContrib + 50,
|
||||
handler: getQuickNavigateHandler(quickOpenNavigatePreviousInRecentFilesPicker, false),
|
||||
when: recentFilesPickerContext,
|
||||
primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_R,
|
||||
mac: { primary: KeyMod.WinCtrl | KeyMod.Shift | KeyCode.KEY_R }
|
||||
});
|
||||
|
||||
KeybindingsRegistry.registerKeybindingRule({
|
||||
id: ReloadWindowAction.ID,
|
||||
weight: KeybindingWeight.WorkbenchContrib + 50,
|
||||
when: IsDevelopmentContext,
|
||||
primary: KeyMod.CtrlCmd | KeyCode.KEY_R
|
||||
});
|
||||
|
||||
// --- Menu Registration
|
||||
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarFileMenu, {
|
||||
title: nls.localize({ key: 'miOpenRecent', comment: ['&& denotes a mnemonic'] }, "Open &&Recent"),
|
||||
submenu: MenuId.MenubarRecentMenu,
|
||||
group: '2_open',
|
||||
order: 4
|
||||
});
|
||||
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarRecentMenu, {
|
||||
group: 'y_more',
|
||||
command: {
|
||||
id: OpenRecentAction.ID,
|
||||
title: nls.localize({ key: 'miMore', comment: ['&& denotes a mnemonic'] }, "&&More...")
|
||||
},
|
||||
order: 1
|
||||
});
|
||||
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarAppearanceMenu, {
|
||||
group: '1_toggle_view',
|
||||
command: {
|
||||
id: ToggleFullScreenAction.ID,
|
||||
title: nls.localize({ key: 'miToggleFullScreen', comment: ['&& denotes a mnemonic'] }, "&&Full Screen"),
|
||||
toggled: IsFullscreenContext
|
||||
},
|
||||
order: 1
|
||||
});
|
||||
@@ -11,12 +11,15 @@ import { IWorkspaceContextService, WorkbenchState, IWorkspaceFolder } from 'vs/p
|
||||
import { IWorkspaceEditingService } from 'vs/workbench/services/workspace/common/workspaceEditing';
|
||||
import { IWorkspacesService } from 'vs/platform/workspaces/common/workspaces';
|
||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { ICommandService } from 'vs/platform/commands/common/commands';
|
||||
import { ICommandService, ICommandHandler } from 'vs/platform/commands/common/commands';
|
||||
import { ADD_ROOT_FOLDER_COMMAND_ID, ADD_ROOT_FOLDER_LABEL, PICK_WORKSPACE_FOLDER_COMMAND_ID } from 'vs/workbench/browser/actions/workspaceCommands';
|
||||
import { IFileDialogService } from 'vs/platform/dialogs/common/dialogs';
|
||||
import { INotificationService } from 'vs/platform/notification/common/notification';
|
||||
import { Schemas } from 'vs/base/common/network';
|
||||
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
|
||||
import { ITextFileService, ISaveOptions } from 'vs/workbench/services/textfile/common/textfiles';
|
||||
import { toResource } from 'vs/workbench/common/editor';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
|
||||
export class OpenFileAction extends Action {
|
||||
|
||||
@@ -36,21 +39,33 @@ export class OpenFileAction extends Action {
|
||||
}
|
||||
}
|
||||
|
||||
export class OpenLocalFileAction extends Action {
|
||||
export namespace OpenLocalFileCommand {
|
||||
export const ID = 'workbench.action.files.openLocalFile';
|
||||
export const LABEL = nls.localize('openLocalFile', "Open Local File...");
|
||||
|
||||
static readonly ID = 'workbench.action.files.openLocalFile';
|
||||
static LABEL = nls.localize('openLocalFile', "Open Local File...");
|
||||
|
||||
constructor(
|
||||
id: string,
|
||||
label: string,
|
||||
@IFileDialogService private readonly dialogService: IFileDialogService
|
||||
) {
|
||||
super(id, label);
|
||||
export function handler(): ICommandHandler {
|
||||
return accessor => {
|
||||
const dialogService = accessor.get(IFileDialogService);
|
||||
return dialogService.pickFileAndOpen({ forceNewWindow: false, availableFileSystems: [Schemas.file] });
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
run(event?: any, data?: ITelemetryData): Promise<any> {
|
||||
return this.dialogService.pickFileAndOpen({ forceNewWindow: false, telemetryExtraData: data, availableFileSystems: [Schemas.file] });
|
||||
export namespace SaveLocalFileCommand {
|
||||
export const ID = 'workbench.action.files.saveLocalFile';
|
||||
export const LABEL = nls.localize('saveLocalFile', "Save Local File...");
|
||||
|
||||
export function handler(): ICommandHandler {
|
||||
return accessor => {
|
||||
const textFileService = accessor.get(ITextFileService);
|
||||
const editorService = accessor.get(IEditorService);
|
||||
let resource: URI | undefined = toResource(editorService.activeEditor);
|
||||
const options: ISaveOptions = { force: true, availableFileSystems: [Schemas.file] };
|
||||
if (resource) {
|
||||
return textFileService.saveAs(resource, undefined, options);
|
||||
}
|
||||
return Promise.resolve(undefined);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,21 +87,15 @@ export class OpenFolderAction extends Action {
|
||||
}
|
||||
}
|
||||
|
||||
export class OpenLocalFolderAction extends Action {
|
||||
export namespace OpenLocalFolderCommand {
|
||||
export const ID = 'workbench.action.files.openLocalFolder';
|
||||
export const LABEL = nls.localize('openLocalFolder', "Open Local Folder...");
|
||||
|
||||
static readonly ID = 'workbench.action.files.openLocalFolder';
|
||||
static LABEL = nls.localize('openLocalFolder', "Open Local Folder...");
|
||||
|
||||
constructor(
|
||||
id: string,
|
||||
label: string,
|
||||
@IFileDialogService private readonly dialogService: IFileDialogService
|
||||
) {
|
||||
super(id, label);
|
||||
}
|
||||
|
||||
run(event?: any, data?: ITelemetryData): Promise<any> {
|
||||
return this.dialogService.pickFolderAndOpen({ forceNewWindow: false, telemetryExtraData: data, availableFileSystems: [Schemas.file] });
|
||||
export function handler(): ICommandHandler {
|
||||
return accessor => {
|
||||
const dialogService = accessor.get(IFileDialogService);
|
||||
return dialogService.pickFolderAndOpen({ forceNewWindow: false, availableFileSystems: [Schemas.file] });
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -109,21 +118,16 @@ export class OpenFileFolderAction extends Action {
|
||||
}
|
||||
}
|
||||
|
||||
export class OpenLocalFileFolderAction extends Action {
|
||||
export namespace OpenLocalFileFolderCommand {
|
||||
|
||||
static readonly ID = 'workbench.action.files.openLocalFileFolder';
|
||||
static LABEL = nls.localize('openLocalFileFolder', "Open Local...");
|
||||
export const ID = 'workbench.action.files.openLocalFileFolder';
|
||||
export const LABEL = nls.localize('openLocalFileFolder', "Open Local...");
|
||||
|
||||
constructor(
|
||||
id: string,
|
||||
label: string,
|
||||
@IFileDialogService private readonly dialogService: IFileDialogService
|
||||
) {
|
||||
super(id, label);
|
||||
}
|
||||
|
||||
run(event?: any, data?: ITelemetryData): Promise<any> {
|
||||
return this.dialogService.pickFileFolderAndOpen({ forceNewWindow: false, telemetryExtraData: data, availableFileSystems: [Schemas.file] });
|
||||
export function handler(): ICommandHandler {
|
||||
return accessor => {
|
||||
const dialogService = accessor.get(IFileDialogService);
|
||||
return dialogService.pickFileFolderAndOpen({ forceNewWindow: false, availableFileSystems: [Schemas.file] });
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -30,10 +30,10 @@ import { Disposable } from 'vs/base/common/lifecycle';
|
||||
export abstract class Composite extends Component implements IComposite {
|
||||
|
||||
private readonly _onTitleAreaUpdate: Emitter<void> = this._register(new Emitter<void>());
|
||||
get onTitleAreaUpdate(): Event<void> { return this._onTitleAreaUpdate.event; }
|
||||
readonly onTitleAreaUpdate: Event<void> = this._onTitleAreaUpdate.event;
|
||||
|
||||
private readonly _onDidChangeVisibility: Emitter<boolean> = this._register(new Emitter<boolean>());
|
||||
get onDidChangeVisibility(): Event<boolean> { return this._onDidChangeVisibility.event; }
|
||||
readonly onDidChangeVisibility: Event<boolean> = this._onDidChangeVisibility.event;
|
||||
|
||||
private _onDidFocus: Emitter<void>;
|
||||
get onDidFocus(): Event<void> {
|
||||
@@ -150,7 +150,7 @@ export abstract class Composite extends Component implements IComposite {
|
||||
/**
|
||||
* Returns an array of actions to show in the action bar of the composite.
|
||||
*/
|
||||
getActions(): IAction[] {
|
||||
getActions(): ReadonlyArray<IAction> {
|
||||
return [];
|
||||
}
|
||||
|
||||
@@ -158,14 +158,14 @@ export abstract class Composite extends Component implements IComposite {
|
||||
* Returns an array of actions to show in the action bar of the composite
|
||||
* in a less prominent way then action from getActions.
|
||||
*/
|
||||
getSecondaryActions(): IAction[] {
|
||||
getSecondaryActions(): ReadonlyArray<IAction> {
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of actions to show in the context menu of the composite
|
||||
*/
|
||||
getContextMenuActions(): IAction[] {
|
||||
getContextMenuActions(): ReadonlyArray<IAction> {
|
||||
return [];
|
||||
}
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { IContextKeyService, IContextKey, RawContextKey } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { InputFocusedContext } from 'vs/platform/contextkey/common/contextkeys';
|
||||
import { IWindowsConfiguration } from 'vs/platform/windows/common/windows';
|
||||
import { ActiveEditorContext, EditorsVisibleContext, TextCompareEditorVisibleContext, TextCompareEditorActiveContext, ActiveEditorGroupEmptyContext, MultipleEditorGroupsContext, TEXT_DIFF_EDITOR_ID, SplitEditorsVertically, InEditorZenModeContext } from 'vs/workbench/common/editor';
|
||||
import { ActiveEditorContext, EditorsVisibleContext, TextCompareEditorVisibleContext, TextCompareEditorActiveContext, ActiveEditorGroupEmptyContext, MultipleEditorGroupsContext, TEXT_DIFF_EDITOR_ID, SplitEditorsVertically, InEditorZenModeContext, IsCenteredLayoutContext } from 'vs/workbench/common/editor';
|
||||
import { trackFocus, addDisposableListener, EventType } from 'vs/base/browser/dom';
|
||||
import { preferredSideBySideGroupDirection, GroupDirection, IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
@@ -16,16 +16,22 @@ import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/
|
||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { WorkbenchState, IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
|
||||
import { SideBarVisibleContext } from 'vs/workbench/common/viewlet';
|
||||
import { IWorkbenchLayoutService, Parts } from 'vs/workbench/services/layout/browser/layoutService';
|
||||
import { IWorkbenchLayoutService, Parts, Position } from 'vs/workbench/services/layout/browser/layoutService';
|
||||
import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet';
|
||||
import { isMacintosh, isLinux, isWindows } from 'vs/base/common/platform';
|
||||
import { isMacintosh, isLinux, isWindows, isWeb } from 'vs/base/common/platform';
|
||||
import { PanelPositionContext } from 'vs/workbench/common/panel';
|
||||
|
||||
export const IsMacContext = new RawContextKey<boolean>('isMac', isMacintosh);
|
||||
export const IsLinuxContext = new RawContextKey<boolean>('isLinux', isLinux);
|
||||
export const IsWindowsContext = new RawContextKey<boolean>('isWindows', isWindows);
|
||||
|
||||
export const IsWebContext = new RawContextKey<boolean>('isWeb', isWeb);
|
||||
export const IsMacNativeContext = new RawContextKey<boolean>('isMacNative', isMacintosh && !isWeb);
|
||||
|
||||
export const RemoteAuthorityContext = new RawContextKey<string>('remoteAuthority', '');
|
||||
|
||||
export const RemoteConnectionState = new RawContextKey<'' | 'initializing' | 'disconnected' | 'connected'>('remoteConnectionState', '');
|
||||
|
||||
export const HasMacNativeTabsContext = new RawContextKey<boolean>('hasMacNativeTabs', false);
|
||||
|
||||
export const SupportsWorkspacesContext = new RawContextKey<boolean>('supportsWorkspaces', true);
|
||||
@@ -38,6 +44,8 @@ export const WorkspaceFolderCountContext = new RawContextKey<number>('workspaceF
|
||||
|
||||
export const RemoteFileDialogContext = new RawContextKey<boolean>('remoteFileDialogVisible', false);
|
||||
|
||||
export const IsFullscreenContext = new RawContextKey<boolean>('isFullscreen', false);
|
||||
|
||||
export class WorkbenchContextKeysHandler extends Disposable {
|
||||
private inputFocusedContext: IContextKey<boolean>;
|
||||
|
||||
@@ -54,8 +62,10 @@ export class WorkbenchContextKeysHandler extends Disposable {
|
||||
|
||||
|
||||
private inZenModeContext: IContextKey<boolean>;
|
||||
|
||||
private isFullscreenContext: IContextKey<boolean>;
|
||||
private isCenteredLayoutContext: IContextKey<boolean>;
|
||||
private sideBarVisibleContext: IContextKey<boolean>;
|
||||
private panelPositionContext: IContextKey<string>;
|
||||
|
||||
constructor(
|
||||
@IContextKeyService private contextKeyService: IContextKeyService,
|
||||
@@ -93,6 +103,9 @@ export class WorkbenchContextKeysHandler extends Disposable {
|
||||
}));
|
||||
|
||||
this._register(this.layoutService.onZenModeChange(enabled => this.inZenModeContext.set(enabled)));
|
||||
this._register(this.layoutService.onFullscreenChange(fullscreen => this.isFullscreenContext.set(fullscreen)));
|
||||
this._register(this.layoutService.onCenteredLayoutChange(centered => this.isCenteredLayoutContext.set(centered)));
|
||||
this._register(this.layoutService.onPanelPositionChange(position => this.panelPositionContext.set(position)));
|
||||
|
||||
this._register(this.viewletService.onDidViewletClose(() => this.updateSideBarContextKeys()));
|
||||
this._register(this.viewletService.onDidViewletOpen(() => this.updateSideBarContextKeys()));
|
||||
@@ -105,6 +118,9 @@ export class WorkbenchContextKeysHandler extends Disposable {
|
||||
IsLinuxContext.bindTo(this.contextKeyService);
|
||||
IsWindowsContext.bindTo(this.contextKeyService);
|
||||
|
||||
IsWebContext.bindTo(this.contextKeyService);
|
||||
IsMacNativeContext.bindTo(this.contextKeyService);
|
||||
|
||||
RemoteAuthorityContext.bindTo(this.contextKeyService).set(this.environmentService.configuration.remoteAuthority || '');
|
||||
|
||||
// macOS Native Tabs
|
||||
@@ -140,11 +156,21 @@ export class WorkbenchContextKeysHandler extends Disposable {
|
||||
this.splitEditorsVerticallyContext = SplitEditorsVertically.bindTo(this.contextKeyService);
|
||||
this.updateSplitEditorsVerticallyContext();
|
||||
|
||||
// Fullscreen
|
||||
this.isFullscreenContext = IsFullscreenContext.bindTo(this.contextKeyService);
|
||||
|
||||
// Zen Mode
|
||||
this.inZenModeContext = InEditorZenModeContext.bindTo(this.contextKeyService);
|
||||
|
||||
// Centered Layout
|
||||
this.isCenteredLayoutContext = IsCenteredLayoutContext.bindTo(this.contextKeyService);
|
||||
|
||||
// Sidebar
|
||||
this.sideBarVisibleContext = SideBarVisibleContext.bindTo(this.contextKeyService);
|
||||
|
||||
// Panel Position
|
||||
this.panelPositionContext = PanelPositionContext.bindTo(this.contextKeyService);
|
||||
this.panelPositionContext.set(this.layoutService.getPanelPosition() === Position.RIGHT ? 'right' : 'bottom');
|
||||
}
|
||||
|
||||
private updateEditorContextKeys(): void {
|
||||
|
||||
@@ -7,7 +7,7 @@ import { hasWorkspaceFileExtension, IWorkspaceFolderCreationData } from 'vs/plat
|
||||
import { normalize } from 'vs/base/common/path';
|
||||
import { basename } from 'vs/base/common/resources';
|
||||
import { IFileService } from 'vs/platform/files/common/files';
|
||||
import { IWindowsService, IWindowService, IURIToOpen } from 'vs/platform/windows/common/windows';
|
||||
import { IWindowService, IURIToOpen } from 'vs/platform/windows/common/windows';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
|
||||
import { IBackupFileService } from 'vs/workbench/services/backup/common/backup';
|
||||
@@ -20,7 +20,7 @@ import { DataTransfers } from 'vs/base/browser/dnd';
|
||||
import { DragMouseEvent } from 'vs/base/browser/mouseEvent';
|
||||
import { normalizeDriveLetter } from 'vs/base/common/labels';
|
||||
import { MIME_BINARY } from 'vs/base/common/mime';
|
||||
import { isWindows } from 'vs/base/common/platform';
|
||||
import { isWindows, isLinux } from 'vs/base/common/platform';
|
||||
import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { isCodeEditor } from 'vs/editor/browser/editorBrowser';
|
||||
import { IEditorIdentifier, GroupIdentifier } from 'vs/workbench/common/editor';
|
||||
@@ -31,6 +31,7 @@ import { IEditorGroup } from 'vs/workbench/services/editor/common/editorGroupsSe
|
||||
import { IRecentFile } from 'vs/platform/history/common/history';
|
||||
import { IWorkspaceEditingService } from 'vs/workbench/services/workspace/common/workspaceEditing';
|
||||
import { withNullAsUndefined } from 'vs/base/common/types';
|
||||
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
|
||||
|
||||
export interface IDraggedResource {
|
||||
resource: URI;
|
||||
@@ -159,7 +160,6 @@ export class ResourcesDropHandler {
|
||||
constructor(
|
||||
private options: IResourcesDropHandlerOptions,
|
||||
@IFileService private readonly fileService: IFileService,
|
||||
@IWindowsService private readonly windowsService: IWindowsService,
|
||||
@IWindowService private readonly windowService: IWindowService,
|
||||
@ITextFileService private readonly textFileService: ITextFileService,
|
||||
@IBackupFileService private readonly backupFileService: IBackupFileService,
|
||||
@@ -189,7 +189,7 @@ export class ResourcesDropHandler {
|
||||
// Add external ones to recently open list unless dropped resource is a workspace
|
||||
const recents: IRecentFile[] = untitledOrFileResources.filter(d => d.isExternal && d.resource.scheme === Schemas.file).map(d => ({ fileUri: d.resource }));
|
||||
if (recents.length) {
|
||||
this.windowsService.addRecentlyOpened(recents);
|
||||
this.windowService.addRecentlyOpened(recents);
|
||||
}
|
||||
|
||||
const editors: IResourceEditor[] = untitledOrFileResources.map(untitledOrFileResource => ({
|
||||
@@ -327,8 +327,10 @@ export function fillResourceDataTransfers(accessor: ServicesAccessor, resources:
|
||||
const lineDelimiter = isWindows ? '\r\n' : '\n';
|
||||
event.dataTransfer.setData(DataTransfers.TEXT, sources.map(source => source.resource.scheme === Schemas.file ? normalize(normalizeDriveLetter(source.resource.fsPath)) : source.resource.toString()).join(lineDelimiter));
|
||||
|
||||
// Download URL: enables support to drag a tab as file to desktop (only single file supported)
|
||||
if (firstSource.resource.scheme === Schemas.file) {
|
||||
const envService = accessor.get(IWorkbenchEnvironmentService);
|
||||
if (!(isLinux && envService.configuration.remoteAuthority)) {
|
||||
// Download URL: enables support to drag a tab as file to desktop (only single file supported)
|
||||
// Not supported on linux remote due to chrome limitation https://github.com/microsoft/vscode-remote-release/issues/849
|
||||
event.dataTransfer.setData(DataTransfers.DOWNLOAD_URL, [MIME_BINARY, basename(firstSource.resource), firstSource.resource.toString()].join(':'));
|
||||
}
|
||||
|
||||
|
||||
@@ -8,7 +8,6 @@ import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { BaseEditor } from 'vs/workbench/browser/parts/editor/baseEditor';
|
||||
import { IConstructorSignature0, IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { isArray } from 'vs/base/common/types';
|
||||
|
||||
export interface IEditorDescriptor {
|
||||
instantiate(instantiationService: IInstantiationService): BaseEditor;
|
||||
@@ -27,26 +26,25 @@ export interface IEditorRegistry {
|
||||
* input, the input itself will be asked which editor it prefers if this method is provided. Otherwise
|
||||
* the first editor in the list will be returned.
|
||||
*
|
||||
* @param editorInputDescriptor a constructor function that returns an instance of EditorInput for which the
|
||||
* @param inputDescriptors A set of constructor functions that return an instance of EditorInput for which the
|
||||
* registered editor should be used for.
|
||||
*/
|
||||
registerEditor(descriptor: IEditorDescriptor, editorInputDescriptor: SyncDescriptor<EditorInput>): void;
|
||||
registerEditor(descriptor: IEditorDescriptor, editorInputDescriptor: SyncDescriptor<EditorInput>[]): void;
|
||||
registerEditor(descriptor: IEditorDescriptor, inputDescriptors: readonly SyncDescriptor<EditorInput>[]): void;
|
||||
|
||||
/**
|
||||
* Returns the editor descriptor for the given input or null if none.
|
||||
* Returns the editor descriptor for the given input or `undefined` if none.
|
||||
*/
|
||||
getEditor(input: EditorInput): IEditorDescriptor | null;
|
||||
getEditor(input: EditorInput): IEditorDescriptor | undefined;
|
||||
|
||||
/**
|
||||
* Returns the editor descriptor for the given identifier or null if none.
|
||||
* Returns the editor descriptor for the given identifier or `undefined` if none.
|
||||
*/
|
||||
getEditorById(editorId: string): IEditorDescriptor | null;
|
||||
getEditorById(editorId: string): IEditorDescriptor | undefined;
|
||||
|
||||
/**
|
||||
* Returns an array of registered editors known to the platform.
|
||||
*/
|
||||
getEditors(): IEditorDescriptor[];
|
||||
getEditors(): readonly IEditorDescriptor[];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -54,15 +52,12 @@ export interface IEditorRegistry {
|
||||
* can load lazily in the workbench.
|
||||
*/
|
||||
export class EditorDescriptor implements IEditorDescriptor {
|
||||
private ctor: IConstructorSignature0<BaseEditor>;
|
||||
private id: string;
|
||||
private name: string;
|
||||
|
||||
constructor(ctor: IConstructorSignature0<BaseEditor>, id: string, name: string) {
|
||||
this.ctor = ctor;
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
}
|
||||
constructor(
|
||||
private readonly ctor: IConstructorSignature0<BaseEditor>,
|
||||
private readonly id: string,
|
||||
private readonly name: string
|
||||
) { }
|
||||
|
||||
instantiate(instantiationService: IInstantiationService): BaseEditor {
|
||||
return instantiationService.createInstance(this.ctor);
|
||||
@@ -81,34 +76,24 @@ export class EditorDescriptor implements IEditorDescriptor {
|
||||
}
|
||||
}
|
||||
|
||||
const INPUT_DESCRIPTORS_PROPERTY = '__$inputDescriptors';
|
||||
|
||||
class EditorRegistry implements IEditorRegistry {
|
||||
|
||||
private editors: EditorDescriptor[] = [];
|
||||
private readonly mapEditorToInputs = new Map<EditorDescriptor, readonly SyncDescriptor<EditorInput>[]>();
|
||||
|
||||
registerEditor(descriptor: EditorDescriptor, editorInputDescriptor: SyncDescriptor<EditorInput>): void;
|
||||
registerEditor(descriptor: EditorDescriptor, editorInputDescriptor: SyncDescriptor<EditorInput>[]): void;
|
||||
registerEditor(descriptor: EditorDescriptor, editorInputDescriptor: SyncDescriptor<EditorInput> | SyncDescriptor<EditorInput>[]): void {
|
||||
|
||||
// Support both non-array and array parameter
|
||||
let inputDescriptors: SyncDescriptor<EditorInput>[] = [];
|
||||
if (!isArray(editorInputDescriptor)) {
|
||||
inputDescriptors.push(editorInputDescriptor);
|
||||
} else {
|
||||
inputDescriptors = editorInputDescriptor;
|
||||
}
|
||||
|
||||
registerEditor(descriptor: EditorDescriptor, inputDescriptors: readonly SyncDescriptor<EditorInput>[]): void {
|
||||
// Register (Support multiple Editors per Input)
|
||||
descriptor[INPUT_DESCRIPTORS_PROPERTY] = inputDescriptors;
|
||||
this.mapEditorToInputs.set(descriptor, inputDescriptors);
|
||||
|
||||
this.editors.push(descriptor);
|
||||
}
|
||||
|
||||
getEditor(input: EditorInput): EditorDescriptor | null {
|
||||
getEditor(input: EditorInput): EditorDescriptor | undefined {
|
||||
const findEditorDescriptors = (input: EditorInput, byInstanceOf?: boolean): EditorDescriptor[] => {
|
||||
const matchingDescriptors: EditorDescriptor[] = [];
|
||||
|
||||
for (const editor of this.editors) {
|
||||
const inputDescriptors: SyncDescriptor<EditorInput>[] = editor[INPUT_DESCRIPTORS_PROPERTY];
|
||||
const inputDescriptors = this.mapEditorToInputs.get(editor) || [];
|
||||
for (const inputDescriptor of inputDescriptors) {
|
||||
const inputClass = inputDescriptor.ctor;
|
||||
|
||||
@@ -139,7 +124,7 @@ class EditorRegistry implements IEditorRegistry {
|
||||
};
|
||||
|
||||
const descriptors = findEditorDescriptors(input);
|
||||
if (descriptors && descriptors.length > 0) {
|
||||
if (descriptors.length > 0) {
|
||||
|
||||
// Ask the input for its preferred Editor
|
||||
const preferredEditorId = input.getPreferredEditorId(descriptors.map(d => d.getId()));
|
||||
@@ -151,20 +136,20 @@ class EditorRegistry implements IEditorRegistry {
|
||||
return descriptors[0];
|
||||
}
|
||||
|
||||
return null;
|
||||
return undefined;
|
||||
}
|
||||
|
||||
getEditorById(editorId: string): EditorDescriptor | null {
|
||||
getEditorById(editorId: string): EditorDescriptor | undefined {
|
||||
for (const editor of this.editors) {
|
||||
if (editor.getId() === editorId) {
|
||||
return editor;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
return undefined;
|
||||
}
|
||||
|
||||
getEditors(): EditorDescriptor[] {
|
||||
getEditors(): readonly EditorDescriptor[] {
|
||||
return this.editors.slice(0);
|
||||
}
|
||||
|
||||
@@ -175,8 +160,10 @@ class EditorRegistry implements IEditorRegistry {
|
||||
getEditorInputs(): SyncDescriptor<EditorInput>[] {
|
||||
const inputClasses: SyncDescriptor<EditorInput>[] = [];
|
||||
for (const editor of this.editors) {
|
||||
const editorInputDescriptors: SyncDescriptor<EditorInput>[] = editor[INPUT_DESCRIPTORS_PROPERTY];
|
||||
inputClasses.push(...editorInputDescriptors.map(descriptor => descriptor.ctor));
|
||||
const editorInputDescriptors = this.mapEditorToInputs.get(editor);
|
||||
if (editorInputDescriptors) {
|
||||
inputClasses.push(...editorInputDescriptors.map(descriptor => descriptor.ctor));
|
||||
}
|
||||
}
|
||||
|
||||
return inputClasses;
|
||||
|
||||
@@ -8,7 +8,7 @@ import * as resources from 'vs/base/common/resources';
|
||||
import { IconLabel, IIconLabelValueOptions, IIconLabelCreationOptions } from 'vs/base/browser/ui/iconLabel/iconLabel';
|
||||
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { IModeService } from 'vs/editor/common/services/modeService';
|
||||
import { toResource, IEditorInput, SideBySideEditor } from 'vs/workbench/common/editor';
|
||||
import { toResource, IEditorInput, SideBySideEditor, Verbosity } from 'vs/workbench/common/editor';
|
||||
import { PLAINTEXT_MODE_ID } from 'vs/editor/common/modes/modesRegistry';
|
||||
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
@@ -35,6 +35,7 @@ export interface IResourceLabelProps {
|
||||
export interface IResourceLabelOptions extends IIconLabelValueOptions {
|
||||
fileKind?: FileKind;
|
||||
fileDecorations?: { colors: boolean, badges: boolean, data?: IDecorationData };
|
||||
descriptionVerbosity?: Verbosity;
|
||||
}
|
||||
|
||||
export interface IFileLabelOptions extends IResourceLabelOptions {
|
||||
@@ -52,19 +53,19 @@ export interface IResourceLabel extends IDisposable {
|
||||
setLabel(label?: string, description?: string, options?: IIconLabelValueOptions): void;
|
||||
|
||||
/**
|
||||
* Convinient method to apply a label by passing a resource along.
|
||||
* Convenient method to apply a label by passing a resource along.
|
||||
*
|
||||
* Note: for file resources consider to use the #setFile() method instead.
|
||||
*/
|
||||
setResource(label: IResourceLabelProps, options?: IResourceLabelOptions): void;
|
||||
|
||||
/**
|
||||
* Convinient method to render a file label based on a resource.
|
||||
* Convenient method to render a file label based on a resource.
|
||||
*/
|
||||
setFile(resource: URI, options?: IFileLabelOptions): void;
|
||||
|
||||
/**
|
||||
* Convinient method to apply a label by passing an editor along.
|
||||
* Convenient method to apply a label by passing an editor along.
|
||||
*/
|
||||
setEditor(editor: IEditorInput, options?: IResourceLabelOptions): void;
|
||||
|
||||
@@ -94,7 +95,8 @@ export class ResourceLabels extends Disposable {
|
||||
@IModelService private readonly modelService: IModelService,
|
||||
@IDecorationsService private readonly decorationsService: IDecorationsService,
|
||||
@IThemeService private readonly themeService: IThemeService,
|
||||
@IFileService private readonly fileService: IFileService
|
||||
@IFileService private readonly fileService: IFileService,
|
||||
@ILabelService private readonly labelService: ILabelService
|
||||
) {
|
||||
super();
|
||||
|
||||
@@ -145,6 +147,10 @@ export class ResourceLabels extends Disposable {
|
||||
this._widgets.forEach(widget => widget.notifyFileAssociationsChange());
|
||||
}
|
||||
}));
|
||||
|
||||
this._register(this.labelService.onDidChangeFormatters(() => {
|
||||
this._widgets.forEach(widget => widget.notifyFormattersChange());
|
||||
}));
|
||||
}
|
||||
|
||||
get(index: number): IResourceLabel {
|
||||
@@ -212,9 +218,10 @@ export class ResourceLabel extends ResourceLabels {
|
||||
@IModelService modelService: IModelService,
|
||||
@IDecorationsService decorationsService: IDecorationsService,
|
||||
@IThemeService themeService: IThemeService,
|
||||
@IFileService fileService: IFileService
|
||||
@IFileService fileService: IFileService,
|
||||
@ILabelService labelService: ILabelService
|
||||
) {
|
||||
super(DEFAULT_LABELS_CONTAINER, instantiationService, extensionService, configurationService, modelService, decorationsService, themeService, fileService);
|
||||
super(DEFAULT_LABELS_CONTAINER, instantiationService, extensionService, configurationService, modelService, decorationsService, themeService, fileService, labelService);
|
||||
|
||||
this._label = this._register(this.create(container, options));
|
||||
}
|
||||
@@ -232,7 +239,7 @@ enum Redraw {
|
||||
class ResourceLabelWidget extends IconLabel {
|
||||
|
||||
private _onDidRender = this._register(new Emitter<void>());
|
||||
get onDidRender(): Event<void> { return this._onDidRender.event; }
|
||||
readonly onDidRender: Event<void> = this._onDidRender.event;
|
||||
|
||||
private label?: IResourceLabelProps;
|
||||
private options?: IResourceLabelOptions;
|
||||
@@ -309,6 +316,13 @@ class ResourceLabelWidget extends IconLabel {
|
||||
this.render(true);
|
||||
}
|
||||
|
||||
notifyFormattersChange(): void {
|
||||
if (this.label && this.label.resource) {
|
||||
this.setFile(this.label.resource, this.options);
|
||||
}
|
||||
this.render(false);
|
||||
}
|
||||
|
||||
setResource(label: IResourceLabelProps, options?: IResourceLabelOptions): void {
|
||||
const hasResourceChanged = this.hasResourceChanged(label, options);
|
||||
|
||||
@@ -352,7 +366,7 @@ class ResourceLabelWidget extends IconLabel {
|
||||
this.setResource({
|
||||
resource: toResource(editor, { supportSideBySide: SideBySideEditor.MASTER }),
|
||||
name: withNullAsUndefined(editor.getName()),
|
||||
description: withNullAsUndefined(editor.getDescription())
|
||||
description: editor.getDescription(options ? options.descriptionVerbosity : undefined)
|
||||
}, options);
|
||||
}
|
||||
|
||||
|
||||
@@ -3,20 +3,20 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { IDisposable, dispose, Disposable } from 'vs/base/common/lifecycle';
|
||||
import { Disposable, DisposableStore } from 'vs/base/common/lifecycle';
|
||||
import { Event, Emitter } from 'vs/base/common/event';
|
||||
import { EventType, addDisposableListener, addClass, removeClass, isAncestor, getClientArea, position, size } from 'vs/base/browser/dom';
|
||||
import { EventType, addDisposableListener, addClass, removeClass, isAncestor, getClientArea, position, size, EventHelper } from 'vs/base/browser/dom';
|
||||
import { onDidChangeFullscreen, isFullscreen, getZoomFactor } from 'vs/base/browser/browser';
|
||||
import { IBackupFileService } from 'vs/workbench/services/backup/common/backup';
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { isWindows, isLinux, isMacintosh } from 'vs/base/common/platform';
|
||||
import { isWindows, isLinux, isMacintosh, isWeb, isNative } from 'vs/base/common/platform';
|
||||
import { pathsToEditors } from 'vs/workbench/common/editor';
|
||||
import { SidebarPart } from 'vs/workbench/browser/parts/sidebar/sidebarPart';
|
||||
import { PanelPart } from 'vs/workbench/browser/parts/panel/panelPart';
|
||||
import { PanelRegistry, Extensions as PanelExtensions } from 'vs/workbench/browser/panel';
|
||||
import { Position, Parts, IWorkbenchLayoutService, ILayoutOptions } from 'vs/workbench/services/layout/browser/layoutService';
|
||||
import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace';
|
||||
import { IStorageService, StorageScope, IWillSaveStateEvent, WillSaveStateReason } from 'vs/platform/storage/common/storage';
|
||||
import { IStorageService, StorageScope, WillSaveStateReason } from 'vs/platform/storage/common/storage';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet';
|
||||
import { IPanelService } from 'vs/workbench/services/panel/common/panelService';
|
||||
@@ -27,13 +27,14 @@ import { IWindowService, MenuBarVisibility, getTitleBarStyle } from 'vs/platform
|
||||
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
|
||||
import { IEditorService, IResourceEditor } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
|
||||
import { Sizing, Direction, Grid, View } from 'vs/base/browser/ui/grid/grid';
|
||||
import { Sizing, Direction, Grid } from 'vs/base/browser/ui/grid/grid';
|
||||
import { WorkbenchLegacyLayout } from 'vs/workbench/browser/legacyLayout';
|
||||
import { IDimension } from 'vs/platform/layout/browser/layoutService';
|
||||
import { Part } from 'vs/workbench/browser/part';
|
||||
import { IStatusbarService } from 'vs/platform/statusbar/common/statusbar';
|
||||
import { IActivityBarService } from 'vs/workbench/services/activityBar/browser/activityBarService';
|
||||
import { IFileService } from 'vs/platform/files/common/files';
|
||||
import { IView } from 'vs/base/browser/ui/grid/gridview';
|
||||
|
||||
enum Settings {
|
||||
MENUBAR_VISIBLE = 'window.menuBarVisibility',
|
||||
@@ -43,7 +44,8 @@ enum Settings {
|
||||
SIDEBAR_POSITION = 'workbench.sideBar.location',
|
||||
PANEL_POSITION = 'workbench.panel.defaultLocation',
|
||||
|
||||
ZEN_MODE_RESTORE = 'zenMode.restore'
|
||||
ZEN_MODE_RESTORE = 'zenMode.restore',
|
||||
|
||||
}
|
||||
|
||||
enum Storage {
|
||||
@@ -51,6 +53,7 @@ enum Storage {
|
||||
|
||||
PANEL_HIDDEN = 'workbench.panel.hidden',
|
||||
PANEL_POSITION = 'workbench.panel.location',
|
||||
PANEL_SIZE_BEFORE_MAXIMIZED = 'workbench.panel.sizeBeforeMaximized',
|
||||
|
||||
ZEN_MODE_ENABLED = 'workbench.zenmode.active',
|
||||
CENTERED_LAYOUT_ENABLED = 'workbench.centerededitorlayout.active',
|
||||
@@ -61,13 +64,22 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
|
||||
_serviceBrand: ServiceIdentifier<any>;
|
||||
|
||||
private readonly _onTitleBarVisibilityChange: Emitter<void> = this._register(new Emitter<void>());
|
||||
get onTitleBarVisibilityChange(): Event<void> { return this._onTitleBarVisibilityChange.event; }
|
||||
readonly onTitleBarVisibilityChange: Event<void> = this._onTitleBarVisibilityChange.event;
|
||||
|
||||
private readonly _onZenMode: Emitter<boolean> = this._register(new Emitter<boolean>());
|
||||
get onZenModeChange(): Event<boolean> { return this._onZenMode.event; }
|
||||
private readonly _onZenModeChange: Emitter<boolean> = this._register(new Emitter<boolean>());
|
||||
readonly onZenModeChange: Event<boolean> = this._onZenModeChange.event;
|
||||
|
||||
private readonly _onFullscreenChange: Emitter<boolean> = this._register(new Emitter<boolean>());
|
||||
readonly onFullscreenChange: Event<boolean> = this._onFullscreenChange.event;
|
||||
|
||||
private readonly _onCenteredLayoutChange: Emitter<boolean> = this._register(new Emitter<boolean>());
|
||||
readonly onCenteredLayoutChange: Event<boolean> = this._onCenteredLayoutChange.event;
|
||||
|
||||
private readonly _onPanelPositionChange: Emitter<string> = this._register(new Emitter<string>());
|
||||
readonly onPanelPositionChange: Event<string> = this._onPanelPositionChange.event;
|
||||
|
||||
private readonly _onLayout = this._register(new Emitter<IDimension>());
|
||||
get onLayout(): Event<IDimension> { return this._onLayout.event; }
|
||||
readonly onLayout: Event<IDimension> = this._onLayout.event;
|
||||
|
||||
private _dimension: IDimension;
|
||||
get dimension(): IDimension { return this._dimension; }
|
||||
@@ -77,16 +89,16 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
|
||||
|
||||
private parts: Map<string, Part> = new Map<string, Part>();
|
||||
|
||||
private workbenchGrid: Grid<View> | WorkbenchLegacyLayout;
|
||||
private workbenchGrid: Grid | WorkbenchLegacyLayout;
|
||||
|
||||
private disposed: boolean;
|
||||
|
||||
private titleBarPartView: View;
|
||||
private activityBarPartView: View;
|
||||
private sideBarPartView: View;
|
||||
private panelPartView: View;
|
||||
private editorPartView: View;
|
||||
private statusBarPartView: View;
|
||||
private titleBarPartView: IView;
|
||||
private activityBarPartView: IView;
|
||||
private sideBarPartView: IView;
|
||||
private panelPartView: IView;
|
||||
private editorPartView: IView;
|
||||
private statusBarPartView: IView;
|
||||
|
||||
private environmentService: IWorkbenchEnvironmentService;
|
||||
private configurationService: IConfigurationService;
|
||||
@@ -130,6 +142,7 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
|
||||
|
||||
panel: {
|
||||
hidden: false,
|
||||
sizeBeforeMaximize: 0,
|
||||
position: Position.BOTTOM,
|
||||
height: 350,
|
||||
width: 350,
|
||||
@@ -147,7 +160,7 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
|
||||
transitionedToCenteredEditorLayout: false,
|
||||
wasSideBarVisible: false,
|
||||
wasPanelVisible: false,
|
||||
transitionDisposeables: [] as IDisposable[]
|
||||
transitionDisposables: new DisposableStore()
|
||||
}
|
||||
};
|
||||
|
||||
@@ -186,9 +199,6 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
|
||||
|
||||
private registerLayoutListeners(): void {
|
||||
|
||||
// Storage
|
||||
this._register(this.storageService.onWillSaveState(e => this.saveLayoutState(e)));
|
||||
|
||||
// Restore editor if hidden and it changes
|
||||
this._register(this.editorService.onDidVisibleEditorsChange(() => this.setEditorHidden(false)));
|
||||
this._register(this.editorGroupService.onDidActivateGroup(() => this.setEditorHidden(false)));
|
||||
@@ -206,8 +216,13 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
|
||||
// Prevent workbench from scrolling #55456
|
||||
this._register(addDisposableListener(this.container, EventType.SCROLL, () => this.container.scrollTop = 0));
|
||||
|
||||
// Prevent native context menus in web #73781
|
||||
if (isWeb) {
|
||||
this._register(addDisposableListener(this.container, EventType.CONTEXT_MENU, (e) => EventHelper.stop(e, true)));
|
||||
}
|
||||
|
||||
// Menubar visibility changes
|
||||
if ((isWindows || isLinux) && getTitleBarStyle(this.configurationService, this.environmentService) === 'custom') {
|
||||
if ((isWindows || isLinux || isWeb) && getTitleBarStyle(this.configurationService, this.environmentService) === 'custom') {
|
||||
this._register(this.titleService.onMenubarVisibilityChange(visible => this.onMenubarToggled(visible)));
|
||||
}
|
||||
}
|
||||
@@ -242,6 +257,8 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
|
||||
this._onTitleBarVisibilityChange.fire();
|
||||
this.layout(); // handle title bar when fullscreen changes
|
||||
}
|
||||
|
||||
this._onFullscreenChange.fire(this.state.fullscreen);
|
||||
}
|
||||
|
||||
private doUpdateLayoutConfiguration(skipLayout?: boolean): void {
|
||||
@@ -274,6 +291,7 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
|
||||
// Menubar visibility
|
||||
const newMenubarVisibility = this.configurationService.getValue<MenuBarVisibility>(Settings.MENUBAR_VISIBLE);
|
||||
this.setMenubarVisibility(newMenubarVisibility, !!skipLayout);
|
||||
|
||||
}
|
||||
|
||||
private setSideBarPosition(position: Position): void {
|
||||
@@ -302,7 +320,7 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
|
||||
// Layout
|
||||
if (this.workbenchGrid instanceof Grid) {
|
||||
if (!wasHidden) {
|
||||
this.state.sideBar.width = this.workbenchGrid.getViewSize(this.sideBarPartView);
|
||||
this.state.sideBar.width = this.workbenchGrid.getViewSize(this.sideBarPartView).width;
|
||||
}
|
||||
|
||||
this.workbenchGrid.removeView(this.sideBarPartView);
|
||||
@@ -381,11 +399,15 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
|
||||
}
|
||||
}
|
||||
|
||||
// Panel size before maximized
|
||||
this.state.panel.sizeBeforeMaximize = this.storageService.getNumber(Storage.PANEL_SIZE_BEFORE_MAXIMIZED, StorageScope.GLOBAL, 0);
|
||||
|
||||
// Statusbar visibility
|
||||
this.state.statusBar.hidden = !this.configurationService.getValue<string>(Settings.STATUSBAR_VISIBLE);
|
||||
|
||||
// Zen mode enablement
|
||||
this.state.zenMode.restore = this.storageService.getBoolean(Storage.ZEN_MODE_ENABLED, StorageScope.WORKSPACE, false) && this.configurationService.getValue(Settings.ZEN_MODE_RESTORE);
|
||||
|
||||
}
|
||||
|
||||
private resolveEditorsToOpen(fileService: IFileService): Promise<IResourceEditor[]> | IResourceEditor[] {
|
||||
@@ -500,7 +522,7 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
|
||||
return false;
|
||||
} else if (!this.state.fullscreen) {
|
||||
return true;
|
||||
} else if (isMacintosh) {
|
||||
} else if (isMacintosh && isNative) {
|
||||
return false;
|
||||
} else if (this.state.menuBar.visibility === 'visible') {
|
||||
return true;
|
||||
@@ -541,13 +563,17 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
|
||||
return offset;
|
||||
}
|
||||
|
||||
getWorkbenchContainer(): HTMLElement {
|
||||
return this.parent;
|
||||
}
|
||||
|
||||
getWorkbenchElement(): HTMLElement {
|
||||
return this.container;
|
||||
}
|
||||
|
||||
toggleZenMode(skipLayout?: boolean, restoring = false): void {
|
||||
this.state.zenMode.active = !this.state.zenMode.active;
|
||||
this.state.zenMode.transitionDisposeables = dispose(this.state.zenMode.transitionDisposeables);
|
||||
this.state.zenMode.transitionDisposables.clear();
|
||||
|
||||
const setLineNumbers = (lineNumbers: any) => this.editorService.visibleTextEditorWidgets.forEach(editor => editor.updateOptions({ lineNumbers }));
|
||||
|
||||
@@ -586,11 +612,11 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
|
||||
|
||||
if (config.hideLineNumbers) {
|
||||
setLineNumbers('off');
|
||||
this.state.zenMode.transitionDisposeables.push(this.editorService.onDidVisibleEditorsChange(() => setLineNumbers('off')));
|
||||
this.state.zenMode.transitionDisposables.add(this.editorService.onDidVisibleEditorsChange(() => setLineNumbers('off')));
|
||||
}
|
||||
|
||||
if (config.hideTabs && this.editorGroupService.partOptions.showTabs) {
|
||||
this.state.zenMode.transitionDisposeables.push(this.editorGroupService.enforcePartOptions({ showTabs: false }));
|
||||
this.state.zenMode.transitionDisposables.add(this.editorGroupService.enforcePartOptions({ showTabs: false }));
|
||||
}
|
||||
|
||||
if (config.centerLayout) {
|
||||
@@ -631,7 +657,23 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
|
||||
}
|
||||
|
||||
// Event
|
||||
this._onZenMode.fire(this.state.zenMode.active);
|
||||
this._onZenModeChange.fire(this.state.zenMode.active);
|
||||
|
||||
// State
|
||||
if (this.state.zenMode.active) {
|
||||
this.storageService.store(Storage.ZEN_MODE_ENABLED, true, StorageScope.WORKSPACE);
|
||||
|
||||
// Exit zen mode on shutdown unless configured to keep
|
||||
this.state.zenMode.transitionDisposables.add(this.storageService.onWillSaveState(e => {
|
||||
if (e.reason === WillSaveStateReason.SHUTDOWN && this.state.zenMode.active) {
|
||||
if (!this.configurationService.getValue(Settings.ZEN_MODE_RESTORE)) {
|
||||
this.toggleZenMode(true); // We will not restore zen mode, need to clear all zen mode state changes
|
||||
}
|
||||
}
|
||||
}));
|
||||
} else {
|
||||
this.storageService.remove(Storage.ZEN_MODE_ENABLED, StorageScope.WORKSPACE);
|
||||
}
|
||||
}
|
||||
|
||||
private setStatusBarHidden(hidden: boolean, skipLayout?: boolean): void {
|
||||
@@ -665,16 +707,24 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
|
||||
if (this.configurationService.getValue('workbench.useExperimentalGridLayout')) {
|
||||
|
||||
// Create view wrappers for all parts
|
||||
this.titleBarPartView = new View(titleBar);
|
||||
this.sideBarPartView = new View(sideBar);
|
||||
this.activityBarPartView = new View(activityBar);
|
||||
this.editorPartView = new View(editorPart);
|
||||
this.panelPartView = new View(panelPart);
|
||||
this.statusBarPartView = new View(statusBar);
|
||||
this.titleBarPartView = titleBar;
|
||||
this.sideBarPartView = sideBar;
|
||||
this.activityBarPartView = activityBar;
|
||||
this.editorPartView = editorPart;
|
||||
this.panelPartView = panelPart;
|
||||
this.statusBarPartView = statusBar;
|
||||
|
||||
this.workbenchGrid = new Grid(this.editorPartView, { proportionalLayout: false });
|
||||
|
||||
this.container.prepend(this.workbenchGrid.element);
|
||||
|
||||
this._register((this.sideBarPartView as SidebarPart).onDidVisibilityChange((visible) => {
|
||||
this.setSideBarHidden(!visible, true);
|
||||
}));
|
||||
|
||||
this._register((this.panelPartView as PanelPart).onDidVisibilityChange((visible) => {
|
||||
this.setPanelHidden(!visible, true);
|
||||
}));
|
||||
} else {
|
||||
this.workbenchGrid = instantiationService.createInstance(
|
||||
WorkbenchLegacyLayout,
|
||||
@@ -753,52 +803,52 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
|
||||
|
||||
// Hide parts
|
||||
if (this.state.panel.hidden) {
|
||||
this.panelPartView.hide();
|
||||
this.workbenchGrid.setViewVisible(this.panelPartView, false);
|
||||
}
|
||||
|
||||
if (this.state.statusBar.hidden) {
|
||||
this.statusBarPartView.hide();
|
||||
this.workbenchGrid.setViewVisible(this.statusBarPartView, false);
|
||||
}
|
||||
|
||||
if (!this.isVisible(Parts.TITLEBAR_PART)) {
|
||||
this.titleBarPartView.hide();
|
||||
if (titlebarInGrid && !this.isVisible(Parts.TITLEBAR_PART)) {
|
||||
this.workbenchGrid.setViewVisible(this.titleBarPartView, false);
|
||||
}
|
||||
|
||||
if (this.state.activityBar.hidden) {
|
||||
this.activityBarPartView.hide();
|
||||
this.workbenchGrid.setViewVisible(this.activityBarPartView, false);
|
||||
}
|
||||
|
||||
if (this.state.sideBar.hidden) {
|
||||
this.sideBarPartView.hide();
|
||||
this.workbenchGrid.setViewVisible(this.sideBarPartView, false);
|
||||
}
|
||||
|
||||
if (this.state.editor.hidden) {
|
||||
this.editorPartView.hide();
|
||||
this.workbenchGrid.setViewVisible(this.editorPartView, false);
|
||||
}
|
||||
|
||||
// Show visible parts
|
||||
if (!this.state.editor.hidden) {
|
||||
this.editorPartView.show();
|
||||
this.workbenchGrid.setViewVisible(this.editorPartView, true);
|
||||
}
|
||||
|
||||
if (!this.state.statusBar.hidden) {
|
||||
this.statusBarPartView.show();
|
||||
this.workbenchGrid.setViewVisible(this.statusBarPartView, true);
|
||||
}
|
||||
|
||||
if (this.isVisible(Parts.TITLEBAR_PART)) {
|
||||
this.titleBarPartView.show();
|
||||
this.workbenchGrid.setViewVisible(this.titleBarPartView, true);
|
||||
}
|
||||
|
||||
if (!this.state.activityBar.hidden) {
|
||||
this.activityBarPartView.show();
|
||||
this.workbenchGrid.setViewVisible(this.activityBarPartView, true);
|
||||
}
|
||||
|
||||
if (!this.state.sideBar.hidden) {
|
||||
this.sideBarPartView.show();
|
||||
this.workbenchGrid.setViewVisible(this.sideBarPartView, true);
|
||||
}
|
||||
|
||||
if (!this.state.panel.hidden) {
|
||||
this.panelPartView.show();
|
||||
this.workbenchGrid.setViewVisible(this.panelPartView, true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -828,25 +878,68 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
|
||||
this.layout();
|
||||
}
|
||||
}
|
||||
|
||||
this._onCenteredLayoutChange.fire(this.state.editor.centered);
|
||||
}
|
||||
|
||||
resizePart(part: Parts, sizeChange: number): void {
|
||||
let view: View;
|
||||
switch (part) {
|
||||
case Parts.SIDEBAR_PART:
|
||||
view = this.sideBarPartView;
|
||||
case Parts.PANEL_PART:
|
||||
view = this.panelPartView;
|
||||
case Parts.EDITOR_PART:
|
||||
view = this.editorPartView;
|
||||
if (this.workbenchGrid instanceof Grid) {
|
||||
this.workbenchGrid.resizeView(view, this.workbenchGrid.getViewSize(view) + sizeChange);
|
||||
} else {
|
||||
this.workbenchGrid.resizePart(part, sizeChange);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return; // Cannot resize other parts
|
||||
if (this.workbenchGrid instanceof Grid) {
|
||||
let viewSize;
|
||||
const sizeChangePxWidth = this.workbenchGrid.width * sizeChange / 100;
|
||||
const sizeChangePxHeight = this.workbenchGrid.height * sizeChange / 100;
|
||||
|
||||
switch (part) {
|
||||
case Parts.SIDEBAR_PART:
|
||||
viewSize = this.workbenchGrid.getViewSize(this.sideBarPartView);
|
||||
this.workbenchGrid.resizeView(this.sideBarPartView,
|
||||
{
|
||||
width: viewSize.width + sizeChangePxWidth,
|
||||
height: viewSize.height
|
||||
});
|
||||
|
||||
break;
|
||||
case Parts.PANEL_PART:
|
||||
viewSize = this.workbenchGrid.getViewSize(this.panelPartView);
|
||||
|
||||
this.workbenchGrid.resizeView(this.panelPartView,
|
||||
{
|
||||
width: viewSize.width + (this.getPanelPosition() !== Position.BOTTOM ? sizeChangePxWidth : 0),
|
||||
height: viewSize.height + (this.getPanelPosition() !== Position.BOTTOM ? 0 : sizeChangePxHeight)
|
||||
});
|
||||
|
||||
break;
|
||||
case Parts.EDITOR_PART:
|
||||
viewSize = this.workbenchGrid.getViewSize(this.editorPartView);
|
||||
|
||||
// Single Editor Group
|
||||
if (this.editorGroupService.count === 1) {
|
||||
if (this.isVisible(Parts.SIDEBAR_PART)) {
|
||||
this.workbenchGrid.resizeView(this.editorPartView,
|
||||
{
|
||||
width: viewSize.width + sizeChangePxWidth,
|
||||
height: viewSize.height
|
||||
});
|
||||
} else if (this.isVisible(Parts.PANEL_PART)) {
|
||||
this.workbenchGrid.resizeView(this.editorPartView,
|
||||
{
|
||||
width: viewSize.width + (this.getPanelPosition() !== Position.BOTTOM ? sizeChangePxWidth : 0),
|
||||
height: viewSize.height + (this.getPanelPosition() !== Position.BOTTOM ? 0 : sizeChangePxHeight)
|
||||
});
|
||||
}
|
||||
} else {
|
||||
const activeGroup = this.editorGroupService.activeGroup;
|
||||
|
||||
const { width, height } = this.editorGroupService.getSize(activeGroup);
|
||||
this.editorGroupService.setSize(activeGroup, { width: width + sizeChangePxWidth, height: height + sizeChangePxHeight });
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
return; // Cannot resize other parts
|
||||
}
|
||||
} else {
|
||||
// Legacy Layout
|
||||
this.workbenchGrid.resizePart(part, sizeChange);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -981,7 +1074,28 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
|
||||
|
||||
toggleMaximizedPanel(): void {
|
||||
if (this.workbenchGrid instanceof Grid) {
|
||||
this.workbenchGrid.maximizeViewSize(this.panelPartView);
|
||||
const curSize = this.workbenchGrid.getViewSize2(this.panelPartView);
|
||||
const size = { ...curSize };
|
||||
|
||||
if (!this.isPanelMaximized()) {
|
||||
if (this.state.panel.position === Position.BOTTOM) {
|
||||
size.height = this.panelPartView.maximumHeight;
|
||||
this.state.panel.sizeBeforeMaximize = curSize.height;
|
||||
} else {
|
||||
size.width = this.panelPartView.maximumWidth;
|
||||
this.state.panel.sizeBeforeMaximize = curSize.width;
|
||||
}
|
||||
|
||||
this.storageService.store(Storage.PANEL_SIZE_BEFORE_MAXIMIZED, this.state.panel.sizeBeforeMaximize, StorageScope.GLOBAL);
|
||||
} else {
|
||||
if (this.state.panel.position === Position.BOTTOM) {
|
||||
size.height = this.state.panel.sizeBeforeMaximize;
|
||||
} else {
|
||||
size.width = this.state.panel.sizeBeforeMaximize;
|
||||
}
|
||||
}
|
||||
|
||||
this.workbenchGrid.resizeView(this.panelPartView, size);
|
||||
} else {
|
||||
this.workbenchGrid.layout({ toggleMaximizedPanel: true, source: Parts.PANEL_PART });
|
||||
}
|
||||
@@ -990,7 +1104,12 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
|
||||
isPanelMaximized(): boolean {
|
||||
if (this.workbenchGrid instanceof Grid) {
|
||||
try {
|
||||
return this.workbenchGrid.getViewSize2(this.panelPartView).height === this.getPart(Parts.PANEL_PART).maximumHeight;
|
||||
// The panel is maximum when the editor is minimum
|
||||
if (this.state.panel.position === Position.BOTTOM) {
|
||||
return this.workbenchGrid.getViewSize2(this.editorPartView).height <= this.editorPartView.minimumHeight;
|
||||
} else {
|
||||
return this.workbenchGrid.getViewSize2(this.editorPartView).width <= this.editorPartView.minimumWidth;
|
||||
}
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
@@ -1069,6 +1188,8 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
|
||||
} else {
|
||||
this.workbenchGrid.layout();
|
||||
}
|
||||
|
||||
this._onPanelPositionChange.fire(positionToString(this.state.panel.position));
|
||||
}
|
||||
|
||||
private savePanelDimension(): void {
|
||||
@@ -1077,25 +1198,9 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
|
||||
}
|
||||
|
||||
if (this.state.panel.position === Position.BOTTOM) {
|
||||
this.state.panel.height = this.workbenchGrid.getViewSize(this.panelPartView);
|
||||
this.state.panel.height = this.workbenchGrid.getViewSize(this.panelPartView).height;
|
||||
} else {
|
||||
this.state.panel.width = this.workbenchGrid.getViewSize(this.panelPartView);
|
||||
}
|
||||
}
|
||||
|
||||
private saveLayoutState(e: IWillSaveStateEvent): void {
|
||||
|
||||
// Zen Mode
|
||||
if (this.state.zenMode.active) {
|
||||
this.storageService.store(Storage.ZEN_MODE_ENABLED, true, StorageScope.WORKSPACE);
|
||||
} else {
|
||||
this.storageService.remove(Storage.ZEN_MODE_ENABLED, StorageScope.WORKSPACE);
|
||||
}
|
||||
|
||||
if (e.reason === WillSaveStateReason.SHUTDOWN && this.state.zenMode.active) {
|
||||
if (!this.configurationService.getValue(Settings.ZEN_MODE_RESTORE)) {
|
||||
this.toggleZenMode(true); // We will not restore zen mode, need to clear all zen mode state changes
|
||||
}
|
||||
this.state.panel.width = this.workbenchGrid.getViewSize(this.panelPartView).width;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -10,16 +10,16 @@ import { IStorageService, StorageScope } from 'vs/platform/storage/common/storag
|
||||
import { IContextViewService } from 'vs/platform/contextview/browser/contextView';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { IThemeService } from 'vs/platform/theme/common/themeService';
|
||||
import { isMacintosh } from 'vs/base/common/platform';
|
||||
import { isMacintosh, isWeb } from 'vs/base/common/platform';
|
||||
import { memoize } from 'vs/base/common/decorators';
|
||||
import { Dimension, getClientArea, size, position, hide, show } from 'vs/base/browser/dom';
|
||||
import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
|
||||
import { getZoomFactor } from 'vs/base/browser/browser';
|
||||
import { Part } from 'vs/workbench/browser/part';
|
||||
|
||||
const TITLE_BAR_HEIGHT = isMacintosh ? 22 : 30;
|
||||
const TITLE_BAR_HEIGHT = isMacintosh && !isWeb ? 22 : 30;
|
||||
const STATUS_BAR_HEIGHT = 22;
|
||||
const ACTIVITY_BAR_WIDTH = 50;
|
||||
const ACTIVITY_BAR_WIDTH = 48;
|
||||
|
||||
const MIN_SIDEBAR_PART_WIDTH = 170;
|
||||
const DEFAULT_SIDEBAR_PART_WIDTH = 300;
|
||||
@@ -726,8 +726,8 @@ export class WorkbenchLegacyLayout extends Disposable implements IVerticalSashLa
|
||||
} else {
|
||||
const activeGroup = this.editorGroupService.activeGroup;
|
||||
|
||||
const activeGroupSize = this.editorGroupService.getSize(activeGroup);
|
||||
this.editorGroupService.setSize(activeGroup, activeGroupSize + sizeChangePxWidth);
|
||||
const { width, height } = this.editorGroupService.getSize(activeGroup);
|
||||
this.editorGroupService.setSize(activeGroup, { width: width + sizeChangePxWidth, height: height + sizeChangePxHeight });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -161,6 +161,7 @@ body.web {
|
||||
/* START Keyboard Focus Indication Styles */
|
||||
|
||||
.monaco-workbench [tabindex="0"]:focus,
|
||||
.monaco-workbench [tabindex="-1"]:focus,
|
||||
.monaco-workbench .synthetic-focus,
|
||||
.monaco-workbench select:focus,
|
||||
.monaco-workbench input[type="button"]:focus,
|
||||
@@ -174,6 +175,7 @@ body.web {
|
||||
}
|
||||
|
||||
.monaco-workbench [tabindex="0"]:active,
|
||||
.monaco-workbench [tabindex="-1"]:active,
|
||||
.monaco-workbench select:active,
|
||||
.monaco-workbench input[type="button"]:active,
|
||||
.monaco-workbench input[type="checkbox"]:active,
|
||||
|
||||
@@ -41,6 +41,13 @@ export class PanelRegistry extends CompositeRegistry<Panel> {
|
||||
super.deregisterComposite(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a panel by id.
|
||||
*/
|
||||
getPanel(id: string): PanelDescriptor | null {
|
||||
return this.getComposite(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of registered panels known to the platform.
|
||||
*/
|
||||
|
||||
@@ -8,11 +8,11 @@ import * as nls from 'vs/nls';
|
||||
import * as DOM from 'vs/base/browser/dom';
|
||||
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
|
||||
import { EventType as TouchEventType, GestureEvent } from 'vs/base/browser/touch';
|
||||
import { Action } from 'vs/base/common/actions';
|
||||
import { Action, IAction } from 'vs/base/common/actions';
|
||||
import { KeyCode } from 'vs/base/common/keyCodes';
|
||||
import { dispose } from 'vs/base/common/lifecycle';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { SyncActionDescriptor } from 'vs/platform/actions/common/actions';
|
||||
import { SyncActionDescriptor, IMenuService, MenuId } from 'vs/platform/actions/common/actions';
|
||||
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
@@ -21,11 +21,13 @@ import { ICssStyleCollector, ITheme, IThemeService, registerThemingParticipant }
|
||||
import { ActivityAction, ActivityActionViewItem, ICompositeBar, ICompositeBarColors, ToggleCompositePinnedAction } from 'vs/workbench/browser/parts/compositeBarActions';
|
||||
import { ViewletDescriptor } from 'vs/workbench/browser/viewlet';
|
||||
import { Extensions as ActionExtensions, IWorkbenchActionRegistry } from 'vs/workbench/common/actions';
|
||||
import { IActivity, IGlobalActivity } from 'vs/workbench/common/activity';
|
||||
import { IActivity } from 'vs/workbench/common/activity';
|
||||
import { ACTIVITY_BAR_FOREGROUND } from 'vs/workbench/common/theme';
|
||||
import { IActivityBarService } from 'vs/workbench/services/activityBar/browser/activityBarService';
|
||||
import { IWorkbenchLayoutService, Parts } from 'vs/workbench/services/layout/browser/layoutService';
|
||||
import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet';
|
||||
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { createAndFillInActionBarActions } from 'vs/platform/actions/browser/menuEntryActionViewItem';
|
||||
|
||||
export class ViewletActivityAction extends ActivityAction {
|
||||
|
||||
@@ -104,20 +106,15 @@ export class ToggleViewletAction extends Action {
|
||||
}
|
||||
}
|
||||
|
||||
export class GlobalActivityAction extends ActivityAction {
|
||||
|
||||
constructor(activity: IGlobalActivity) {
|
||||
super(activity);
|
||||
}
|
||||
}
|
||||
|
||||
export class GlobalActivityActionViewItem extends ActivityActionViewItem {
|
||||
|
||||
constructor(
|
||||
action: GlobalActivityAction,
|
||||
action: ActivityAction,
|
||||
colors: (theme: ITheme) => ICompositeBarColors,
|
||||
@IThemeService themeService: IThemeService,
|
||||
@IContextMenuService protected contextMenuService: IContextMenuService
|
||||
@IMenuService private readonly menuService: IMenuService,
|
||||
@IContextMenuService protected contextMenuService: IContextMenuService,
|
||||
@IContextKeyService private readonly contextKeyService: IContextKeyService,
|
||||
) {
|
||||
super(action, { draggable: false, colors, icon: true }, themeService);
|
||||
}
|
||||
@@ -148,16 +145,19 @@ export class GlobalActivityActionViewItem extends ActivityActionViewItem {
|
||||
}
|
||||
|
||||
private showContextMenu(): void {
|
||||
const globalAction = this._action as GlobalActivityAction;
|
||||
const activity = globalAction.activity as IGlobalActivity;
|
||||
const actions = activity.getActions();
|
||||
const globalActivityActions: IAction[] = [];
|
||||
const globalActivityMenu = this.menuService.createMenu(MenuId.GlobalActivity, this.contextKeyService);
|
||||
const actionsDisposable = createAndFillInActionBarActions(globalActivityMenu, undefined, { primary: [], secondary: globalActivityActions });
|
||||
|
||||
const containerPosition = DOM.getDomNodePagePosition(this.container);
|
||||
const location = { x: containerPosition.left + containerPosition.width / 2, y: containerPosition.top };
|
||||
|
||||
this.contextMenuService.showContextMenu({
|
||||
getAnchor: () => location,
|
||||
getActions: () => actions,
|
||||
onHide: () => dispose(actions)
|
||||
getActions: () => globalActivityActions,
|
||||
onHide: () => {
|
||||
globalActivityMenu.dispose();
|
||||
dispose(actionsDisposable);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -173,7 +173,7 @@ export class PlaceHolderViewletActivityAction extends ViewletActivityAction {
|
||||
super({ id, name: id, cssClass: `extensionViewlet-placeholder-${id.replace(/\./g, '-')}` }, viewletService, layoutService, telemetryService);
|
||||
|
||||
const iconClass = `.monaco-workbench .activitybar .monaco-action-bar .action-label.${this.class}`; // Generate Placeholder CSS to show the icon in the activity bar
|
||||
DOM.createCSSRule(iconClass, `-webkit-mask: url('${iconUrl || ''}') no-repeat 50% 50%`);
|
||||
DOM.createCSSRule(iconClass, `-webkit-mask: url('${DOM.asDomUri(iconUrl) || ''}') no-repeat 50% 50%; -webkit-mask-size: 24px;`);
|
||||
}
|
||||
|
||||
setActivity(activity: IActivity): void {
|
||||
@@ -260,8 +260,8 @@ export class NextSideBarViewAction extends SwitchSideBarViewAction {
|
||||
}
|
||||
|
||||
const registry = Registry.as<IWorkbenchActionRegistry>(ActionExtensions.WorkbenchActions);
|
||||
registry.registerWorkbenchAction(new SyncActionDescriptor(PreviousSideBarViewAction, PreviousSideBarViewAction.ID, PreviousSideBarViewAction.LABEL), 'View: Open Previous Side Bar View', nls.localize('view', "View"));
|
||||
registry.registerWorkbenchAction(new SyncActionDescriptor(NextSideBarViewAction, NextSideBarViewAction.ID, NextSideBarViewAction.LABEL), 'View: Open Next Side Bar View', nls.localize('view', "View"));
|
||||
registry.registerWorkbenchAction(new SyncActionDescriptor(PreviousSideBarViewAction, PreviousSideBarViewAction.ID, PreviousSideBarViewAction.LABEL), 'View: Previous Side Bar View', nls.localize('view', "View"));
|
||||
registry.registerWorkbenchAction(new SyncActionDescriptor(NextSideBarViewAction, NextSideBarViewAction.ID, NextSideBarViewAction.LABEL), 'View: Next Side Bar View', nls.localize('view', "View"));
|
||||
|
||||
registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => {
|
||||
|
||||
|
||||
@@ -7,15 +7,15 @@ import 'vs/css!./media/activitybarpart';
|
||||
import * as nls from 'vs/nls';
|
||||
import { illegalArgument } from 'vs/base/common/errors';
|
||||
import { ActionsOrientation, ActionBar } from 'vs/base/browser/ui/actionbar/actionbar';
|
||||
import { GlobalActivityExtensions, IGlobalActivityRegistry } from 'vs/workbench/common/activity';
|
||||
import { GLOBAL_ACTIVITY_ID } from 'vs/workbench/common/activity';
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { Part } from 'vs/workbench/browser/part';
|
||||
import { GlobalActivityActionViewItem, GlobalActivityAction, ViewletActivityAction, ToggleViewletAction, PlaceHolderToggleCompositePinnedAction, PlaceHolderViewletActivityAction } from 'vs/workbench/browser/parts/activitybar/activitybarActions';
|
||||
import { GlobalActivityActionViewItem, ViewletActivityAction, ToggleViewletAction, PlaceHolderToggleCompositePinnedAction, PlaceHolderViewletActivityAction } from 'vs/workbench/browser/parts/activitybar/activitybarActions';
|
||||
import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet';
|
||||
import { IBadge } from 'vs/workbench/services/activity/common/activity';
|
||||
import { IWorkbenchLayoutService, Parts, Position as SideBarPosition } from 'vs/workbench/services/layout/browser/layoutService';
|
||||
import { IInstantiationService, ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IDisposable, toDisposable, dispose } from 'vs/base/common/lifecycle';
|
||||
import { IDisposable, toDisposable, DisposableStore } from 'vs/base/common/lifecycle';
|
||||
import { ToggleActivityBarVisibilityAction } from 'vs/workbench/browser/actions/layoutActions';
|
||||
import { IThemeService, ITheme } from 'vs/platform/theme/common/themeService';
|
||||
import { ACTIVITY_BAR_BACKGROUND, ACTIVITY_BAR_BORDER, ACTIVITY_BAR_FOREGROUND, ACTIVITY_BAR_BADGE_BACKGROUND, ACTIVITY_BAR_BADGE_FOREGROUND, ACTIVITY_BAR_DRAG_AND_DROP_BACKGROUND, ACTIVITY_BAR_INACTIVE_FOREGROUND } from 'vs/workbench/common/theme';
|
||||
@@ -25,7 +25,7 @@ import { Dimension, addClass } from 'vs/base/browser/dom';
|
||||
import { IStorageService, StorageScope, IWorkspaceStorageChangeEvent } from 'vs/platform/storage/common/storage';
|
||||
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { URI, UriComponents } from 'vs/base/common/uri';
|
||||
import { ToggleCompositePinnedAction, ICompositeBarColors } from 'vs/workbench/browser/parts/compositeBarActions';
|
||||
import { ToggleCompositePinnedAction, ICompositeBarColors, ActivityAction } from 'vs/workbench/browser/parts/compositeBarActions';
|
||||
import { ViewletDescriptor } from 'vs/workbench/browser/viewlet';
|
||||
import { IViewsService, IViewContainersRegistry, Extensions as ViewContainerExtensions, ViewContainer, TEST_VIEW_CONTAINER_ID, IViewDescriptorCollection } from 'vs/workbench/common/views';
|
||||
import { IContextKeyService, ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
|
||||
@@ -48,24 +48,26 @@ export class ActivitybarPart extends Part implements IActivityBarService {
|
||||
|
||||
_serviceBrand: ServiceIdentifier<any>;
|
||||
|
||||
private static readonly ACTION_HEIGHT = 50;
|
||||
private static readonly ACTION_HEIGHT = 48;
|
||||
private static readonly PINNED_VIEWLETS = 'workbench.activity.pinnedViewlets';
|
||||
|
||||
//#region IView
|
||||
|
||||
readonly minimumWidth: number = 50;
|
||||
readonly maximumWidth: number = 50;
|
||||
readonly minimumWidth: number = 48;
|
||||
readonly maximumWidth: number = 48;
|
||||
readonly minimumHeight: number = 0;
|
||||
readonly maximumHeight: number = Number.POSITIVE_INFINITY;
|
||||
|
||||
//#endregion
|
||||
|
||||
private globalActionBar: ActionBar;
|
||||
private globalActivityIdToActions: { [globalActivityId: string]: GlobalActivityAction; } = Object.create(null);
|
||||
private globalActivityAction: ActivityAction;
|
||||
private globalActivityActionBar: ActionBar;
|
||||
|
||||
private cachedViewlets: ICachedViewlet[] = [];
|
||||
|
||||
private compositeBar: CompositeBar;
|
||||
private compositeActions: { [compositeId: string]: { activityAction: ViewletActivityAction, pinnedAction: ToggleCompositePinnedAction } } = Object.create(null);
|
||||
private compositeActions: Map<string, { activityAction: ViewletActivityAction, pinnedAction: ToggleCompositePinnedAction }> = new Map();
|
||||
|
||||
private readonly viewletDisposables: Map<string, IDisposable> = new Map<string, IDisposable>();
|
||||
|
||||
constructor(
|
||||
@@ -119,15 +121,13 @@ export class ActivitybarPart extends Part implements IActivityBarService {
|
||||
this._register(this.viewletService.onDidViewletClose(viewlet => this.compositeBar.deactivateComposite(viewlet.getId())));
|
||||
|
||||
// Extension registration
|
||||
let disposables: IDisposable[] = [];
|
||||
let disposables = this._register(new DisposableStore());
|
||||
this._register(this.extensionService.onDidRegisterExtensions(() => {
|
||||
disposables = dispose(disposables);
|
||||
disposables.clear();
|
||||
this.onDidRegisterExtensions();
|
||||
this.compositeBar.onDidChange(() => this.saveCachedViewlets(), this, disposables);
|
||||
this.storageService.onDidChangeStorage(e => this.onDidStorageChange(e), this, disposables);
|
||||
}));
|
||||
|
||||
this._register(toDisposable(() => dispose(disposables)));
|
||||
}
|
||||
|
||||
private onDidRegisterExtensions(): void {
|
||||
@@ -161,34 +161,30 @@ export class ActivitybarPart extends Part implements IActivityBarService {
|
||||
return this.compositeBar.showActivity(viewletOrActionId, badge, clazz, priority);
|
||||
}
|
||||
|
||||
return this.showGlobalActivity(viewletOrActionId, badge, clazz);
|
||||
if (viewletOrActionId === GLOBAL_ACTIVITY_ID) {
|
||||
return this.showGlobalActivity(badge, clazz);
|
||||
}
|
||||
|
||||
throw illegalArgument('globalActivityId');
|
||||
}
|
||||
|
||||
private showGlobalActivity(globalActivityId: string, badge: IBadge, clazz?: string): IDisposable {
|
||||
if (!badge) {
|
||||
throw illegalArgument('badge');
|
||||
}
|
||||
private showGlobalActivity(badge: IBadge, clazz?: string): IDisposable {
|
||||
this.globalActivityAction.setBadge(badge, clazz);
|
||||
|
||||
const action = this.globalActivityIdToActions[globalActivityId];
|
||||
if (!action) {
|
||||
throw illegalArgument('globalActivityId');
|
||||
}
|
||||
|
||||
action.setBadge(badge, clazz);
|
||||
|
||||
return toDisposable(() => action.setBadge(undefined));
|
||||
return toDisposable(() => this.globalActivityAction.setBadge(undefined));
|
||||
}
|
||||
|
||||
createContentArea(parent: HTMLElement): HTMLElement {
|
||||
this.element = parent;
|
||||
|
||||
const content = document.createElement('div');
|
||||
addClass(content, 'content');
|
||||
parent.appendChild(content);
|
||||
|
||||
// Top Actionbar with action items for each viewlet action
|
||||
// Viewlets action bar
|
||||
this.compositeBar.create(content);
|
||||
|
||||
// Top Actionbar with action items for each viewlet action
|
||||
// Global action bar
|
||||
const globalActivities = document.createElement('div');
|
||||
addClass(globalActivities, 'global-activity');
|
||||
content.appendChild(globalActivities);
|
||||
@@ -208,7 +204,7 @@ export class ActivitybarPart extends Part implements IActivityBarService {
|
||||
|
||||
const borderColor = this.getColor(ACTIVITY_BAR_BORDER) || this.getColor(contrastBorder);
|
||||
const isPositionLeft = this.layoutService.getSideBarPosition() === SideBarPosition.LEFT;
|
||||
container.style.boxSizing = borderColor && isPositionLeft ? 'border-box' : null;
|
||||
container.style.boxSizing = borderColor && isPositionLeft ? 'border-box' : '';
|
||||
container.style.borderRightWidth = borderColor && isPositionLeft ? '1px' : null;
|
||||
container.style.borderRightStyle = borderColor && isPositionLeft ? 'solid' : null;
|
||||
container.style.borderRightColor = isPositionLeft ? borderColor : null;
|
||||
@@ -229,27 +225,23 @@ export class ActivitybarPart extends Part implements IActivityBarService {
|
||||
}
|
||||
|
||||
private createGlobalActivityActionBar(container: HTMLElement): void {
|
||||
const activityRegistry = Registry.as<IGlobalActivityRegistry>(GlobalActivityExtensions);
|
||||
const descriptors = activityRegistry.getActivities();
|
||||
const actions = descriptors
|
||||
.map(d => this.instantiationService.createInstance(d))
|
||||
.map(a => new GlobalActivityAction(a));
|
||||
|
||||
this.globalActionBar = this._register(new ActionBar(container, {
|
||||
this.globalActivityActionBar = this._register(new ActionBar(container, {
|
||||
actionViewItemProvider: a => this.instantiationService.createInstance(GlobalActivityActionViewItem, a, (theme: ITheme) => this.getActivitybarItemColors(theme)),
|
||||
orientation: ActionsOrientation.VERTICAL,
|
||||
ariaLabel: nls.localize('globalActions', "Global Actions"),
|
||||
ariaLabel: nls.localize('manage', "Manage"),
|
||||
animated: false
|
||||
}));
|
||||
|
||||
actions.forEach(a => {
|
||||
this.globalActivityIdToActions[a.id] = a;
|
||||
this.globalActionBar.push(a);
|
||||
this.globalActivityAction = new ActivityAction({
|
||||
id: 'workbench.actions.manage',
|
||||
name: nls.localize('manage', "Manage"),
|
||||
cssClass: 'update-activity'
|
||||
});
|
||||
this.globalActivityActionBar.push(this.globalActivityAction);
|
||||
}
|
||||
|
||||
private getCompositeActions(compositeId: string): { activityAction: ViewletActivityAction, pinnedAction: ToggleCompositePinnedAction } {
|
||||
let compositeActions = this.compositeActions[compositeId];
|
||||
let compositeActions = this.compositeActions.get(compositeId);
|
||||
if (!compositeActions) {
|
||||
const viewlet = this.viewletService.getViewlet(compositeId);
|
||||
if (viewlet) {
|
||||
@@ -265,7 +257,7 @@ export class ActivitybarPart extends Part implements IActivityBarService {
|
||||
};
|
||||
}
|
||||
|
||||
this.compositeActions[compositeId] = compositeActions;
|
||||
this.compositeActions.set(compositeId, compositeActions);
|
||||
}
|
||||
|
||||
return compositeActions;
|
||||
@@ -341,11 +333,11 @@ export class ActivitybarPart extends Part implements IActivityBarService {
|
||||
|
||||
private hideComposite(compositeId: string): void {
|
||||
this.compositeBar.hideComposite(compositeId);
|
||||
const compositeActions = this.compositeActions[compositeId];
|
||||
const compositeActions = this.compositeActions.get(compositeId);
|
||||
if (compositeActions) {
|
||||
compositeActions.activityAction.dispose();
|
||||
compositeActions.pinnedAction.dispose();
|
||||
delete this.compositeActions[compositeId];
|
||||
this.compositeActions.delete(compositeId);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -379,8 +371,8 @@ export class ActivitybarPart extends Part implements IActivityBarService {
|
||||
|
||||
// Layout composite bar
|
||||
let availableHeight = contentAreaSize.height;
|
||||
if (this.globalActionBar) {
|
||||
availableHeight -= (this.globalActionBar.viewItems.length * ActivitybarPart.ACTION_HEIGHT); // adjust height for global actions showing
|
||||
if (this.globalActivityActionBar) {
|
||||
availableHeight -= (this.globalActivityActionBar.viewItems.length * ActivitybarPart.ACTION_HEIGHT); // adjust height for global actions showing
|
||||
}
|
||||
this.compositeBar.layout(new Dimension(width, availableHeight));
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
height: 40px;
|
||||
line-height: 40px;
|
||||
margin-right: 0;
|
||||
padding: 0 0 0 50px;
|
||||
padding: 0 0 0 48px;
|
||||
box-sizing: border-box;
|
||||
font-size: 15px;
|
||||
}
|
||||
@@ -54,11 +54,12 @@
|
||||
position: absolute;
|
||||
top: 20px;
|
||||
right: 8px;
|
||||
font-size: 11px;
|
||||
font-size: 9px;
|
||||
font-weight: 600;
|
||||
min-width: 8px;
|
||||
height: 18px;
|
||||
line-height: 18px;
|
||||
padding: 0 5px;
|
||||
height: 16px;
|
||||
line-height: 16px;
|
||||
padding: 0 4px;
|
||||
border-radius: 20px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
.monaco-workbench .part.activitybar {
|
||||
width: 50px;
|
||||
width: 48px;
|
||||
}
|
||||
|
||||
.monaco-workbench .activitybar > .content {
|
||||
@@ -24,5 +24,9 @@
|
||||
}
|
||||
|
||||
.monaco-workbench .activitybar > .content > .composite-bar > .monaco-action-bar .action-label.toggle-more {
|
||||
-webkit-mask: url('ellipsis-global.svg') no-repeat 50% 50%;
|
||||
-webkit-mask: url('ellipsis-activity-bar.svg') no-repeat 50% 50%;
|
||||
}
|
||||
|
||||
.monaco-workbench .activitybar .global-activity .monaco-action-bar .action-label.update-activity {
|
||||
-webkit-mask: url('settings-activity-bar.svg') no-repeat 50% 50%;
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M6 12C6 12.2967 5.91203 12.5867 5.74721 12.8334C5.58238 13.08 5.34812 13.2723 5.07403 13.3858C4.79994 13.4994 4.49834 13.5291 4.20737 13.4712C3.91639 13.4133 3.64912 13.2704 3.43934 13.0607C3.22956 12.8509 3.0867 12.5836 3.02882 12.2926C2.97094 12.0017 3.00065 11.7001 3.11418 11.426C3.22771 11.1519 3.41997 10.9176 3.66665 10.7528C3.91332 10.588 4.20333 10.5 4.5 10.5C4.89783 10.5 5.27936 10.658 5.56066 10.9393C5.84197 11.2206 6 11.6022 6 12Z" fill="white"/>
|
||||
<path d="M13.5 12C13.5 12.2967 13.412 12.5867 13.2472 12.8334C13.0824 13.08 12.8481 13.2723 12.574 13.3858C12.2999 13.4994 11.9983 13.5291 11.7074 13.4712C11.4164 13.4133 11.1491 13.2704 10.9393 13.0607C10.7296 12.8509 10.5867 12.5836 10.5288 12.2926C10.4709 12.0017 10.5006 11.7001 10.6142 11.426C10.7277 11.1519 10.92 10.9176 11.1666 10.7528C11.4133 10.588 11.7033 10.5 12 10.5C12.3978 10.5 12.7794 10.658 13.0607 10.9393C13.342 11.2206 13.5 11.6022 13.5 12Z" fill="white"/>
|
||||
<path d="M21 12C21 12.2967 20.912 12.5867 20.7472 12.8334C20.5824 13.08 20.3481 13.2723 20.074 13.3858C19.7999 13.4994 19.4983 13.5291 19.2074 13.4712C18.9164 13.4133 18.6491 13.2704 18.4393 13.0607C18.2296 12.8509 18.0867 12.5836 18.0288 12.2926C17.9709 12.0017 18.0006 11.7001 18.1142 11.426C18.2277 11.1519 18.42 10.9176 18.6666 10.7528C18.9133 10.588 19.2033 10.5 19.5 10.5C19.8978 10.5 20.2794 10.658 20.5607 10.9393C20.842 11.2206 21 11.6022 21 12Z" fill="white"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.5 KiB |
@@ -1 +0,0 @@
|
||||
<svg fill="none" height="28" viewBox="0 0 28 28" width="28" xmlns="http://www.w3.org/2000/svg"><path d="m7.53846 13.7692c0 .5477-.16241 1.0831-.4667 1.5385-.30428.4554-.73678.8104-1.24279 1.02s-1.06281.2644-1.59999.1576c-.53718-.1069-1.03061-.3706-1.41789-.7579s-.65103-.8807-.75788-1.4179-.05201-1.094.15759-1.6c.20959-.506.56453-.9385 1.01993-1.2428s.9908-.4667 1.5385-.4667c.73445 0 1.43881.2918 1.95814.8111.51934.5193.81109 1.2237.81109 1.9581zm6.46154-2.7692c-.5477 0-1.0831.1624-1.5385.4667s-.8103.7368-1.0199 1.2428-.2645 1.0628-.1576 1.6c.1068.5372.3706 1.0306.7579 1.4179.3872.3873.8807.651 1.4179.7579.5371.1068 1.0939.052 1.5999-.1576s.9385-.5646 1.2428-1.02.4667-.9908.4667-1.5385c0-.7344-.2917-1.4388-.8111-1.9581-.5193-.5193-1.2237-.8111-1.9581-.8111zm9.2308 0c-.5477 0-1.0831.1624-1.5385.4667s-.8104.7368-1.02 1.2428-.2644 1.0628-.1576 1.6c.1069.5372.3706 1.0306.7579 1.4179s.8807.651 1.4179.7579c.5372.1068 1.094.052 1.6-.1576s.9385-.5646 1.2428-1.02.4667-.9908.4667-1.5385c0-.7344-.2918-1.4388-.8111-1.9581s-1.2237-.8111-1.9581-.8111z" fill="#fff"/></svg>
|
||||
|
Before Width: | Height: | Size: 1.0 KiB |
@@ -0,0 +1,3 @@
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M14.4198 0L15.2504 4.15289L18.7742 1.80367L22.1963 5.22578L19.8471 8.74964L24 9.58022V14.4198L19.8471 15.2504L22.1963 18.7742L18.7742 22.1963L15.2504 19.8471L14.4198 24H9.5802L8.74962 19.8471L5.22579 22.1963L1.80368 18.7742L4.15291 15.2504L0 14.4198V9.58022L4.1529 8.74964L1.80367 5.2258L5.22578 1.80369L8.74963 4.15292L9.5802 3.68124e-05L14.4198 0ZM18.2347 10.184L17.6927 8.87549L19.9795 5.44529L18.5547 4.02052L15.1245 6.30732L13.816 5.76534L13.0075 1.72278L10.9925 1.7228L10.184 5.76536L8.87549 6.30734L5.4453 4.02055L4.02053 5.44531L6.30734 8.87553L5.7653 10.184L1.72277 10.9926V13.0075L5.7653 13.816L6.30735 15.1245L4.02053 18.5547L5.4453 19.9795L8.87551 17.6927L10.184 18.2347L10.9925 22.2772H13.0075L13.816 18.2347L15.1245 17.6927L18.5547 19.9795L19.9795 18.5547L17.6927 15.1245L18.2347 13.816L22.2772 13.0075V10.9926L18.2347 10.184ZM13.7143 12C13.7143 12.9468 12.9468 13.7143 12 13.7143C11.0532 13.7143 10.2857 12.9468 10.2857 12C10.2857 11.0532 11.0532 10.2857 12 10.2857C12.9468 10.2857 13.7143 11.0532 13.7143 12ZM15.4286 12C15.4286 13.8935 13.8935 15.4286 12 15.4286C10.1065 15.4286 8.57143 13.8935 8.57143 12C8.57143 10.1065 10.1065 8.57143 12 8.57143C13.8935 8.57143 15.4286 10.1065 15.4286 12Z" fill="#F4F4F4"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.3 KiB |
@@ -201,6 +201,7 @@ export class CompositeBar extends Widget implements ICompositeBar {
|
||||
|
||||
const activity: ICompositeActivity = { badge, clazz, priority };
|
||||
this.model.addActivity(compositeId, activity);
|
||||
|
||||
return toDisposable(() => this.model.removeActivity(compositeId, activity));
|
||||
}
|
||||
|
||||
@@ -427,7 +428,7 @@ export class CompositeBar extends Widget implements ICompositeBar {
|
||||
});
|
||||
}
|
||||
|
||||
private getContextMenuActions(): IAction[] {
|
||||
private getContextMenuActions(): ReadonlyArray<IAction> {
|
||||
const actions: IAction[] = this.model.visibleItems
|
||||
.map(({ id, name, activityAction }) => (<IAction>{
|
||||
id,
|
||||
|
||||