@@ -13,6 +13,7 @@ const closeButton = document.querySelector(".close-button");
1313// --- MONACO: Global variable to hold the editor instance ---
1414let editor ;
1515let validationTimeout ;
16+ let validationController ;
1617
1718// --- MONACO: Function to define and register our custom language ---
1819function registerKidCodeLanguage ( ) {
@@ -48,14 +49,14 @@ function registerKidCodeLanguage() {
4849 } ,
4950 } ,
5051 ] ,
51- [ / \d + / , "number" ] ,
52+ [ / - ? \d + (?: \. \d + ) ? / , "number" ] , // supports decimals & negatives
5253 [ / # .* $ / , "comment" ] ,
5354 [ / " ( [ ^ " \\ ] | \\ .) * $ / , "string.invalid" ] ,
5455 [ / " / , { token : "string.quote" , bracket : "@open" , next : "@string" } ] ,
5556 ] ,
5657 string : [
5758 [ / [ ^ \\ " ] + / , "string" ] ,
58- [ / \\ ./ , "string.escape.invalid " ] ,
59+ [ / \\ ./ , "string.escape" ] , // valid generic escapes
5960 [ / " / , { token : "string.quote" , bracket : "@close" , next : "@pop" } ] ,
6061 ] ,
6162 } ,
@@ -160,17 +161,24 @@ function initializeExamples() {
160161// --- 2. ADD EVENT LISTENER TO THE RUN BUTTON ---
161162runButton . addEventListener ( "click" , async ( ) => {
162163 const code = editor . getValue ( ) ;
164+
165+ // 🧹 Ensure a clean slate even if backend omits ClearEvent
166+ drawnLines = [ ] ;
167+ codyState = { x : 250 , y : 250 , direction : 0 , color : "blue" } ;
163168 clearCanvas ( ) ;
164169 outputArea . textContent = "" ;
170+
165171 try {
166172 const response = await fetch ( "/api/execute" , {
167173 method : "POST" ,
168174 headers : { "Content-Type" : "application/json" } ,
169- body : JSON . stringify ( { code : code } ) ,
175+ body : JSON . stringify ( { code } ) ,
170176 } ) ;
177+
171178 if ( ! response . ok ) {
172179 throw new Error ( `HTTP error! status: ${ response . status } ` ) ;
173180 }
181+
174182 const events = await response . json ( ) ;
175183 renderEvents ( events ) ;
176184 } catch ( error ) {
@@ -181,24 +189,47 @@ runButton.addEventListener("click", async () => {
181189// --- NEW: Function to handle validation ---
182190async function validateCode ( ) {
183191 const code = editor . getValue ( ) ;
192+
193+ // Cancel any in-flight validation to prevent stale results
194+ if ( validationController ) {
195+ validationController . abort ( ) ;
196+ }
197+ const controller = new AbortController ( ) ;
198+ validationController = controller ;
199+
184200 try {
185201 const response = await fetch ( "/api/validate" , {
186202 method : "POST" ,
187203 headers : { "Content-Type" : "application/json" } ,
188- body : JSON . stringify ( { code : code } ) ,
204+ body : JSON . stringify ( { code } ) ,
205+ signal : controller . signal ,
189206 } ) ;
207+
208+ if ( ! response . ok ) {
209+ throw new Error ( `HTTP error ${ response . status } ` ) ;
210+ }
211+
190212 const errors = await response . json ( ) ;
191- const markers = errors . map ( ( err ) => ( {
192- message : err . message ,
193- severity : monaco . MarkerSeverity . Error ,
194- startLineNumber : err . lineNumber ,
195- endLineNumber : err . lineNumber ,
196- startColumn : 1 ,
197- endColumn : 100 ,
198- } ) ) ;
199- monaco . editor . setModelMarkers ( editor . getModel ( ) , "kidcode" , markers ) ;
213+ const model = editor . getModel ( ) ;
214+ const markers = ( Array . isArray ( errors ) ? errors : [ ] ) . map ( ( err ) => {
215+ const line = Number ( err . lineNumber ) > 0 ? Number ( err . lineNumber ) : 1 ;
216+ const endCol = model ? model . getLineMaxColumn ( line ) : 100 ;
217+ return {
218+ message : String ( err . message || "Syntax error" ) ,
219+ severity : monaco . MarkerSeverity . Error ,
220+ startLineNumber : line ,
221+ endLineNumber : line ,
222+ startColumn : 1 ,
223+ endColumn : endCol ,
224+ } ;
225+ } ) ;
226+
227+ monaco . editor . setModelMarkers ( model , "kidcode" , markers ) ;
200228 } catch ( error ) {
229+ if ( error . name === "AbortError" ) return ; // ignore outdated requests
201230 console . error ( "Validation request failed:" , error ) ;
231+ } finally {
232+ if ( validationController === controller ) validationController = null ;
202233 }
203234}
204235
@@ -262,14 +293,14 @@ function renderEvents(events) {
262293 fromY : event . fromY ,
263294 toX : event . toX ,
264295 toY : event . toY ,
265- color : event . color ,
296+ color : event . color ?? codyState . color ,
266297 } ) ;
267298 }
268299 codyState = {
269300 x : event . toX ,
270301 y : event . toY ,
271302 direction : event . newDirection ,
272- color : event . color ,
303+ color : event . color ?? codyState . color ,
273304 } ;
274305 break ;
275306 case "SayEvent" :
0 commit comments