lexgui 0.1.42 → 0.1.44

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