diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index 5c5ac48..0000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,13 +0,0 @@ -// Place your settings in this file to overwrite default and user settings. -{ - "files.exclude": { - "out": false, // set this to true to hide the "out" folder with the compiled JS files - "dist": false // set this to true to hide the "dist" folder with the compiled JS files - }, - "search.exclude": { - "out": true, // set this to false to include "out" folder in search results - "dist": true // set this to false to include "dist" folder in search results - }, - // Turn off tsc task auto detection since we have the necessary tasks as npm scripts - "typescript.tsc.autoDetect": "off" -} \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 907e77c..6c8b8e5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,8 @@ # Changelog +## v0.6.7 +- Auto generate module from python cells when running Mojo cell + ## v0.6.6 - Default to using MDL.AI when opening a .md file - Improve README.md diff --git a/src/kernel.ts b/src/kernel.ts index d82eadb..91da0fb 100644 --- a/src/kernel.ts +++ b/src/kernel.ts @@ -54,7 +54,8 @@ export class Kernel { // Build a object containing languages and their cells let cellsStripped: Cell[] = []; let matchingCells = 0; - let pythonCells = 0; + let pythonMatchingCells = 0; + let pythonCells: Cell[] = []; for (const cell of cellsUpToCurrent) { if (cell.document.languageId === cells[0].document.languageId) { matchingCells++; @@ -64,9 +65,15 @@ export class Kernel { cell: cell, }); } + // Also capture python cells if they exist when running Mojo if (cells[0].document.languageId === "mojo") { - if(cell.document.languageId === "python") { - pythonCells += 1; + if (cell.document.languageId === "python") { + pythonMatchingCells++ + pythonCells.push({ + index: pythonMatchingCells, + contents: cell.document.getText(), + cell: cell, + }); } } } @@ -86,7 +93,7 @@ export class Kernel { 'Authorization': `Bearer ${getGroqAIKey()}`, } - const messages: ChatMessage[] = [{"role": "user", "content": "You're generating codeblocks to help users solve programming problems, make sure that you put the name of the language in the markdown blocks like ```python"}] + const messages: ChatMessage[] = [{ "role": "user", "content": "You're generating codeblocks to help users solve programming problems, make sure that you put the name of the language in the markdown blocks like ```python" }] for (const message of cellsStripped) { messages.push({ role: "user", content: message.contents }); } @@ -210,7 +217,7 @@ export class Kernel { return } lastRunLanguage = "mojo"; - let mojoResult = processCellsMojo(cellsStripped); + let mojoResult = processCellsMojo(cellsStripped, pythonCells); output = mojoResult.stream clearOutput = mojoResult.clearOutput break; @@ -231,14 +238,13 @@ export class Kernel { output = processCellsGo(cellsStripped); break; case "python": - let command = "python" + let command = "python3" if (commandNotOnPath(command, "")) { - if (commandNotOnPath("python3", "https://www.python.org/downloads/")) { + if (commandNotOnPath("python", "https://www.python.org/downloads/")) { exec.end(false, (new Date).getTime()); return - } else { - command = "python3" } + command = "python" } lastRunLanguage = "python"; let pyResult = processCellsPython(cellsStripped, command); @@ -343,7 +349,7 @@ export class Kernel { if (lastRunLanguage == "shell") { currentCellOutput = outputs[1] } else { - currentCellOutput = outputs[currentCellLang.index + pythonCells]; + currentCellOutput = outputs[currentCellLang.index + pythonCells.length]; } if (!clearOutput && currentCellOutput.trim()) { exec.replaceOutput([new NotebookCellOutput([NotebookCellOutputItem.text(currentCellOutput)])]); @@ -360,7 +366,6 @@ export class Kernel { } // Loop through all the cells and increment version of image if it exists - if (doc.getCells().length >= (cells[0].index + 1)) { let cell = doc.getCells(new NotebookRange(cells[0].index + 1, cells[0].index + 2))[0] if (cell.kind === vscode.NotebookCellKind.Markup) { @@ -392,8 +397,8 @@ export class Kernel { }).then(() => { // Execute commands to toggle cell edit mode and then toggle it back to preview. vscode.commands.executeCommand('notebook.cell.edit').then(() => { - vscode.commands.executeCommand('notebook.cell.quitEdit').then(() => { - // Optionally, add any additional logic that needs to run after the refresh. + vscode.commands.executeCommand('notebook.cell.quitEdit').then(() => { + // Optionally, add any additional logic that needs to run after the refresh. }); }); }); diff --git a/src/languages/mojo.ts b/src/languages/mojo.ts index 4d577e9..bcc7f6f 100644 --- a/src/languages/mojo.ts +++ b/src/languages/mojo.ts @@ -4,19 +4,29 @@ import { getTempPath, modularHome } from "../config"; import { Cell, CommentDecorator } from "../types"; import path from "path"; import { window } from "vscode"; +import { processCellsPython } from "./python"; +import { commandNotOnPath } from "../utils"; let tempDir = getTempPath(); -export let processCellsMojo = (cells: Cell[]): { stream: ChildProcessWithoutNullStreams, clearOutput: boolean } => { +export let processCellsMojo = (cells: Cell[], pythonCells: Cell[]): { stream: ChildProcessWithoutNullStreams, clearOutput: boolean } => { + // If any python cells exist, make sure the generated file is current + if (pythonCells) { + let command = "python3" + if (commandNotOnPath(command, "")) { + command = "python" + } + processCellsPython(pythonCells, command) + } const activeFilePath = path.dirname(window.activeTextEditor?.document.uri.fsPath as string); let outerScope = ""; let innerScope = `def main():`; - let pythonFileExists = existsSync(path.join(tempDir, "md_notebook.py")); + let pythonFileExists = existsSync(path.join(tempDir, "mdl.py")); if (pythonFileExists) { outerScope += "from python import Python\n" - innerScope += `\n sys = Python.import_module("sys")\n sys.path.append("${activeFilePath}")\n sys.path.append("${tempDir}")\n py = Python.import_module("md_notebook")\n` + innerScope += `\n sys = Python.import_module("sys")\n sys.path.append("${activeFilePath}")\n sys.path.append("${tempDir}")\n py = Python.import_module("mdl")\n` } let cellCount = 0; let clearOutput = false; @@ -24,7 +34,7 @@ export let processCellsMojo = (cells: Cell[]): { stream: ChildProcessWithoutNull for (const cell of cells) { innerScope += `\n print("!!output-start-cell")\n`; - cell.contents = cell.contents.trim(); + // cell.contents = cell.contents.trim(); const regex = /(\s*print\s*\()(.*?)(\)\s*$)/gm; cell.contents = cell.contents.replace(regex, (_, before, content, after) => { @@ -40,15 +50,24 @@ export let processCellsMojo = (cells: Cell[]): { stream: ChildProcessWithoutNull }); cellCount++; - if(cell.contents.startsWith("#mdl:skip") || cell.contents.startsWith("# mdl:skip")) { + if (cell.contents.startsWith("#mdl:skip") || cell.contents.startsWith("# mdl:skip")) { continue; - } + } let lines = cell.contents.split("\n"); const len = lines.length; let i = 0 for (let line of lines) { i++ - if(line.startsWith("struct") || line.startsWith("trait") || line.startsWith("from")) { + // Keep things in outerScope if they should not go in main() + if ( + line.startsWith("struct") || + line.startsWith("trait") || + line.startsWith("fn") || + line.startsWith("alias") || + line.startsWith("from") || + line.startsWith("import") || + line.startsWith("@") + ) { inOuterScope = true; } else if (!line.startsWith(" ") && !(line === "")) { inOuterScope = false; @@ -76,7 +95,7 @@ export let processCellsMojo = (cells: Cell[]): { stream: ChildProcessWithoutNull if (line.startsWith("fn main():") || line.startsWith("def main():")) { continue; } - if (pythonFileExists && (line.includes('Python.import_module("sys")') || line.trim() == "from python import Python")){ + if (pythonFileExists && (line.includes('Python.import_module("sys")') || line.trim() == "from python import Python")) { continue; } @@ -90,7 +109,7 @@ export let processCellsMojo = (cells: Cell[]): { stream: ChildProcessWithoutNull } } - if(inOuterScope) { + if (inOuterScope) { outerScope += line + "\n" } else { innerScope += " " + line + "\n"; @@ -105,9 +124,9 @@ export let processCellsMojo = (cells: Cell[]): { stream: ChildProcessWithoutNull mkdirSync(tempDir, { recursive: true }); writeFileSync(mainFile, outerScope + innerScope); let env = process.env; - if(typeof modularHome === "string") { - env = {"MODULAR_HOME": modularHome, ...env} + if (typeof modularHome === "string") { + env = { "MODULAR_HOME": modularHome, ...env } } - - return { stream: spawn('mojo', [mainFile], {cwd: activeFilePath, env}), clearOutput }; + + return { stream: spawn('mojo', [mainFile], { cwd: activeFilePath, env }), clearOutput }; }; diff --git a/src/languages/python.ts b/src/languages/python.ts index b04ef39..ae0c92e 100644 --- a/src/languages/python.ts +++ b/src/languages/python.ts @@ -2,12 +2,12 @@ import { ChildProcessWithoutNullStreams, spawn } from "child_process"; import { mkdirSync, writeFileSync } from "fs"; import { getTempPath } from "../config"; import { Cell, CommentDecorator } from "../types"; -import vscode from "vscode" +import vscode from "vscode" import path from "path" let tempDir = getTempPath(); -export let processCellsPython = (cells: Cell[], command: string): {stream: ChildProcessWithoutNullStreams, clearOutput: boolean }=> { +export let processCellsPython = (cells: Cell[], command: string): { stream: ChildProcessWithoutNullStreams, clearOutput: boolean } => { let innerScope = ""; let cellCount = 0; @@ -31,23 +31,23 @@ export let processCellsPython = (cells: Cell[], command: string): {stream: Child return `${before}${content}${after}`; }); cellCount++; - if(cell.contents.startsWith("#mdl:skip") || cell.contents.startsWith("# mdl:skip")) { + if (cell.contents.startsWith("#mdl:skip") || cell.contents.startsWith("# mdl:skip")) { continue; - } - if(cell.contents.startsWith("#mdl:skip")) { + } + if (cell.contents.startsWith("#mdl:skip")) { continue - } + } let lines = cell.contents.split("\n"); const len = lines.length; let i = 0 for (let line of lines) { i++ - if (i==1 && line.replace(/\s/g, "").substring(0, 6) == "#file:") { + if (i == 1 && line.replace(/\s/g, "").substring(0, 6) == "#file:") { let file = line.split(":")[1].trim() - if (file != "main.py"){ + if (file != "main.py") { let cleaned = "" - for(let line2 of lines){ - if(line2.trim() != 'print("!!output-start-cell", flush=True)'){ + for (let line2 of lines) { + if (line2.trim() != 'print("!!output-start-cell", flush=True)') { cleaned += line2 + "\n" } } @@ -78,11 +78,11 @@ export let processCellsPython = (cells: Cell[], command: string): {stream: Child } }; - let mainFile = path.join(tempDir, "md_notebook.py"); + let mainFile = path.join(tempDir, "mdl.py"); let header = `import sys\nsys.path.append("${activeFilePath}")\nsys.path.append("${tempDir}")\nfrom builtins import *\n` mkdirSync(tempDir, { recursive: true }); writeFileSync(mainFile, header + innerScope); - - return {stream: spawn(command, [mainFile], {cwd: activeFilePath}), clearOutput}; + + return { stream: spawn(command, [mainFile], { cwd: activeFilePath }), clearOutput }; };