Skip to content

Commit 620f967

Browse files
committed
Add support for 'preview' functionality
1 parent c4408eb commit 620f967

File tree

10 files changed

+470
-7
lines changed

10 files changed

+470
-7
lines changed

.gitmodules

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
[submodule "preview/playground"]
2+
path = preview/playground
3+
url = [email protected]:tinygo-org/playground.git

.vscodeignore

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,13 @@ vsc-extension-quickstart.md
1111
**/*.map
1212
**/*.ts
1313
webpack.config.js
14+
preview/playground/resources
15+
preview/playground/.*
16+
preview/playground/*.tar.gz
17+
preview/playground/*.go
18+
preview/playground/dashboard.*
19+
preview/playground/Dockerfile
20+
preview/playground/go.*
21+
preview/playground/Makefile
22+
preview/playground/index.html
23+
preview/playground/project.js

package.json

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "vscode-tinygo",
33
"displayName": "TinyGo",
4-
"version": "0.2.0",
4+
"version": "0.3.0",
55
"publisher": "tinygo",
66
"description": "TinyGo support for Visual Studio Code",
77
"license": "BSD-3-Clause",
@@ -19,16 +19,32 @@
1919
},
2020
"activationEvents": [
2121
"onLanguage:go",
22-
"onCommand:vscode-tinygo.selectTarget"
22+
"onCommand:vscode-tinygo.selectTarget",
23+
"onCommand:vscode-tinygo.showPreviewToSide",
24+
"onWebviewPanel:vscode-tinygo.preview"
2325
],
2426
"main": "./dist/extension.js",
2527
"contributes": {
2628
"commands": [
2729
{
2830
"command": "vscode-tinygo.selectTarget",
2931
"title": "TinyGo target"
32+
},
33+
{
34+
"command": "vscode-tinygo.showPreviewToSide",
35+
"title": "TinyGo Preview",
36+
"icon": "$(open-preview)"
3037
}
31-
]
38+
],
39+
"menus": {
40+
"editor/title": [
41+
{
42+
"when": "resourceLangId == go && tinygoHasPreview",
43+
"command": "vscode-tinygo.showPreviewToSide",
44+
"group": "navigation"
45+
}
46+
]
47+
}
3248
},
3349
"scripts": {
3450
"compile": "tsc -p ./",

preview/playground

Submodule playground added at 1d27696

preview/webview.css

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
html {
2+
height: 100%;
3+
}
4+
body {
5+
height: 100%;
6+
padding: 0; /* disable default padding */
7+
display: flex;
8+
flex-direction: column;
9+
}
10+
11+
#schematic {
12+
height: 100%;
13+
flex-grow: 1;
14+
}
15+

preview/webview.html

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
<!DOCTYPE html>
2+
3+
<html>
4+
<head>
5+
<meta charset="utf-8"/>
6+
<!-- make all URLs relative to the playground directory -->
7+
<base href="{PLAYGROUND_PATH}"/>
8+
<link rel="stylesheet" href="simulator.css"/>
9+
<link rel="stylesheet" href="../webview.css"/>
10+
<meta http-equiv="Content-Security-Policy" content="{CSP}"/>
11+
<script src="simulator.js" defer></script>
12+
<script src="../webview.js" defer></script>
13+
</head>
14+
<body>
15+
<svg id="schematic">
16+
<g id="schematic-wrapper" style="transform: translate(50%, 50%)">
17+
<g id="schematic-parts"></g>
18+
<g id="schematic-wires"></g>
19+
</g>
20+
</svg>
21+
<div id="panels">
22+
<div class="tabbar">
23+
<span class="tab active" data-for="#terminal-box"><a>Terminal</a></span>
24+
<span class="tab" data-for="#properties"><a>Properties</a></span>
25+
<span class="tab" data-for="#add"><a>Add</a></span>
26+
</div>
27+
<div class="tabcontent active" id="terminal-box">
28+
<textarea id="terminal" readonly></textarea>
29+
</div>
30+
<div class="tabcontent" id="properties">
31+
<div class="content"></div>
32+
</div>
33+
<div class="tabcontent" id="add">
34+
Loading...
35+
</div>
36+
</div>
37+
</body>
38+
</html>

preview/webview.js

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
'use strict';
2+
3+
let messageHandler;
4+
let schematic;
5+
6+
// Obtain a handle to the VS Code API.
7+
let vscode = acquireVsCodeApi();
8+
9+
// Check whether we're actually restoring panel state instead of loading a
10+
// completely new preview panel.
11+
let state = vscode.getState();
12+
if (state) {
13+
// We've got a state from a previous run.
14+
// Restore it and signal we're ready.
15+
start(state);
16+
}
17+
18+
onmessage = async function(e) {
19+
if (e.data.type === 'start') {
20+
// This is a fresh new webview, not one restored from an existing state.
21+
// Therefore, save the state to start with.
22+
state = e.data.state;
23+
saveState();
24+
start(e.data.state);
25+
} else if (e.data.type === 'compiling') {
26+
document.querySelector('#schematic').classList.add('compiling');
27+
terminal.clear('Compiling...');
28+
} else if (e.data.type === 'loading') {
29+
// Compiled, loading the program now.
30+
terminal.clear('Loading...');
31+
} else if (e.data.type === 'started') {
32+
// Message is sent right before actually starting the program.
33+
document.querySelector('#schematic').classList.remove('compiling');
34+
terminal.clear('Running...');
35+
} else if (e.data.type === 'notifyUpdate') {
36+
// Worker notifies us that there are pending updates.
37+
// Wait for the browser to tell us to update the screen.
38+
requestAnimationFrame(() => {
39+
vscode.postMessage({
40+
type: 'getUpdate',
41+
});
42+
});
43+
} else if (e.data.type === 'properties') {
44+
// Set properties in the properties panel at the bottom.
45+
schematic.setProperties(e.data.properties);
46+
} else if (e.data.type === 'update') {
47+
// Received updates. Apply them to the webview.
48+
schematic.update(e.data.updates);
49+
} else if (e.data.type === 'error') {
50+
terminal.showError(e.data.message);
51+
} else {
52+
console.log('unknown message:', e.data);
53+
}
54+
};
55+
56+
async function start(state) {
57+
schematic = new Schematic(state);
58+
await schematic.refresh();
59+
vscode.postMessage({
60+
type: 'ready',
61+
workerConfig: schematic.configForWorker(),
62+
});
63+
}
64+
65+
function workerPostMessage(message) {
66+
vscode.postMessage(message);
67+
}
68+
69+
function saveState() {
70+
vscode.setState(state);
71+
}

src/compiler.ts

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import * as vscode from 'vscode';
2+
import * as cp from 'child_process';
3+
import * as path from 'path';
4+
import * as os from 'os';
5+
import {promises as fs} from 'fs';
6+
7+
// Compiler wraps the tinygo command.
8+
export class Compiler {
9+
buildTags: string[];
10+
context: vscode.ExtensionContext;
11+
importPath: string;
12+
process: cp.ChildProcess | undefined;
13+
14+
constructor(context: vscode.ExtensionContext, importPath: string, buildTags: string[]) {
15+
this.context = context;
16+
this.importPath = importPath;
17+
this.buildTags = buildTags;
18+
}
19+
20+
async compile() {
21+
// Compile to WebAssembly.
22+
const outputPath = path.join(os.tmpdir(), 'vscode-tinygo-build-' + (Math.random() * 1e12).toFixed() + '.wasm');
23+
try {
24+
let promise = new Promise((resolve, reject) => {
25+
// Both -opt=1 and -no-debug improve compile time slightly.
26+
this.process = cp.execFile('tinygo', ['build', '-tags='+this.buildTags.join(','), '-opt=1', '-no-debug', '-o='+outputPath],
27+
{
28+
cwd: this.importPath,
29+
}, (error, stdout, stderr) => {
30+
if (error) {
31+
reject(stderr);
32+
} else {
33+
resolve(undefined);
34+
}
35+
});
36+
});
37+
await promise;
38+
39+
// Read the resulting file.
40+
let binary = await fs.readFile(outputPath);
41+
return binary;
42+
} finally {
43+
// Make sure to remove the file when finished, even if it doesn't
44+
// exist anymore.
45+
try {
46+
fs.unlink(outputPath);
47+
} catch (e) {
48+
// ignore any error
49+
}
50+
}
51+
}
52+
53+
// Stop the compilation process immediately.
54+
kill() {
55+
if (this.process) {
56+
this.process.kill();
57+
this.process = undefined;
58+
}
59+
}
60+
}

src/extension.ts

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import * as vscode from 'vscode';
2-
import cp = require('child_process');
3-
import util = require('util');
2+
import * as cp from 'child_process';
3+
import * as util from 'util';
4+
import * as preview from './preview';
45

56
let statusbarItem: vscode.StatusBarItem;
67

@@ -18,6 +19,16 @@ export async function activate(context: vscode.ExtensionContext) {
1819
statusbarItem.command = 'vscode-tinygo.selectTarget';
1920
updateStatusBar();
2021

22+
// Add 'preview' button to appropriate source files.
23+
preview.updateStatus(context);
24+
context.subscriptions.push(vscode.commands.registerCommand('vscode-tinygo.showPreviewToSide', async (uri: vscode.Uri) => {
25+
preview.createNewPane(context, uri);
26+
}));
27+
28+
// Make sure these 'preview' panels are restored when VS Code is closed and
29+
// then opened.
30+
vscode.window.registerWebviewPanelSerializer('vscode-tinygo.preview', new preview.PreviewSerializer(context));
31+
2132
// Register the command, _after_ the list of targets has been read. This
2233
// makes sure the user will never see an empty list.
2334
let disposable = vscode.commands.registerCommand('vscode-tinygo.selectTarget', async () => {
@@ -81,8 +92,9 @@ export async function activate(context: vscode.ExtensionContext) {
8192
config.update('toolsEnvVars', envVars, vscode.ConfigurationTarget.Workspace);
8293

8394
// Update status bar.
84-
context.workspaceState.update('target', target);
95+
context.workspaceState.update('tinygo-target', target);
8596
updateStatusBar();
97+
preview.updateStatus(context);
8698

8799
// Move the just picked target to the top of the list.
88100
moveElementToFront(targets, target);
@@ -103,7 +115,7 @@ export function deactivate() {
103115
// updateStatusBar updates the TinyGo sign in the status bar with the currently
104116
// selected target.
105117
function updateStatusBar() {
106-
let target = workspaceState.get('target', '-');
118+
let target = workspaceState.get('tinygo-target', '-');
107119
if (target != '-') {
108120
statusbarItem.text = 'TinyGo: ' + target;
109121
} else {

0 commit comments

Comments
 (0)