diff --git a/extensions/markdown-language-features/package.json b/extensions/markdown-language-features/package.json
index 6fa682e351d..9ea81491be4 100644
--- a/extensions/markdown-language-features/package.json
+++ b/extensions/markdown-language-features/package.json
@@ -27,6 +27,11 @@
],
"contributes": {
"commands": [
+ {
+ "command": "unicorn",
+ "title": "🦄 unicorn",
+ "category": "Markdown"
+ },
{
"command": "markdown.showPreview",
"title": "%markdown.preview.title%",
diff --git a/extensions/markdown-language-features/src/extension.ts b/extensions/markdown-language-features/src/extension.ts
index 53e0c6286e1..536a12d9f57 100644
--- a/extensions/markdown-language-features/src/extension.ts
+++ b/extensions/markdown-language-features/src/extension.ts
@@ -59,4 +59,12 @@ export function activate(context: vscode.ExtensionContext) {
logger.updateConfiguration();
previewManager.updateConfiguration();
}));
+
+ vscode.commands.registerCommand('unicorn', () => {
+ if (vscode.window.activeTextEditor) {
+ vscode.window.showWebviewWidget(vscode.window.activeTextEditor, vscode.window.activeTextEditor.selection.active, 'unicorn', 'Webview', {}).then(webview => {
+ webview.html = '
';
+ });
+ }
+ });
}
diff --git a/src/vs/vscode.proposed.d.ts b/src/vs/vscode.proposed.d.ts
index f61737f5919..088c3616e2d 100644
--- a/src/vs/vscode.proposed.d.ts
+++ b/src/vs/vscode.proposed.d.ts
@@ -685,6 +685,8 @@ declare module 'vscode' {
* @param reviver Webview serializer.
*/
export function registerWebviewSerializer(viewType: string, reviver: WebviewSerializer): Disposable;
+
+ export function showWebviewWidget(editor: TextEditor, position: Position, viewType: string, title: string, options: WebviewOptions): Thenable;
}
//#endregion
diff --git a/src/vs/workbench/api/electron-browser/mainThreadWebview.ts b/src/vs/workbench/api/electron-browser/mainThreadWebview.ts
index 0bf8ddedefa..04052285280 100644
--- a/src/vs/workbench/api/electron-browser/mainThreadWebview.ts
+++ b/src/vs/workbench/api/electron-browser/mainThreadWebview.ts
@@ -18,7 +18,10 @@ import { IWebviewEditorService, WebviewInputOptions, WebviewReviver } from 'vs/w
import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService';
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
import { IEditorGroupService } from 'vs/workbench/services/group/common/groupService';
+import { ICodeEditor } from '../../../editor/browser/editorBrowser';
+import { EDITOR_CONTRIBUTION_ID, WebviewWidgetContribution } from '../../parts/webview/electron-browser/webviewWidget';
import { extHostNamedCustomer } from './extHostCustomers';
+import { WebviewElement } from 'vs/workbench/parts/webview/electron-browser/webviewElement';
@extHostNamedCustomer(MainContext.MainThreadWebviews)
export class MainThreadWebviews implements MainThreadWebviewsShape, WebviewReviver {
@@ -34,7 +37,8 @@ export class MainThreadWebviews implements MainThreadWebviewsShape, WebviewReviv
private _toDispose: IDisposable[] = [];
private readonly _proxy: ExtHostWebviewsShape;
- private readonly _webviews = new Map();
+ private readonly _webviewInputs = new Map();
+ private readonly _webviews = new Map();
private readonly _revivers = new Set();
private _activeWebview: WebviewHandle | undefined = undefined;
@@ -77,7 +81,7 @@ export class MainThreadWebviews implements MainThreadWebviewsShape, WebviewReviv
state: undefined
};
- this._webviews.set(handle, webview);
+ this._webviewInputs.set(handle, webview);
}
$disposeWebview(handle: WebviewHandle): void {
@@ -92,7 +96,14 @@ export class MainThreadWebviews implements MainThreadWebviewsShape, WebviewReviv
$setHtml(handle: WebviewHandle, value: string): void {
const webview = this.getWebview(handle);
- webview.html = value;
+ if (webview) {
+ webview.html = value;
+ } else {
+ const webview = this._webviews.get(handle);
+ if (webview) {
+ webview.contents = value;
+ }
+ }
}
$reveal(handle: WebviewHandle, column: Position): void {
@@ -122,11 +133,24 @@ export class MainThreadWebviews implements MainThreadWebviewsShape, WebviewReviv
this._revivers.delete(viewType);
}
+ $showWebviewWidget(handle: WebviewHandle, editorId: string, lineNumber: number, viewType: string, options: WebviewInputOptions): void {
+ const editor = this._editorService.getActiveEditor();
+ if (editor && editor.getControl()) {
+ (editor.getControl() as ICodeEditor).getContribution(EDITOR_CONTRIBUTION_ID).showWebviewWidget(lineNumber, 0, webview => {
+ this._webviews.set(handle, webview);
+ webview.onDidClickLink(uri => this.onDidClickLink(uri, webview.options));
+ webview.onMessage(message => this._proxy.$onMessage(handle, message));
+ });
+ }
+
+ return undefined;
+ }
+
reviveWebview(webview: WebviewEditorInput): TPromise {
const viewType = webview.state.viewType;
return this._extensionService.activateByEvent(`onView:${viewType}`).then(() => {
const handle = 'revival-' + MainThreadWebviews.revivalPool++;
- this._webviews.set(handle, webview);
+ this._webviewInputs.set(handle, webview);
webview._events = this.createWebviewEventDelegate(handle);
return this._proxy.$deserializeWebview(handle, webview.state.viewType, webview.state.state, webview.position, webview.options)
@@ -142,7 +166,7 @@ export class MainThreadWebviews implements MainThreadWebviewsShape, WebviewReviv
private _onWillShutdown(): TPromise {
const toRevive: WebviewHandle[] = [];
- this._webviews.forEach((view, key) => {
+ this._webviewInputs.forEach((view, key) => {
if (this.canRevive(view)) {
toRevive.push(key);
}
@@ -158,7 +182,7 @@ export class MainThreadWebviews implements MainThreadWebviewsShape, WebviewReviv
return TPromise.join(reviveResponses).then(results => {
for (const result of results) {
- const view = this._webviews.get(result.handle);
+ const view = this._webviewInputs.get(result.handle);
if (view) {
if (result.state) {
view.state.state = result.state;
@@ -184,10 +208,10 @@ export class MainThreadWebviews implements MainThreadWebviewsShape, WebviewReviv
}
private getWebview(handle: WebviewHandle): WebviewEditorInput {
- const webview = this._webviews.get(handle);
- if (!webview) {
- throw new Error('Unknown webview handle:' + handle);
- }
+ const webview = this._webviewInputs.get(handle);
+ // if (!webview) {
+ // throw new Error('Unknown webview handle:' + handle);
+ // }
return webview;
}
@@ -195,8 +219,8 @@ export class MainThreadWebviews implements MainThreadWebviewsShape, WebviewReviv
const activeEditor = this._editorService.getActiveEditor();
let newActiveWebview: { input: WebviewEditorInput, handle: WebviewHandle } | undefined = undefined;
if (activeEditor && activeEditor.input instanceof WebviewEditorInput) {
- for (const handle of map.keys(this._webviews)) {
- const input = this._webviews.get(handle);
+ for (const handle of map.keys(this._webviewInputs)) {
+ const input = this._webviewInputs.get(handle);
if (input.matches(activeEditor.input)) {
newActiveWebview = { input, handle };
break;
@@ -211,7 +235,7 @@ export class MainThreadWebviews implements MainThreadWebviewsShape, WebviewReviv
// Broadcast view state update for currently active
if (typeof this._activeWebview !== 'undefined') {
- const oldActiveWebview = this._webviews.get(this._activeWebview);
+ const oldActiveWebview = this._webviewInputs.get(this._activeWebview);
if (oldActiveWebview) {
this._proxy.$onDidChangeWeviewViewState(this._activeWebview, false, oldActiveWebview.position);
}
diff --git a/src/vs/workbench/api/node/extHost.api.impl.ts b/src/vs/workbench/api/node/extHost.api.impl.ts
index 6757325af76..80e479583b5 100644
--- a/src/vs/workbench/api/node/extHost.api.impl.ts
+++ b/src/vs/workbench/api/node/extHost.api.impl.ts
@@ -421,6 +421,9 @@ export function createApiFactory(
}),
registerWebviewSerializer: proposedApiFunction(extension, (viewType: string, serializer: vscode.WebviewSerializer) => {
return extHostWebviews.registerWebviewSerializer(viewType, serializer);
+ }),
+ showWebviewWidget: proposedApiFunction(extension, (editor: vscode.TextEditor, position: vscode.Position, viewType: string, title: string, options: vscode.WebviewOptions) => {
+ return extHostWebviews.showWebviewWidget(editor, position.line, viewType, title, options);
})
};
diff --git a/src/vs/workbench/api/node/extHost.protocol.ts b/src/vs/workbench/api/node/extHost.protocol.ts
index aa980077368..8529238873c 100644
--- a/src/vs/workbench/api/node/extHost.protocol.ts
+++ b/src/vs/workbench/api/node/extHost.protocol.ts
@@ -359,6 +359,8 @@ export interface MainThreadWebviewsShape extends IDisposable {
$registerSerializer(viewType: string): void;
$unregisterSerializer(viewType: string): void;
+
+ $showWebviewWidget(handle: WebviewHandle, editorId: string, lineNumber: number, viewType: string, options: vscode.WebviewOptions): void;
}
export interface ExtHostWebviewsShape {
diff --git a/src/vs/workbench/api/node/extHostWebview.ts b/src/vs/workbench/api/node/extHostWebview.ts
index b947841462d..5746e13bb29 100644
--- a/src/vs/workbench/api/node/extHostWebview.ts
+++ b/src/vs/workbench/api/node/extHostWebview.ts
@@ -10,6 +10,7 @@ import * as typeConverters from 'vs/workbench/api/node/extHostTypeConverters';
import { Position } from 'vs/platform/editor/common/editor';
import { TPromise } from 'vs/base/common/winjs.base';
import { Disposable } from './extHostTypes';
+import { ExtHostTextEditor } from './extHostTextEditor';
export class ExtHostWebview implements vscode.Webview {
@@ -141,7 +142,7 @@ export class ExtHostWebviews implements ExtHostWebviewsShape {
private readonly _serializers = new Map();
constructor(
- mainContext: IMainContext
+ mainContext: IMainContext,
) {
this._proxy = mainContext.getProxy(MainContext.MainThreadWebviews);
}
@@ -178,6 +179,15 @@ export class ExtHostWebviews implements ExtHostWebviewsShape {
});
}
+ async showWebviewWidget(editor: vscode.TextEditor, lineNumber: number, viewType: string, title: string, options: vscode.WebviewOptions) {
+ const handle = ExtHostWebviews.webviewHandlePool++ + '';
+ this._proxy.$showWebviewWidget(handle, (editor as ExtHostTextEditor).id, lineNumber, viewType, options);
+
+ const webview = new ExtHostWebview(handle, this._proxy, viewType, undefined, options);
+ this._webviews.set(handle, webview);
+ return webview;
+ }
+
$onMessage(handle: WebviewHandle, message: any): void {
const webview = this.getWebview(handle);
if (webview) {
diff --git a/src/vs/workbench/parts/webview/electron-browser/webviewElement.ts b/src/vs/workbench/parts/webview/electron-browser/webviewElement.ts
index 0ea8ed3965e..9e9ccc1d6dc 100644
--- a/src/vs/workbench/parts/webview/electron-browser/webviewElement.ts
+++ b/src/vs/workbench/parts/webview/electron-browser/webviewElement.ts
@@ -184,6 +184,10 @@ export class WebviewElement {
parent.appendChild(this._webview);
}
+ public getDomNode() {
+ return this._webview;
+ }
+
public notifyFindWidgetFocusChanged(isFocused: boolean) {
this._contextKey.set(isFocused || document.activeElement === this._webview);
}
diff --git a/src/vs/workbench/parts/webview/electron-browser/webviewWidget.ts b/src/vs/workbench/parts/webview/electron-browser/webviewWidget.ts
new file mode 100644
index 00000000000..78e33ac2a0f
--- /dev/null
+++ b/src/vs/workbench/parts/webview/electron-browser/webviewWidget.ts
@@ -0,0 +1,106 @@
+/*---------------------------------------------------------------------------------------------
+ * Copyright (c) Microsoft Corporation. All rights reserved.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ *--------------------------------------------------------------------------------------------*/
+
+import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
+import { ZoneWidget } from 'vs/editor/contrib/zoneWidget/zoneWidget';
+import { IContextViewService } from 'vs/platform/contextview/browser/contextView';
+import { IEnvironmentService } from 'vs/platform/environment/common/environment';
+import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
+import { IThemeService } from 'vs/platform/theme/common/themeService';
+import { WebviewElement } from 'vs/workbench/parts/webview/electron-browser/webviewElement';
+import { IPartService, Parts } from 'vs/workbench/services/part/common/partService';
+import { IEditorContribution } from 'vs/editor/common/editorCommon';
+import { registerEditorContribution } from 'vs/editor/browser/editorExtensions';
+import { IInstantiationService } from '../../../../platform/instantiation/common/instantiation';
+import { DomScrollableElement } from 'vs/base/browser/ui/scrollbar/scrollableElement';
+
+export const EDITOR_CONTRIBUTION_ID = 'editor.contrib.webview';
+
+export class WebviewWidget extends ZoneWidget {
+
+ private _webview: WebviewElement;
+
+ constructor(
+ editor: ICodeEditor,
+ private readonly _delegate: (view: WebviewElement) => void,
+ @ITelemetryService telemetryService: ITelemetryService,
+ @IThemeService private readonly _themeService: IThemeService,
+ @IPartService private readonly _partService: IPartService,
+ @IContextViewService private readonly _contextViewService: IContextViewService,
+ @IEnvironmentService private readonly _environmentService: IEnvironmentService
+ ) {
+ super(editor, {});
+
+ // this._applyTheme(_themeService.getTheme());
+ // this._callOnDispose.push(_themeService.onThemeChange(this._applyTheme.bind(this)));
+
+ this.create();
+ }
+
+ protected _fillContainer(container: HTMLElement): void {
+ this._webview = new WebviewElement(
+ this._partService.getContainer(Parts.EDITOR_PART),
+ this._themeService,
+ this._environmentService,
+ this._contextViewService,
+ undefined,
+ undefined,
+ {
+ enableWrappedPostMessage: true,
+ useSameOriginForRoot: false
+ });
+ this._webview.mountTo(container);
+
+ const e = new DomScrollableElement(this._webview.getDomNode(), {});
+ e.getDomNode().style.width = '100%';
+ e.getDomNode().style.height = '100%';
+ container.appendChild(e.getDomNode());
+ this._delegate(this._webview);
+ }
+}
+
+export interface IWebviewWidgetContribution extends IEditorContribution {
+ showWebviewWidget(lineNumber: number, column: number, delegate: (view: WebviewElement) => void): void;
+ closeWebviewWidget(): void;
+}
+
+
+export class WebviewWidgetContribution implements IWebviewWidgetContribution {
+ private _webviewWidget: WebviewWidget;
+
+ constructor(
+ private editor: ICodeEditor,
+ @IInstantiationService private readonly instantiationService: IInstantiationService
+ ) { }
+
+ showWebviewWidget(lineNumber: number, column: number, delegate: (view: WebviewElement) => void): void {
+ if (this._webviewWidget) {
+ this._webviewWidget.dispose();
+ }
+
+ this._webviewWidget = this.instantiationService.createInstance(WebviewWidget, this.editor, delegate);
+ this._webviewWidget.show({ lineNumber, column: 1 }, 20);
+ // this.webviewWidgetVisible.set(true);
+ }
+
+ public closeWebviewWidget(): void {
+ if (this._webviewWidget) {
+ this._webviewWidget.dispose();
+ this._webviewWidget = null;
+ // this.webviewWidgetVisible.reset();
+ this.editor.focus();
+ }
+ }
+
+ getId(): string {
+ return EDITOR_CONTRIBUTION_ID;
+ }
+
+ dispose(): void {
+ this.closeWebviewWidget();
+ }
+}
+
+registerEditorContribution(WebviewWidgetContribution);
\ No newline at end of file