3 Commits

Author SHA1 Message Date
Ruben
4433be1fd5 add ctx Path and remove unneccesary Logging 2025-09-20 13:01:27 +02:00
Ruben
65af5f4600 add icon 2025-09-20 12:51:22 +02:00
Ruben
7f39455bd0 allow .jav Main Methods 2025-09-20 12:42:46 +02:00
9 changed files with 126 additions and 192 deletions

Binary file not shown.

BIN
TX-main.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 664 KiB

View File

@@ -37,7 +37,7 @@ exports.JavaMainCodeLensProvider = void 0;
const vscode = __importStar(require("vscode"));
class JavaMainCodeLensProvider {
constructor() {
this.regexMain = /public\s+static\s+void\s+main\s*\(\s*String\s*\[\]\s*\w*\s*\)/g;
this.regexMain = /public\s+static\s+(?:void\s+)?main\s*\(\s*(?:String\s*\[\]\s*\w*|\w*)?\s*\)/g;
}
provideCodeLenses(document) {
const text = document.getText();

View File

@@ -1 +1 @@
{"version":3,"file":"codelensProvider.js","sourceRoot":"","sources":["../src/codelensProvider.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AACA,+CAAiC;AACjC,MAAa,wBAAwB;IAArC;QACU,cAAS,GAAG,gEAAgE,CAAC;IAYvF,CAAC;IAXC,iBAAiB,CAAC,QAA6B;QAC7C,MAAM,IAAI,GAAG,QAAQ,CAAC,OAAO,EAAE,CAAC;QAChC,MAAM,UAAU,GAAsB,EAAE,CAAC;QACzC,IAAI,CAAyB,CAAC;QAC9B,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;YAChD,MAAM,GAAG,GAAG,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;YACzC,MAAM,KAAK,GAAG,IAAI,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;YACzC,UAAU,CAAC,IAAI,CAAC,IAAI,MAAM,CAAC,QAAQ,CAAC,KAAK,EAAE,EAAE,OAAO,EAAE,yBAAyB,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,YAAY,EAAE,CAAC,CAAC,CAAC;QAC3H,CAAC;QACD,OAAO,UAAU,CAAC;IACpB,CAAC;CACF;AAbD,4DAaC"}
{"version":3,"file":"codelensProvider.js","sourceRoot":"","sources":["../src/codelensProvider.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AACA,+CAAiC;AACjC,MAAa,wBAAwB;IAArC;QACU,cAAS,GAAE,8EAA8E,CAAA;IAYnG,CAAC;IAXC,iBAAiB,CAAC,QAA6B;QAC7C,MAAM,IAAI,GAAG,QAAQ,CAAC,OAAO,EAAE,CAAC;QAChC,MAAM,UAAU,GAAsB,EAAE,CAAC;QACzC,IAAI,CAAyB,CAAC;QAC9B,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;YAChD,MAAM,GAAG,GAAG,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;YACzC,MAAM,KAAK,GAAG,IAAI,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;YACzC,UAAU,CAAC,IAAI,CAAC,IAAI,MAAM,CAAC,QAAQ,CAAC,KAAK,EAAE,EAAE,OAAO,EAAE,yBAAyB,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,YAAY,EAAE,CAAC,CAAC,CAAC;QAC3H,CAAC;QACD,OAAO,UAAU,CAAC;IACpB,CAAC;CACF;AAbD,4DAaC"}

View File

@@ -42,52 +42,33 @@ const path = __importStar(require("path"));
const codelensProvider_1 = require("./codelensProvider");
function getConfig(key, def) { const v = vscode.workspace.getConfiguration().get(key); return v === undefined ? def : v; }
function getWorkspaceFolderUri(docUri) { return docUri ? vscode.workspace.getWorkspaceFolder(docUri)?.uri : vscode.workspace.workspaceFolders?.[0]?.uri; }
function toAbs(folder, workspace) { return path.isAbsolute(folder) ? folder : (workspace ? path.join(workspace.fsPath, folder) : folder); }
function buildClasspath(folders) { return folders.join(path.delimiter); }
function readPackageName(text) { return text.match(/^\s*package\s+([\w\.]+)\s*;/m)?.[1]; }
function fqcnFromDocument(doc) { const pkg = readPackageName(doc.getText()); const simple = path.basename(doc.fileName).replace(/\.java$/i, ""); return pkg ? `${pkg}.${simple}` : simple; }
function execInTerminal(cmd, cwd, name = "Java Class Runner") { const t = vscode.window.terminals.find(tt => tt.name === name) || vscode.window.createTerminal({ name }); t.show(true); if (cwd)
t.sendText(`cd "${cwd}"`); t.sendText(cmd); }
function ensureDir(dir) { if (!fs.existsSync(dir))
fs.mkdirSync(dir, { recursive: true }); }
function psExec(cmdPath) { if (process.platform === "win32" && (cmdPath.includes("\\") || cmdPath.includes("/") || cmdPath.includes(" ")))
return `& "${cmdPath}"`; return cmdPath; }
function nearestOutFoldersFor(docPath, workspace) {
const res = [];
const fileDir = path.dirname(docPath);
const add = (p) => { if (fs.existsSync(p) && !res.includes(p))
res.push(p); };
add(path.join(fileDir, "out"));
if (workspace)
add(path.join(workspace.fsPath, "out"));
if (workspace) {
let cur = fileDir;
while (cur.startsWith(workspace.fsPath)) {
add(path.join(cur, "out"));
const parent = path.dirname(cur);
if (parent === cur)
break;
cur = parent;
}
}
return res;
}
async function compileJava(javaFile, outDir, classpath, javacPath) {
async function compileJava(javaFile, outDir, classpath, ctxpath) {
ensureDir(outDir);
if (javaFile.includes(".java")) {
return new Promise((resolve, reject) => {
const args = [javaFile, "-cp", classpath, "-d", outDir];
const proc = cp.spawn("javac", args, { shell: process.platform === "win32" });
let stderr = "";
proc.stderr.on("data", d => stderr += d.toString());
proc.on("close", code => code === 0 ? resolve() : reject(new Error(`javac exit code ${code}\n${stderr}`)));
});
}
return new Promise((resolve, reject) => {
const args = ["-d", outDir];
if (classpath.trim().length > 0) {
args.push("-cp", classpath);
}
args.push(javaFile);
const proc = cp.spawn(javacPath, args, { shell: process.platform === "win32" });
const args = ["-jar", ctxpath + "/JavaTXcompiler-0.1-jar-with-dependencies.jar", javaFile, "-cp", classpath, "-d", outDir];
const proc = cp.spawn("java", args, { shell: process.platform === "win32" });
let stderr = "";
proc.stderr.on("data", d => stderr += d.toString());
proc.on("close", code => code === 0 ? resolve() : reject(new Error(`javac exit code ${code}\n${stderr}`)));
});
}
function activate(ctx) {
ctx.subscriptions.push(vscode.languages.registerCodeLensProvider({ language: "java" }, new codelensProvider_1.JavaMainCodeLensProvider()));
ctx.subscriptions.push(vscode.languages.registerCodeLensProvider([{ language: "java" }, { pattern: "**/*.jav" }], new codelensProvider_1.JavaMainCodeLensProvider()));
ctx.subscriptions.push(vscode.commands.registerCommand("javaClassRunner.runMain", async () => {
const ed = vscode.window.activeTextEditor;
if (!ed || ed.document.languageId !== "java") {
@@ -95,86 +76,58 @@ function activate(ctx) {
return;
}
const ws = getWorkspaceFolderUri(ed.document.uri);
const cpFolders = getConfig("javaClassRunner.classpathFolders", ["classes"]).map(f => toAbs(f, ws)).filter(f => f && fs.existsSync(f));
const outDirCfg = getConfig("javaClassRunner.compile.outDir", ".java-class-runner/out");
const outDir = toAbs(outDirCfg, ws);
const compileEnabled = getConfig("javaClassRunner.compile.enabled", true);
const javaPath = getConfig("javaClassRunner.java.path", "java");
const javacPath = getConfig("javaClassRunner.javac.path", "javac");
const fileDir = path.dirname(ed.document.fileName);
const outDir = path.join(fileDir, "out", "main");
const cpFolders = [outDir, path.join(fileDir, "out")];
ensureDir(outDir);
if (fs.existsSync(outDir)) {
for (const entry of fs.readdirSync(outDir)) {
const fullPath = path.join(outDir, entry);
if (fs.lstatSync(fullPath).isDirectory()) {
fs.rmSync(fullPath, { recursive: true, force: true });
}
else {
fs.unlinkSync(fullPath);
}
}
}
const wdCfg = getConfig("javaClassRunner.run.workingDirectory", "${workspaceFolder}");
const wd = wdCfg.replace("${workspaceFolder}", ws?.fsPath ?? process.cwd());
const vmArgs = getConfig("javaClassRunner.run.vmArgs", []);
const programArgs = getConfig("javaClassRunner.run.programArgs", []);
const fqcn = fqcnFromDocument(ed.document);
if (!fqcn) {
vscode.window.showErrorMessage("Konnte FQCN nicht bestimmen.");
return;
}
const detectedOuts = nearestOutFoldersFor(ed.document.fileName, ws);
// compile: include detected outs so javac can resolve prebuilt dependencies (.class)
if (compileEnabled) {
try {
await compileJava(ed.document.fileName, outDir, buildClasspath([...cpFolders, ...detectedOuts]), javacPath);
}
catch (err) {
vscode.window.showErrorMessage(`Kompilierung fehlgeschlagen: ${err?.message || String(err)}`);
return;
}
try {
await compileJava(ed.document.fileName, outDir, `"${cpFolders.join(";")}"`, ctx.extensionPath);
}
// runtime cp: compile out + configured + detected outs
const cpCombined = buildClasspath([outDir, ...cpFolders, ...detectedOuts].filter(Boolean));
const cpArg = cpCombined.length ? `-cp "${cpCombined}"` : "";
const cmd = `${psExec(javaPath)} ${cpArg} ${vmArgs.join(" ")} ${fqcn} ${programArgs.join(" ")}`.trim();
execInTerminal(cmd, wd);
}));
ctx.subscriptions.push(vscode.commands.registerCommand("javaClassRunner.runFromClassesFolder", async () => {
const ws = getWorkspaceFolderUri();
const cpFolders = getConfig("javaClassRunner.classpathFolders", ["classes"]).map(f => toAbs(f, ws)).filter(f => f && fs.existsSync(f));
if (cpFolders.length === 0) {
vscode.window.showErrorMessage("Kein gültiger Klassen-Ordner gefunden. Prüfe 'javaClassRunner.classpathFolders'.");
catch (err) {
vscode.window.showErrorMessage(`Kompilierung fehlgeschlagen: ${err?.message || String(err)}`);
return;
}
const javaPath = getConfig("javaClassRunner.java.path", "java");
const wdCfg = getConfig("javaClassRunner.run.workingDirectory", "${workspaceFolder}");
const wd = wdCfg.replace("${workspaceFolder}", ws?.fsPath ?? process.cwd());
const vmArgs = getConfig("javaClassRunner.run.vmArgs", []);
const programArgs = getConfig("javaClassRunner.run.programArgs", []);
async function listMainClassesInFolder(root) {
const out = [];
const walk = async (dir) => {
const entries = await fs.promises.readdir(dir, { withFileTypes: true });
for (const e of entries) {
const full = path.join(dir, e.name);
if (e.isDirectory())
await walk(full);
else if (e.isFile() && e.name.endsWith(".class") && !e.name.includes("$")) {
const rel = path.relative(root, full).replace(/\.class$/, "");
const fqcn = rel.split(path.sep).join(".");
out.push(fqcn);
}
// Find the first .class file in outDir (excluding inner classes with $)
let mainClass;
const walk = (dir) => {
const entries = fs.readdirSync(dir, { withFileTypes: true });
for (const e of entries) {
const full = path.join(dir, e.name);
if (e.isDirectory())
walk(full);
else if (e.isFile() && e.name.endsWith(".class") && !e.name.includes("$") && !mainClass) {
const rel = path.relative(outDir, full).replace(/\.class$/, "");
mainClass = rel.split(path.sep).join(".");
}
};
if (fs.existsSync(root))
await walk(root);
return out.sort();
}
const classes = [];
for (const folder of cpFolders) {
const list = await listMainClassesInFolder(folder);
for (const c of list)
if (!classes.includes(c))
classes.push(c);
}
if (classes.length === 0) {
vscode.window.showWarningMessage("Keine .class-Dateien gefunden (ohne $).");
if (mainClass)
break;
}
};
if (fs.existsSync(outDir))
walk(outDir);
if (!mainClass) {
vscode.window.showErrorMessage("Keine .class-Datei im Ausgabeverzeichnis gefunden.");
return;
}
const picked = await vscode.window.showQuickPick(classes, { placeHolder: "Wähle eine Main-Klasse (FQCN)" });
if (!picked)
return;
const cpCombined = buildClasspath(cpFolders);
const cpArg = cpCombined.length ? `-cp "${cpCombined}"` : "";
const cmd = `${psExec(javaPath)} ${cpArg} ${vmArgs.join(" ")} ${picked} ${programArgs.join(" ")}`.trim();
const cmd = `java -cp "${cpFolders.join(";")}" ${mainClass}`.trim();
execInTerminal(cmd, wd);
}));
}

File diff suppressed because one or more lines are too long

View File

@@ -1,8 +1,9 @@
{
"name": "java-class-runner",
"displayName": "Java Class Runner (Run Main from .java + classpath folder)",
"description": "Führt Java Main-Methoden aus und nutzt .class-Ordner als Classpath. Fügt einen 'Run' CodeLens über main(...) hinzu.",
"version": "1.0.2",
"icon": "TX-main.png",
"name": "java-tx-main-runner",
"displayName": "Java-TX Main Runner",
"description": "Führt Java und Java-TX Main-Methoden aus und nutzt den /out Ordner als Classpath. Fügt einen 'Run' CodeLens über main(...) hinzu.",
"version": "0.0.2",
"engines": {
"vscode": "^1.85.0"
},

View File

@@ -1,7 +1,7 @@
import * as vscode from "vscode";
export class JavaMainCodeLensProvider implements vscode.CodeLensProvider {
private regexMain = /public\s+static\s+void\s+main\s*\(\s*String\s*\[\]\s*\w*\s*\)/g;
private regexMain =/public\s+static\s+(?:void\s+)?main\s*\(\s*(?:String\s*\[\]\s*\w*|\w*)?\s*\)/g
provideCodeLenses(document: vscode.TextDocument): vscode.CodeLens[] {
const text = document.getText();
const codeLenses: vscode.CodeLens[] = [];

View File

@@ -7,120 +7,100 @@ import { JavaMainCodeLensProvider } from "./codelensProvider";
function getConfig<T>(key: string, def: T): T { const v = vscode.workspace.getConfiguration().get<T>(key); return v===undefined?def:v; }
function getWorkspaceFolderUri(docUri?: vscode.Uri): vscode.Uri | undefined { return docUri ? vscode.workspace.getWorkspaceFolder(docUri)?.uri : vscode.workspace.workspaceFolders?.[0]?.uri; }
function toAbs(folder: string, workspace?: vscode.Uri): string { return path.isAbsolute(folder) ? folder : (workspace ? path.join(workspace.fsPath, folder) : folder); }
function buildClasspath(folders: string[]): string { return folders.join(path.delimiter); }
function readPackageName(text: string): string | undefined { return text.match(/^\s*package\s+([\w\.]+)\s*;/m)?.[1]; }
function fqcnFromDocument(doc: vscode.TextDocument): string | undefined { const pkg = readPackageName(doc.getText()); const simple = path.basename(doc.fileName).replace(/\.java$/i,""); return pkg ? `${pkg}.${simple}` : simple; }
function execInTerminal(cmd: string, cwd?: string, name="Java Class Runner") { const t = vscode.window.terminals.find(tt=>tt.name===name) || vscode.window.createTerminal({name}); t.show(true); if (cwd) t.sendText(`cd "${cwd}"`); t.sendText(cmd); }
function ensureDir(dir: string) { if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true }); }
function psExec(cmdPath: string): string { if (process.platform==="win32" && (cmdPath.includes("\\")||cmdPath.includes("/")||cmdPath.includes(" "))) return `& "${cmdPath}"`; return cmdPath; }
function nearestOutFoldersFor(docPath: string, workspace?: vscode.Uri): string[] {
const res: string[] = [];
const fileDir = path.dirname(docPath);
const add = (p:string)=>{ if (fs.existsSync(p) && !res.includes(p)) res.push(p); };
add(path.join(fileDir,"out"));
if (workspace) add(path.join(workspace.fsPath,"out"));
if (workspace) {
let cur=fileDir;
while (cur.startsWith(workspace.fsPath)) {
add(path.join(cur,"out"));
const parent = path.dirname(cur);
if (parent===cur) break;
cur = parent;
}
}
return res;
}
async function compileJava(javaFile: string, outDir: string, classpath: string, javacPath: string): Promise<void> {
async function compileJava(javaFile: string, outDir: string, classpath: string, ctxpath : string): Promise<void> {
ensureDir(outDir);
if(javaFile.includes(".java")){
return new Promise((resolve, reject) => {
const args = [javaFile, "-cp", classpath, "-d", outDir];
const proc = cp.spawn("javac", args, { shell: process.platform==="win32" });
let stderr=""; proc.stderr.on("data", d=>stderr+=d.toString());
proc.on("close", code=> code===0 ? resolve() : reject(new Error(`javac exit code ${code}\n${stderr}`)));
});
}
return new Promise((resolve, reject) => {
const args = ["-d", outDir];
if (classpath.trim().length>0) { args.push("-cp", classpath); }
args.push(javaFile);
const proc = cp.spawn(javacPath, args, { shell: process.platform==="win32" });
const args = ["-jar", ctxpath + "/JavaTXcompiler-0.1-jar-with-dependencies.jar", javaFile, "-cp", classpath, "-d", outDir];
const proc = cp.spawn("java", args, { shell: process.platform==="win32" });
let stderr=""; proc.stderr.on("data", d=>stderr+=d.toString());
proc.on("close", code=> code===0 ? resolve() : reject(new Error(`javac exit code ${code}\n${stderr}`)));
});
}
export function activate(ctx: vscode.ExtensionContext) {
ctx.subscriptions.push(vscode.languages.registerCodeLensProvider({ language: "java" }, new JavaMainCodeLensProvider()));
ctx.subscriptions.push(
vscode.languages.registerCodeLensProvider(
[{ language: "java" }, { pattern: "**/*.jav" }],
new JavaMainCodeLensProvider()
)
);
ctx.subscriptions.push(vscode.commands.registerCommand("javaClassRunner.runMain", async () => {
const ed = vscode.window.activeTextEditor;
if (!ed || ed.document.languageId!=="java") { vscode.window.showErrorMessage("Öffne eine Java-Datei mit main(...)"); return; }
const ws = getWorkspaceFolderUri(ed.document.uri);
const cpFolders = getConfig<string[]>("javaClassRunner.classpathFolders", ["classes"]).map(f=>toAbs(f, ws)).filter(f=>f && fs.existsSync(f));
const outDirCfg = getConfig<string>("javaClassRunner.compile.outDir", ".java-class-runner/out");
const outDir = toAbs(outDirCfg, ws);
const compileEnabled = getConfig<boolean>("javaClassRunner.compile.enabled", true);
const javaPath = getConfig<string>("javaClassRunner.java.path", "java");
const javacPath = getConfig<string>("javaClassRunner.javac.path", "javac");
const fileDir = path.dirname(ed.document.fileName);
const outDir = path.join(fileDir, "out", "main");
const cpFolders = [outDir, path.join(fileDir, "out")];
ensureDir(outDir);
if (fs.existsSync(outDir)) {
for (const entry of fs.readdirSync(outDir)) {
const fullPath = path.join(outDir, entry);
if (fs.lstatSync(fullPath).isDirectory()) {
fs.rmSync(fullPath, { recursive: true, force: true });
} else {
fs.unlinkSync(fullPath);
}
}
}
const wdCfg = getConfig<string>("javaClassRunner.run.workingDirectory", "${workspaceFolder}");
const wd = wdCfg.replace("${workspaceFolder}", ws?.fsPath ?? process.cwd());
const vmArgs = getConfig<string[]>("javaClassRunner.run.vmArgs", []);
const programArgs = getConfig<string[]>("javaClassRunner.run.programArgs", []);
const fqcn = fqcnFromDocument(ed.document);
if (!fqcn) { vscode.window.showErrorMessage("Konnte FQCN nicht bestimmen."); return; }
const detectedOuts = nearestOutFoldersFor(ed.document.fileName, ws);
// compile: include detected outs so javac can resolve prebuilt dependencies (.class)
if (compileEnabled) {
try { await compileJava(ed.document.fileName, outDir, buildClasspath([...cpFolders, ...detectedOuts]), javacPath); }
catch (err:any) { vscode.window.showErrorMessage(`Kompilierung fehlgeschlagen: ${err?.message || String(err)}`); return; }
try {
await compileJava(ed.document.fileName, outDir, `"${cpFolders.join(";")}"`, ctx.extensionPath); }
catch (err:any) {
vscode.window.showErrorMessage(`Kompilierung fehlgeschlagen: ${err?.message || String(err)}`);
return;
}
// runtime cp: compile out + configured + detected outs
const cpCombined = buildClasspath([outDir, ...cpFolders, ...detectedOuts].filter(Boolean));
const cpArg = cpCombined.length ? `-cp "${cpCombined}"` : "";
const cmd = `${psExec(javaPath)} ${cpArg} ${vmArgs.join(" ")} ${fqcn} ${programArgs.join(" ")}`.trim();
execInTerminal(cmd, wd);
}));
ctx.subscriptions.push(vscode.commands.registerCommand("javaClassRunner.runFromClassesFolder", async () => {
const ws = getWorkspaceFolderUri();
const cpFolders = getConfig<string[]>("javaClassRunner.classpathFolders", ["classes"]).map(f=>toAbs(f, ws)).filter(f=>f && fs.existsSync(f));
if (cpFolders.length===0) { vscode.window.showErrorMessage("Kein gültiger Klassen-Ordner gefunden. Prüfe 'javaClassRunner.classpathFolders'."); return; }
const javaPath = getConfig<string>("javaClassRunner.java.path", "java");
const wdCfg = getConfig<string>("javaClassRunner.run.workingDirectory", "${workspaceFolder}");
const wd = wdCfg.replace("${workspaceFolder}", ws?.fsPath ?? process.cwd());
const vmArgs = getConfig<string[]>("javaClassRunner.run.vmArgs", []);
const programArgs = getConfig<string[]>("javaClassRunner.run.programArgs", []);
async function listMainClassesInFolder(root: string): Promise<string[]> {
const out: string[] = [];
const walk = async (dir: string) => {
const entries = await fs.promises.readdir(dir, { withFileTypes: true });
for (const e of entries) {
const full = path.join(dir, e.name);
if (e.isDirectory()) await walk(full);
else if (e.isFile() && e.name.endsWith(".class") && !e.name.includes("$")) {
const rel = path.relative(root, full).replace(/\.class$/,"");
const fqcn = rel.split(path.sep).join(".");
out.push(fqcn);
}
// Find the first .class file in outDir (excluding inner classes with $)
let mainClass: string | undefined;
const walk = (dir: string) => {
const entries = fs.readdirSync(dir, { withFileTypes: true });
for (const e of entries) {
const full = path.join(dir, e.name);
if (e.isDirectory()) walk(full);
else if (e.isFile() && e.name.endsWith(".class") && !e.name.includes("$") && !mainClass) {
const rel = path.relative(outDir, full).replace(/\.class$/,"");
mainClass = rel.split(path.sep).join(".");
}
};
if (fs.existsSync(root)) await walk(root);
return out.sort();
if (mainClass) break;
}
};
if (fs.existsSync(outDir)) walk(outDir);
if (!mainClass) {
vscode.window.showErrorMessage("Keine .class-Datei im Ausgabeverzeichnis gefunden.");
return;
}
const classes: string[] = [];
for (const folder of cpFolders) {
const list = await listMainClassesInFolder(folder);
for (const c of list) if (!classes.includes(c)) classes.push(c);
}
if (classes.length===0) { vscode.window.showWarningMessage("Keine .class-Dateien gefunden (ohne $)."); return; }
const picked = await vscode.window.showQuickPick(classes, { placeHolder: "Wähle eine Main-Klasse (FQCN)" });
if (!picked) return;
const cpCombined = buildClasspath(cpFolders);
const cpArg = cpCombined.length ? `-cp "${cpCombined}"` : "";
const cmd = `${psExec(javaPath)} ${cpArg} ${vmArgs.join(" ")} ${picked} ${programArgs.join(" ")}`.trim();
const cmd = `java -cp "${cpFolders.join(";")}" ${mainClass}`.trim();
execInTerminal(cmd, wd);
}));
}
export function deactivate() {}