src/welcome.ts: add welcome webview
This change is the initial change for adding a welcome page
for the extension. This adds the basic structure and a link to
open the release notes, which uses the communication channel
between the webview and the extension.
The webview is based on the microsoft webview example:
https://github.com/microsoft/vscode-extension-samples/tree/master/webview-sample
Updates golang/vscode-go#949
Change-Id: I08f63346781dcf9afb24b8d482394a0db7cf6492
Reviewed-on: https://go-review.googlesource.com/c/vscode-go/+/280596
Trust: Suzy Mueller <suzmue@golang.org>
Trust: Hyang-Ah Hana Kim <hyangah@gmail.com>
Run-TryBot: Suzy Mueller <suzmue@golang.org>
Reviewed-by: Hyang-Ah Hana Kim <hyangah@gmail.com>
diff --git a/docs/commands.md b/docs/commands.md
index f1450e9..6914126 100644
--- a/docs/commands.md
+++ b/docs/commands.md
@@ -95,6 +95,10 @@
Extract logs in the `gopls (server)` output channel to the editor.
+### `Go: Welcome`
+
+Open the welcome page for the Go extension.
+
### `Go: Toggle gc details`
Toggle the display of compiler optimization choices
diff --git a/images/go-logo-blue.png b/media/go-logo-blue.png
similarity index 100%
rename from images/go-logo-blue.png
rename to media/go-logo-blue.png
Binary files differ
diff --git a/images/gutter-blockblue.svg b/media/gutter-blockblue.svg
similarity index 100%
rename from images/gutter-blockblue.svg
rename to media/gutter-blockblue.svg
diff --git a/images/gutter-blockgreen.svg b/media/gutter-blockgreen.svg
similarity index 100%
rename from images/gutter-blockgreen.svg
rename to media/gutter-blockgreen.svg
diff --git a/images/gutter-blockred.svg b/media/gutter-blockred.svg
similarity index 100%
rename from images/gutter-blockred.svg
rename to media/gutter-blockred.svg
diff --git a/images/gutter-blockyellow.svg b/media/gutter-blockyellow.svg
similarity index 100%
rename from images/gutter-blockyellow.svg
rename to media/gutter-blockyellow.svg
diff --git a/images/gutter-slashblue.svg b/media/gutter-slashblue.svg
similarity index 100%
rename from images/gutter-slashblue.svg
rename to media/gutter-slashblue.svg
diff --git a/images/gutter-slashgreen.svg b/media/gutter-slashgreen.svg
similarity index 100%
rename from images/gutter-slashgreen.svg
rename to media/gutter-slashgreen.svg
diff --git a/images/gutter-slashred.svg b/media/gutter-slashred.svg
similarity index 100%
rename from images/gutter-slashred.svg
rename to media/gutter-slashred.svg
diff --git a/images/gutter-slashyellow.svg b/media/gutter-slashyellow.svg
similarity index 100%
rename from images/gutter-slashyellow.svg
rename to media/gutter-slashyellow.svg
diff --git a/images/gutter-vertblue.svg b/media/gutter-vertblue.svg
similarity index 100%
rename from images/gutter-vertblue.svg
rename to media/gutter-vertblue.svg
diff --git a/images/gutter-vertgreen.svg b/media/gutter-vertgreen.svg
similarity index 100%
rename from images/gutter-vertgreen.svg
rename to media/gutter-vertgreen.svg
diff --git a/images/gutter-vertred.svg b/media/gutter-vertred.svg
similarity index 100%
rename from images/gutter-vertred.svg
rename to media/gutter-vertred.svg
diff --git a/images/gutter-vertyellow.svg b/media/gutter-vertyellow.svg
similarity index 100%
rename from images/gutter-vertyellow.svg
rename to media/gutter-vertyellow.svg
diff --git a/media/welcome.css b/media/welcome.css
new file mode 100644
index 0000000..caee018
--- /dev/null
+++ b/media/welcome.css
@@ -0,0 +1,4 @@
+/*---------------------------------------------------------
+ * Copyright 2020 The Go Authors. All rights reserved.
+ * Licensed under the MIT License. See LICENSE in the project root for license information.
+ *--------------------------------------------------------*/
diff --git a/media/welcome.js b/media/welcome.js
new file mode 100644
index 0000000..8457bbe
--- /dev/null
+++ b/media/welcome.js
@@ -0,0 +1,22 @@
+/*---------------------------------------------------------
+ * Copyright 2020 The Go Authors. All rights reserved.
+ * Licensed under the MIT License. See LICENSE in the project root for license information.
+ *--------------------------------------------------------*/
+
+// This script will be run within the webview itself
+// It cannot access the main VS Code APIs directly.
+(function () {
+ const vscode = acquireVsCodeApi();
+
+ function showReleaseNotes() {
+ vscode.postMessage({
+ command: 'showReleaseNotes',
+ });
+ }
+
+ document.querySelector(".release-notes").addEventListener('click', () => {
+ showReleaseNotes();
+ });
+
+}());
+
diff --git a/package.json b/package.json
index d530bc5..e1a1188 100644
--- a/package.json
+++ b/package.json
@@ -8,7 +8,7 @@
"name": "Go Team at Google"
},
"license": "MIT",
- "icon": "images/go-logo-blue.png",
+ "icon": "media/go-logo-blue.png",
"categories": [
"Programming Languages",
"Snippets",
@@ -97,7 +97,8 @@
"onCommand:go.locate.tools",
"onCommand:go.show.commands",
"onDebugInitialConfigurations",
- "onDebugResolve:go"
+ "onDebugResolve:go",
+ "onWebviewPanel:welcomeGo"
],
"main": "./dist/goMain.js",
"contributes": {
@@ -251,6 +252,11 @@
"description": "Extract logs in the `gopls (server)` output channel to the editor."
},
{
+ "command": "go.welcome",
+ "title": "Go: Welcome",
+ "description": "Open the welcome page for the Go extension."
+ },
+ {
"command": "go.toggle.gc_details",
"title": "Go: Toggle gc details",
"description": "Toggle the display of compiler optimization choices"
diff --git a/src/goCover.ts b/src/goCover.ts
index f1e96a5..2d525b3 100644
--- a/src/goCover.ts
+++ b/src/goCover.ts
@@ -54,18 +54,18 @@
export function initCoverageDecorators(ctx: vscode.ExtensionContext) {
// Initialize gutter svgs
gutterSvgs = {
- blockred: ctx.asAbsolutePath('images/gutter-blockred.svg'),
- blockgreen: ctx.asAbsolutePath('images/gutter-blockgreen.svg'),
- blockblue: ctx.asAbsolutePath('images/gutter-blockblue.svg'),
- blockyellow: ctx.asAbsolutePath('images/gutter-blockyellow.svg'),
- slashred: ctx.asAbsolutePath('images/gutter-slashred.svg'),
- slashgreen: ctx.asAbsolutePath('images/gutter-slashgreen.svg'),
- slashblue: ctx.asAbsolutePath('images/gutter-slashblue.svg'),
- slashyellow: ctx.asAbsolutePath('images/gutter-slashyellow.svg'),
- verticalred: ctx.asAbsolutePath('images/gutter-vertred.svg'),
- verticalgreen: ctx.asAbsolutePath('images/gutter-vertgreen.svg'),
- verticalblue: ctx.asAbsolutePath('images/gutter-vertblue.svg'),
- verticalyellow: ctx.asAbsolutePath('images/gutter-vertyellow.svg')
+ blockred: ctx.asAbsolutePath('media/gutter-blockred.svg'),
+ blockgreen: ctx.asAbsolutePath('media/gutter-blockgreen.svg'),
+ blockblue: ctx.asAbsolutePath('media/gutter-blockblue.svg'),
+ blockyellow: ctx.asAbsolutePath('media/gutter-blockyellow.svg'),
+ slashred: ctx.asAbsolutePath('media/gutter-slashred.svg'),
+ slashgreen: ctx.asAbsolutePath('media/gutter-slashgreen.svg'),
+ slashblue: ctx.asAbsolutePath('media/gutter-slashblue.svg'),
+ slashyellow: ctx.asAbsolutePath('media/gutter-slashyellow.svg'),
+ verticalred: ctx.asAbsolutePath('media/gutter-vertred.svg'),
+ verticalgreen: ctx.asAbsolutePath('media/gutter-vertgreen.svg'),
+ verticalblue: ctx.asAbsolutePath('media/gutter-vertblue.svg'),
+ verticalyellow: ctx.asAbsolutePath('media/gutter-vertyellow.svg')
};
const goConfig = getGoConfig();
diff --git a/src/goMain.ts b/src/goMain.ts
index 197363f..c7cd808 100644
--- a/src/goMain.ts
+++ b/src/goMain.ts
@@ -70,6 +70,7 @@
resolvePath,
} from './util';
import { clearCacheForTools, fileExists, getCurrentGoRoot, setCurrentGoRoot } from './utils/pathUtils';
+import { WelcomePanel } from './welcome';
export let buildDiagnosticCollection: vscode.DiagnosticCollection;
export let lintDiagnosticCollection: vscode.DiagnosticCollection;
@@ -91,6 +92,15 @@
setWorkspaceState(ctx.workspaceState);
setEnvironmentVariableCollection(ctx.environmentVariableCollection);
+ if (vscode.window.registerWebviewPanelSerializer) {
+ // Make sure we register a serializer in activation event
+ vscode.window.registerWebviewPanelSerializer(WelcomePanel.viewType, {
+ async deserializeWebviewPanel(webviewPanel: vscode.WebviewPanel, state: any) {
+ WelcomePanel.revive(webviewPanel, ctx.extensionUri);
+ }
+ });
+ }
+
if (isNightly()) {
promptForLanguageServerDefaultChange(cfg);
@@ -470,6 +480,11 @@
showServerOutputChannel();
}));
+ ctx.subscriptions.push(
+ vscode.commands.registerCommand('go.welcome', () => {
+ WelcomePanel.createOrShow(ctx.extensionUri);
+ }));
+
ctx.subscriptions.push(vscode.commands.registerCommand('go.toggle.gc_details', () => {
if (!languageServerIsRunning) {
vscode.window.showErrorMessage('"Go: Toggle gc details" command is available only when the language server is running');
diff --git a/src/welcome.ts b/src/welcome.ts
new file mode 100644
index 0000000..3300888
--- /dev/null
+++ b/src/welcome.ts
@@ -0,0 +1,158 @@
+/*---------------------------------------------------------
+ * Copyright 2020 The Go Authors. All rights reserved.
+ * Licensed under the MIT License. See LICENSE in the project root for license information.
+ *--------------------------------------------------------*/
+
+// This code is modified from:
+// https://github.com/microsoft/vscode-extension-samples/tree/master/webview-sample
+
+import vscode = require('vscode');
+
+export class WelcomePanel {
+ public static currentPanel: WelcomePanel | undefined;
+
+ public static readonly viewType = 'welcomeGo';
+
+ public static createOrShow(extensionUri: vscode.Uri) {
+ const column = vscode.window.activeTextEditor
+ ? vscode.window.activeTextEditor.viewColumn
+ : undefined;
+
+ // If we already have a panel, show it.
+ if (WelcomePanel.currentPanel) {
+ WelcomePanel.currentPanel.panel.reveal(column);
+ return;
+ }
+
+ // Otherwise, create a new panel.
+ const panel = vscode.window.createWebviewPanel(
+ WelcomePanel.viewType,
+ 'Go - Welcome',
+ column || vscode.ViewColumn.One,
+ {
+ // Enable javascript in the webview
+ enableScripts: true,
+
+ // And restrict the webview to only loading content from our extension's directory.
+ localResourceRoots: [vscode.Uri.joinPath(extensionUri)],
+ }
+ );
+ panel.iconPath = vscode.Uri.joinPath(extensionUri, 'media', 'go-logo-blue.png');
+
+ WelcomePanel.currentPanel = new WelcomePanel(panel, extensionUri);
+ }
+
+ public static revive(panel: vscode.WebviewPanel, extensionUri: vscode.Uri) {
+ WelcomePanel.currentPanel = new WelcomePanel(panel, extensionUri);
+ }
+
+ private readonly panel: vscode.WebviewPanel;
+ private readonly extensionUri: vscode.Uri;
+ private readonly dataroot: vscode.Uri;
+ private disposables: vscode.Disposable[] = [];
+
+ private constructor(panel: vscode.WebviewPanel, extensionUri: vscode.Uri) {
+ this.panel = panel;
+ this.extensionUri = extensionUri;
+ this.dataroot = vscode.Uri.joinPath(this.extensionUri, 'media');
+
+ // Set the webview's initial html content
+ this.update();
+
+ // Listen for when the panel is disposed
+ // This happens when the user closes the panel or when the panel is closed programatically
+ this.panel.onDidDispose(() => this.dispose(), null, this.disposables);
+
+ // Handle messages from the webview
+ this.panel.webview.onDidReceiveMessage(
+ (message) => {
+ console.log(message);
+ switch (message.command) {
+ case 'alert':
+ vscode.window.showErrorMessage(message.text);
+ return;
+ case 'showReleaseNotes':
+ const uri = vscode.Uri.joinPath(this.extensionUri, 'CHANGELOG.md');
+ vscode.commands.executeCommand('markdown.showPreviewToSide', uri);
+ return;
+ }
+ },
+ null,
+ this.disposables
+ );
+ }
+
+ public dispose() {
+ WelcomePanel.currentPanel = undefined;
+
+ // Clean up our resources
+ this.panel.dispose();
+
+ while (this.disposables.length) {
+ const x = this.disposables.pop();
+ if (x) {
+ x.dispose();
+ }
+ }
+ }
+
+ private update() {
+ const webview = this.panel.webview;
+ this.panel.webview.html = this.getHtmlForWebview(webview);
+ }
+
+ private getHtmlForWebview(webview: vscode.Webview) {
+ // Local path to css styles and images
+ const scriptPathOnDisk = vscode.Uri.joinPath(this.dataroot, 'welcome.js');
+ const stylePath = vscode.Uri.joinPath(this.dataroot, 'welcome.css');
+ const gopherPath = vscode.Uri.joinPath(this.dataroot, 'go-logo-blue.png');
+
+ // Uri to load styles and images into webview
+ const scriptURI = webview.asWebviewUri(scriptPathOnDisk);
+ const stylesURI = webview.asWebviewUri(stylePath);
+ const gopherURI = webview.asWebviewUri(gopherPath);
+
+ // Use a nonce to only allow specific scripts to be run
+ const nonce = getNonce();
+ return `<!DOCTYPE html>
+ <html lang="en">
+ <head>
+ <meta charset="UTF-8">
+
+ <!--
+ Use a content security policy to only allow loading images from https or from our extension directory,
+ and only allow scripts that have a specific nonce.
+ -->
+ <meta http-equiv="Content-Security-Policy" content="default-src 'none'; style-src ${webview.cspSource}; img-src ${webview.cspSource} https:; script-src 'nonce-${nonce}';">
+
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+
+ <link href="${stylesURI}" rel="stylesheet">
+
+ <title>Go - Welcome</title>
+ </head>
+ <body>
+ <div class="header">
+ <img src="${gopherURI}" alt="logo"/>
+ <h1>Go - Welcome</h1>
+ </div>
+
+ <p>Rich Go language support for Visual Studio Code</p>
+ <!-- linking to a document does not actually work, but is used here to give it the appearance
+ of a link -->
+ <p><a class="release-notes"">Release Notes</a></p>
+
+ <script nonce="${nonce}" src="${scriptURI}"></script>
+ </body>
+ </html>`;
+ }
+}
+
+function getNonce() {
+ let text = '';
+ const possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
+ for (let i = 0; i < 32; i++) {
+ text += possible.charAt(Math.floor(Math.random() * possible.length));
+ }
+ return text;
+}