lexgui 0.1.42 → 0.1.43

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -88,7 +88,7 @@ class CodeSelection {
88
88
  {
89
89
  swapElements( this, 'fromX', 'toX' );
90
90
  swapElements( this, 'fromY', 'toY' );
91
- }
91
+ }
92
92
  else if( this.sameLine() && this.fromX > this.toX )
93
93
  {
94
94
  swapElements( this, 'fromX', 'toX' );
@@ -96,7 +96,7 @@ class CodeSelection {
96
96
  }
97
97
 
98
98
  selectInline( cursor, x, y, width, isSearchResult ) {
99
-
99
+
100
100
  this.chars = width / this.editor.charWidth;
101
101
  this.fromX = x;
102
102
  this.toX = x + this.chars;
@@ -104,7 +104,7 @@ class CodeSelection {
104
104
 
105
105
  var domEl = document.createElement( 'div' );
106
106
  domEl.className = this.className;
107
-
107
+
108
108
  domEl._top = y * this.editor.lineHeight;
109
109
  domEl.style.top = domEl._top + "px";
110
110
  domEl._left = x * this.editor.charWidth;
@@ -164,9 +164,9 @@ class ScrollBar {
164
164
  this.root = document.createElement( 'div' );
165
165
  this.root.className = "lexcodescrollbar";
166
166
 
167
- if( type & ScrollBar.SCROLLBAR_VERTICAL )
167
+ if( type & ScrollBar.SCROLLBAR_VERTICAL )
168
168
  this.root.classList.add( 'vertical' );
169
- else if( type & ScrollBar.SCROLLBAR_HORIZONTAL )
169
+ else if( type & ScrollBar.SCROLLBAR_HORIZONTAL )
170
170
  this.root.classList.add( 'horizontal' );
171
171
 
172
172
  this.thumb = document.createElement( 'div' );
@@ -176,11 +176,11 @@ class ScrollBar {
176
176
  this.root.appendChild( this.thumb );
177
177
 
178
178
  this.thumb.addEventListener( "mousedown", inner_mousedown );
179
-
179
+
180
180
  this.lastPosition = new LX.vec2( 0, 0 );
181
181
 
182
182
  let that = this;
183
-
183
+
184
184
  function inner_mousedown( e )
185
185
  {
186
186
  var doc = editor.root.ownerDocument;
@@ -194,7 +194,7 @@ class ScrollBar {
194
194
  function inner_mousemove( e )
195
195
  {
196
196
  var dt = that.lastPosition.sub( new LX.vec2( e.x, e.y ) );
197
- if( that.type & ScrollBar.SCROLLBAR_VERTICAL )
197
+ if( that.type & ScrollBar.SCROLLBAR_VERTICAL )
198
198
  editor.updateVerticalScrollFromScrollBar( dt.y )
199
199
  else
200
200
  editor.updateHorizontalScrollFromScrollBar( dt.x )
@@ -250,7 +250,7 @@ class CodeEditor {
250
250
  window.editor = this;
251
251
 
252
252
  CodeEditor.__instances.push( this );
253
-
253
+
254
254
  // File explorer
255
255
  if( options.fileExplorer ?? false )
256
256
  {
@@ -269,35 +269,35 @@ class CodeEditor {
269
269
  'skipVisibility': true,
270
270
  'children': []
271
271
  };
272
-
273
- this.explorer = panel.addTree( null, sceneData, {
272
+
273
+ this.explorer = panel.addTree( null, sceneData, {
274
274
  filter: false,
275
275
  rename: false,
276
276
  skip_default_icon: true,
277
- onevent: (event) => {
277
+ onevent: (event) => {
278
278
  switch(event.type) {
279
279
  // case LX.TreeEvent.NODE_SELECTED:
280
280
  // if( !this.tabs.tabDOMs[ event.node.id ] ) break;
281
281
  case LX.TreeEvent.NODE_DBLCLICKED:
282
282
  this.loadTab( event.node.id );
283
283
  break;
284
- case LX.TreeEvent.NODE_DELETED:
284
+ case LX.TreeEvent.NODE_DELETED:
285
285
  this.tabs.delete( event.node.id );
286
286
  delete this.loadedTabs[ event.node.id ];
287
287
  break;
288
- // case LX.TreeEvent.NODE_CONTEXTMENU:
288
+ // case LX.TreeEvent.NODE_CONTEXTMENU:
289
289
  // LX.addContextMenu( event.multiple ? "Selected Nodes" : event.node.id, event.value, m => {
290
- //
290
+ //
291
291
  // });
292
292
  // break;
293
- // case LX.TreeEvent.NODE_DRAGGED:
294
- // console.log(event.node.id + " is now child of " + event.value.id);
293
+ // case LX.TreeEvent.NODE_DRAGGED:
294
+ // console.log(event.node.id + " is now child of " + event.value.id);
295
295
  // break;
296
296
  }
297
297
  }
298
- });
298
+ });
299
299
 
300
- this.addExplorerItem = function( item )
300
+ this.addExplorerItem = function( item )
301
301
  {
302
302
  if( !this.explorer.data.children.find( (value, index) => value.id === item.id ) )
303
303
  this.explorer.data.children.push( item );
@@ -347,7 +347,7 @@ class CodeEditor {
347
347
  this.root.addEventListener( 'focus', this.processFocus.bind( this, true ) );
348
348
  this.root.addEventListener( 'focusout', this.processFocus.bind( this, false ) );
349
349
  }
350
-
350
+
351
351
  this.root.addEventListener( 'mousedown', this.processMouse.bind(this) );
352
352
  this.root.addEventListener( 'mouseup', this.processMouse.bind(this) );
353
353
  this.root.addEventListener( 'mousemove', this.processMouse.bind(this) );
@@ -403,8 +403,8 @@ class CodeEditor {
403
403
  if( this.visibleLinesViewport.y < (this.code.lines.length - 1) )
404
404
  {
405
405
  const totalLinesInViewport = ((this.codeScroller.offsetHeight - 36) / this.lineHeight)|0;
406
- const scrollDownBoundary =
407
- ( Math.max( this.visibleLinesViewport.y - totalLinesInViewport, 0 ) - 1 ) * this.lineHeight;
406
+ const scrollDownBoundary =
407
+ ( Math.max( this.visibleLinesViewport.y - totalLinesInViewport, 0 ) - 1 ) * this.lineHeight;
408
408
 
409
409
  if( scrollTop >= scrollDownBoundary )
410
410
  this.processLines( CodeEditor.UPDATE_VISIBLE_LINES );
@@ -468,7 +468,7 @@ class CodeEditor {
468
468
  {
469
469
  var box = document.createElement( 'div' );
470
470
  box.className = "searchbox";
471
-
471
+
472
472
  var searchPanel = new LX.Panel();
473
473
  box.appendChild( searchPanel.root );
474
474
 
@@ -491,7 +491,7 @@ class CodeEditor {
491
491
  {
492
492
  var box = document.createElement( 'div' );
493
493
  box.className = "searchbox gotoline";
494
-
494
+
495
495
  var searchPanel = new LX.Panel();
496
496
  box.appendChild( searchPanel.root );
497
497
 
@@ -513,7 +513,7 @@ class CodeEditor {
513
513
  {
514
514
  this.codeSizer = document.createElement( 'div' );
515
515
  this.codeSizer.className = "code-sizer";
516
-
516
+
517
517
  // Append all childs
518
518
  while( this.codeScroller.firstChild )
519
519
  this.codeSizer.appendChild( this.codeScroller.firstChild );
@@ -555,7 +555,7 @@ class CodeEditor {
555
555
  };
556
556
 
557
557
  this.stringKeys = { // adding @ because some words are always true in (e.g. constructor..)
558
- "@\"": "\"",
558
+ "@\"": "\"",
559
559
  "@'": "'"
560
560
  };
561
561
 
@@ -565,8 +565,10 @@ class CodeEditor {
565
565
  this.languages = {
566
566
  'Plain Text': { ext: 'txt', blockComments: false, singleLineComments: false },
567
567
  'JavaScript': { ext: 'js' },
568
- 'C++': { ext: 'cpp' },
568
+ 'C': { ext: [ 'c', 'h' ] },
569
+ 'C++': { ext: [ 'cpp', 'hpp' ] },
569
570
  'CSS': { ext: 'css' },
571
+ 'CMake': { ext: 'cmake', singleLineCommentToken: '#', blockComments: false, ignoreCase: true },
570
572
  'GLSL': { ext: 'glsl' },
571
573
  'WGSL': { ext: 'wgsl' },
572
574
  'JSON': { ext: 'json', blockComments: false, singleLineComments: false },
@@ -579,7 +581,7 @@ class CodeEditor {
579
581
  };
580
582
 
581
583
  this.specialKeys = [
582
- 'Backspace', 'Enter', 'ArrowUp', 'ArrowDown',
584
+ 'Backspace', 'Enter', 'ArrowUp', 'ArrowDown',
583
585
  'ArrowRight', 'ArrowLeft', 'Delete', 'Home',
584
586
  'End', 'Tab', 'Escape'
585
587
  ];
@@ -593,10 +595,10 @@ class CodeEditor {
593
595
  for( let lang in CodeEditor.keywords ) CodeEditor.keywords[lang] = CodeEditor.keywords[lang].reduce((a, v) => ({ ...a, [v]: true}), {});
594
596
  for( let lang in CodeEditor.utils ) CodeEditor.utils[lang] = CodeEditor.utils[lang].reduce((a, v) => ({ ...a, [v]: true}), {});
595
597
  for( let lang in CodeEditor.types ) CodeEditor.types[lang] = CodeEditor.types[lang].reduce((a, v) => ({ ...a, [v]: true}), {});
596
- for( let lang in CodeEditor.builtin ) CodeEditor.builtin[lang] = CodeEditor.builtin[lang].reduce((a, v) => ({ ...a, [v]: true}), {});
598
+ for( let lang in CodeEditor.builtIn ) CodeEditor.builtIn[lang] = CodeEditor.builtIn[lang].reduce((a, v) => ({ ...a, [v]: true}), {});
597
599
  for( let lang in CodeEditor.statementsAndDeclarations ) CodeEditor.statementsAndDeclarations[lang] = CodeEditor.statementsAndDeclarations[lang].reduce((a, v) => ({ ...a, [v]: true}), {});
598
600
  for( let lang in CodeEditor.symbols ) CodeEditor.symbols[lang] = CodeEditor.symbols[lang].reduce((a, v) => ({ ...a, [v]: true}), {});
599
-
601
+
600
602
  CodeEditor._staticReady = true;
601
603
  }
602
604
 
@@ -619,7 +621,7 @@ class CodeEditor {
619
621
  if( cursor.selection ) {
620
622
  this.deleteSelection( cursor );
621
623
  // Remove entire line when selecting with triple click
622
- if( this._tripleClickSelection )
624
+ if( this._tripleClickSelection )
623
625
  {
624
626
  this.actions['Backspace'].callback( ln, cursor, e );
625
627
  this.lineDown( cursor, true );
@@ -632,7 +634,7 @@ class CodeEditor {
632
634
 
633
635
  var deleteFromPosition = cursor.position - 1;
634
636
  var numCharsDeleted = 1;
635
-
637
+
636
638
  // Delete full word
637
639
  if( e.shiftKey )
638
640
  {
@@ -652,7 +654,7 @@ class CodeEditor {
652
654
 
653
655
  if( this.useAutoComplete )
654
656
  this.showAutoCompleteBox( 'foo', cursor );
655
- }
657
+ }
656
658
  else if( this.code.lines[ ln - 1 ] != undefined ) {
657
659
 
658
660
  this.lineUp( cursor );
@@ -669,7 +671,7 @@ class CodeEditor {
669
671
  this.action( 'Delete', false, ( ln, cursor, e ) => {
670
672
 
671
673
  this._addUndoStep( cursor );
672
-
674
+
673
675
  if( cursor.selection ) {
674
676
  // Use 'Backspace' as it's the same callback...
675
677
  this.actions['Backspace'].callback( ln, cursor, e );
@@ -680,7 +682,7 @@ class CodeEditor {
680
682
  if( letter ) {
681
683
  this.code.lines[ ln ] = sliceChars( this.code.lines[ ln ], cursor.position );
682
684
  this.processLine( ln );
683
- }
685
+ }
684
686
  else if( this.code.lines[ ln + 1 ] != undefined ) {
685
687
  this.code.lines[ ln ] += this.code.lines[ ln + 1 ];
686
688
  this.code.lines.splice( ln + 1, 1 );
@@ -690,7 +692,7 @@ class CodeEditor {
690
692
  });
691
693
 
692
694
  this.action( 'Tab', true, ( ln, cursor, e ) => {
693
-
695
+
694
696
  if( this._skipTabs )
695
697
  {
696
698
  this._skipTabs--;
@@ -718,7 +720,7 @@ class CodeEditor {
718
720
  }, "shiftKey");
719
721
 
720
722
  this.action( 'Home', false, ( ln, cursor, e ) => {
721
-
723
+
722
724
  let idx = firstNonspaceIndex( this.code.lines[ ln ] );
723
725
 
724
726
  // We already are in the first non space index...
@@ -738,7 +740,7 @@ class CodeEditor {
738
740
  if( e.shiftKey && !e.cancelShift )
739
741
  {
740
742
  // Get last selection range
741
- if( cursor.selection )
743
+ if( cursor.selection )
742
744
  lastX += cursor.selection.chars;
743
745
 
744
746
  if( !cursor.selection )
@@ -756,9 +758,9 @@ class CodeEditor {
756
758
  });
757
759
 
758
760
  this.action( 'End', false, ( ln, cursor, e ) => {
759
-
761
+
760
762
  if( ( e.shiftKey || e._shiftKey ) && !e.cancelShift ) {
761
-
763
+
762
764
  var string = this.code.lines[ ln ].substring( cursor.position );
763
765
  if( !cursor.selection )
764
766
  this.startSelection( cursor );
@@ -767,7 +769,7 @@ class CodeEditor {
767
769
  else
768
770
  {
769
771
  this.resetCursorPos( CodeEditor.CURSOR_LEFT, cursor );
770
- this.cursorToString( cursor, this.code.lines[ ln ] );
772
+ this.cursorToString( cursor, this.code.lines[ ln ] );
771
773
  this._processSelection( cursor, e );
772
774
  }
773
775
  } else if( !e.keepSelection )
@@ -839,7 +841,7 @@ class CodeEditor {
839
841
  if( !letter ) {
840
842
  this.cursorToPosition( cursor, this.code.lines[ cursor.line ].length );
841
843
  }
842
-
844
+
843
845
  this._processSelection( cursor, e, false );
844
846
 
845
847
  } else {
@@ -849,7 +851,7 @@ class CodeEditor {
849
851
  var letter = this.getCharAtPos( cursor );
850
852
  if( !letter ) this.actions['End'].callback( cursor.line, cursor, e );
851
853
  }
852
- }
854
+ }
853
855
  // Move up autocomplete selection
854
856
  else
855
857
  {
@@ -880,7 +882,7 @@ class CodeEditor {
880
882
  if( e.shiftKey ) {
881
883
  this._processSelection( cursor, e );
882
884
  }
883
- }
885
+ }
884
886
  // Move down autocomplete selection
885
887
  else
886
888
  {
@@ -916,7 +918,7 @@ class CodeEditor {
916
918
  // Selections...
917
919
  if( e.shiftKey ) {
918
920
  if( !cursor.selection )
919
- this.startSelection( cursor );
921
+ this.startSelection( cursor );
920
922
  }
921
923
  else
922
924
  this.endSelection();
@@ -950,9 +952,9 @@ class CodeEditor {
950
952
  }
951
953
  }
952
954
  else if( cursor.line > 0 ) {
953
-
955
+
954
956
  if( e.shiftKey && !cursor.selection ) this.startSelection( cursor );
955
-
957
+
956
958
  this.lineUp( cursor );
957
959
 
958
960
  e.cancelShift = e.keepSelection = true;
@@ -967,7 +969,7 @@ class CodeEditor {
967
969
  this.action( 'ArrowRight', false, ( ln, cursor, e ) => {
968
970
 
969
971
  // Nothing to do..
970
- if( cursor.line == this.code.lines.length - 1 &&
972
+ if( cursor.line == this.code.lines.length - 1 &&
971
973
  cursor.position == this.code.lines[ cursor.line ].length )
972
974
  return;
973
975
 
@@ -1031,14 +1033,14 @@ class CodeEditor {
1031
1033
  }
1032
1034
  }
1033
1035
  else if( this.code.lines[ cursor.line + 1 ] !== undefined ) {
1034
-
1036
+
1035
1037
  if( e.shiftKey ) {
1036
1038
  if( !cursor.selection ) this.startSelection( cursor );
1037
1039
  }
1038
1040
  else this.endSelection();
1039
1041
 
1040
1042
  this.lineDown( cursor, true );
1041
-
1043
+
1042
1044
  if( e.shiftKey ) this._processSelection( cursor, e, false );
1043
1045
 
1044
1046
  this.hideAutoCompleteBox();
@@ -1047,10 +1049,10 @@ class CodeEditor {
1047
1049
  });
1048
1050
 
1049
1051
  // Default code tab
1050
-
1052
+
1051
1053
  this.loadedTabs = { };
1052
1054
  this.openedTabs = { };
1053
-
1055
+
1054
1056
  if( options.allowAddScripts ?? true )
1055
1057
  {
1056
1058
  this.addTab("+", false, "New File");
@@ -1072,7 +1074,7 @@ class CodeEditor {
1072
1074
  display: "swap"
1073
1075
  }
1074
1076
  );
1075
-
1077
+
1076
1078
  // Add to the document.fonts (FontFaceSet)
1077
1079
  document.fonts.add( commitMono );
1078
1080
 
@@ -1093,7 +1095,7 @@ class CodeEditor {
1093
1095
 
1094
1096
  // This received key inputs from the entire document...
1095
1097
  onKeyPressed( e ) {
1096
-
1098
+
1097
1099
  // Toggle visibility of the file explorer
1098
1100
  if( e.key == 'b' && e.ctrlKey && this.explorer )
1099
1101
  {
@@ -1162,7 +1164,7 @@ class CodeEditor {
1162
1164
 
1163
1165
  // Add first line
1164
1166
  this.code.lines[ lidx ] = [
1165
- this.code.lines[ lidx ].slice( 0, cursor.position ),
1167
+ this.code.lines[ lidx ].slice( 0, cursor.position ),
1166
1168
  first_line
1167
1169
  ].join('');
1168
1170
 
@@ -1189,8 +1191,8 @@ class CodeEditor {
1189
1191
  else
1190
1192
  {
1191
1193
  this.code.lines[ lidx ] = [
1192
- this.code.lines[ lidx ].slice( 0, cursor.position ),
1193
- new_lines[ 0 ],
1194
+ this.code.lines[ lidx ].slice( 0, cursor.position ),
1195
+ new_lines[ 0 ],
1194
1196
  this.code.lines[ lidx ].slice( cursor.position )
1195
1197
  ].join('');
1196
1198
 
@@ -1249,7 +1251,7 @@ class CodeEditor {
1249
1251
  {
1250
1252
  const fr = new FileReader();
1251
1253
  fr.readAsText( file );
1252
- fr.onload = e => {
1254
+ fr.onload = e => {
1253
1255
  const text = e.currentTarget.result;
1254
1256
  inner_add_tab( text, file.name );
1255
1257
  };
@@ -1267,7 +1269,7 @@ class CodeEditor {
1267
1269
 
1268
1270
  return;
1269
1271
  }
1270
-
1272
+
1271
1273
  let cursor = document.createElement( 'div' );
1272
1274
  cursor.name = "cursor" + this.cursors.childElementCount;
1273
1275
  cursor.className = "cursor";
@@ -1284,7 +1286,7 @@ class CodeEditor {
1284
1286
 
1285
1287
  Object.defineProperty( cursor, 'line', {
1286
1288
  get: (v) => { return cursor._line },
1287
- set: (v) => {
1289
+ set: (v) => {
1288
1290
  cursor._line = v;
1289
1291
  if( cursor.isMain ) this._setActiveLine( v );
1290
1292
  }
@@ -1292,7 +1294,7 @@ class CodeEditor {
1292
1294
 
1293
1295
  Object.defineProperty( cursor, 'position', {
1294
1296
  get: (v) => { return cursor._position },
1295
- set: (v) => {
1297
+ set: (v) => {
1296
1298
  cursor._position = v;
1297
1299
  if( cursor.isMain ) this._updateDataInfoPanel( "@cursor-pos", "Col " + ( v + 1 ) );
1298
1300
  }
@@ -1351,7 +1353,7 @@ class CodeEditor {
1351
1353
  }
1352
1354
  }
1353
1355
 
1354
- if( deleteRedo )
1356
+ if( deleteRedo )
1355
1357
  {
1356
1358
  // Remove all redo steps
1357
1359
  this.code.redoSteps.length = 0;
@@ -1459,7 +1461,8 @@ class CodeEditor {
1459
1461
  {
1460
1462
  iconEl = document.createElement( 'i' );
1461
1463
  iconEl.className = icon;
1462
- } else {
1464
+ } else
1465
+ {
1463
1466
  iconEl = document.createElement( 'img' );
1464
1467
  iconEl.src = "https://raw.githubusercontent.com/jxarco/lexgui.js/master/" + icon;
1465
1468
  }
@@ -1477,21 +1480,38 @@ class CodeEditor {
1477
1480
  }
1478
1481
 
1479
1482
  _changeLanguageFromExtension( ext ) {
1480
-
1483
+
1481
1484
  if( !ext )
1482
- return this._changeLanguage( this.code.language );
1485
+ {
1486
+ return this._changeLanguage( this.code.language );
1487
+ }
1483
1488
 
1484
1489
  for( let l in this.languages )
1485
1490
  {
1486
- if( this.languages[l].ext == ext )
1487
- return this._changeLanguage( l );
1491
+ const langExtension = this.languages[ l ].ext;
1492
+
1493
+ if( langExtension.constructor == Array )
1494
+ {
1495
+ if( langExtension.indexOf( ext ) > -1 )
1496
+ {
1497
+ return this._changeLanguage( l );
1498
+ }
1499
+ }
1500
+ else
1501
+ {
1502
+ if( langExtension == ext )
1503
+ {
1504
+ return this._changeLanguage( l );
1505
+ }
1506
+ }
1507
+
1488
1508
  }
1489
1509
 
1490
1510
  this._changeLanguage( 'Plain Text' );
1491
1511
  }
1492
1512
 
1493
1513
  _createPanelInfo() {
1494
-
1514
+
1495
1515
  if( !this.skipCodeInfo )
1496
1516
  {
1497
1517
  let panel = new LX.Panel({ className: "lexcodetabinfo", width: "calc(100%)", height: "auto" });
@@ -1543,12 +1563,36 @@ class CodeEditor {
1543
1563
  _getFileIcon( name, extension ) {
1544
1564
 
1545
1565
  const isNewTabButton = name ? ( name === '+' ) : false;
1546
- const ext = extension ?? LX.getExtension( name );
1547
- return ext == 'html' ? "fa-solid fa-code orange" :
1548
- ext == 'css' ? "fa-solid fa-hashtag dodgerblue" :
1549
- ext == 'xml' ? "fa-solid fa-rss orange" :
1550
- ext == 'bat' ? "fa-brands fa-windows lightblue" :
1551
- [ 'js', 'py', 'json', 'cpp', 'rs', 'md' ].indexOf( ext ) > -1 ? "images/" + ext + ".png" :
1566
+
1567
+ if( !extension )
1568
+ {
1569
+ extension = LX.getExtension( name );
1570
+ }
1571
+ else
1572
+ {
1573
+ const possibleExtensions = [].concat( extension );
1574
+
1575
+ if( name )
1576
+ {
1577
+ const fileExtension = LX.getExtension( name );
1578
+ const idx = possibleExtensions.indexOf( fileExtension );
1579
+
1580
+ if( idx > -1)
1581
+ {
1582
+ extension = possibleExtensions[ idx ];
1583
+ }
1584
+ }
1585
+ else
1586
+ {
1587
+ extension = possibleExtensions[ 0 ];
1588
+ }
1589
+ }
1590
+
1591
+ return extension == "html" ? "fa-solid fa-code orange" :
1592
+ extension == "css" ? "fa-solid fa-hashtag dodgerblue" :
1593
+ extension == "xml" ? "fa-solid fa-rss orange" :
1594
+ extension == "bat" ? "fa-brands fa-windows lightblue" :
1595
+ [ 'js', 'py', 'json', 'cpp', 'hpp', 'rs', 'md' ].indexOf( extension ) > -1 ? "images/" + extension + ".png" :
1552
1596
  !isNewTabButton ? "fa-solid fa-align-left gray" : undefined;
1553
1597
  }
1554
1598
 
@@ -1573,10 +1617,10 @@ class CodeEditor {
1573
1617
  this._removeSecondaryCursors();
1574
1618
  var cursor = this._getCurrentCursor( true );
1575
1619
 
1576
- this.saveCursor( cursor, this.code.cursorState );
1620
+ this.saveCursor( cursor, this.code.cursorState );
1577
1621
 
1578
1622
  this.code = this.loadedTabs[ name ];
1579
- this.restoreCursor( cursor, this.code.cursorState );
1623
+ this.restoreCursor( cursor, this.code.cursorState );
1580
1624
 
1581
1625
  this.endSelection();
1582
1626
  this._updateDataInfoPanel( "@tab-name", name );
@@ -1592,7 +1636,7 @@ class CodeEditor {
1592
1636
  }
1593
1637
 
1594
1638
  _onContextMenuTab( isNewTabButton, event, name, ) {
1595
-
1639
+
1596
1640
  if( isNewTabButton )
1597
1641
  return;
1598
1642
 
@@ -1604,7 +1648,7 @@ class CodeEditor {
1604
1648
  }
1605
1649
 
1606
1650
  addTab( name, selected, title, options = {} ) {
1607
-
1651
+
1608
1652
  // If already loaded, set new name...
1609
1653
  const repeats = Object.keys( editor.loadedTabs ).slice( 1 ).reduce( ( v, key ) => {
1610
1654
  const noRepeatName = key.replace( /[_\d+]/g, '');
@@ -1647,7 +1691,7 @@ class CodeEditor {
1647
1691
 
1648
1692
  this.loadedTabs[ name ] = code;
1649
1693
  this.openedTabs[ name ] = code;
1650
-
1694
+
1651
1695
  const tabIcon = this._getFileIcon( name );
1652
1696
 
1653
1697
  if( this.explorer && !isNewTabButton )
@@ -1656,23 +1700,23 @@ class CodeEditor {
1656
1700
  this.explorer.frefresh( name );
1657
1701
  }
1658
1702
 
1659
- this.tabs.add( name, code, {
1660
- selected: selected,
1661
- fixed: isNewTabButton,
1662
- title: code.title,
1663
- icon: tabIcon,
1703
+ this.tabs.add( name, code, {
1704
+ selected: selected,
1705
+ fixed: isNewTabButton,
1706
+ title: code.title,
1707
+ icon: tabIcon,
1664
1708
  onSelect: this._onSelectTab.bind( this, isNewTabButton ),
1665
1709
  onContextMenu: this._onContextMenuTab.bind( this, isNewTabButton )
1666
1710
  } );
1667
1711
 
1668
1712
  // Move into the sizer..
1669
1713
  this.codeSizer.appendChild( code );
1670
-
1714
+
1671
1715
  this.endSelection();
1672
1716
 
1673
1717
  if( selected )
1674
1718
  {
1675
- this.code = code;
1719
+ this.code = code;
1676
1720
  this.resetCursorPos( CodeEditor.CURSOR_LEFT | CodeEditor.CURSOR_TOP );
1677
1721
  this.processLines();
1678
1722
  }
@@ -1726,26 +1770,26 @@ class CodeEditor {
1726
1770
  }
1727
1771
 
1728
1772
  this.openedTabs[ name ] = code;
1729
-
1773
+
1730
1774
  const isNewTabButton = ( name === '+' );
1731
1775
  const tabIcon = this._getFileIcon( name );
1732
1776
 
1733
- this.tabs.add(name, code, {
1734
- selected: true,
1735
- fixed: isNewTabButton,
1736
- title: code.title,
1737
- icon: tabIcon,
1777
+ this.tabs.add(name, code, {
1778
+ selected: true,
1779
+ fixed: isNewTabButton,
1780
+ title: code.title,
1781
+ icon: tabIcon,
1738
1782
  onSelect: this._onSelectTab.bind( this, isNewTabButton ),
1739
1783
  onContextMenu: this._onContextMenuTab.bind( this, isNewTabButton )
1740
1784
  });
1741
1785
 
1742
1786
  // Move into the sizer..
1743
1787
  this.codeSizer.appendChild( code );
1744
-
1788
+
1745
1789
  this.endSelection();
1746
1790
 
1747
1791
  // Select as current...
1748
- this.code = code;
1792
+ this.code = code;
1749
1793
  this.resetCursorPos( CodeEditor.CURSOR_LEFT | CodeEditor.CURSOR_TOP );
1750
1794
  this.processLines();
1751
1795
  this._changeLanguageFromExtension( LX.getExtension( name ) );
@@ -1799,7 +1843,7 @@ class CodeEditor {
1799
1843
 
1800
1844
  if( cursor.selection )
1801
1845
  {
1802
- this.canOpenContextMenu |= (cursor.line >= cursor.selection.fromY && cursor.line <= cursor.selection.toY
1846
+ this.canOpenContextMenu |= (cursor.line >= cursor.selection.fromY && cursor.line <= cursor.selection.toY
1803
1847
  && cursor.position >= cursor.selection.fromX && cursor.position <= cursor.selection.toX);
1804
1848
  if( this.canOpenContextMenu )
1805
1849
  return;
@@ -1811,7 +1855,7 @@ class CodeEditor {
1811
1855
  this.endSelection();
1812
1856
  this.processClick( e );
1813
1857
  }
1814
-
1858
+
1815
1859
  else if( e.type == 'mouseup' )
1816
1860
  {
1817
1861
  this._onMouseUp( e );
@@ -1859,11 +1903,11 @@ class CodeEditor {
1859
1903
  m.add( "Cut", () => { this._cutContent( cursor ); } );
1860
1904
  m.add( "Paste", () => { this._pasteContent( cursor ); } );
1861
1905
  m.add( "" );
1862
- m.add( "Format/JSON", () => {
1906
+ m.add( "Format/JSON", () => {
1863
1907
  let json = this.toJSONFormat( this.getText() );
1864
1908
  if( !json )
1865
1909
  return;
1866
- this.code.lines = json.split( "\n" );
1910
+ this.code.lines = json.split( "\n" );
1867
1911
  this.processLines();
1868
1912
  } );
1869
1913
  }
@@ -1911,7 +1955,7 @@ class CodeEditor {
1911
1955
  this.cursorToLine( cursor, ln, true );
1912
1956
  this.cursorToPosition( cursor, string.length );
1913
1957
  }
1914
-
1958
+
1915
1959
  // Add new cursor
1916
1960
  else
1917
1961
  {
@@ -1957,7 +2001,7 @@ class CodeEditor {
1957
2001
  let ccw = true;
1958
2002
 
1959
2003
  // Check if we must change ccw or not ... (not with mouse)
1960
- if( !isMouseEvent && cursor.line >= cursor.selection.fromY &&
2004
+ if( !isMouseEvent && cursor.line >= cursor.selection.fromY &&
1961
2005
  (cursor.line == cursor.selection.fromY ? cursor.position >= cursor.selection.fromX : true) )
1962
2006
  {
1963
2007
  ccw = ( e && this._lastSelectionKeyDir && ( e.key == 'ArrowRight' || e.key == 'ArrowDown' || e.key == 'End' ) );
@@ -2020,7 +2064,7 @@ class CodeEditor {
2020
2064
 
2021
2065
  // Compute new width and selection margins
2022
2066
  let string;
2023
-
2067
+
2024
2068
  if(sId == 0) // First line 2 cases (single line, multiline)
2025
2069
  {
2026
2070
  const reverse = fromX > toX;
@@ -2034,7 +2078,7 @@ class CodeEditor {
2034
2078
  string = (i == toY) ? this.code.lines[ i ].substring( 0, toX ) : this.code.lines[ i ]; // Last line, any multiple line...
2035
2079
  if( isVisible ) domEl.style.left = this.xPadding;
2036
2080
  }
2037
-
2081
+
2038
2082
  const stringWidth = this.measureString( string );
2039
2083
  cursor.selection.chars += stringWidth / this.charWidth;
2040
2084
 
@@ -2071,7 +2115,7 @@ class CodeEditor {
2071
2115
 
2072
2116
  // Compute new width and selection margins
2073
2117
  let string;
2074
-
2118
+
2075
2119
  if( sId == 0 )
2076
2120
  {
2077
2121
  string = this.code.lines[ i ].substr(toX);
@@ -2083,10 +2127,10 @@ class CodeEditor {
2083
2127
  string = (i == fromY) ? this.code.lines[ i ].substring(0, fromX) : this.code.lines[ i ]; // Last line, any multiple line...
2084
2128
  if( isVisible ) domEl.style.left = this.xPadding;
2085
2129
  }
2086
-
2130
+
2087
2131
  const stringWidth = this.measureString( string );
2088
2132
  cursor.selection.chars += stringWidth / this.charWidth;
2089
-
2133
+
2090
2134
  if( isVisible )
2091
2135
  {
2092
2136
  domEl.style.width = (stringWidth || 8) + "px";
@@ -2098,10 +2142,10 @@ class CodeEditor {
2098
2142
  }
2099
2143
 
2100
2144
  async processKey( e ) {
2101
-
2145
+
2102
2146
  const numCursors = this.cursors.childElementCount;
2103
2147
 
2104
- if( !this.code || e.srcElement.constructor != HTMLDivElement )
2148
+ if( !this.code || e.srcElement.constructor != HTMLDivElement )
2105
2149
  return;
2106
2150
 
2107
2151
  const key = e.key ?? e.detail.key;
@@ -2306,7 +2350,7 @@ class CodeEditor {
2306
2350
  return;
2307
2351
  }
2308
2352
  }
2309
-
2353
+
2310
2354
  // Apply binded actions...
2311
2355
 
2312
2356
  for( const actKey in this.actions ) {
@@ -2338,11 +2382,11 @@ class CodeEditor {
2338
2382
  const enclosableKeys = [ "\"", "'", "(", "{" ];
2339
2383
  if( enclosableKeys.indexOf( key ) > -1 )
2340
2384
  {
2341
- if( this._encloseSelectedWordWithKey( key, lidx, cursor ) )
2385
+ if( this._encloseSelectedWordWithKey( key, lidx, cursor ) )
2342
2386
  return;
2343
2387
  }
2344
2388
 
2345
- // Until this point, if there was a selection, we need
2389
+ // Until this point, if there was a selection, we need
2346
2390
  // to delete the content..
2347
2391
 
2348
2392
  if( cursor.selection )
@@ -2359,8 +2403,8 @@ class CodeEditor {
2359
2403
  if( !sameKeyNext )
2360
2404
  {
2361
2405
  this.code.lines[ lidx ] = [
2362
- this.code.lines[ lidx ].slice( 0, cursor.position ),
2363
- key,
2406
+ this.code.lines[ lidx ].slice( 0, cursor.position ),
2407
+ key,
2364
2408
  this.code.lines[ lidx ].slice( cursor.position )
2365
2409
  ].join('');
2366
2410
  }
@@ -2368,7 +2412,7 @@ class CodeEditor {
2368
2412
  this.cursorToRight( key, cursor );
2369
2413
 
2370
2414
  // Some custom cases for auto key pair (), {}, "", '', ...
2371
-
2415
+
2372
2416
  const keyMustPair = (this.pairKeys[ key ] !== undefined);
2373
2417
  if( keyMustPair && !this.wasKeyPaired )
2374
2418
  {
@@ -2429,7 +2473,7 @@ class CodeEditor {
2429
2473
  text_to_copy = "\n" + this.code.lines[ cursor.line ];
2430
2474
  }
2431
2475
  else {
2432
-
2476
+
2433
2477
  // Some selections don't depend on mouse up..
2434
2478
  if( cursor.selection ) cursor.selection.invertIfNecessary();
2435
2479
 
@@ -2438,11 +2482,11 @@ class CodeEditor {
2438
2482
 
2439
2483
  // Get linear start index
2440
2484
  let index = 0;
2441
-
2485
+
2442
2486
  for( let i = 0; i <= cursor.selection.fromY; i++ )
2443
2487
  index += ( i == cursor.selection.fromY ? cursor.selection.fromX : this.code.lines[ i ].length );
2444
2488
 
2445
- index += cursor.selection.fromY * separator.length;
2489
+ index += cursor.selection.fromY * separator.length;
2446
2490
  const num_chars = cursor.selection.chars + ( cursor.selection.toY - cursor.selection.fromY ) * separator.length;
2447
2491
  const text = code.substr( index, num_chars );
2448
2492
  const lines = text.split( separator );
@@ -2468,7 +2512,7 @@ class CodeEditor {
2468
2512
  this.lineUp( cursor );
2469
2513
  }
2470
2514
  else {
2471
-
2515
+
2472
2516
  // Some selections don't depend on mouse up..
2473
2517
  if( cursor.selection ) cursor.selection.invertIfNecessary();
2474
2518
 
@@ -2477,11 +2521,11 @@ class CodeEditor {
2477
2521
 
2478
2522
  // Get linear start index
2479
2523
  let index = 0;
2480
-
2524
+
2481
2525
  for(let i = 0; i <= cursor.selection.fromY; i++)
2482
2526
  index += (i == cursor.selection.fromY ? cursor.selection.fromX : this.code.lines[ i ].length);
2483
2527
 
2484
- index += cursor.selection.fromY * separator.length;
2528
+ index += cursor.selection.fromY * separator.length;
2485
2529
  const num_chars = cursor.selection.chars + (cursor.selection.toY - cursor.selection.fromY) * separator.length;
2486
2530
  const text = code.substr(index, num_chars);
2487
2531
  const lines = text.split(separator);
@@ -2494,7 +2538,7 @@ class CodeEditor {
2494
2538
  }
2495
2539
 
2496
2540
  _duplicateLine( lidx, cursor ) {
2497
-
2541
+
2498
2542
  this.endSelection();
2499
2543
  this._addUndoStep( cursor, true );
2500
2544
  this.code.lines.splice( lidx, 0, this.code.lines[ lidx ] );
@@ -2651,20 +2695,20 @@ class CodeEditor {
2651
2695
  }
2652
2696
 
2653
2697
  processLines( mode ) {
2654
-
2698
+
2655
2699
  var code_html = "";
2656
2700
  this._blockCommentCache.length = 0;
2657
-
2701
+
2658
2702
  // Reset all lines content
2659
2703
  this.code.innerHTML = "";
2660
-
2704
+
2661
2705
  // Get info about lines in viewport
2662
2706
  const lastScrollTop = this.getScrollTop();
2663
- this.firstLineInViewport = ( mode ?? CodeEditor.KEEP_VISIBLE_LINES ) & CodeEditor.UPDATE_VISIBLE_LINES ?
2707
+ this.firstLineInViewport = ( mode ?? CodeEditor.KEEP_VISIBLE_LINES ) & CodeEditor.UPDATE_VISIBLE_LINES ?
2664
2708
  ( (lastScrollTop / this.lineHeight)|0 ) : this.firstLineInViewport;
2665
2709
  const totalLinesInViewport = ((this.codeScroller.offsetHeight - 36) / this.lineHeight)|0;
2666
- this.visibleLinesViewport = new LX.vec2(
2667
- Math.max( this.firstLineInViewport - this.lineScrollMargin.x, 0 ),
2710
+ this.visibleLinesViewport = new LX.vec2(
2711
+ Math.max( this.firstLineInViewport - this.lineScrollMargin.x, 0 ),
2668
2712
  Math.min( this.firstLineInViewport + totalLinesInViewport + this.lineScrollMargin.y, this.code.lines.length )
2669
2713
  );
2670
2714
 
@@ -2674,15 +2718,15 @@ class CodeEditor {
2674
2718
  if( diff <= this.lineScrollMargin.y )
2675
2719
  this.visibleLinesViewport.y += diff;
2676
2720
  }
2677
-
2721
+
2678
2722
  // Process visible lines
2679
2723
  for( let i = this.visibleLinesViewport.x; i < this.visibleLinesViewport.y; ++i )
2680
2724
  {
2681
2725
  code_html += this.processLine( i, true );
2682
2726
  }
2683
-
2727
+
2684
2728
  this.code.innerHTML = code_html;
2685
-
2729
+
2686
2730
  // Update scroll data
2687
2731
  this.codeScroller.scrollTop = lastScrollTop;
2688
2732
  this.code.style.top = ( this.visibleLinesViewport.x * this.lineHeight ) + "px";
@@ -2720,10 +2764,10 @@ class CodeEditor {
2720
2764
  }
2721
2765
 
2722
2766
  // multi-line strings not supported by now
2723
- delete this._buildingString;
2767
+ delete this._buildingString;
2724
2768
  delete this._pendingString;
2725
2769
  delete this._markdownHeader;
2726
-
2770
+
2727
2771
  let linestring = this.code.lines[ linenum ];
2728
2772
 
2729
2773
  // Single line
@@ -2758,14 +2802,14 @@ class CodeEditor {
2758
2802
  it--;
2759
2803
  prev = tokensToEvaluate[ it ];
2760
2804
  }
2761
-
2805
+
2762
2806
  it = i + 1;
2763
2807
  let next = tokensToEvaluate[ it ];
2764
2808
  while( next == ' ' || next == '"' ) {
2765
2809
  it++;
2766
2810
  next = tokensToEvaluate[ it ];
2767
2811
  }
2768
-
2812
+
2769
2813
  const token = tokensToEvaluate[ i ];
2770
2814
 
2771
2815
  if( lang.blockComments ?? true )
@@ -2783,7 +2827,8 @@ class CodeEditor {
2783
2827
  nextWithSpaces: tokensToEvaluate[ i + 1 ],
2784
2828
  tokenIndex: i,
2785
2829
  isFirstToken: (i == 0),
2786
- isLastToken: (i == tokensToEvaluate.length - 1)
2830
+ isLastToken: (i == tokensToEvaluate.length - 1),
2831
+ tokens: tokensToEvaluate
2787
2832
  } );
2788
2833
  }
2789
2834
 
@@ -2805,10 +2850,10 @@ class CodeEditor {
2805
2850
  const stringKeys = Object.values( this.stringKeys );
2806
2851
  // Count times we started a string BEFORE the comment
2807
2852
  var err = false;
2808
- err |= stringKeys.some( function(v) {
2809
- var re = new RegExp( v, "g" );
2853
+ err |= stringKeys.some( function(v) {
2854
+ var re = new RegExp( v, "g" );
2810
2855
  var matches = (linestring.substring( 0, idx ).match( re ) || []);
2811
- return (matches.length % 2) !== 0;
2856
+ return (matches.length % 2) !== 0;
2812
2857
  } );
2813
2858
  return err ? undefined : idx;
2814
2859
  }
@@ -2891,9 +2936,21 @@ class CodeEditor {
2891
2936
  return tokens;
2892
2937
  }
2893
2938
 
2894
- _mustHightlightWord( token, kindArray ) {
2939
+ _mustHightlightWord( token, kindArray, lang ) {
2940
+
2941
+ if( !lang )
2942
+ {
2943
+ lang = this.languages[ this.highlight ];
2944
+ }
2945
+
2946
+ let t = token;
2947
+
2948
+ if( lang.ignoreCase )
2949
+ {
2950
+ t = t.toLowerCase();
2951
+ }
2895
2952
 
2896
- return kindArray[this.highlight] && kindArray[this.highlight][token] != undefined;
2953
+ return kindArray[ this.highlight ] && kindArray[ this.highlight ][ t ] != undefined;
2897
2954
  }
2898
2955
 
2899
2956
  _evaluateToken( ctxData ) {
@@ -2911,10 +2968,10 @@ class CodeEditor {
2911
2968
 
2912
2969
  var usePreviousTokenToCheckString = false;
2913
2970
 
2914
- if( highlight == 'cpp' && prev && prev.includes( '#' ) ) // preprocessor code..
2971
+ if( [ 'cpp', 'c' ].indexOf( highlight ) > -1 && prev && prev.includes( '#' ) ) // preprocessor code..
2915
2972
  {
2916
2973
  customStringKeys['@<'] = '>';
2917
- }
2974
+ }
2918
2975
  else if( highlight == 'markdown' && ( ctxData.prevWithSpaces == '[' || ctxData.nextWithSpaces == ']' ) )
2919
2976
  {
2920
2977
  // console.warn(prev, token, next)
@@ -2935,43 +2992,43 @@ class CodeEditor {
2935
2992
  if( this._buildingString != undefined )
2936
2993
  {
2937
2994
  checkIfStringEnded( usePreviousTokenToCheckString ? ctxData.nextWithSpaces : token );
2938
- }
2995
+ }
2939
2996
  else if( customStringKeys[ '@' + ( usePreviousTokenToCheckString ? ctxData.prevWithSpaces : token ) ] )
2940
- {
2997
+ {
2941
2998
  // Start new string
2942
2999
  this._buildingString = ( usePreviousTokenToCheckString ? ctxData.prevWithSpaces : token );
2943
3000
 
2944
3001
  // Check if string ended in same token using next...
2945
- if( usePreviousTokenToCheckString )
3002
+ if( usePreviousTokenToCheckString )
2946
3003
  {
2947
3004
  checkIfStringEnded( ctxData.nextWithSpaces );
2948
3005
  }
2949
3006
  }
2950
3007
  }
2951
-
3008
+
2952
3009
  const usesBlockComments = lang.blockComments ?? true;
2953
3010
  const blockCommentsTokens = lang.blockCommentsTokens ?? this.defaultBlockCommentTokens;
2954
3011
  const singleLineCommentToken = lang.singleLineCommentToken ?? this.defaultSingleLineCommentToken;
2955
-
3012
+
2956
3013
  let token_classname = "";
2957
3014
  let discardToken = false;
2958
3015
 
2959
3016
  if( this._buildingBlockComment != undefined )
2960
3017
  token_classname = "cm-com";
2961
-
3018
+
2962
3019
  else if( this._buildingString != undefined )
2963
3020
  discardToken = this._appendStringToken( token );
2964
-
2965
- else if( ( this._mustHightlightWord( token, CodeEditor.keywords ) || highlight == 'xml' ) && ( lang.tags ?? false ? ( this._enclosedByTokens( token, tokenIndex, '<', '>' ) ) : true ) )
3021
+
3022
+ else if( this._isKeyword( ctxData, lang ) )
2966
3023
  token_classname = "cm-kwd";
2967
3024
 
2968
- else if( this._mustHightlightWord( token, CodeEditor.builtin ) && ( lang.tags ?? false ? ( this._enclosedByTokens( token, tokenIndex, '<', '>' ) ) : true ) )
3025
+ else if( this._mustHightlightWord( token, CodeEditor.builtIn, lang ) && ( lang.tags ?? false ? ( this._enclosedByTokens( token, tokenIndex, '<', '>' ) ) : true ) )
2969
3026
  token_classname = "cm-bln";
2970
3027
 
2971
- else if( this._mustHightlightWord( token, CodeEditor.statementsAndDeclarations ) )
3028
+ else if( this._mustHightlightWord( token, CodeEditor.statementsAndDeclarations, lang ) )
2972
3029
  token_classname = "cm-std";
2973
3030
 
2974
- else if( this._mustHightlightWord( token, CodeEditor.symbols ) )
3031
+ else if( this._mustHightlightWord( token, CodeEditor.symbols, lang ) )
2975
3032
  token_classname = "cm-sym";
2976
3033
 
2977
3034
  else if( token.substr( 0, singleLineCommentToken.length ) == singleLineCommentToken )
@@ -2980,16 +3037,16 @@ class CodeEditor {
2980
3037
  else if( this._isNumber( token ) || this._isNumber( token.replace(/[px]|[em]|%/g,'') ) )
2981
3038
  token_classname = "cm-dec";
2982
3039
 
2983
- else if( this._isCSSClass( token, prev, next ) )
3040
+ else if( this._isCSSClass( ctxData ) )
2984
3041
  token_classname = "cm-kwd";
2985
3042
 
2986
- else if ( this._isType( token, prev, next ) )
3043
+ else if ( this._isType( ctxData, lang ) )
2987
3044
  token_classname = "cm-typ";
2988
3045
 
2989
3046
  else if ( highlight == 'batch' && ( token == '@' || prev == ':' || prev == '@' ) )
2990
3047
  token_classname = "cm-kwd";
2991
3048
 
2992
- else if ( [ 'cpp', 'wgsl', 'glsl' ].indexOf( highlight ) > -1 && token.includes( '#' ) ) // C++ preprocessor
3049
+ else if ( [ 'cpp', 'c', 'wgsl', 'glsl' ].indexOf( highlight ) > -1 && token.includes( '#' ) ) // C++ preprocessor
2993
3050
  token_classname = "cm-ppc";
2994
3051
 
2995
3052
  else if ( highlight == 'cpp' && prev == '<' && (next == '>' || next == '*') ) // Defining template type in C++
@@ -3003,7 +3060,7 @@ class CodeEditor {
3003
3060
 
3004
3061
  else if ( highlight == 'css' && prev == undefined && next == ':' ) // CSS attribute
3005
3062
  token_classname = "cm-typ";
3006
-
3063
+
3007
3064
  else if ( this._markdownHeader || ( highlight == 'markdown' && isFirstToken && token.replaceAll('#', '').length != token.length ) ) // Header
3008
3065
  {
3009
3066
  token_classname = "cm-kwd";
@@ -3014,7 +3071,7 @@ class CodeEditor {
3014
3071
  token_classname = "cm-mtd";
3015
3072
 
3016
3073
 
3017
- if( usesBlockComments && this._buildingBlockComment != undefined
3074
+ if( usesBlockComments && this._buildingBlockComment != undefined
3018
3075
  && token.substr( 0, blockCommentsTokens[ 1 ].length ) == blockCommentsTokens[ 1 ] )
3019
3076
  {
3020
3077
  this._blockCommentCache.push( new LX.vec2( this._buildingBlockComment, this._currentLineNumber ) );
@@ -3033,14 +3090,18 @@ class CodeEditor {
3033
3090
  this._buildingString = this._stringEnded ? undefined : this._buildingString;
3034
3091
 
3035
3092
  if( discardToken )
3093
+ {
3036
3094
  return "";
3095
+ }
3037
3096
 
3038
3097
  token = token.replace( "<", "&lt;" );
3039
3098
  token = token.replace( ">", "&gt;" );
3040
3099
 
3041
3100
  // No highlighting, no need to put it inside another span..
3042
3101
  if( !token_classname.length )
3102
+ {
3043
3103
  return token;
3104
+ }
3044
3105
 
3045
3106
  return "<span class='" + highlight + " " + token_classname + "'>" + token + "</span>";
3046
3107
  }
@@ -3075,7 +3136,10 @@ class CodeEditor {
3075
3136
  if( tagEndIndex < 0 ) // Not found..
3076
3137
  return;
3077
3138
 
3078
- return ( tagStartIndex < tokenStartIndex ) && ( tagEndIndex >= ( tokenStartIndex + token.length ) ) && !this._mustHightlightWord( token, CodeEditor.symbols );
3139
+ if( ( tagStartIndex < tokenStartIndex ) && ( tagEndIndex >= ( tokenStartIndex + token.length ) ) && !this._mustHightlightWord( token, CodeEditor.symbols ) )
3140
+ {
3141
+ return [ tagStartIndex, tagEndIndex ];
3142
+ }
3079
3143
  }
3080
3144
 
3081
3145
  _inBlockCommentSection( line ) {
@@ -3083,52 +3147,104 @@ class CodeEditor {
3083
3147
  for( var section of this._blockCommentCache )
3084
3148
  {
3085
3149
  if( line >= section.x && line <= section.y )
3150
+ {
3086
3151
  return true;
3152
+ }
3087
3153
  }
3088
3154
 
3089
3155
  return false;
3090
3156
  }
3091
3157
 
3092
- _isCSSClass( token, prev, next ) {
3158
+ _isKeyword( ctxData, lang ) {
3159
+
3160
+ const token = ctxData.token;
3161
+ const tokenIndex = ctxData.tokenIndex;
3162
+ const tokens = ctxData.tokens;
3163
+
3164
+ let isKwd = this._mustHightlightWord( token, CodeEditor.keywords ) || this.highlight == 'XML';
3165
+
3166
+ if( this.highlight == 'CMake' )
3167
+ {
3168
+ // Highlight $ symbol
3169
+ if( token == '$' && this._enclosedByTokens( tokens[ tokenIndex + 2 ], tokenIndex + 2, '{', '}' ) )
3170
+ {
3171
+ isKwd = true;
3172
+ }
3173
+ // Highlight what is between the { }
3174
+ else if( this._enclosedByTokens( token, tokenIndex, '{', '}' ) )
3175
+ {
3176
+ isKwd |= ( ctxData.tokens[ tokenIndex - 2 ] == '$' );
3177
+ }
3178
+ }
3179
+ else if( lang.tags )
3180
+ {
3181
+ isKwd &= ( this._enclosedByTokens( token, tokenIndex, '<', '>' ) != undefined );
3182
+ }
3183
+
3184
+
3185
+ return isKwd;
3186
+ }
3187
+
3188
+ _isCSSClass( ctxData ) {
3189
+
3190
+ const token = ctxData.token;
3191
+ const prev = ctxData.prev;
3192
+ const next = ctxData.next;
3093
3193
 
3094
3194
  if( this.highlight != 'CSS' )
3195
+ {
3095
3196
  return false;
3197
+ }
3096
3198
 
3097
- return ( prev == '.' || prev == '::'
3098
- || ( prev == ':' && next == '{' )
3199
+ return ( prev == '.' || prev == '::'
3200
+ || ( prev == ':' && next == '{' )
3099
3201
  || ( token[ 0 ] == '#' && prev != ':' ) );
3100
3202
  }
3101
3203
 
3102
3204
  _isNumber( token ) {
3103
3205
 
3104
- if(this.highlight == 'C++')
3206
+ const subToken = token.substring( 0, token.length - 1 );
3207
+
3208
+ if( this.highlight == 'C++' )
3105
3209
  {
3106
3210
  if( token.lastChar == 'f' )
3107
- return this._isNumber( token.substring(0, token.length - 1) )
3211
+ {
3212
+ return this._isNumber( subToken )
3213
+ }
3108
3214
  else if( token.lastChar == 'u' )
3109
- return !(token.includes('.')) && this._isNumber( token.substring(0, token.length - 1) );
3215
+ {
3216
+ return !(token.includes('.')) && this._isNumber( subToken );
3217
+ }
3110
3218
  }
3111
-
3112
- else if(this.highlight == 'WGSL')
3219
+ else if( this.highlight == 'WGSL' )
3113
3220
  {
3114
3221
  if( token.lastChar == 'u' )
3115
- return !(token.includes('.')) && this._isNumber( token.substring(0, token.length - 1) );
3222
+ {
3223
+ return !(token.includes('.')) && this._isNumber( subToken );
3224
+ }
3116
3225
  }
3117
-
3118
- else if(this.highlight == 'CSS')
3226
+ else if( this.highlight == 'CSS' )
3119
3227
  {
3120
3228
  if( token.lastChar == '%' )
3121
- return this._isNumber( token.substring(0, token.length - 1) )
3229
+ {
3230
+ return this._isNumber( subToken )
3231
+ }
3122
3232
  }
3123
-
3124
- return token.length && token != ' ' && !Number.isNaN(+token);
3233
+
3234
+ return token.length && token != ' ' && !Number.isNaN( +token );
3125
3235
  }
3126
3236
 
3127
- _isType( token, prev, next ) {
3128
-
3237
+ _isType( ctxData, lang ) {
3238
+
3239
+ const token = ctxData.token;
3240
+ const prev = ctxData.prev;
3241
+ const next = ctxData.next;
3242
+
3129
3243
  // Common case
3130
- if( this._mustHightlightWord( token, CodeEditor.types ) )
3244
+ if( this._mustHightlightWord( token, CodeEditor.types, lang ) )
3245
+ {
3131
3246
  return true;
3247
+ }
3132
3248
 
3133
3249
  if( this.highlight == 'JavaScript' )
3134
3250
  {
@@ -3140,11 +3256,11 @@ class CodeEditor {
3140
3256
  }
3141
3257
  else if ( this.highlight == 'WGSL' )
3142
3258
  {
3143
- const not_kwd = !this._mustHightlightWord( token, CodeEditor.keywords );
3144
- return (prev == 'struct' && next == '{') ||
3145
- (not_kwd && prev == ':' && next == ';') ||
3146
- ( not_kwd &&
3147
- ( prev == ':' && next == ')' || prev == ':' && next == ',' || prev == '>' && next == '{'
3259
+ const not_kwd = !this._mustHightlightWord( token, CodeEditor.keywords, lang );
3260
+ return (prev == 'struct' && next == '{') ||
3261
+ (not_kwd && prev == ':' && next == ';') ||
3262
+ ( not_kwd &&
3263
+ ( prev == ':' && next == ')' || prev == ':' && next == ',' || prev == '>' && next == '{'
3148
3264
  || prev == '<' && next == ',' || prev == '<' && next == '>' || prev == '>' && token != ';' && !next ));
3149
3265
  }
3150
3266
  }
@@ -3153,13 +3269,13 @@ class CodeEditor {
3153
3269
 
3154
3270
  if( !cursor.selection || (cursor.selection.fromY != cursor.selection.toY) )
3155
3271
  return false;
3156
-
3272
+
3157
3273
  cursor.selection.invertIfNecessary();
3158
3274
 
3159
3275
  // Insert first..
3160
3276
  this.code.lines[ lidx ] = [
3161
- this.code.lines[ lidx ].slice(0, cursor.selection.fromX),
3162
- key,
3277
+ this.code.lines[ lidx ].slice(0, cursor.selection.fromX),
3278
+ key,
3163
3279
  this.code.lines[ lidx ].slice(cursor.selection.fromX)
3164
3280
  ].join('');
3165
3281
 
@@ -3178,14 +3294,14 @@ class CodeEditor {
3178
3294
 
3179
3295
  // Insert the other
3180
3296
  this.code.lines[ lidx ] = [
3181
- this.code.lines[ lidx ].slice(0, cursor.position),
3182
- key,
3297
+ this.code.lines[ lidx ].slice(0, cursor.position),
3298
+ key,
3183
3299
  this.code.lines[ lidx ].slice(cursor.position)
3184
3300
  ].join('');
3185
3301
 
3186
3302
  // Recompute and reposition current selection
3187
-
3188
- cursor.selection.fromX++;
3303
+
3304
+ cursor.selection.fromX++;
3189
3305
  cursor.selection.toX++;
3190
3306
 
3191
3307
  this._processSelection( cursor );
@@ -3197,7 +3313,7 @@ class CodeEditor {
3197
3313
 
3198
3314
  lineUp( cursor, resetLeft ) {
3199
3315
 
3200
- if( this.code.lines[ cursor.line - 1 ] == undefined )
3316
+ if( this.code.lines[ cursor.line - 1 ] == undefined )
3201
3317
  return false;
3202
3318
 
3203
3319
  cursor.line--;
@@ -3208,10 +3324,10 @@ class CodeEditor {
3208
3324
  }
3209
3325
 
3210
3326
  lineDown( cursor, resetLeft ) {
3211
-
3212
- if( this.code.lines[ cursor.line + 1 ] == undefined )
3327
+
3328
+ if( this.code.lines[ cursor.line + 1 ] == undefined )
3213
3329
  return false;
3214
-
3330
+
3215
3331
  cursor.line++;
3216
3332
 
3217
3333
  this.cursorToBottom( cursor, resetLeft );
@@ -3250,8 +3366,8 @@ class CodeEditor {
3250
3366
 
3251
3367
  deleteSelection( cursor ) {
3252
3368
 
3253
- // I think it's not necessary but...
3254
- if( this.disableEdition )
3369
+ // I think it's not necessary but...
3370
+ if( this.disableEdition )
3255
3371
  return;
3256
3372
 
3257
3373
  // Some selections don't depend on mouse up..
@@ -3265,14 +3381,14 @@ class CodeEditor {
3265
3381
  for( let i = 0; i <= cursor.selection.fromY; i++ )
3266
3382
  index += (i == cursor.selection.fromY ? cursor.selection.fromX : this.code.lines[ i ].length);
3267
3383
 
3268
- index += cursor.selection.fromY * separator.length;
3384
+ index += cursor.selection.fromY * separator.length;
3269
3385
 
3270
3386
  const num_chars = cursor.selection.chars + (cursor.selection.toY - cursor.selection.fromY) * separator.length;
3271
3387
  const pre = code.slice( 0, index );
3272
3388
  const post = code.slice( index + num_chars );
3273
3389
 
3274
3390
  this.code.lines = ( pre + post ).split( separator );
3275
-
3391
+
3276
3392
  this.cursorToLine( cursor, cursor.selection.fromY, true );
3277
3393
  this.cursorToPosition( cursor, cursor.selection.fromX );
3278
3394
  this.endSelection( cursor );
@@ -3370,7 +3486,7 @@ class CodeEditor {
3370
3486
  cursor._top = Math.max(cursor._top, 0);
3371
3487
  cursor.style.top = "calc(" + cursor._top + "px)";
3372
3488
  this.restartBlink();
3373
-
3489
+
3374
3490
  if( resetLeft )
3375
3491
  this.resetCursorPos( CodeEditor.CURSOR_LEFT, cursor );
3376
3492
 
@@ -3400,10 +3516,10 @@ class CodeEditor {
3400
3516
 
3401
3517
  cursorToString( cursor, text, reverse ) {
3402
3518
 
3403
- if( !text.length )
3519
+ if( !text.length )
3404
3520
  return;
3405
3521
 
3406
- for( let char of text )
3522
+ for( let char of text )
3407
3523
  reverse ? this.cursorToLeft( char, cursor ) : this.cursorToRight( char, cursor );
3408
3524
  }
3409
3525
 
@@ -3491,7 +3607,7 @@ class CodeEditor {
3491
3607
  }
3492
3608
 
3493
3609
  resetCursorPos( flag, cursor ) {
3494
-
3610
+
3495
3611
  cursor = cursor ?? this._getCurrentCursor();
3496
3612
 
3497
3613
  if( flag & CodeEditor.CURSOR_LEFT )
@@ -3510,14 +3626,14 @@ class CodeEditor {
3510
3626
  }
3511
3627
 
3512
3628
  _addSpaceTabs( cursor, n ) {
3513
-
3629
+
3514
3630
  for( var i = 0; i < n; ++i ) {
3515
3631
  this.actions[ 'Tab' ].callback( cursor.line, cursor, null );
3516
3632
  }
3517
3633
  }
3518
3634
 
3519
3635
  _addSpaces( n ) {
3520
-
3636
+
3521
3637
  for( var i = 0; i < n; ++i ) {
3522
3638
  this.root.dispatchEvent( new CustomEvent( 'keydown', { 'detail': {
3523
3639
  skip_undo: true,
@@ -3564,33 +3680,33 @@ class CodeEditor {
3564
3680
  }
3565
3681
 
3566
3682
  getScrollLeft() {
3567
-
3683
+
3568
3684
  if( !this.codeScroller ) return 0;
3569
3685
  return this.codeScroller.scrollLeft;
3570
3686
  }
3571
3687
 
3572
3688
  getScrollTop() {
3573
-
3689
+
3574
3690
  if( !this.codeScroller ) return 0;
3575
3691
  return this.codeScroller.scrollTop;
3576
3692
  }
3577
3693
 
3578
3694
  setScrollLeft( value ) {
3579
-
3695
+
3580
3696
  if( !this.codeScroller ) return;
3581
3697
  this.codeScroller.scrollLeft = value;
3582
3698
  this.setScrollBarValue( 'horizontal', 0 );
3583
3699
  }
3584
3700
 
3585
3701
  setScrollTop( value ) {
3586
-
3702
+
3587
3703
  if( !this.codeScroller ) return;
3588
3704
  this.codeScroller.scrollTop = value;
3589
3705
  this.setScrollBarValue( 'vertical' );
3590
3706
  }
3591
3707
 
3592
3708
  resize( pMaxLength ) {
3593
-
3709
+
3594
3710
  setTimeout( () => {
3595
3711
 
3596
3712
  // Update max viewport
@@ -3648,7 +3764,7 @@ class CodeEditor {
3648
3764
  {
3649
3765
  const scrollBarHeight = this.vScrollbar.thumb.parentElement.offsetHeight;
3650
3766
  const scrollThumbHeight = this.vScrollbar.thumb.offsetHeight;
3651
-
3767
+
3652
3768
  const scrollHeight = this.codeScroller.scrollHeight - this.codeScroller.clientHeight;
3653
3769
  const currentScroll = this.codeScroller.scrollTop;
3654
3770
 
@@ -3687,13 +3803,13 @@ class CodeEditor {
3687
3803
  const scrollWidth = this.codeScroller.scrollWidth - this.codeScroller.clientWidth;
3688
3804
  const currentScroll = (this.hScrollbar.thumb._left * scrollWidth) / ( scrollBarWidth - scrollThumbWidth );
3689
3805
  this.codeScroller.scrollLeft = currentScroll;
3690
-
3806
+
3691
3807
 
3692
3808
  this._discardScroll = true;
3693
3809
  }
3694
3810
 
3695
3811
  updateVerticalScrollFromScrollBar( value ) {
3696
-
3812
+
3697
3813
  value = this.vScrollbar.thumb._top - value;
3698
3814
 
3699
3815
  // Move scrollbar thumb
@@ -3712,12 +3828,12 @@ class CodeEditor {
3712
3828
  }
3713
3829
 
3714
3830
  getCharAtPos( cursor, offset = 0 ) {
3715
-
3831
+
3716
3832
  return this.code.lines[ cursor.line ][ cursor.position + offset ];
3717
3833
  }
3718
3834
 
3719
3835
  getWordAtPos( cursor, offset = 0 ) {
3720
-
3836
+
3721
3837
  const col = cursor.line;
3722
3838
  const words = this.code.lines[ col ];
3723
3839
 
@@ -3761,13 +3877,13 @@ class CodeEditor {
3761
3877
  from--;
3762
3878
  word = words.substring( from, to );
3763
3879
  }
3764
- }
3765
-
3880
+ }
3881
+
3766
3882
  return [ word, from, to ];
3767
3883
  }
3768
3884
 
3769
3885
  _measureChar( char = "a", use_floating = false, get_bb = false ) {
3770
-
3886
+
3771
3887
  var line = document.createElement( "pre" );
3772
3888
  var text = document.createElement( "span" );
3773
3889
  line.appendChild( text );
@@ -3831,7 +3947,7 @@ class CodeEditor {
3831
3947
  }
3832
3948
 
3833
3949
  showAutoCompleteBox( key, cursor ) {
3834
-
3950
+
3835
3951
  if( !cursor.isMain )
3836
3952
  return;
3837
3953
 
@@ -3846,8 +3962,8 @@ class CodeEditor {
3846
3962
  let suggestions = [];
3847
3963
 
3848
3964
  // Add language special keys...
3849
- suggestions = suggestions.concat(
3850
- Object.keys( CodeEditor.builtin[ this.highlight ] ?? {} ),
3965
+ suggestions = suggestions.concat(
3966
+ Object.keys( CodeEditor.builtIn[ this.highlight ] ?? {} ),
3851
3967
  Object.keys( CodeEditor.keywords[ this.highlight ] ?? {} ),
3852
3968
  Object.keys( CodeEditor.statementsAndDeclarations[ this.highlight ] ?? {} ),
3853
3969
  Object.keys( CodeEditor.types[ this.highlight ] ?? {} ),
@@ -3857,7 +3973,7 @@ class CodeEditor {
3857
3973
  // Add words in current tab plus remove current word
3858
3974
  // suggestions = suggestions.concat( Object.keys(this.code.tokens).filter( a => a != word ) );
3859
3975
 
3860
- // Remove 1/2 char words and duplicates...
3976
+ // Remove 1/2 char words and duplicates...
3861
3977
  suggestions = suggestions.filter( (value, index) => value.length > 2 && suggestions.indexOf(value) === index );
3862
3978
 
3863
3979
  // Order...
@@ -3872,7 +3988,7 @@ class CodeEditor {
3872
3988
  this.autocomplete.appendChild( pre );
3873
3989
 
3874
3990
  var icon = document.createElement( 'a' );
3875
-
3991
+
3876
3992
  if( this._mustHightlightWord( s, CodeEditor.utils ) )
3877
3993
  icon.className = "fa fa-cube";
3878
3994
  else if( this._mustHightlightWord( s, CodeEditor.types ) )
@@ -3884,7 +4000,7 @@ class CodeEditor {
3884
4000
 
3885
4001
  pre.addEventListener( 'click', () => {
3886
4002
  this.autoCompleteWord( s );
3887
- } );
4003
+ } );
3888
4004
 
3889
4005
  // Highlight the written part
3890
4006
  const index = s.toLowerCase().indexOf( word.toLowerCase() );
@@ -3930,7 +4046,7 @@ class CodeEditor {
3930
4046
  }
3931
4047
 
3932
4048
  autoCompleteWord( suggestion ) {
3933
-
4049
+
3934
4050
  if( !this.isAutoCompleteActive )
3935
4051
  return;
3936
4052
 
@@ -3957,7 +4073,7 @@ class CodeEditor {
3957
4073
  }
3958
4074
 
3959
4075
  _getSelectedAutoComplete() {
3960
-
4076
+
3961
4077
  if( !this.isAutoCompleteActive )
3962
4078
  return;
3963
4079
 
@@ -3997,7 +4113,7 @@ class CodeEditor {
3997
4113
  }
3998
4114
 
3999
4115
  showSearchBox( clear ) {
4000
-
4116
+
4001
4117
  this.hideSearchLineBox();
4002
4118
 
4003
4119
  this.searchbox.classList.add( 'opened' );
@@ -4066,7 +4182,7 @@ class CodeEditor {
4066
4182
  }
4067
4183
 
4068
4184
  const getIndex = l => {
4069
-
4185
+
4070
4186
  var string = this.code.lines[ l ];
4071
4187
 
4072
4188
  if( reverse )
@@ -4120,10 +4236,10 @@ class CodeEditor {
4120
4236
  };
4121
4237
  return;
4122
4238
  }
4123
-
4239
+
4124
4240
  /*
4125
4241
  Position idx is computed from last pos, which could be in same line,
4126
- so we search in the substring (first_ocurrence, end). That's why we
4242
+ so we search in the substring (first_ocurrence, end). That's why we
4127
4243
  have to add the length of the substring (0, first_ocurrence)
4128
4244
  */
4129
4245
 
@@ -4136,9 +4252,9 @@ class CodeEditor {
4136
4252
 
4137
4253
  this._lastTextFound = text;
4138
4254
 
4139
- this.codeScroller.scrollTo(
4140
- Math.max( char * this.charWidth - this.codeScroller.clientWidth, 0 ),
4141
- Math.max( line - 10, 0 ) * this.lineHeight
4255
+ this.codeScroller.scrollTo(
4256
+ Math.max( char * this.charWidth - this.codeScroller.clientWidth, 0 ),
4257
+ Math.max( line - 10, 0 ) * this.lineHeight
4142
4258
  );
4143
4259
 
4144
4260
  if( callback )
@@ -4162,7 +4278,7 @@ class CodeEditor {
4162
4278
  }
4163
4279
 
4164
4280
  showSearchLineBox() {
4165
-
4281
+
4166
4282
  this.hideSearchBox();
4167
4283
 
4168
4284
  this.searchlinebox.classList.add( 'opened' );
@@ -4326,7 +4442,7 @@ class CodeEditor {
4326
4442
 
4327
4443
  delete this._currentLineString;
4328
4444
  delete this._currentLineNumber;
4329
- delete this._buildingString;
4445
+ delete this._buildingString;
4330
4446
  delete this._pendingString;
4331
4447
  delete this._buildingBlockComment;
4332
4448
  delete this._markdownHeader;
@@ -4338,8 +4454,13 @@ CodeEditor.keywords = {
4338
4454
 
4339
4455
  'JavaScript': ['var', 'let', 'const', 'this', 'in', 'of', 'true', 'false', 'new', 'function', 'NaN', 'static', 'class', 'constructor', 'null', 'typeof', 'debugger', 'abstract',
4340
4456
  'arguments', 'extends', 'instanceof', 'Infinity'],
4341
- 'C++': ['int', 'float', 'double', 'bool', 'char', 'wchar_t', 'const', 'static_cast', 'dynamic_cast', 'new', 'delete', 'void', 'true', 'false', 'auto', 'struct', 'typedef', 'nullptr',
4342
- 'NULL', 'unsigned', 'namespace'],
4457
+ 'C': ['int', 'float', 'double', 'long', 'short', 'char', 'const', 'void', 'true', 'false', 'auto', 'struct', 'typedef', 'signed', 'volatile', 'unsigned', 'static', 'extern', 'enum', 'register',
4458
+ 'union'],
4459
+ 'C++': ['int', 'float', 'double', 'bool', 'long', 'short', 'char', 'wchar_t', 'const', 'static_cast', 'dynamic_cast', 'new', 'delete', 'void', 'true', 'false', 'auto', 'struct', 'typedef', 'nullptr',
4460
+ 'NULL', 'signed', 'unsigned', 'namespace', 'enum', 'extern', 'union', 'sizeof', 'static'],
4461
+ 'CMake': ['cmake_minimum_required', 'set', 'not', 'if', 'endif', 'exists', 'string', 'strequal', 'add_definitions', 'macro', 'endmacro', 'file', 'list', 'source_group', 'add_executable',
4462
+ 'target_include_directories', 'set_target_properties', 'set_property', 'add_compile_options', 'add_link_options', 'include_directories', 'add_library', 'target_link_libraries',
4463
+ 'target_link_options', 'add_subdirectory', 'add_compile_definitions', 'project', 'cache'],
4343
4464
  'JSON': ['true', 'false'],
4344
4465
  'GLSL': ['true', 'false', 'function', 'int', 'float', 'vec2', 'vec3', 'vec4', 'mat2x2', 'mat3x3', 'mat4x4', 'struct'],
4345
4466
  'CSS': ['body', 'html', 'canvas', 'div', 'input', 'span', '.'],
@@ -4347,10 +4468,10 @@ CodeEditor.keywords = {
4347
4468
  'sampler', 'sampler_comparison', 'texture_depth_2d', 'texture_depth_2d_array', 'texture_depth_cube', 'texture_depth_cube_array', 'texture_depth_multisampled_2d',
4348
4469
  'texture_external', 'texture_1d', 'texture_2d', 'texture_2d_array', 'texture_3d', 'texture_cube', 'texture_cube_array', 'texture_storage_1d', 'texture_storage_2d',
4349
4470
  'texture_storage_2d_array', 'texture_storage_3d', 'vec2u', 'vec3u', 'vec4u'],
4350
- 'Rust': ['as', 'const', 'crate', 'enum', 'extern', 'false', 'fn', 'impl', 'in', 'let', 'mod', 'move', 'mut', 'pub', 'ref', 'self', 'Self', 'static', 'struct', 'super', 'trait', 'true',
4471
+ 'Rust': ['as', 'const', 'crate', 'enum', 'extern', 'false', 'fn', 'impl', 'in', 'let', 'mod', 'move', 'mut', 'pub', 'ref', 'self', 'Self', 'static', 'struct', 'super', 'trait', 'true',
4351
4472
  'type', 'unsafe', 'use', 'where', 'abstract', 'become', 'box', 'final', 'macro', 'override', 'priv', 'typeof', 'unsized', 'virtual'],
4352
4473
  'Python': ['False', 'def', 'None', 'True', 'in', 'is', 'and', 'lambda', 'nonlocal', 'not', 'or'],
4353
- 'Batch': ['set', 'SET', 'echo', 'ECHO', 'off', 'OFF', 'del', 'DEL', 'defined', 'DEFINED', 'setlocal', 'SETLOCAL', 'enabledelayedexpansion', 'ENABLEDELAYEDEXPANSION', 'driverquery',
4474
+ 'Batch': ['set', 'SET', 'echo', 'ECHO', 'off', 'OFF', 'del', 'DEL', 'defined', 'DEFINED', 'setlocal', 'SETLOCAL', 'enabledelayedexpansion', 'ENABLEDELAYEDEXPANSION', 'driverquery',
4354
4475
  'DRIVERQUERY', 'print', 'PRINT'],
4355
4476
  'HTML': ['html', 'meta', 'title', 'link', 'script', 'body', 'DOCTYPE', 'head', 'br', 'i', 'a', 'li', 'img', 'tr', 'td', 'h1', 'h2', 'h3', 'h4', 'h5'],
4356
4477
  'Markdown': ['br', 'i', 'a', 'li', 'img', 'table', 'title', 'tr', 'td', 'h1', 'h2', 'h3', 'h4', 'h5'],
@@ -4362,9 +4483,9 @@ CodeEditor.utils = { // These ones don't have hightlight, used as suggestions to
4362
4483
  'bind', 'prototype', 'length', 'assign', 'entries', 'values', 'concat', 'substring', 'substr', 'splice', 'slice', 'buffer', 'appendChild', 'createElement', 'prompt',
4363
4484
  'alert'],
4364
4485
  'WGSL': ['textureSample'],
4365
- 'Python': ['abs', 'all', 'any', 'ascii', 'bin', 'bool', 'bytearray', 'bytes', 'callable', 'chr', 'classmethod', 'compile', 'complex', 'delattr', 'dict', 'dir', 'divmod',
4486
+ 'Python': ['abs', 'all', 'any', 'ascii', 'bin', 'bool', 'bytearray', 'bytes', 'callable', 'chr', 'classmethod', 'compile', 'complex', 'delattr', 'dict', 'dir', 'divmod',
4366
4487
  'enumerate', 'eval', 'exec', 'filter', 'float', 'format', 'frozenset', 'getattr', 'globals', 'hasattr', 'hash', 'help', 'hex', 'id', 'input', 'int', 'isinstance',
4367
- 'issubclass', 'iter', 'len', 'list', 'locals', 'map', 'max', 'memoryview', 'min', 'next', 'object', 'oct', 'open', 'ord', 'pow', 'print', 'property', 'range', 'repr',
4488
+ 'issubclass', 'iter', 'len', 'list', 'locals', 'map', 'max', 'memoryview', 'min', 'next', 'object', 'oct', 'open', 'ord', 'pow', 'print', 'property', 'range', 'repr',
4368
4489
  'reversed', 'round', 'set', 'setattr', 'slice', 'sorted', 'staticmethod', 'str', 'sum', 'super', 'tuple', 'type', 'vars', 'zip']
4369
4490
  };
4370
4491
 
@@ -4373,14 +4494,14 @@ CodeEditor.types = {
4373
4494
  'JavaScript': ['Object', 'String', 'Function', 'Boolean', 'Symbol', 'Error', 'Number', 'TextEncoder', 'TextDecoder', 'Array', 'ArrayBuffer', 'InputEvent', 'MouseEvent',
4374
4495
  'Int8Array', 'Int16Array', 'Int32Array', 'Float32Array', 'Float64Array', 'Element'],
4375
4496
  'Rust': ['u128'],
4376
- 'Python': ['int', 'type', 'float', 'map', 'list', 'ArithmeticError', 'AssertionError', 'AttributeError', 'Exception', 'EOFError', 'FloatingPointError', 'GeneratorExit',
4497
+ 'Python': ['int', 'type', 'float', 'map', 'list', 'ArithmeticError', 'AssertionError', 'AttributeError', 'Exception', 'EOFError', 'FloatingPointError', 'GeneratorExit',
4377
4498
  'ImportError', 'IndentationError', 'IndexError', 'KeyError', 'KeyboardInterrupt', 'LookupError', 'MemoryError', 'NameError', 'NotImplementedError', 'OSError',
4378
- 'OverflowError', 'ReferenceError', 'RuntimeError', 'StopIteration', 'SyntaxError', 'TabError', 'SystemError', 'SystemExit', 'TypeError', 'UnboundLocalError',
4499
+ 'OverflowError', 'ReferenceError', 'RuntimeError', 'StopIteration', 'SyntaxError', 'TabError', 'SystemError', 'SystemExit', 'TypeError', 'UnboundLocalError',
4379
4500
  'UnicodeError', 'UnicodeEncodeError', 'UnicodeDecodeError', 'UnicodeTranslateError', 'ValueError', 'ZeroDivisionError'],
4380
4501
  'C++': ['uint8_t', 'uint16_t', 'uint32_t']
4381
4502
  };
4382
4503
 
4383
- CodeEditor.builtin = {
4504
+ CodeEditor.builtIn = {
4384
4505
 
4385
4506
  'JavaScript': ['document', 'console', 'window', 'navigator', 'performance'],
4386
4507
  'CSS': ['*', '!important'],
@@ -4393,11 +4514,12 @@ CodeEditor.statementsAndDeclarations = {
4393
4514
 
4394
4515
  'JavaScript': ['for', 'if', 'else', 'case', 'switch', 'return', 'while', 'continue', 'break', 'do', 'import', 'from', 'throw', 'async', 'try', 'catch', 'await'],
4395
4516
  'CSS': ['@', 'import'],
4396
- 'C++': ['std', 'for', 'if', 'else', 'return', 'continue', 'break', 'case', 'switch', 'while', 'using', 'glm', 'spdlog'],
4517
+ 'C': ['for', 'if', 'else', 'return', 'continue', 'break', 'case', 'switch', 'while', 'using', 'default', 'goto', 'do'],
4518
+ 'C++': ['std', 'for', 'if', 'else', 'return', 'continue', 'break', 'case', 'switch', 'while', 'using', 'glm', 'spdlog', 'default'],
4397
4519
  'GLSL': ['for', 'if', 'else', 'return', 'continue', 'break'],
4398
4520
  'WGSL': ['const','for', 'if', 'else', 'return', 'continue', 'break', 'storage', 'read', 'read_write', 'uniform', 'function', 'workgroup'],
4399
4521
  'Rust': ['break', 'else', 'continue', 'for', 'if', 'loop', 'match', 'return', 'while', 'do', 'yield'],
4400
- 'Python': ['if', 'raise', 'del', 'import', 'return', 'elif', 'try', 'else', 'while', 'as', 'except', 'with', 'assert', 'finally', 'yield', 'break', 'for', 'class', 'continue',
4522
+ 'Python': ['if', 'raise', 'del', 'import', 'return', 'elif', 'try', 'else', 'while', 'as', 'except', 'with', 'assert', 'finally', 'yield', 'break', 'for', 'class', 'continue',
4401
4523
  'global', 'pass', 'from'],
4402
4524
  'Batch': ['if', 'IF', 'for', 'FOR', 'in', 'IN', 'do', 'DO', 'call', 'CALL', 'goto', 'GOTO', 'exit', 'EXIT']
4403
4525
  };
@@ -4405,7 +4527,9 @@ CodeEditor.statementsAndDeclarations = {
4405
4527
  CodeEditor.symbols = {
4406
4528
 
4407
4529
  'JavaScript': ['<', '>', '[', ']', '{', '}', '(', ')', ';', '=', '|', '||', '&', '&&', '?', '??'],
4530
+ 'C': ['<', '>', '[', ']', '{', '}', '(', ')', ';', '=', '|', '||', '&', '&&', '?', '*', '-', '+'],
4408
4531
  'C++': ['<', '>', '[', ']', '{', '}', '(', ')', ';', '=', '|', '||', '&', '&&', '?', '::', '*', '-', '+'],
4532
+ 'CMake': ['{', '}'],
4409
4533
  'JSON': ['[', ']', '{', '}', '(', ')'],
4410
4534
  'GLSL': ['[', ']', '{', '}', '(', ')'],
4411
4535
  'WGSL': ['[', ']', '{', '}', '(', ')', '->'],