Skip to content

Commit 843fe26

Browse files
authored
Merge branch 'main' into update-package-json
2 parents f2434c6 + 96e40fa commit 843fe26

File tree

8 files changed

+287
-79
lines changed

8 files changed

+287
-79
lines changed

README.md

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,7 @@ This extension adds support for Processing sketches in VSCode. Includes familiar
1010

1111
## Requirements
1212

13-
You will need **Processing 4.4.6 or later** installed on your computer.
14-
15-
Download Processing here: [Processing](https://processing.org).
13+
You will need **Processing 4.4.6 or later** installed on your computer ([Download Processing](https://processing.org)).
1614

1715
**IMPORTANT:** Run Processing at least once after installing it. This creates the files the extension needs.
1816

client/src/extension.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { setupSidebar } from './setupSidebar';
99
import { setupDecorators } from './setupDecorators';
1010
import { setupPDEFiles } from './setupPDEFiles';
1111
import { EventEmitter } from 'stream';
12+
import setupConsole from './setupConsole';
1213

1314

1415
export interface ProcessingVersion {
@@ -38,6 +39,7 @@ export async function activate(context: ExtensionContext) {
3839
setupCommands(context);
3940
setupLanguageServer();
4041
setupSidebar(context);
42+
setupConsole(context);
4143
setupDecorators(context);
4244
setupPDEFiles();
4345
}

client/src/setupCommands.ts

Lines changed: 70 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -1,77 +1,77 @@
11
import { basename, dirname, join } from 'path';
22
import { ExtensionContext, commands, Uri, window, workspace } from 'vscode';
3-
import { state } from './extension';
3+
// import { state } from './extension';
44

5-
const sketchNumber = 0;
5+
// const sketchNumber = 0;
66

77
export function setupCommands(context: ExtensionContext) {
8-
const runSketch = commands.registerCommand('processing.sketch.run', (resource: Uri) => {
9-
// TODO: Use VScode contexts to highlight run button when sketch is running, blocked until we do not run the sketch in a terminal
10-
// https://code.visualstudio.com/api/references/when-clause-contexts
11-
12-
const autosave = workspace
13-
.getConfiguration('processing')
14-
.get<boolean>('autosave');
15-
if (autosave === true) {
16-
// Save all files before running the sketch
17-
commands.executeCommand('workbench.action.files.saveAll');
18-
}
19-
if (resource == undefined) {
20-
const editor = window.activeTextEditor;
21-
if (editor) {
22-
resource = editor.document.uri;
23-
}
24-
}
25-
26-
if (!resource) {
27-
return;
28-
}
29-
30-
// TODO: Give feedback if the sketch is starting
31-
32-
let terminal = state.terminal;
33-
// Create a new terminal
34-
if (terminal === undefined || terminal.exitStatus) {
35-
window.terminals.forEach(t => {
36-
if (t.name === "Sketch") {
37-
t.dispose();
38-
}
39-
});
40-
state.terminal = window.createTerminal("Sketch");
41-
terminal = state.terminal;
42-
// Show the terminal panel the first time
43-
terminal.show(true);
44-
} else {
45-
// Send the command to the terminal
46-
terminal.sendText('\x03', false);
47-
}
48-
49-
// clear the terminal
50-
terminal.sendText("clear", true);
51-
52-
let path = state.selectedVersion.path;
53-
if (process.platform === "win32") {
54-
// on windows we need to escape spaces
55-
path = `& "${path}"`;
56-
}
57-
58-
let cmd = `${path} cli --sketch="${dirname(resource.fsPath)}" --run`;
59-
if (process.platform === "win32") {
60-
// on windows we need to pipe stderr to stdout and convert to string
61-
cmd += ` 2>&1`;
62-
}
63-
64-
terminal.sendText(cmd, true);
65-
});
66-
67-
const stopSketch = commands.registerCommand('processing.sketch.stop', () => {
68-
if (state.terminal === undefined) {
69-
return;
70-
}
71-
72-
// Send the command to the terminal
73-
state.terminal.sendText('\x03', false);
74-
});
8+
// const runSketch = commands.registerCommand('processing.sketch.run', (resource: Uri) => {
9+
// // TODO: Use VScode contexts to highlight run button when sketch is running, blocked until we do not run the sketch in a terminal
10+
// // https://code.visualstudio.com/api/references/when-clause-contexts
11+
12+
// const autosave = workspace
13+
// .getConfiguration('processing')
14+
// .get<boolean>('autosave');
15+
// if (autosave === true) {
16+
// // Save all files before running the sketch
17+
// commands.executeCommand('workbench.action.files.saveAll');
18+
// }
19+
// if (resource == undefined) {
20+
// const editor = window.activeTextEditor;
21+
// if (editor) {
22+
// resource = editor.document.uri;
23+
// }
24+
// }
25+
26+
// if (!resource) {
27+
// return;
28+
// }
29+
30+
// return;
31+
32+
// let terminal = state.terminal;
33+
// // Create a new terminal
34+
// if (terminal === undefined || terminal.exitStatus) {
35+
// window.terminals.forEach(t => {
36+
// if (t.name === "Sketch") {
37+
// t.dispose();
38+
// }
39+
// });
40+
// state.terminal = window.createTerminal("Sketch");
41+
// terminal = state.terminal;
42+
// // Show the terminal panel the first time
43+
// terminal.show(true);
44+
// } else {
45+
// // Send the command to the terminal
46+
// terminal.sendText('\x03', false);
47+
// }
48+
49+
// // clear the terminal
50+
// terminal.sendText("clear", true);
51+
52+
// let path = state.selectedVersion.path;
53+
// if (process.platform === "win32") {
54+
// // on windows we need to escape spaces
55+
// path = `& "${path}"`;
56+
// }
57+
58+
// let cmd = `${path} cli --sketch="${dirname(resource.fsPath)}" --run`;
59+
// if (process.platform === "win32") {
60+
// // on windows we need to pipe stderr to stdout and convert to string
61+
// cmd += ` 2>&1`;
62+
// }
63+
64+
// terminal.sendText(cmd, true);
65+
// });
66+
67+
// const stopSketch = commands.registerCommand('processing.sketch.stop', () => {
68+
// if (state.terminal === undefined) {
69+
// return;
70+
// }
71+
72+
// // Send the command to the terminal
73+
// state.terminal.sendText('\x03', false);
74+
// });
7575

7676
const openSketch = commands.registerCommand('processing.sketch.open', async (folder: string, isReadOnly: boolean) => {
7777
if (!folder) {
@@ -161,7 +161,7 @@ export function setupCommands(context: ExtensionContext) {
161161

162162
// TODO: Add command to select Processing version and set the setting
163163

164-
context.subscriptions.push(runSketch, stopSketch, openSketch, newSketch);
164+
context.subscriptions.push(openSketch, newSketch);
165165
}
166166

167167
// Helper function to convert a number to alphabetical (e.g., 0 = a, 1 = b, ..., 25 = z, 26 = aa, etc.)

client/src/setupConsole.ts

Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
import { ChildProcess, spawn } from 'child_process';
2+
import { commands, ExtensionContext, Uri, WebviewView, WebviewViewProvider, WebviewViewResolveContext, window, workspace } from 'vscode';
3+
import { state } from './extension';
4+
import { dirname } from 'path';
5+
import * as treeKill from 'tree-kill';
6+
7+
export default function setupConsole(context: ExtensionContext) {
8+
const sketchProcesses: ChildProcess[] = [];
9+
10+
const provider = new ProcessingConsoleViewProvider();
11+
12+
const register = window.registerWebviewViewProvider('processingConsoleView', provider);
13+
14+
const startSketch = commands.registerCommand('processing.sketch.run', (resource: Uri) => {
15+
const autosave = workspace
16+
.getConfiguration('processing')
17+
.get<boolean>('autosave');
18+
if (autosave === true) {
19+
// Save all files before running the sketch
20+
commands.executeCommand('workbench.action.files.saveAll');
21+
}
22+
if (resource == undefined) {
23+
const editor = window.activeTextEditor;
24+
if (editor) {
25+
resource = editor.document.uri;
26+
}
27+
}
28+
29+
if (!resource) {
30+
return;
31+
}
32+
commands.executeCommand('processingConsoleView.focus');
33+
commands.executeCommand('processing.sketch.stop');
34+
35+
const proc = spawn(
36+
state.selectedVersion.path,
37+
['cli', `--sketch=${dirname(resource.fsPath)}`, '--run'],
38+
{
39+
shell: false,
40+
}
41+
);
42+
proc.stdout.on("data", (data) => {
43+
if(proc != sketchProcesses[0]) {
44+
// If this is not the most recent process, ignore its output
45+
return;
46+
}
47+
provider.webview?.webview.postMessage({ type: 'stdout', value: data?.toString() });
48+
});
49+
proc.stderr.on("data", (data) => {
50+
if (proc != sketchProcesses[0]) {
51+
// If this is not the most recent process, ignore its output
52+
return;
53+
}
54+
provider.webview?.webview.postMessage({ type: 'stderr', value: data?.toString() });
55+
// TODO: Handle and highlight errors in the editor
56+
});
57+
proc.on('close', (code) => {
58+
provider.webview?.webview.postMessage({ type: 'close', value: code?.toString() });
59+
sketchProcesses.splice(sketchProcesses.indexOf(proc), 1);
60+
commands.executeCommand('setContext', 'processing.sketch.running', sketchProcesses.length > 0);
61+
});
62+
provider.webview?.show?.(true);
63+
provider.webview?.webview.postMessage({ type: 'clear'});
64+
sketchProcesses.unshift(proc);
65+
commands.executeCommand('setContext', 'processing.sketch.running', true);
66+
});
67+
68+
const restartSketch = commands.registerCommand('processing.sketch.restart', (resource: Uri) => {
69+
commands.executeCommand('processing.sketch.run', resource);
70+
});
71+
72+
const stopSketch = commands.registerCommand('processing.sketch.stop', () => {
73+
for (const proc of sketchProcesses) {
74+
treeKill(proc.pid as number);
75+
}
76+
});
77+
78+
context.subscriptions.push(
79+
register,
80+
startSketch,
81+
restartSketch,
82+
stopSketch
83+
);
84+
}
85+
86+
// TODO: Add setting for timestamps
87+
// TODO: Add setting for collapsing similar messages
88+
// TODO: Add option to enable/disable stdout and stderr
89+
class ProcessingConsoleViewProvider implements WebviewViewProvider {
90+
public webview?: WebviewView;
91+
92+
public resolveWebviewView(webviewView: WebviewView, context: WebviewViewResolveContext): Thenable<void> | void {
93+
webviewView.webview.options = { enableScripts: true };
94+
webviewView.webview.html = `
95+
<!DOCTYPE html>
96+
<html>
97+
<body>
98+
<script>
99+
window.addEventListener('message', event => {
100+
101+
const message = event.data; // The JSON data our extension sent
102+
103+
const isScrolledToBottom = (window.innerHeight + window.scrollY) >= document.body.offsetHeight;
104+
105+
const ts = document.createElement("span");
106+
ts.style.color = "gray";
107+
const now = new Date();
108+
const hours = now.getHours().toString().padStart(2, '0');
109+
const minutes = now.getMinutes().toString().padStart(2, '0');
110+
const seconds = now.getSeconds().toString().padStart(2, '0');
111+
ts.textContent = "[" + hours + ":" + minutes + ":" + seconds + "] ";
112+
113+
114+
switch (message.type) {
115+
case 'clear':
116+
document.body.innerHTML = '';
117+
break;
118+
case 'stdout':
119+
var pre = document.createElement("pre");
120+
pre.style.color = "white";
121+
pre.textContent = message.value;
122+
if (pre.textContent.endsWith("\\n")) {
123+
pre.textContent = pre.textContent.slice(0, -1);
124+
}
125+
pre.prepend(ts);
126+
document.body.appendChild(pre);
127+
break;
128+
case 'stderr':
129+
var pre = document.createElement("pre");
130+
pre.style.color = "red";
131+
pre.textContent = message.value;
132+
if (pre.textContent.endsWith("\\n")) {
133+
pre.textContent = pre.textContent.slice(0, -1);
134+
}
135+
pre.prepend(ts);
136+
document.body.appendChild(pre);
137+
break;
138+
case 'close':
139+
var pre = document.createElement("pre");
140+
pre.style.color = "gray";
141+
pre.textContent = "Process exited with code " + message.value;
142+
pre.prepend(ts);
143+
document.body.appendChild(pre);
144+
break;
145+
}
146+
147+
if (isScrolledToBottom) {
148+
window.scrollTo(0, document.body.scrollHeight);
149+
}
150+
});
151+
</script>
152+
</body>
153+
</html>
154+
`;
155+
webviewView.onDidDispose(() => {
156+
commands.executeCommand("processing.sketch.stop");
157+
});
158+
this.webview = webviewView;
159+
}
160+
161+
}

client/tsconfig.tsbuildinfo

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
{"root":["./src/compareversions.ts","./src/extension.ts","./src/setupcommands.ts","./src/setupdecorators.ts","./src/setuplanguageserver.ts","./src/setuppdefiles.ts","./src/setupselectedversion.ts","./src/setupsidebar.ts"],"version":"5.8.3"}
1+
{"root":["./src/compareversions.ts","./src/extension.ts","./src/setupcommands.ts","./src/setupconsole.ts","./src/setupdecorators.ts","./src/setuplanguageserver.ts","./src/setuppdefiles.ts","./src/setupselectedversion.ts","./src/setupsidebar.ts"],"version":"5.8.3"}

media/restart.svg

Lines changed: 5 additions & 0 deletions
Loading

package-lock.json

Lines changed: 16 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)