Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/run using play button #24

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions client/src/assets/play-arrow.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
46 changes: 46 additions & 0 deletions client/src/assets/stop-square.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
33 changes: 17 additions & 16 deletions client/src/extension.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import * as path from 'path';
import * as vscode from 'vscode';
const childProcess = require('child_process');
import { SketchRunner } from './sketchRunner';

import {
LanguageClient,
Expand Down Expand Up @@ -43,34 +43,35 @@ export function activate(context: vscode.ExtensionContext) {
clientOptions
);

let disposable = vscode.commands.registerCommand('extension.processing', () => {
// Running the Sketch entered in Extension Host
vscode.window.showInformationMessage(`Running Processing Sketch.!`);
try{
// exec(`mkdir client/out/class`)
let workspacePath = vscode.workspace.rootPath;
childProcess.exec(`cp -a ${workspacePath}/** ${__dirname}/class`)
childProcess.exec(`cp ${__dirname.substring(0,__dirname.length-11)}/server/out/compile/** ${__dirname}/class`)
childProcess.exec(`cd ${__dirname.substring(0,__dirname.length-11)}/client/out/class ; java -classpath ${__dirname.substring(0,__dirname.length-11)}/server/src/processing/jar/core.jar: ProcessingDefault`)
} catch(e) {
vscode.window.showInformationMessage(`Error occured while running sketch.!`);
}
let clientPath = context.asAbsolutePath(path.join('client'))
let serverPath = context.asAbsolutePath(path.join('server'))

let serverCompilePath = path.join(serverPath, 'out', 'compile')
let clientSketchPath = path.join(clientPath, 'out', 'class')
let processingCoreFile = path.join(serverPath, 'src', 'processing', 'jar', 'core.jar')

const sketchRunner = SketchRunner.getInstance();
sketchRunner.initilize(processingCoreFile, clientSketchPath, serverCompilePath)

});
let sketchRunnerDisp = vscode.commands.registerCommand("extension.processing.runSketch", () => sketchRunner.runSketch())
let sketchStopperDisp = vscode.commands.registerCommand("extension.processing.stopSketch", () => sketchRunner.stopSketch())

let referenceDisposable = vscode.commands.registerCommand('processing.command.findReferences', (...args: any[]) => {
vscode.commands.executeCommand('editor.action.findReferences', vscode.Uri.file(args[0].uri.substring(7,args[0].uri.length)), new vscode.Position(args[0].lineNumber,args[0].column));
})

context.subscriptions.push(disposable);
context.subscriptions.push(referenceDisposable)
context.subscriptions.push(sketchRunnerDisp)
context.subscriptions.push(sketchStopperDisp)

client.start();
}

export function deactivate(): Thenable<void> | undefined {
export async function deactivate(): Promise<void> | undefined {
if (!client) {
return undefined;
}
const sketchRunner = SketchRunner.getInstance();
await sketchRunner.stopSketch();
return client.stop();
}
212 changes: 212 additions & 0 deletions client/src/sketchRunner.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,212 @@
import * as os from "os"
import { ChildProcess, spawn } from 'child_process';
import { BufferedOutputChannel } from "./utils/outputBuffer";
import * as vscode from "vscode";

const fs = require('fs')
const path = require('path')

/**
* Responable for starting a compiled sketch
*/
export class SketchRunner implements vscode.Disposable {

public static NAME: string = "Processing Sketch"; //Output channel name

/**
* There should be only one instance of the SketchRunner class to avoid
* running a sketch multiple times
*
* @returns Instance of the SketchRunner class
*/
public static getInstance(): SketchRunner {
if (SketchRunner._sketchrunner === null) {
SketchRunner._sketchrunner = new SketchRunner();
}
return SketchRunner._sketchrunner
}

private static _sketchrunner: SketchRunner = null
private _child: ChildProcess;
private _workDir: string;
private _compilePath: string;
private _outputChannel: vscode.OutputChannel
private _bufferedOutputChannel: BufferedOutputChannel;
private _cpArg : string

/**
* Setup the arguments for the childproces executing the sketch
*
* @param processingCoreFile Path to the processing core.jar
* @param clientSketchPath Client side path to the compiled version of the sketch
* @param compilePath Server side path to the compiled version of the sketch
*/
public initilize(processingCoreFile: string, clientSketchPath: string, compilePath: string){
this._workDir = clientSketchPath
this._compilePath = compilePath
this._outputChannel = vscode.window.createOutputChannel(SketchRunner.NAME);
this._bufferedOutputChannel = new BufferedOutputChannel(this._outputChannel.append, 300);

//The termination of the class path argument is OS dependend
if (process.platform === 'win32') {
this._cpArg = `${processingCoreFile};`
}
else {
this._cpArg = `${processingCoreFile}:`
}
}

public get initialized(): boolean {
return !!this._outputChannel;
}

public dispose() {
if(this.isRunning) {
return this.stop()
}

this._outputChannel.dispose();
this._bufferedOutputChannel.dispose();
}

private get isRunning(): boolean {
return this._child ? true : false;
}

/**
* Starts a sketch when non is running.
*
* @returns Has the sketch started
*/
public async runSketch(): Promise<boolean>{
if(this.isRunning) {
this.stop();
vscode.window.showWarningMessage(`Sketch is already running, stopping sketch.`, )
return false
}

try {
const result = await this.start();
return result
}
catch(error) {
console.log(error)
vscode.window.showErrorMessage(`Error occured while running sketch.!`);
return false
}
}

/**
* Stops a running sketch.
*
* @returns Has the sketch stopped
*/
public async stopSketch(): Promise<boolean> {
if(this.isRunning){
const result = await this.stop()
return result
}
else {
return false
}
}

/**
* Executes a copy(comes from the server) of the compiled sketch.
* The output is piped to the outputchannel.
*
* @returns Exectution state
*/
private start(): Promise<boolean> {
this.copyCompiledSketch(this._compilePath , this._workDir)

this._bufferedOutputChannel.appendLine(`[Starting] Running processing sketch`);
this._outputChannel.show(false)
vscode.commands.executeCommand('setContext', 'processing.runningSketch', true)

if (this.isRunning) {
this.stop()
}

return new Promise((resolve, reject) => {

// Setting the cwd in the child-process directly prevents issues where
// the sketch and the client are not on the same drive.
this._child = spawn(`java`,
["-cp", `${this._cpArg}`, "ProcessingDefault"], {cwd: this._workDir})

this._child.on("error", (err) => {
reject(err)
});

this._child.on('close', (close) => {
this.stop();
});

this._child.stdout.on("data", (data) => {
if (this.isRunning) {
this._bufferedOutputChannel.append(data.toString());
}
});
resolve(true);
})
}

/**
* Execution of the sketch is stopped. After which the child no longer exists.
*
* @returns Stopping state
*/
private stop(): Promise<boolean> {

vscode.commands.executeCommand('setContext', 'processing.runningSketch', false)

return new Promise((resolve, reject) => {
if (!this.isRunning) {
resolve(false);
return;
}
try {
if (this._bufferedOutputChannel) {
this._bufferedOutputChannel.appendLine(`[Done] Stopped the sketch ${os.EOL}`);
}
this._child.kill();
this._child = null;
resolve(true);
} catch (error) {
console.log(error)
reject(error);
}
});
}

/**
* Duplicates .class files from one place to the other.
*
* @param src Path to the source. Directories are accepted.
* @param dest Path to the desination
*/
private copyCompiledSketch(src : string, dest : string) {

var exists = fs.existsSync(src);
var stats = exists && fs.statSync(src);
var isDirectory = exists && stats.isDirectory();

if (isDirectory) {
if(!fs.existsSync(dest)) {
fs.mkdirSync(dest);
}

for (let i = 0; i < fs.readdirSync(src).length; i++) {
const contents = fs.readdirSync(src)[i];
this.copyCompiledSketch(path.join(src, contents), path.join(dest, contents));
}

} else if (path.extname(src) === '.class'){
fs.copyFileSync(src, dest);

}

};

}
Loading