diff --git a/extensions/markdown/src/features/previewContentProvider.ts b/extensions/markdown/src/features/previewContentProvider.ts index a0356d51ce47b..3a9fa3419bf05 100644 --- a/extensions/markdown/src/features/previewContentProvider.ts +++ b/extensions/markdown/src/features/previewContentProvider.ts @@ -312,6 +312,10 @@ export class MarkdownPreviewWebviewManager { vscode.workspace.onDidChangeTextDocument(event => { this.update(event.document.uri); }, null, this.disposables); + + vscode.window.onDidChangeActiveEditor(editor => { + vscode.commands.executeCommand('setContext', 'markdownPreview', editor && editor.editorType === 'webview'); + }, null, this.disposables); } public dispose(): void { @@ -362,14 +366,6 @@ export class MarkdownPreviewWebviewManager { vscode.commands.executeCommand(e.command, ...e.args); }); - view.onBecameActive(() => { - vscode.commands.executeCommand('setContext', 'markdownPreview', true); - }); - - view.onBecameInactive(() => { - vscode.commands.executeCommand('setContext', 'markdownPreview', false); - }); - this.webviews.set(resource.fsPath, view); return view; } diff --git a/src/vs/vscode.d.ts b/src/vs/vscode.d.ts index a6d31fc4b46be..2554c4a8dc1ea 100644 --- a/src/vs/vscode.d.ts +++ b/src/vs/vscode.d.ts @@ -1028,6 +1028,10 @@ declare module 'vscode' { * Represents an editor that is attached to a [document](#TextDocument). */ export interface TextEditor { + /** + * Type identifying the editor as a text editor. + */ + readonly editorType: 'texteditor'; /** * The document associated with this text editor. The document will be the same for the entire lifetime of this text editor. diff --git a/src/vs/vscode.proposed.d.ts b/src/vs/vscode.proposed.d.ts index 88767411c1651..e8978983b2fd6 100644 --- a/src/vs/vscode.proposed.d.ts +++ b/src/vs/vscode.proposed.d.ts @@ -526,6 +526,11 @@ declare module 'vscode' { * A webview is an editor with html content, like an iframe. */ export interface Webview { + /** + * Type identifying the editor as a webview editor. + */ + readonly editorType: 'webview'; + /** * Title of the webview. */ @@ -551,16 +556,6 @@ declare module 'vscode' { */ readonly onMessage: Event; - /** - * Fired when the webview becomes the active editor. - */ - readonly onBecameActive: Event; - - /** - * Fired when the webview stops being the active editor - */ - readonly onBecameInactive: Event; - /** * Post a message to the webview content. * @@ -585,5 +580,7 @@ declare module 'vscode' { * @param options Webview content options. */ export function createWebview(title: string, column: ViewColumn, options: WebviewOptions): Webview; + + export const onDidChangeActiveEditor: Event; } } diff --git a/src/vs/workbench/api/electron-browser/mainThreadWebview.ts b/src/vs/workbench/api/electron-browser/mainThreadWebview.ts index 1d7da64f5390f..2adcb73b67496 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadWebview.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadWebview.ts @@ -35,8 +35,6 @@ import URI from 'vs/base/common/uri'; interface WebviewEvents { onMessage(message: any): void; - onFocus(): void; - onBlur(): void; } class WebviewInput extends EditorInput { @@ -290,9 +288,7 @@ export class MainThreadWebview implements MainThreadWebviewShape { $createWebview(handle: number): void { const webview = new WebviewInput('', {}, '', { - onMessage: (message) => this._proxy.$onMessage(handle, message), - onFocus: () => this._proxy.$onBecameActive(handle), - onBlur: () => this._proxy.$onBecameInactive(handle) + onMessage: (message) => this._proxy.$onMessage(handle, message) }); this._webviews.set(handle, webview); } @@ -345,28 +341,25 @@ export class MainThreadWebview implements MainThreadWebviewShape { private onEditorsChanged() { const activeEditor = this._editorService.getActiveEditor(); - let newActiveWebview: WebviewInput | undefined = undefined; + let newActiveWebview: { input: WebviewInput, handle: number } | undefined = undefined; if (activeEditor.input instanceof WebviewInput) { for (const handle of map.keys(this._webviews)) { const input = this._webviews.get(handle); if (input.matches(activeEditor.input)) { - newActiveWebview = input; + newActiveWebview = { input, handle }; break; } } } if (newActiveWebview) { - if (!this._activeWebview || !newActiveWebview.matches(this._activeWebview)) { - if (this._activeWebview) { - this._activeWebview.events.onBlur(); - } - newActiveWebview.events.onFocus(); - this._activeWebview = newActiveWebview; + if (!this._activeWebview || !newActiveWebview.input.matches(this._activeWebview)) { + this._proxy.$onDidChangeActiveWeview(newActiveWebview.handle); + this._activeWebview = newActiveWebview.input; } } else { if (this._activeWebview) { - this._activeWebview.events.onBlur(); + this._proxy.$onDidChangeActiveWeview(undefined); this._activeWebview = undefined; } } diff --git a/src/vs/workbench/api/node/extHost.api.impl.ts b/src/vs/workbench/api/node/extHost.api.impl.ts index 50c74c0efb377..0bf616f6b4fa9 100644 --- a/src/vs/workbench/api/node/extHost.api.impl.ts +++ b/src/vs/workbench/api/node/extHost.api.impl.ts @@ -97,7 +97,8 @@ export function createApiFactory( rpcProtocol.set(ExtHostContext.ExtHostLogService, extHostLogService); const extHostHeapService = rpcProtocol.set(ExtHostContext.ExtHostHeapService, new ExtHostHeapService()); const extHostDecorations = rpcProtocol.set(ExtHostContext.ExtHostDecorations, new ExtHostDecorations(rpcProtocol)); - const extHostDocumentsAndEditors = rpcProtocol.set(ExtHostContext.ExtHostDocumentsAndEditors, new ExtHostDocumentsAndEditors(rpcProtocol)); + const extHostWebviews = rpcProtocol.set(ExtHostContext.ExtHostWebviews, new ExtHostWebviews(rpcProtocol)); + const extHostDocumentsAndEditors = rpcProtocol.set(ExtHostContext.ExtHostDocumentsAndEditors, new ExtHostDocumentsAndEditors(rpcProtocol, extHostWebviews)); const extHostDocuments = rpcProtocol.set(ExtHostContext.ExtHostDocuments, new ExtHostDocuments(rpcProtocol, extHostDocumentsAndEditors)); const extHostDocumentContentProviders = rpcProtocol.set(ExtHostContext.ExtHostDocumentContentProviders, new ExtHostDocumentContentProvider(rpcProtocol, extHostDocumentsAndEditors)); const extHostDocumentSaveParticipant = rpcProtocol.set(ExtHostContext.ExtHostDocumentSaveParticipant, new ExtHostDocumentSaveParticipant(extHostLogService, extHostDocuments, rpcProtocol.getProxy(MainContext.MainThreadTextEditors))); @@ -117,7 +118,6 @@ export function createApiFactory( const extHostTask = rpcProtocol.set(ExtHostContext.ExtHostTask, new ExtHostTask(rpcProtocol, extHostWorkspace)); const extHostWindow = rpcProtocol.set(ExtHostContext.ExtHostWindow, new ExtHostWindow(rpcProtocol)); rpcProtocol.set(ExtHostContext.ExtHostExtensionService, extensionService); - const extHostWebviews = rpcProtocol.set(ExtHostContext.ExtHostWebviews, new ExtHostWebviews(rpcProtocol)); // Check that no named customers are missing const expected: ProxyIdentifier[] = Object.keys(ExtHostContext).map((key) => ExtHostContext[key]); @@ -401,7 +401,10 @@ export function createApiFactory( }), createWebview: proposedApiFunction(extension, (name: string, column: vscode.ViewColumn, options: vscode.WebviewOptions) => { return extHostWebviews.createWebview(name, column, options); - }) + }), + onDidChangeActiveEditor: proposedApiFunction(extension, (listener, thisArg?, disposables?) => { + return extHostDocumentsAndEditors.onDidChangeActiveEditor(listener, thisArg, disposables); + }), }; // namespace: workspace diff --git a/src/vs/workbench/api/node/extHost.protocol.ts b/src/vs/workbench/api/node/extHost.protocol.ts index b4715e17ff2c7..587fbef4950ae 100644 --- a/src/vs/workbench/api/node/extHost.protocol.ts +++ b/src/vs/workbench/api/node/extHost.protocol.ts @@ -356,8 +356,7 @@ export interface MainThreadWebviewShape extends IDisposable { } export interface ExtHostWebviewsShape { $onMessage(handle: number, message: any): void; - $onBecameActive(handle: number): void; - $onBecameInactive(handle: number): void; + $onDidChangeActiveWeview(handle: number | undefined): void; } export interface MainThreadWorkspaceShape extends IDisposable { diff --git a/src/vs/workbench/api/node/extHostDocumentsAndEditors.ts b/src/vs/workbench/api/node/extHostDocumentsAndEditors.ts index 65be19d03aaf2..0eafdce9d7237 100644 --- a/src/vs/workbench/api/node/extHostDocumentsAndEditors.ts +++ b/src/vs/workbench/api/node/extHostDocumentsAndEditors.ts @@ -12,10 +12,16 @@ import { ExtHostTextEditor } from './extHostTextEditor'; import * as assert from 'assert'; import * as typeConverters from './extHostTypeConverters'; import URI from 'vs/base/common/uri'; +import { ExtHostWebview, ExtHostWebviews } from './extHostWebview'; +import { Disposable } from './extHostTypes'; export class ExtHostDocumentsAndEditors implements ExtHostDocumentsAndEditorsShape { + private _disposables: Disposable[] = []; + private _activeEditorId: string; + private _activeWebview: ExtHostWebview; + private readonly _editors = new Map(); private readonly _documents = new Map(); @@ -23,15 +29,34 @@ export class ExtHostDocumentsAndEditors implements ExtHostDocumentsAndEditorsSha private readonly _onDidRemoveDocuments = new Emitter(); private readonly _onDidChangeVisibleTextEditors = new Emitter(); private readonly _onDidChangeActiveTextEditor = new Emitter(); + private readonly _onDidChangeActiveEditor = new Emitter(); readonly onDidAddDocuments: Event = this._onDidAddDocuments.event; readonly onDidRemoveDocuments: Event = this._onDidRemoveDocuments.event; readonly onDidChangeVisibleTextEditors: Event = this._onDidChangeVisibleTextEditors.event; readonly onDidChangeActiveTextEditor: Event = this._onDidChangeActiveTextEditor.event; + readonly onDidChangeActiveEditor: Event = this._onDidChangeActiveEditor.event; constructor( - private readonly _mainContext: IMainContext + private readonly _mainContext: IMainContext, + _extHostWebviews?: ExtHostWebviews ) { + if (_extHostWebviews) { + _extHostWebviews.onDidChangeActiveWebview(webview => { + if (webview) { + if (webview !== this._activeWebview) { + this._onDidChangeActiveEditor.fire(webview); + this._activeWebview = webview; + } + } else { + this._activeWebview = webview; + } + }, this, this._disposables); + } + } + + dispose() { + this._disposables = dispose(this._disposables); } $acceptDocumentsAndEditorsDelta(delta: IDocumentsAndEditorsDelta): void { @@ -117,6 +142,9 @@ export class ExtHostDocumentsAndEditors implements ExtHostDocumentsAndEditorsSha } if (delta.newActiveEditor !== undefined) { this._onDidChangeActiveTextEditor.fire(this.activeEditor()); + + const activeEditor = this.activeEditor(); + this._onDidChangeActiveEditor.fire(activeEditor || this._activeWebview); } } diff --git a/src/vs/workbench/api/node/extHostTextEditor.ts b/src/vs/workbench/api/node/extHostTextEditor.ts index 6ebf86fad18b2..356e6f12d8b21 100644 --- a/src/vs/workbench/api/node/extHostTextEditor.ts +++ b/src/vs/workbench/api/node/extHostTextEditor.ts @@ -313,7 +313,7 @@ export class ExtHostTextEditorOptions implements vscode.TextEditorOptions { export class ExtHostTextEditor implements vscode.TextEditor { - public readonly type = 'texteditor'; + public readonly editorType = 'texteditor'; private readonly _proxy: MainThreadTextEditorsShape; private readonly _id: string; diff --git a/src/vs/workbench/api/node/extHostWebview.ts b/src/vs/workbench/api/node/extHostWebview.ts index 97117f0b4d281..8868daf2b6d7f 100644 --- a/src/vs/workbench/api/node/extHostWebview.ts +++ b/src/vs/workbench/api/node/extHostWebview.ts @@ -5,10 +5,12 @@ import { MainContext, MainThreadWebviewShape, IMainContext, ExtHostWebviewsShape } from './extHost.protocol'; import * as vscode from 'vscode'; -import { Emitter } from 'vs/base/common/event'; +import Event, { Emitter } from 'vs/base/common/event'; import * as typeConverters from 'vs/workbench/api/node/extHostTypeConverters'; -class ExtHostWebview implements vscode.Webview { +export class ExtHostWebview implements vscode.Webview { + public readonly editorType = 'webview'; + private _title: string; private _html: string; private _options: vscode.WebviewOptions; @@ -17,13 +19,7 @@ class ExtHostWebview implements vscode.Webview { public readonly onMessageEmitter = new Emitter(); - public readonly onMessage = this.onMessageEmitter.event; - - public readonly onBecameActiveEmitter = new Emitter(); - public readonly onBecameActive = this.onBecameActiveEmitter.event; - - public readonly onBecameInactiveEmitter = new Emitter(); - public readonly onBecameInactive = this.onBecameInactiveEmitter.event; + public readonly onMessage: Event = this.onMessageEmitter.event; constructor( private readonly _proxy: MainThreadWebviewShape, @@ -114,13 +110,11 @@ export class ExtHostWebviews implements ExtHostWebviewsShape { webview.onMessageEmitter.fire(message); } - $onBecameActive(handle: number): void { + $onDidChangeActiveWeview(handle: number | undefined): void { const webview = this._webviews.get(handle); - webview.onBecameActiveEmitter.fire(); + this._onDidChangeActiveWebview.fire(webview); } - $onBecameInactive(handle: number): void { - const webview = this._webviews.get(handle); - webview.onBecameInactiveEmitter.fire(); - } + private readonly _onDidChangeActiveWebview = new Emitter(); + public readonly onDidChangeActiveWebview = this._onDidChangeActiveWebview.event; } \ No newline at end of file