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 = / .* f n \s + ( \w + ) \( .* \) \s + [ \w | ! ] + \s + { / ;
23+ let errorRegex = / ( c o n s t | v a r ) \s + \w + \s * = \s * e r r o r \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+ } ;
0 commit comments