1- import React from "react" ;
1+ import React , { useEffect , useState } from "react" ;
22
3- import { Button , Space , Tooltip } from "antd" ;
3+ import { Button , Dropdown , MenuProps , Space , Tooltip } from "antd" ;
44
5- import { faBoltLightning , faPlay , faScrewdriverWrench , faStepForward , faUndo } from "@fortawesome/free-solid-svg-icons" ;
5+ import { faAngleDown , faBoltLightning , faClockRotateLeft , faPlay , faScrewdriverWrench , faStepForward , faUndo } from "@fortawesome/free-solid-svg-icons" ;
66import { FontAwesomeIcon } from "@fortawesome/react-fontawesome" ;
77
88import * as VM from "../vm_core/vm_interface" ;
@@ -30,11 +30,23 @@ function RequiresRecompile(){
3030 ) ;
3131}
3232
33+ function convertC0Bpts ( C0Editors : C0EditorTab [ ] ) : Set < string > {
34+ const c0BreakPoint = new Set < string > ( ) ;
35+ for ( let i = 0 ; i < C0Editors . length ; i ++ ) {
36+ for ( const currentEditor of C0Editors )
37+ for ( const bpts of currentEditor . breakpoints ) {
38+ c0BreakPoint . add ( `${ currentEditor . title } @${ bpts . line } ` ) ;
39+ }
40+ }
41+ return c0BreakPoint ;
42+ }
43+
3344function MainControlBarFC ( props : MainControlProps & ContextValue ) {
3445 const appState = props . application_state ;
3546 const is_bc0_valid = props . application_state . BC0SourceCode . toUpperCase ( ) . startsWith ( "C0 C0 FF EE" ) ;
3647
3748 const [ abortSignal , abort , reset ] = AbortRef ( ) ;
49+ const [ execMode , setExecMode ] = useState < "Run" | "AutoStep" > ( "Run" ) ;
3850
3951 const print_update = ( str : string ) => props . set_app_state ( ( s ) => { return { PrintoutValue : s . PrintoutValue + str } } )
4052 const clear_print = ( ) => props . set_app_state ( { PrintoutValue : "" } )
@@ -62,6 +74,42 @@ function MainControlBarFC(props: MainControlProps & ContextValue) {
6274 else props . set_app_state ( { C0Runtime : new_runtime } ) ;
6375 }
6476
77+ const autoStep_c0runtime = async ( ) => {
78+ if ( appState . contentChanged ) {
79+ RequiresRecompile ( ) ;
80+ return ;
81+ }
82+ let init_state : undefined | C0VM_RT = undefined ;
83+ //let new_runtime, can_continue = undefined;
84+
85+ if ( appState . C0Runtime === undefined ) {
86+ init_state = await VM . initialize ( appState . BC0SourceCode , clear_print , appState . C0Editors , print_update , MEM_POOL_SIZE ) ;
87+ if ( init_state === undefined ) return ;
88+ } else {
89+ init_state = appState . C0Runtime ;
90+ }
91+
92+ const c0BreakPoint = convertC0Bpts ( appState . C0Editors ) ;
93+ const bc0BreakPointArr = Array . from ( appState . BC0BreakPoints ) . map ( bp => bp . line ) ;
94+ const bc0BreakPoints = new Set ( bc0BreakPointArr ) ;
95+
96+ if ( init_state === undefined ) return ;
97+
98+ const autoStepFn = VM . autoStep (
99+ init_state as C0VM_RT ,
100+ bc0BreakPoints ,
101+ c0BreakPoint ,
102+ abortSignal ,
103+ props . application_state . c0_only ,
104+ reset ,
105+ print_update ,
106+ s => props . set_app_state ( { C0Runtime : s } ) ,
107+ ( ) => props . set_app_state ( { C0Running : false } )
108+ )
109+
110+ props . set_app_state ( { C0Running : true } , ( ) => autoStepFn ) ;
111+ }
112+
65113 const run_c0runtime = async ( ) => {
66114 if ( appState . contentChanged ) {
67115 RequiresRecompile ( ) ;
@@ -136,10 +184,33 @@ function MainControlBarFC(props: MainControlProps & ContextValue) {
136184 print_update ,
137185 ) ;
138186 } ;
139-
187+
140188 const compilebtn_disabled = appState . C0Running || appState . C0Editors [ 0 ] . content === "" ;
141189 const stepbtn_disabled = ( ! is_bc0_valid ) || appState . C0Running || appState . contentChanged ;
142190 const runbtn_disabled = ( ! is_bc0_valid ) || appState . C0Running || appState . contentChanged ;
191+ const autostepbtn_disabled = ( ! is_bc0_valid ) || appState . C0Running || appState . contentChanged ;
192+ const execbtn_disabled = execMode === "Run" ? runbtn_disabled : autostepbtn_disabled ;
193+
194+ function onKeyPressWrapper ( e : KeyboardEvent ) : void {
195+ const is_action_key = e . key === "a" || e . key === 'r' || e . key === "s" ;
196+ if ( autostepbtn_disabled && is_action_key && e . ctrlKey ) {
197+ if ( ! is_bc0_valid ) globalThis . MSG_EMITTER . warn ( "Action Unavailable" , "Invalid BC0 code." ) ;
198+ else if ( appState . C0Running ) globalThis . MSG_EMITTER . warn ( "Action Unavailable" , "The program is currently running." ) ;
199+ else if ( appState . contentChanged ) RequiresRecompile ( ) ;
200+ }
201+ else if ( e . ctrlKey ) onKeyPress ( e . key ) ;
202+ }
203+
204+ function onKeyPress ( key : string ) : void {
205+ if ( key === 'a' ) autoStep_c0runtime ( ) ;
206+ else if ( key === 'r' ) run_c0runtime ( ) ;
207+ else if ( key === 's' ) step_c0runtime ( ) ;
208+ }
209+
210+ useEffect ( ( ) => {
211+ document . addEventListener ( 'keydown' , onKeyPressWrapper )
212+ return ( ) => document . removeEventListener ( 'keydown' , onKeyPressWrapper ) ;
213+ } )
143214
144215 const CompileButton =
145216 < Button
@@ -162,16 +233,15 @@ function MainControlBarFC(props: MainControlProps & ContextValue) {
162233 Step
163234 </ Button > ;
164235
236+ const AutoStepButton =
237+ < div style = { { fontSize : "1rem" , color : "white" } } >
238+ < FontAwesomeIcon icon = { faClockRotateLeft } /> AutoStep
239+ </ div > ;
240+
165241 const RunButton =
166- < Button
167- icon = { < FontAwesomeIcon icon = { faPlay } /> }
168- size = "large"
169- type = "primary"
170- disabled = { runbtn_disabled }
171- onClick = { run_c0runtime }
172- >
173- Run
174- </ Button > ;
242+ < div style = { { fontSize : "1rem" , color : "white" } } >
243+ < FontAwesomeIcon icon = { faPlay } /> Run
244+ </ div > ;
175245
176246 const AbortButton =
177247 < Button
@@ -193,17 +263,66 @@ function MainControlBarFC(props: MainControlProps & ContextValue) {
193263 Restart
194264 </ Button > ;
195265
266+ const ExecBtnIcon = execMode === "Run" ?
267+ < FontAwesomeIcon icon = { faPlay } /> :
268+ < FontAwesomeIcon icon = { faClockRotateLeft } /> ;
269+
270+ const ExecBtnFn = execMode === "Run" ? run_c0runtime : autoStep_c0runtime ;
271+
272+ const menuItems_ExecBtn : MenuProps [ "items" ] = [
273+ {
274+ label : execMode === "Run" ? AutoStepButton : RunButton ,
275+ key : execMode === "Run" ? "AutoStep" : "Run"
276+ }
277+ ] ;
278+
279+ const menuItems_ChangeModeFn : MenuProps [ "onClick" ] = ( info ) => {
280+ if ( info . key === "Run" || info . key === "AutoStep" ) {
281+ setExecMode ( info . key ) ;
282+ }
283+ } ;
284+
285+ const MenuProp : MenuProps = {
286+ style : { backgroundColor : props . themeColor } ,
287+ items : menuItems_ExecBtn ,
288+ onClick : menuItems_ChangeModeFn
289+ } ;
290+
291+ const ExecBtn =
292+ < Dropdown . Button
293+ disabled = { execbtn_disabled }
294+ type = "primary"
295+ size = "large"
296+ icon = { < FontAwesomeIcon icon = { faAngleDown } /> }
297+ onClick = { ExecBtnFn }
298+ menu = { MenuProp }
299+ >
300+ { ExecBtnIcon } { execMode }
301+ </ Dropdown . Button > ;
302+
196303 const display_CompileBtn = compilebtn_disabled ?
197304 < Tooltip placement = "bottomRight" color = { props . themeColor } title = "Write code in editor to Compile" > { CompileButton } </ Tooltip >
198305 : CompileButton ;
199306
200307 const display_StepBtn = stepbtn_disabled ?
201- < Tooltip placement = "bottomRight" color = { props . themeColor } title = "Compile the code before Step" > { StepButton } </ Tooltip >
308+ < Tooltip
309+ placement = "bottomRight"
310+ color = { props . themeColor }
311+ title = "Compile the code / Abort the program before Step"
312+ >
313+ { StepButton }
314+ </ Tooltip >
202315 : StepButton ;
203-
204- const display_RunBtn = runbtn_disabled ?
205- < Tooltip placement = "bottomRight" color = { props . themeColor } title = "Compile the code before Run" > { RunButton } </ Tooltip >
206- : RunButton ;
316+
317+ const display_ExecBtn = execbtn_disabled ?
318+ < Tooltip
319+ placement = "bottomRight"
320+ color = { props . themeColor }
321+ title = { "Compile the code / Abort the program before " + execMode }
322+ >
323+ { ExecBtn }
324+ </ Tooltip >
325+ : ExecBtn ;
207326
208327 return (
209328 < div className = "main-control" >
@@ -213,7 +332,7 @@ function MainControlBarFC(props: MainControlProps & ContextValue) {
213332 < Space size = "middle" >
214333 { display_CompileBtn }
215334 { display_StepBtn }
216- { display_RunBtn }
335+ { display_ExecBtn }
217336 { appState . C0Running ? AbortButton : RestartButton }
218337 </ Space >
219338 </ div >
0 commit comments