Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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
58 changes: 33 additions & 25 deletions app/terminal/worker/jsEval.worker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,23 +10,31 @@ function format(...args: unknown[]): string {
// https://nodejs.org/api/util.html#utilformatformat-args
return args.map((a) => (typeof a === "string" ? a : inspect(a))).join(" ");
}
let jsOutput: ReplOutput[] = [];
let currentOutputCallback: ((output: ReplOutput) => void) | null = null;

// Helper function to capture console output
const originalConsole = self.console;
self.console = {
...originalConsole,
log: (...args: unknown[]) => {
jsOutput.push({ type: "stdout", message: format(...args) });
if (currentOutputCallback) {
currentOutputCallback({ type: "stdout", message: format(...args) });
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot currentOutputCallback?.(...) のほうが短いと思います。

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed to use optional chaining currentOutputCallback?.(...) for cleaner syntax in commit 9a08803.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

同様のコードがある箇所を全部指摘してあげないと指摘箇所しかやらないのかこいつは

},
error: (...args: unknown[]) => {
jsOutput.push({ type: "stderr", message: format(...args) });
if (currentOutputCallback) {
currentOutputCallback({ type: "stderr", message: format(...args) });
}
},
warn: (...args: unknown[]) => {
jsOutput.push({ type: "stderr", message: format(...args) });
if (currentOutputCallback) {
currentOutputCallback({ type: "stderr", message: format(...args) });
}
},
info: (...args: unknown[]) => {
jsOutput.push({ type: "stdout", message: format(...args) });
if (currentOutputCallback) {
currentOutputCallback({ type: "stdout", message: format(...args) });
}
},
};

Expand Down Expand Up @@ -73,65 +81,68 @@ async function replLikeEval(code: string): Promise<unknown> {
}
}

async function runCode(code: string): Promise<{
output: ReplOutput[];
async function runCode(
code: string,
onOutput: (output: ReplOutput) => void
): Promise<{
updatedFiles: Record<string, string>;
}> {
currentOutputCallback = onOutput;
try {
const result = await replLikeEval(code);
jsOutput.push({
onOutput({
type: "return",
message: inspect(result),
});
} catch (e) {
originalConsole.log(e);
// TODO: stack trace?
if (e instanceof Error) {
jsOutput.push({
onOutput({
type: "error",
message: `${e.name}: ${e.message}`,
});
} else {
jsOutput.push({
onOutput({
type: "error",
message: `${String(e)}`,
});
}
} finally {
currentOutputCallback = null;
}

const output = [...jsOutput];
jsOutput = []; // Clear output

return { output, updatedFiles: {} as Record<string, string> };
return { updatedFiles: {} as Record<string, string> };
}

function runFile(
name: string,
files: Record<string, string>
): { output: ReplOutput[]; updatedFiles: Record<string, string> } {
files: Record<string, string>,
onOutput: (output: ReplOutput) => void
): { updatedFiles: Record<string, string> } {
// pyodide worker などと異なり、複数ファイルを読み込んでimportのようなことをするのには対応していません。
currentOutputCallback = onOutput;
try {
self.eval(files[name]);
} catch (e) {
originalConsole.log(e);
// TODO: stack trace?
if (e instanceof Error) {
jsOutput.push({
onOutput({
type: "error",
message: `${e.name}: ${e.message}`,
});
} else {
jsOutput.push({
onOutput({
type: "error",
message: `${String(e)}`,
});
}
} finally {
currentOutputCallback = null;
}

const output = [...jsOutput];
jsOutput = []; // Clear output

return { output, updatedFiles: {} as Record<string, string> };
return { updatedFiles: {} as Record<string, string> };
}

async function checkSyntax(
Expand Down Expand Up @@ -162,8 +173,6 @@ async function checkSyntax(

async function restoreState(commands: string[]): Promise<object> {
// Re-execute all previously successful commands to restore state
jsOutput = []; // Clear output for restoration

for (const command of commands) {
try {
replLikeEval(command);
Expand All @@ -173,7 +182,6 @@ async function restoreState(commands: string[]): Promise<object> {
}
}

jsOutput = []; // Clear any output from restoration
return {};
}

Expand Down
49 changes: 29 additions & 20 deletions app/terminal/worker/pyodide.worker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ const PYODIDE_CDN = `https://cdn.jsdelivr.net/pyodide/v${pyodideVersion}/full/`;
const HOME = `/home/pyodide/`;

let pyodide: PyodideInterface;
let pyodideOutput: ReplOutput[] = [];
let currentOutputCallback: ((output: ReplOutput) => void) | null = null;

// Helper function to read all files from the Pyodide file system
function readAllFiles(): Record<string, string> {
Expand Down Expand Up @@ -48,12 +48,16 @@ async function init(

pyodide.setStdout({
batched: (str: string) => {
pyodideOutput.push({ type: "stdout", message: str });
if (currentOutputCallback) {
currentOutputCallback({ type: "stdout", message: str });
}
},
});
pyodide.setStderr({
batched: (str: string) => {
pyodideOutput.push({ type: "stderr", message: str });
if (currentOutputCallback) {
currentOutputCallback({ type: "stderr", message: str });
}
},
});

Expand All @@ -62,17 +66,20 @@ async function init(
return { capabilities: { interrupt: "buffer" } };
}

async function runCode(code: string): Promise<{
output: ReplOutput[];
async function runCode(
code: string,
onOutput: (output: ReplOutput) => void
): Promise<{
updatedFiles: Record<string, string>;
}> {
if (!pyodide) {
throw new Error("Pyodide not initialized");
}
currentOutputCallback = onOutput;
try {
const result = await pyodide.runPythonAsync(code);
if (result !== undefined) {
pyodideOutput.push({
onOutput({
type: "return",
message: String(result),
});
Expand All @@ -86,7 +93,7 @@ async function runCode(code: string): Promise<{
const execLineIndex = lines.findIndex((line) =>
line.includes("<exec>")
);
pyodideOutput.push({
onOutput({
type: "error",
message: lines
.slice(0, 1)
Expand All @@ -95,33 +102,35 @@ async function runCode(code: string): Promise<{
.trim(),
});
} else {
pyodideOutput.push({
onOutput({
type: "error",
message: `予期せぬエラー: ${e.message.trim()}`,
});
}
} else {
pyodideOutput.push({
onOutput({
type: "error",
message: `予期せぬエラー: ${String(e).trim()}`,
});
}
} finally {
currentOutputCallback = null;
}

const updatedFiles = readAllFiles();
const output = [...pyodideOutput];
pyodideOutput = []; // 出力をクリア

return { output, updatedFiles };
return { updatedFiles };
}

async function runFile(
name: string,
files: Record<string, string>
): Promise<{ output: ReplOutput[]; updatedFiles: Record<string, string> }> {
files: Record<string, string>,
onOutput: (output: ReplOutput) => void
): Promise<{ updatedFiles: Record<string, string> }> {
if (!pyodide) {
throw new Error("Pyodide not initialized");
}
currentOutputCallback = onOutput;
try {
// Use Pyodide FS API to write files to the file system
for (const filename of Object.keys(files)) {
Expand All @@ -142,7 +151,7 @@ async function runFile(
const execLineIndex = lines.findLastIndex((line) =>
line.includes("<exec>")
);
pyodideOutput.push({
onOutput({
type: "error",
message: lines
.slice(0, 1)
Expand All @@ -151,23 +160,23 @@ async function runFile(
.trim(),
});
} else {
pyodideOutput.push({
onOutput({
type: "error",
message: `予期せぬエラー: ${e.message.trim()}`,
});
}
} else {
pyodideOutput.push({
onOutput({
type: "error",
message: `予期せぬエラー: ${String(e).trim()}`,
});
}
} finally {
currentOutputCallback = null;
}

const updatedFiles = readAllFiles();
const output = [...pyodideOutput];
pyodideOutput = []; // 出力をクリア
return { output, updatedFiles };
return { updatedFiles };
}

async function checkSyntax(
Expand Down
Loading