Skip to content

Commit 16d267e

Browse files
committed
0.7.1: Add Zig
1 parent 9b2bd9b commit 16d267e

8 files changed

Lines changed: 158 additions & 12 deletions

File tree

CHANGELOG.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# Changelog
22

3+
## v0.7.1
4+
5+
- Add zig support and using zvm to install master if zig not on path
6+
37
## v0.7.0
48

59
- Large refactor of the codebase
@@ -8,7 +12,7 @@
812
- Fault tolerance for subprocess errors
913
- Add groq model selection
1014
- Send all the markdown to AI models to understand context, not just the current cell
11-
- Add eslint and prettier formatting, fix all probelms
15+
- Add eslint and prettier formatting, fix all existing problems
1216
- Remove Python cell interop from Mojo feature, to simplify the codebase
1317

1418
## v0.6.20

package-lock.json

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

package.json

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"name": "mdlab",
33
"displayName": "Markdown Lab",
44
"publisher": "jackos",
5-
"version": "0.7.0",
5+
"version": "0.7.1",
66
"description": "Run markdown code blocks interactively in a notebook with any programming language, and generate code blocks with LLMs.",
77
"main": "./out/extension.js",
88
"icon": "mdlab.png",
@@ -138,7 +138,7 @@
138138
"compile": "tsc -p ./",
139139
"watch": "tsc -watch -p ./",
140140
"package": "vsce package",
141-
"install-extension": "cursor --install-extension $(ls mdlab-*) --force",
141+
"install-extension": "code --install-extension $(ls mdlab-*) --force",
142142
"i": "npm run package && npm run install-extension",
143143
"test": "npm run compile && node ./out/kernel-e2e.test.js",
144144
"lint": "eslint src --ext .ts,.tsx",
@@ -147,13 +147,13 @@
147147
"format:check": "prettier --check \"src/**/*.{ts,tsx,js,jsx,json}\""
148148
},
149149
"devDependencies": {
150-
"@types/node": "^22.15.23",
150+
"@types/node": "^22.19.0",
151151
"@types/vscode": "^1.96.2",
152152
"@typescript-eslint/eslint-plugin": "^8.33.0",
153153
"@typescript-eslint/parser": "^8.33.0",
154+
"@vscode/vsce": "^3.4.2",
154155
"eslint": "^9.27.0",
155156
"prettier": "^3.5.3",
156-
"typescript": "^5.8.3",
157-
"@vscode/vsce": "^3.4.2"
157+
"typescript": "^5.8.3"
158158
}
159159
}

src/constants.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ export const CONSTANTS = {
5757
FISH: 'https://fishshell.com/',
5858
NUSHELL: 'https://www.nushell.sh/book/installation.html',
5959
MOJO: 'https://modular.com/mojo',
60+
ZIG: 'https://www.zvm.app/guides/install-zvm/',
6061
},
6162
} as const;
6263

src/extension.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ function registerNotebookController(context: vscode.ExtensionContext): void {
5858
'groq',
5959
'python',
6060
'mojo',
61+
"zig",
6162
];
6263

6364
controller.executeHandler = (

src/kernel.ts

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import { commandNotOnPath, installMojo, outputChannel } from './utils';
2727
import { existsSync, writeFileSync } from 'fs';
2828
import path from 'path';
2929
import { AIService } from './services/aiService';
30+
import { processCellsZig } from './languages/zig';
3031

3132
export let lastRunLanguage = '';
3233

@@ -282,7 +283,12 @@ export class Kernel {
282283
}
283284
lastRunLanguage = 'rust';
284285
return { stream: processCellsRust(cellsStripped), clearOutput };
285-
286+
case 'zig':
287+
if (commandNotOnPath('cargo', 'https://www.zvm.app/guides/install-zvm/')) {
288+
return null;
289+
}
290+
lastRunLanguage = 'zig';
291+
return { stream: processCellsZig(cellsStripped), clearOutput };
286292
case 'go':
287293
if (commandNotOnPath('go', 'https://go.dev/doc/install')) {
288294
return null;
@@ -451,6 +457,18 @@ export class Kernel {
451457
new NotebookCellOutput([NotebookCellOutputItem.text(errorText, mimeType)]),
452458
]);
453459
}
460+
461+
const arr = [buf, data];
462+
buf = Buffer.concat(arr);
463+
const outputs = decoder.decode(buf).split(/!!output-start-cell[\n,""," "]/g);
464+
const currentCellOutput =
465+
lastRunLanguage === 'shell' ? outputs[1] : outputs[currentCellLang.index];
466+
467+
if (!clearOutput && currentCellOutput?.trim()) {
468+
exec.replaceOutput([
469+
new NotebookCellOutput([NotebookCellOutputItem.text(currentCellOutput)]),
470+
]);
471+
}
454472
});
455473

456474
// Set up stdout handler

src/languages/zig.ts

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
import { ChildProcessWithoutNullStreams, spawn, execSync, spawnSync } from 'child_process';
2+
import { mkdirSync, writeFileSync, existsSync } from 'fs';
3+
import { getTempPath } from '../config';
4+
import { Cell } from '../types';
5+
import * as vscode from 'vscode';
6+
import { dirname } from 'path';
7+
import { env } from 'process';
8+
import { homedir } from 'os';
9+
10+
let tempDir = getTempPath();
11+
let mainLine = 'pub fn main() !void {\n'
12+
13+
export const processCellsZig = (cells: Cell[]): ChildProcessWithoutNullStreams => {
14+
let imports = '';
15+
let importNumber = 0;
16+
let outerScope = '';
17+
let innerScope = '';
18+
let containsMain = false;
19+
let parsingImports = false;
20+
let parsingBlock = false;
21+
let parsingIter = 0;
22+
let funcRegex = /.*fn\s+(\w+)\(.*\)\s+[\w|!]+\s+{/;
23+
let errorRegex = /(const|var)\s+\w+\s*=\s*error\s*{/;
24+
25+
for (const cell of cells) {
26+
innerScope += 'std.debug.print("!!output-start-cell\\n", .{});'
27+
let lines = cell.contents.split('\n');
28+
for (let line of lines) {
29+
let funcResult = line.match(funcRegex);
30+
let errorResult = line.match(errorRegex);
31+
if (funcResult) {
32+
if (funcResult[1] === 'main') {
33+
containsMain = true;
34+
mainLine = line + "\n";
35+
continue;
36+
} else {
37+
parsingBlock = true;
38+
}
39+
} else if (errorResult) {
40+
parsingBlock = true;
41+
}
42+
43+
if (line.includes('@import')) {
44+
importNumber++;
45+
imports += line;
46+
imports += '\n';
47+
} else if (parsingBlock) {
48+
outerScope += line;
49+
outerScope += '\n';
50+
} else {
51+
innerScope += line;
52+
innerScope += '\n';
53+
}
54+
55+
const trimmed = line.trim();
56+
if (parsingBlock) {
57+
if (trimmed[0] === '}') {
58+
if (parsingIter === 1) {
59+
parsingIter = 0;
60+
parsingBlock = false;
61+
} else {
62+
parsingIter--;
63+
}
64+
}
65+
if (trimmed[trimmed.length - 1] === '{') {
66+
parsingIter++;
67+
}
68+
}
69+
}
70+
// Drop the closing curly brace if there was a main function
71+
if (containsMain) {
72+
innerScope = innerScope.trim().slice(0, -1);
73+
containsMain = false;
74+
}
75+
}
76+
let main =
77+
imports +
78+
outerScope +
79+
mainLine +
80+
innerScope +
81+
'}';
82+
83+
mkdirSync(`${tempDir}/zig`, { recursive: true });
84+
writeFileSync(`${tempDir}/zig/main.zig`, main);
85+
86+
// Check if zig is on PATH
87+
let zigPath = 'zig';
88+
try {
89+
execSync('which zig', { stdio: 'pipe' });
90+
} catch {
91+
// zig not on PATH, use zvm
92+
const zvmZigPath = `${homedir()}/.zvm/bin/zig`;
93+
if (!existsSync(zvmZigPath)) {
94+
// Install zvm and zig master with progress terminal
95+
vscode.window.showInformationMessage('Installing Zig via zvm - this may take a moment...');
96+
97+
const terminal = vscode.window.createTerminal({ name: 'Zig Installation' });
98+
terminal.show();
99+
terminal.sendText(`curl -fsSL https://raw.githubusercontent.com/tristanisham/zvm/master/install.sh | bash && ${homedir()}/.zvm/self/zvm i master && exit`);
100+
101+
// Wait for installation to complete (poll for zig binary)
102+
const startTime = Date.now();
103+
const timeout = 5 * 60 * 1000; // 5 minute timeout
104+
while (!existsSync(zvmZigPath)) {
105+
if (Date.now() - startTime > timeout) {
106+
vscode.window.showErrorMessage('Zig installation timed out');
107+
throw new Error('Zig installation timed out');
108+
}
109+
spawnSync('sleep', ['1']);
110+
}
111+
vscode.window.showInformationMessage('Zig installation completed!');
112+
}
113+
zigPath = zvmZigPath;
114+
}
115+
116+
return spawn(zigPath, ['run', `${tempDir}/zig/main.zig`]);
117+
};

src/markdownParser.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ export const LANG_IDS = new Map([
1515
['js', 'javascript'],
1616
['ts', 'typescript'],
1717
['rust', 'rust'],
18+
['zig', 'zig'],
1819
['go', 'go'],
1920
['nu', 'nushell'],
2021
['sh', 'bash'],

0 commit comments

Comments
 (0)