Skip to content

Commit

Permalink
src/welcome.ts: add welcome webview
Browse files Browse the repository at this point in the history
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 #949

Change-Id: I08f63346781dcf9afb24b8d482394a0db7cf6492
Reviewed-on: https://go-review.googlesource.com/c/vscode-go/+/280596
Trust: Suzy Mueller <[email protected]>
Trust: Hyang-Ah Hana Kim <[email protected]>
Run-TryBot: Suzy Mueller <[email protected]>
Reviewed-by: Hyang-Ah Hana Kim <[email protected]>
  • Loading branch information
suzmue committed Jan 7, 2021
1 parent de64eaa commit 197bec6
Show file tree
Hide file tree
Showing 20 changed files with 223 additions and 14 deletions.
4 changes: 4 additions & 0 deletions docs/commands.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,10 @@ Generates method stub for implementing the provided interface and inserts at the

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
Expand Down
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
4 changes: 4 additions & 0 deletions media/welcome.css
Original file line number Diff line number Diff line change
@@ -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.
*--------------------------------------------------------*/
22 changes: 22 additions & 0 deletions media/welcome.js
Original file line number Diff line number Diff line change
@@ -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();
});

}());

10 changes: 8 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down Expand Up @@ -97,7 +97,8 @@
"onCommand:go.locate.tools",
"onCommand:go.show.commands",
"onDebugInitialConfigurations",
"onDebugResolve:go"
"onDebugResolve:go",
"onWebviewPanel:welcomeGo"
],
"main": "./dist/goMain.js",
"contributes": {
Expand Down Expand Up @@ -250,6 +251,11 @@
"title": "Go: Extract Language Server Logs To Editor",
"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",
Expand Down
24 changes: 12 additions & 12 deletions src/goCover.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,18 +54,18 @@ let modifiedFiles: {
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();
Expand Down
15 changes: 15 additions & 0 deletions src/goMain.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ import {
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;
Expand All @@ -91,6 +92,15 @@ export function activate(ctx: vscode.ExtensionContext) {
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);

Expand Down Expand Up @@ -470,6 +480,11 @@ See https://github.com/golang/tools/blob/master/gopls/doc/settings.md#importshor
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');
Expand Down
158 changes: 158 additions & 0 deletions src/welcome.ts
Original file line number Diff line number Diff line change
@@ -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;
}

0 comments on commit 197bec6

Please sign in to comment.