@@ -37,6 +37,15 @@ function actionMessage(act: conf.actionType, file: string): string {
3737 }
3838}
3939
40+ async function emptyFolder ( folder : string ) {
41+ if ( nodefs . existsSync ( folder ) ) {
42+ await nodefs . promises . rm ( folder , { recursive : true } ) ;
43+ }
44+ if ( ! nodefs . existsSync ( folder ) ) {
45+ await nodefs . promises . mkdir ( folder , { recursive : true } ) ;
46+ }
47+ }
48+
4049export async function activate ( context : vscode . ExtensionContext ) {
4150 statusBar . activate ( context ) ;
4251 const diag = Diag . activate ( context ) ;
@@ -50,22 +59,21 @@ export async function activate(context: vscode.ExtensionContext) {
5059 async function singleFileMode ( act : conf . actionType , _uri : vscode . Uri ) : Promise < AsmResult > {
5160 logger . channel ( actionMessage ( act , _uri . fsPath ) ) ;
5261
53- if ( nodefs . existsSync ( seperateSpaceFolder . fsPath ) ) {
54- await fs . delete ( seperateSpaceFolder , { recursive : true , useTrash : false } ) ;
55- }
56- await fs . createDirectory ( seperateSpaceFolder ) ;
57- if ( nodefs . existsSync ( assemblyToolsFolder . fsPath ) ) {
58- await fs . delete ( assemblyToolsFolder , { recursive : true , useTrash : false } ) ;
59- }
60- await fs . createDirectory ( assemblyToolsFolder ) ;
62+ const extConfig = vscode . workspace . getConfiguration ( 'masmtasm' ) ;
6163
62- const actions : ACTIONS | undefined = vscode . workspace . getConfiguration ( 'masmtasm' ) . get ( 'ASM.actions' ) ;
64+ await emptyFolder ( assemblyToolsFolder . fsPath ) ;
65+ await emptyFolder ( seperateSpaceFolder . fsPath ) ;
66+
67+ const actions : ACTIONS | undefined = extConfig . get ( 'ASM.actions' ) ;
6368 if ( actions === undefined ) {
6469 throw new Error ( "configurate `masmtasm.ASM.actions` first" ) ;
6570 }
6671 const action = actions [ conf . extConf . asmType ] ;
6772
6873 const doc = await vscode . workspace . openTextDocument ( _uri ) ;
74+ if ( doc . isDirty && extConfig . get ( 'ASM.savefirst' ) ) {
75+ await doc . save ( ) ;
76+ }
6977
7078 const bundlePath = vscode . Uri . joinPath (
7179 context . extensionUri ,
@@ -109,11 +117,250 @@ export async function activate(context: vscode.ExtensionContext) {
109117 autoexec . push ( ...action . debug . map ( cb ) ) ;
110118 }
111119
120+ const box = conf . extConf . emulator === conf . DosEmulatorType . dosboxX ? api . dosboxX : api . dosbox ;
121+ await box . fromBundle ( bundle , assemblyToolsFolder , false ) ;
122+
123+ if ( act !== conf . actionType . open ) {
124+ switch ( extConfig . get ( 'dosbox.run' ) ) {
125+ case "keep" :
126+ break ;
127+ case "exit" :
128+ autoexec . push ( 'exit' ) ;
129+ break ;
130+ case 'pause' :
131+ autoexec . push ( 'pause' , 'exit' ) ;
132+ break ;
133+ case "choose" :
134+ default :
135+ autoexec . push (
136+ "@choice Do you need to keep the DOSBox" ,
137+ "@IF ERRORLEVEL 2 exit" ,
138+ "@IF ERRORLEVEL 1 echo on"
139+ ) ;
140+ break ;
141+ }
142+ }
143+
144+ const dosboxConf : { [ id : string ] : string } | undefined =
145+ conf . extConf . emulator === conf . DosEmulatorType . dosboxX
146+ ? vscode . workspace . getConfiguration ( "masmtasm" ) . get ( "dosbox.config" )
147+ : vscode . workspace . getConfiguration ( "masmtasm" ) . get ( "dosboxX.config" ) ;
148+ if ( dosboxConf ) {
149+ for ( const id in dosboxConf ) {
150+ const [ section , key ] = id . toLowerCase ( ) . split ( '.' ) ;
151+ const value = dosboxConf [ id ] ;
152+ box . updateConf ( section , key , value ) ;
153+ }
154+ }
155+
156+ box . updateAutoexec ( autoexec ) ;
157+
158+ if ( act !== conf . actionType . open ) {
159+ const [ hook , promise ] = messageCollector ( ) ;
160+ nodefs . watchFile ( logUri . fsPath , ( ) => {
161+ try {
162+ if ( nodefs . existsSync ( logUri . fsPath ) ) {
163+ const text = nodefs . readFileSync ( logUri . fsPath , { encoding : 'utf-8' } ) ;
164+ hook ( text ) ;
165+ }
166+ }
167+ catch ( e ) {
168+ console . error ( e ) ;
169+ }
170+ } ) ;
171+ promise . then ( val => {
172+ console . log ( val ) ;
173+ } ) ;
174+ }
175+
176+ await box . run ( ) ;
177+
178+ if ( result === '<should-not-return>' ) {
179+ if ( nodefs . existsSync ( logUri . fsPath ) ) {
180+ result = nodefs . readFileSync ( logUri . fsPath , { encoding : 'utf-8' } ) ;
181+ }
182+ }
183+ }
184+
185+ if ( conf . extConf . emulator === conf . DosEmulatorType . jsdos ) {
186+ await api . jsdos . jszip . loadAsync ( bundle ) ;
187+ api . jsdos . jszip . file ( 'code/' + fileInfo . base , doc . getText ( ) ) ;
188+ const autoexec = [
189+ `mount c .` ,
190+ `mount d ./code` ,
191+ 'd:' ,
192+ ...action . before
193+ ] ;
194+ function cb ( val : string ) {
195+ const r = val
196+ . replace ( "${file}" , fileInfo . base )
197+ . replace ( "${filename}" , fileInfo . name ) ;
198+ if ( val . startsWith ( '>' ) ) {
199+ return r . replace ( ">" , "" ) ;
200+ }
201+ return r ;
202+ }
203+ if ( act === conf . actionType . run ) {
204+ autoexec . push ( ...action . run . map ( cb ) ) ;
205+ }
206+ if ( act === conf . actionType . debug ) {
207+ autoexec . push ( ...action . debug . map ( cb ) ) ;
208+ }
209+ api . jsdos . updateAutoexec ( autoexec ) ;
210+ const webview = await api . jsdos . runInWebview ( ) ;
211+ if ( act !== conf . actionType . open ) {
212+ const [ hook , promise ] = messageCollector ( ) ;
213+ webview . onDidReceiveMessage ( e => {
214+ switch ( e . command ) {
215+ case 'stdout' :
216+ hook ( e . value ) ;
217+ break ;
218+ }
219+ } ) ;
220+ result = await promise ;
221+ }
222+ }
223+
224+ if ( conf . extConf . emulator === conf . DosEmulatorType . msdos ) {
225+ const terminal = api . msdosPlayer ( ) ;
226+
227+ terminal . show ( ) ;
228+ api . dosbox . fromBundle ( bundle , assemblyToolsFolder ) ;
229+ action . before . forEach (
230+ val => {
231+ ( terminal as vscode . Terminal ) . sendText ( val . replace ( 'C:' , assemblyToolsFolder . fsPath ) ) ;
232+ }
233+ ) ;
234+ if ( act === conf . actionType . open ) {
235+ terminal . sendText ( `cd "${ vscode . Uri . joinPath ( _uri , '..' ) . fsPath } "` ) ;
236+ }
237+ else {
238+ terminal . sendText ( `cd "${ folder . fsPath } "` ) ;
239+ function cb ( val : string ) {
240+ const r = val
241+ . replace ( "${file}" , fileInfo . base )
242+ . replace ( "${filename}" , fileInfo . name ) ;
243+ if ( val . startsWith ( '>' ) ) {
244+ return r . replace ( ">" , "" ) ;
245+ } else {
246+ return r + `>> ${ logFilename } \n type ${ logFilename } ` ;
247+ }
248+ }
249+ if ( act === conf . actionType . run ) {
250+ action . run . map ( cb ) . forEach ( val => ( terminal as vscode . Terminal ) . sendText ( val ) ) ;
251+ }
252+ if ( act === conf . actionType . debug ) {
253+ action . debug . map ( cb ) . forEach ( val => ( terminal as vscode . Terminal ) . sendText ( val ) ) ;
254+ }
255+ const logUri = vscode . Uri . joinPath ( folder , logFilename ) ;
256+ const [ hook , promise ] = messageCollector ( ) ;
257+ nodefs . watchFile ( logUri . fsPath , ( ) => {
258+ try {
259+ if ( nodefs . existsSync ( logUri . fsPath ) ) {
260+ const text = nodefs . readFileSync ( logUri . fsPath , { encoding : 'utf-8' } ) ;
261+ hook ( text ) ;
262+ }
263+ }
264+ catch ( e ) {
265+ console . error ( e ) ;
266+ }
267+ } ) ;
268+ //terminal.sendText('exit', true);
269+ result = await promise ;
270+ }
271+
272+ }
273+
274+ const diagnose = diag . process ( result , doc , conf . extConf . asmType ) ;
275+ if ( diagnose ) {
276+ if ( diagnose ?. error > 0 ) {
277+ vscode . window . showErrorMessage ( logger . localize ( "ASM.error" ) ) ;
278+ logger . outputChannel . show ( ) ;
279+ }
280+ logger . channel (
281+ logger . localize ( 'diag.msg' , diagnose . error . toString ( ) , diagnose . warn . toString ( ) ) ,
282+ "\n\t" + result . replace ( / \r / g, "" ) . replace ( / [ \n ] * / g, "\n\t" )
283+ ) ;
284+ }
285+
286+ return {
287+ message : result ,
288+ error : diagnose ?. error ,
289+ warn : diagnose ?. warn
290+ } ;
291+ }
292+
293+ async function workspaceMode ( act : conf . actionType , _uri : vscode . Uri ) : Promise < AsmResult > {
294+ logger . channel ( actionMessage ( act , _uri . fsPath ) ) ;
295+
296+ const extConfig = vscode . workspace . getConfiguration ( 'masmtasm' ) ;
297+
298+ emptyFolder ( assemblyToolsFolder . fsPath ) ;
299+
300+ const actions : ACTIONS | undefined = extConfig . get ( 'ASM.actions' ) ;
301+ if ( actions === undefined ) {
302+ throw new Error ( "configurate `masmtasm.ASM.actions` first" ) ;
303+ }
304+ const action = actions [ conf . extConf . asmType ] ;
305+
306+ const doc = await vscode . workspace . openTextDocument ( _uri ) ;
307+ if ( doc . isDirty && extConfig . get ( 'ASM.savefirst' ) ) {
308+ await doc . save ( ) ;
309+ }
310+
311+ const bundlePath = vscode . Uri . joinPath (
312+ context . extensionUri ,
313+ action [ "baseBundle" ] . replace ( '<built-in>/' , "resources/" )
314+ ) ;
315+ const bundle = await fs . readFile ( bundlePath ) ;
316+
317+ const timeStamp = new Date ( ) . getTime ( ) . toString ( ) ;
318+ const logFilename = timeStamp . substr ( timeStamp . length - 5 , 8 ) + '.log' . toUpperCase ( ) ;
319+
320+ let result = "<should-not-return>" ;
321+ const workspaceFolder = vscode . workspace . workspaceFolders ?. find ( val => {
322+ const r = path . relative ( val . uri . fsPath , _uri . fsPath ) ;
323+ return ! r . startsWith ( ".." ) ;
324+ } ) ;
325+ if ( workspaceFolder === undefined ) {
326+ throw new Error ( "can't get current workspace of file:" + _uri . fsPath ) ;
327+ }
328+ const rel = path . relative ( workspaceFolder . uri . fsPath , _uri . fsPath ) ;
329+ const fileInfo = path . parse ( rel ) ;
330+ const folder = vscode . Uri . joinPath ( _uri , ".." ) ;
331+
332+ if ( conf . extConf . emulator === conf . DosEmulatorType . dosbox || conf . extConf . emulator === conf . DosEmulatorType . dosboxX ) {
333+ const autoexec = [
334+ `mount c "${ assemblyToolsFolder . fsPath } ""` ,
335+ `mount d "${ workspaceFolder . uri . fsPath } ""` ,
336+ 'd:' ,
337+ ...action . before
338+ ] ;
339+ const logUri = vscode . Uri . joinPath ( assemblyToolsFolder , logFilename ) ;
340+ if ( nodefs . existsSync ( logUri . fsPath ) ) {
341+ await fs . delete ( logUri ) ;
342+ }
343+ function cb ( val : string ) {
344+ const r = val
345+ . replace ( "${file}" , path . resolve ( fileInfo . dir , fileInfo . base ) )
346+ . replace ( "${filename}" , path . resolve ( fileInfo . dir , fileInfo . name ) ) ;
347+ if ( val . startsWith ( '>' ) ) {
348+ return r . replace ( ">" , "" ) ;
349+ }
350+ return r + " >>C:\\" + logFilename ;
351+ }
352+ if ( act === conf . actionType . run ) {
353+ autoexec . push ( ...action . run . map ( cb ) ) ;
354+ }
355+ if ( act === conf . actionType . debug ) {
356+ autoexec . push ( ...action . debug . map ( cb ) ) ;
357+ }
358+
112359 const box = conf . extConf . emulator === conf . DosEmulatorType . dosboxX ? api . dosboxX : api . dosbox ;
113360 await box . fromBundle ( bundle , assemblyToolsFolder ) ;
114361
115362 if ( act !== conf . actionType . open ) {
116- switch ( vscode . workspace . getConfiguration ( 'masm-tasm' ) . get ( 'dosbox.run' ) ) {
363+ switch ( extConfig . get ( 'dosbox.run' ) ) {
117364 case "keep" :
118365 break ;
119366 case "exit" :
@@ -282,10 +529,20 @@ export async function activate(context: vscode.ExtensionContext) {
282529 } ;
283530 }
284531
285- const workingMode = singleFileMode ;
532+ const mode = vscode . workspace . getConfiguration ( 'masmtasm' ) . get ( 'ASM.mode' ) ;
533+ let workingMode = singleFileMode ;
534+ switch ( mode ) {
535+ case "workspace" :
536+ workingMode = workspaceMode ;
537+ break ;
538+ case "single file" :
539+ workingMode = singleFileMode ;
540+ const msg = logger . localize ( "ASM.singleFileMode" , seperateSpaceFolder . fsPath ) ;
541+ logger . channel ( msg ) ;
542+ break ;
543+ }
544+
286545
287- const msg = logger . localize ( "ASM.singleFileMode" , seperateSpaceFolder . fsPath ) ;
288- logger . channel ( msg ) ;
289546
290547 context . subscriptions . push (
291548 vscode . commands . registerCommand ( 'masm-tasm.openEmulator' , ( uri : vscode . Uri ) => workingMode ( conf . actionType . open , uri ) ) ,
0 commit comments