lexgui 0.7.13 → 0.7.14

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.
@@ -356,6 +356,7 @@ class CodeEditor
356
356
  this.highlight = options.highlight ?? 'Plain Text';
357
357
  this.newTabOptions = options.newTabOptions;
358
358
  this.customSuggestions = options.customSuggestions ?? [];
359
+ this.explorerName = options.explorerName ?? "EXPLORER";
359
360
 
360
361
  // Editor callbacks
361
362
  this.onSave = options.onSave ?? options.onsave; // LEGACY onsave
@@ -375,45 +376,43 @@ class CodeEditor
375
376
 
376
377
  let panel = new LX.Panel();
377
378
 
378
- panel.addTitle( options.explorerName ?? "EXPLORER" );
379
+ panel.addTitle( this.explorerName );
379
380
 
380
- let sceneData = {
381
- 'id': 'WORKSPACE',
382
- 'skipVisibility': true,
383
- 'children': []
384
- };
381
+ let sceneData = [];
385
382
 
386
383
  this.explorer = panel.addTree( null, sceneData, {
387
384
  filter: false,
388
385
  rename: false,
389
386
  skipDefaultIcon: true,
390
- onevent: (event) => {
391
- switch(event.type) {
392
- // case LX.TreeEvent.NODE_SELECTED:
393
- // if( !this.tabs.tabDOMs[ event.node.id ] ) break;
394
- case LX.TreeEvent.NODE_DBLCLICKED:
395
- this.loadTab( event.node.id );
396
- break;
397
- case LX.TreeEvent.NODE_DELETED:
398
- this.closeTab( event.node.id );
399
- break;
400
- // case LX.TreeEvent.NODE_CONTEXTMENU:
401
- // LX.addContextMenu( event.multiple ? "Selected Nodes" : event.node.id, event.value, m => {
402
- //
403
- // });
404
- // break;
405
- // case LX.TreeEvent.NODE_DRAGGED:
406
- // console.log(event.node.id + " is now child of " + event.value.id);
407
- // break;
387
+ onevent: (event) =>
388
+ {
389
+ switch( event.type )
390
+ {
391
+ // case LX.TreeEvent.NODE_SELECTED:
392
+ // if( !this.tabs.tabDOMs[ event.node.id ] ) break;
393
+ case LX.TreeEvent.NODE_DBLCLICKED:
394
+ this.loadTab( event.node.id );
395
+ break;
396
+ case LX.TreeEvent.NODE_DELETED:
397
+ this.closeTab( event.node.id );
398
+ break;
399
+ // case LX.TreeEvent.NODE_CONTEXTMENU:
400
+ // LX.addContextMenu( event.multiple ? "Selected Nodes" : event.node.id, event.value, m => {
401
+ //
402
+ // });
403
+ // break;
404
+ // case LX.TreeEvent.NODE_DRAGGED:
405
+ // console.log(event.node.id + " is now child of " + event.value.id);
406
+ // break;
408
407
  }
409
408
  }
410
409
  });
411
410
 
412
411
  this.addExplorerItem = function( item )
413
412
  {
414
- if( !this.explorer.innerTree.data.children.find( ( value, index ) => value.id === item.id ) )
413
+ if( !this.explorer.innerTree.data.find( ( value, index ) => value.id === item.id ) )
415
414
  {
416
- this.explorer.innerTree.data.children.push( item );
415
+ this.explorer.innerTree.data.push( item );
417
416
  }
418
417
  };
419
418
 
@@ -487,6 +486,17 @@ class CodeEditor
487
486
 
488
487
  this.codeArea.root.classList.add( 'lexcodearea' );
489
488
 
489
+ const codeResizeObserver = new ResizeObserver( entries => {
490
+
491
+ if( !this.code )
492
+ {
493
+ return;
494
+ }
495
+
496
+ this.resize();
497
+ });
498
+ codeResizeObserver.observe( this.codeArea.root );
499
+
490
500
  // Full editor
491
501
  area.root.classList.add('codebasearea');
492
502
 
@@ -894,11 +904,13 @@ class CodeEditor
894
904
  }
895
905
  else
896
906
  {
897
- const indentSpaces = this.tabSpaces - (cursor.position % this.tabSpaces);
898
- this._addSpaces( indentSpaces );
907
+ const indentSpaces = this.tabSpaces - ( cursor.position % this.tabSpaces );
908
+ this._addSpaces( cursor, indentSpaces );
899
909
  }
900
910
  }
901
- }, "shiftKey");
911
+ }, ( cursor, e ) => {
912
+ return e.shiftKey || ( cursor.selection && !cursor.selection.sameLine() );
913
+ });
902
914
 
903
915
  this.action( 'Home', false, ( ln, cursor, e ) => {
904
916
 
@@ -910,7 +922,7 @@ class CodeEditor
910
922
  const prestring = this.code.lines[ ln ].substring( 0, idx );
911
923
  let lastX = cursor.position;
912
924
 
913
- this.resetCursorPos( CodeEditor.CURSOR_LEFT, cursor );
925
+ this.resetCursorPos( CodeEditor.CURSOR_LEFT, cursor, true );
914
926
  if( idx > 0 )
915
927
  {
916
928
  this.cursorToString( cursor, prestring );
@@ -921,7 +933,6 @@ class CodeEditor
921
933
  idx = 0;
922
934
  }
923
935
 
924
- this.setScrollLeft( 0 );
925
936
  this.mergeCursors( ln );
926
937
 
927
938
  if( e.shiftKey && !e.cancelShift )
@@ -953,10 +964,10 @@ class CodeEditor
953
964
  }
954
965
  });
955
966
 
956
- this.action( 'End', false, ( ln, cursor, e ) => {
957
-
958
- if( ( e.shiftKey || e._shiftKey ) && !e.cancelShift ) {
959
-
967
+ this.action( 'End', false, ( ln, cursor, e ) =>
968
+ {
969
+ if( ( e.shiftKey || e._shiftKey ) && !e.cancelShift )
970
+ {
960
971
  var string = this.code.lines[ ln ].substring( cursor.position );
961
972
  if( !cursor.selection )
962
973
  this.startSelection( cursor );
@@ -1075,11 +1086,14 @@ class CodeEditor
1075
1086
  const letter = this.getCharAtPos( cursor );
1076
1087
 
1077
1088
  // Go to end of line if out of range
1078
- if( !letter || !canGoDown ) {
1079
- this.cursorToPosition( cursor, Math.max(this.code.lines[ cursor.line ].length, 0) );
1089
+ if( !letter || !canGoDown )
1090
+ {
1091
+ this.resetCursorPos( CodeEditor.CURSOR_LEFT, cursor );
1092
+ this.cursorToRight( this.code.lines[ cursor.line ], cursor );
1080
1093
  }
1081
1094
 
1082
- if( e.shiftKey ) {
1095
+ if( e.shiftKey )
1096
+ {
1083
1097
  this._processSelection( cursor, e );
1084
1098
  }
1085
1099
  }
@@ -1145,8 +1159,8 @@ class CodeEditor
1145
1159
  else {
1146
1160
  cursor.selection.invertIfNecessary();
1147
1161
  this.resetCursorPos( CodeEditor.CURSOR_LEFT_TOP, cursor );
1148
- this.cursorToLine( cursor, cursor.selection.fromY, true );
1149
- this.cursorToPosition( cursor, cursor.selection.fromX );
1162
+ this.cursorToLine( cursor, cursor.selection.fromY );
1163
+ this.cursorToPosition( cursor, cursor.selection.fromX, true );
1150
1164
  this.endSelection();
1151
1165
  }
1152
1166
  }
@@ -1228,7 +1242,7 @@ class CodeEditor
1228
1242
  cursor.selection.invertIfNecessary();
1229
1243
  this.resetCursorPos( CodeEditor.CURSOR_LEFT_TOP, cursor );
1230
1244
  this.cursorToLine( cursor, cursor.selection.toY );
1231
- this.cursorToPosition( cursor, cursor.selection.toX );
1245
+ this.cursorToPosition( cursor, cursor.selection.toX, true );
1232
1246
  this.endSelection( cursor );
1233
1247
  }
1234
1248
  }
@@ -1259,8 +1273,8 @@ class CodeEditor
1259
1273
  this.loadedTabs = { };
1260
1274
  this.openedTabs = { };
1261
1275
 
1262
- const onLoadAll = () => {
1263
-
1276
+ const onLoadAll = async () =>
1277
+ {
1264
1278
  // Create inspector panel when the initial state is complete
1265
1279
  // and we have at least 1 tab opened
1266
1280
  this.statusPanel = this._createStatusPanel( options );
@@ -1269,44 +1283,46 @@ class CodeEditor
1269
1283
  area.attach( this.statusPanel );
1270
1284
  }
1271
1285
 
1272
- // Wait until the fonts are all loaded
1273
- document.fonts.ready.then(() => {
1274
- // Load any font size from local storage
1275
- const savedFontSize = window.localStorage.getItem( "lexcodeeditor-font-size" );
1276
- if( savedFontSize )
1277
- {
1278
- this._setFontSize( parseInt( savedFontSize ) );
1279
- }
1280
- else // Use default size
1281
- {
1282
- const r = document.querySelector( ':root' );
1283
- const s = getComputedStyle( r );
1284
- this.fontSize = parseInt( s.getPropertyValue( "--code-editor-font-size" ) );
1285
- this.charWidth = this._measureChar( "a", true );
1286
- this.processLines();
1287
- }
1286
+ if( document.fonts.status == "loading" )
1287
+ {
1288
+ await document.fonts.ready;
1289
+ }
1288
1290
 
1289
- LX.emit( "@font-size", this.fontSize );
1291
+ // Load any font size from local storage
1292
+ const savedFontSize = window.localStorage.getItem( "lexcodeeditor-font-size" );
1293
+ if( savedFontSize )
1294
+ {
1295
+ this._setFontSize( parseInt( savedFontSize ) );
1296
+ }
1297
+ else // Use default size
1298
+ {
1299
+ const r = document.querySelector( ':root' );
1300
+ const s = getComputedStyle( r );
1301
+ this.fontSize = parseInt( s.getPropertyValue( "--code-editor-font-size" ) );
1302
+ this.charWidth = this._measureChar();
1303
+ this.processLines();
1304
+ }
1290
1305
 
1291
- // Get final sizes for editor elements based on Tabs and status bar offsets
1292
- LX.doAsync( () => {
1293
- this._verticalTopOffset = this.tabs?.root.getBoundingClientRect().height ?? 0;
1294
- this._verticalBottomOffset = this.statusPanel?.root.getBoundingClientRect().height ?? 0;
1295
- this._fullVerticalOffset = this._verticalTopOffset + this._verticalBottomOffset;
1306
+ LX.emit( "@font-size", this.fontSize );
1296
1307
 
1297
- this.gutter.style.marginTop = `${ this._verticalTopOffset }px`;
1298
- this.gutter.style.height = `calc(100% - ${ this._fullVerticalOffset }px)`;
1299
- this.vScrollbar.root.style.marginTop = `${ this._verticalTopOffset }px`;
1300
- this.vScrollbar.root.style.height = `calc(100% - ${ this._fullVerticalOffset }px)`;
1301
- this.hScrollbar.root.style.bottom = `${ this._verticalBottomOffset }px`;
1302
- this.codeArea.root.style.height = `calc(100% - ${ this._fullVerticalOffset }px)`;
1303
- }, 50 );
1308
+ // Get final sizes for editor elements based on Tabs and status bar offsets
1309
+ LX.doAsync( () => {
1310
+ this._verticalTopOffset = this.tabs?.root.getBoundingClientRect().height ?? 0;
1311
+ this._verticalBottomOffset = this.statusPanel?.root.getBoundingClientRect().height ?? 0;
1312
+ this._fullVerticalOffset = this._verticalTopOffset + this._verticalBottomOffset;
1304
1313
 
1305
- if( options.callback )
1306
- {
1307
- options.callback.call( this, this );
1308
- }
1309
- });
1314
+ this.gutter.style.marginTop = `${ this._verticalTopOffset }px`;
1315
+ this.gutter.style.height = `calc(100% - ${ this._fullVerticalOffset }px)`;
1316
+ this.vScrollbar.root.style.marginTop = `${ this._verticalTopOffset }px`;
1317
+ this.vScrollbar.root.style.height = `calc(100% - ${ this._fullVerticalOffset }px)`;
1318
+ this.hScrollbar.root.style.bottom = `${ this._verticalBottomOffset }px`;
1319
+ this.codeArea.root.style.height = `calc(100% - ${ this._fullVerticalOffset }px)`;
1320
+ }, 50 );
1321
+
1322
+ if( options.callback )
1323
+ {
1324
+ options.callback.call( this, this );
1325
+ }
1310
1326
 
1311
1327
  window.editor = this;
1312
1328
  };
@@ -1342,13 +1358,13 @@ class CodeEditor
1342
1358
  }});
1343
1359
  }
1344
1360
  }
1345
- else if( options.defaultTab ?? true )
1346
- {
1347
- this.addTab( options.name || "untitled", true, options.title, { language: options.highlight ?? "Plain Text" } );
1348
- onLoadAll();
1349
- }
1350
1361
  else
1351
1362
  {
1363
+ if( options.defaultTab ?? true )
1364
+ {
1365
+ this.addTab( options.name || "untitled", true, options.title, { language: options.highlight ?? "Plain Text" } );
1366
+ }
1367
+
1352
1368
  onLoadAll();
1353
1369
  }
1354
1370
  }
@@ -1403,7 +1419,7 @@ class CodeEditor
1403
1419
  let lastLine = newLines.pop();
1404
1420
 
1405
1421
  this.cursorToLine( cursor, newLines.length ); // Already substracted 1
1406
- this.cursorToPosition( cursor, lastLine.length );
1422
+ this.cursorToPosition( cursor, lastLine.length, true );
1407
1423
 
1408
1424
  this.mustProcessLines = true;
1409
1425
 
@@ -1727,7 +1743,7 @@ class CodeEditor
1727
1743
  // Update explorer icon
1728
1744
  if( this.useFileExplorer )
1729
1745
  {
1730
- const item = this.explorer.innerTree.data.children.filter( (v) => v.id === this.code.tabName )[ 0 ];
1746
+ const item = this.explorer.innerTree.data.filter( (v) => v.id === this.code.tabName )[ 0 ];
1731
1747
  console.assert( item != undefined );
1732
1748
  item.icon = icon;
1733
1749
  this.explorer.innerTree.frefresh( this.code.tabName );
@@ -1813,7 +1829,8 @@ class CodeEditor
1813
1829
  for( const lang of Object.keys( CodeEditor.languages ) )
1814
1830
  {
1815
1831
  m.add( lang, v => {
1816
- this._changeLanguage( v, null, true )
1832
+ this._changeLanguage( v, null, true );
1833
+ this.processLines();
1817
1834
  } );
1818
1835
  }
1819
1836
  });
@@ -2078,7 +2095,7 @@ class CodeEditor
2078
2095
  });
2079
2096
  code.addEventListener( 'dragleave', function(e) {
2080
2097
  e.preventDefault();
2081
- this.parentElement.remove( 'dragging' );
2098
+ this.parentElement.classList.remove( 'dragging' );
2082
2099
  });
2083
2100
  code.addEventListener( 'drop', e => {
2084
2101
  e.preventDefault();
@@ -2136,7 +2153,7 @@ class CodeEditor
2136
2153
 
2137
2154
  if( selected )
2138
2155
  {
2139
- this.resetCursorPos( CodeEditor.CURSOR_LEFT_TOP );
2156
+ this.resetCursorPos( CodeEditor.CURSOR_LEFT_TOP, undefined, true );
2140
2157
  this.mustProcessLines = true;
2141
2158
  }
2142
2159
  else
@@ -2204,7 +2221,7 @@ class CodeEditor
2204
2221
  this.code = code;
2205
2222
  this.mustProcessLines = true;
2206
2223
 
2207
- this.resetCursorPos( CodeEditor.CURSOR_LEFT_TOP );
2224
+ this.resetCursorPos( CodeEditor.CURSOR_LEFT_TOP, undefined, true );
2208
2225
  this.processLines();
2209
2226
  this._changeLanguageFromExtension( LX.getExtension( name ) );
2210
2227
  this._processLinesIfNecessary();
@@ -2249,6 +2266,9 @@ class CodeEditor
2249
2266
  return;
2250
2267
  }
2251
2268
 
2269
+ // Reset visibility
2270
+ code.style.display = "block";
2271
+
2252
2272
  this.openedTabs[ name ] = code;
2253
2273
 
2254
2274
  const isNewTabButton = ( name === '+' );
@@ -2271,10 +2291,11 @@ class CodeEditor
2271
2291
 
2272
2292
  // Select as current...
2273
2293
  this.code = code;
2274
- this.resetCursorPos( CodeEditor.CURSOR_LEFT_TOP );
2275
- this.processLines();
2294
+ this.resetCursorPos( CodeEditor.CURSOR_LEFT_TOP, undefined, true );
2276
2295
  this._changeLanguageFromExtension( LX.getExtension( name ) );
2277
2296
  this._updateDataInfoPanel( "@tab-name", code.tabName );
2297
+
2298
+ this.processLines();
2278
2299
  }
2279
2300
 
2280
2301
  closeTab( name, eraseAll )
@@ -2358,8 +2379,8 @@ class CodeEditor
2358
2379
  }
2359
2380
  }
2360
2381
 
2382
+ this._mouseDown = true;
2361
2383
  this.lastMouseDown = LX.getTime();
2362
- this.state.selectingText = true;
2363
2384
  this.endSelection();
2364
2385
  this.processClick( e );
2365
2386
  }
@@ -2371,8 +2392,11 @@ class CodeEditor
2371
2392
 
2372
2393
  else if( e.type == 'mousemove' )
2373
2394
  {
2374
- if( this.state.selectingText )
2395
+ if( this._mouseDown )
2396
+ {
2397
+ this.state.selectingText = true;
2375
2398
  this.processSelections( e );
2399
+ }
2376
2400
  }
2377
2401
 
2378
2402
  else if ( e.type == 'click' ) // trip
@@ -2391,7 +2415,7 @@ class CodeEditor
2391
2415
  case LX.MOUSE_TRIPLE_CLICK:
2392
2416
  this.resetCursorPos( CodeEditor.CURSOR_LEFT, cursor );
2393
2417
  e._shiftKey = true;
2394
- this.actions['End'].callback(cursor.line, cursor, e);
2418
+ this.actions['End'].callback( cursor.line, cursor, e );
2395
2419
  this._tripleClickSelection = true;
2396
2420
  break;
2397
2421
  }
@@ -2480,8 +2504,16 @@ class CodeEditor
2480
2504
  if( cursor.selection )
2481
2505
  {
2482
2506
  cursor.selection.invertIfNecessary();
2507
+
2508
+ // If single line selection and no chars selected, remove selection
2509
+ const deltaY = cursor.selection.toY - cursor.selection.fromY;
2510
+ if( cursor.selection.chars == 0 && deltaY == 0 )
2511
+ {
2512
+ this.endSelection();
2513
+ }
2483
2514
  }
2484
2515
 
2516
+ this._mouseDown = false;
2485
2517
  this.state.selectingText = false;
2486
2518
  delete this._lastSelectionKeyDir;
2487
2519
  }
@@ -2644,7 +2676,7 @@ class CodeEditor
2644
2676
 
2645
2677
  if( isVisible )
2646
2678
  {
2647
- domEl.style.width = ( stringWidth || 8 ) + "px";
2679
+ domEl.style.width = ( stringWidth || ( deltaY == 0 ? 0 : 8 ) ) + "px";
2648
2680
  domEl._top = i * this.lineHeight;
2649
2681
  domEl.style.top = domEl._top + "px";
2650
2682
  }
@@ -2763,10 +2795,15 @@ class CodeEditor
2763
2795
 
2764
2796
  cursorOffset.x += ( cursor.position - lastProcessedCursor.position );
2765
2797
  cursorOffset.y += ( cursor.line - lastProcessedCursor.line );
2798
+
2799
+ // Set active line in case it's blurred
2800
+ if( !cursor.selection )
2801
+ {
2802
+ cursor.line = cursor.line;
2803
+ }
2766
2804
  }
2767
2805
 
2768
2806
  // Clear tmp
2769
-
2770
2807
  delete this._lastProcessedCursorIndex;
2771
2808
  }
2772
2809
 
@@ -2868,6 +2905,7 @@ class CodeEditor
2868
2905
  async _processKeyAtCursor( e, key, cursor )
2869
2906
  {
2870
2907
  const skipUndo = e.detail.skipUndo ?? false;
2908
+ const skipDeleteSelection = e.detail.skipDeleteSelection ?? false;
2871
2909
 
2872
2910
  // keys with length > 1 are probably special keys
2873
2911
  if( key.length > 1 && this.specialKeys.indexOf( key ) == -1 )
@@ -2905,33 +2943,19 @@ class CodeEditor
2905
2943
  }
2906
2944
  }
2907
2945
  }
2908
-
2909
2946
  else if( e.altKey )
2910
2947
  {
2911
- switch( key ) {
2912
- case 'd': // duplicate line
2948
+ switch( key )
2949
+ {
2950
+ case 'd': // duplicate line
2913
2951
  e.preventDefault();
2914
2952
  this._duplicateLine( lidx, cursor );
2915
2953
  return;
2916
- case 'ArrowUp':
2917
- if(this.code.lines[ lidx - 1 ] == undefined)
2918
- return;
2919
- this._addUndoStep( cursor, true );
2920
- swapArrayElements( this.code.lines, lidx - 1, lidx );
2921
- this.lineUp( cursor );
2922
- this.processLine( lidx - 1 );
2923
- this.processLine( lidx );
2924
- this.hideAutoCompleteBox();
2954
+ case 'ArrowUp':
2955
+ this.swapLines( lidx, -1, cursor );
2925
2956
  return;
2926
2957
  case 'ArrowDown':
2927
- if(this.code.lines[ lidx + 1 ] == undefined)
2928
- return;
2929
- this._addUndoStep( cursor, true );
2930
- swapArrayElements( this.code.lines, lidx, lidx + 1 );
2931
- this.lineDown( cursor );
2932
- this.processLine( lidx );
2933
- this.processLine( lidx + 1 );
2934
- this.hideAutoCompleteBox();
2958
+ this.swapLines( lidx, 1, cursor );
2935
2959
  return;
2936
2960
  }
2937
2961
  }
@@ -2946,7 +2970,9 @@ class CodeEditor
2946
2970
  e.preventDefault();
2947
2971
 
2948
2972
  if( this._actionMustDelete( cursor, this.actions[ key ], e ) )
2973
+ {
2949
2974
  this.actions['Backspace'].callback( lidx, cursor, e );
2975
+ }
2950
2976
 
2951
2977
  return this.actions[ key ].callback( lidx, cursor, e );
2952
2978
  }
@@ -2974,7 +3000,7 @@ class CodeEditor
2974
3000
  // Until this point, if there was a selection, we need
2975
3001
  // to delete the content..
2976
3002
 
2977
- if( cursor.selection )
3003
+ if( cursor.selection && !skipDeleteSelection )
2978
3004
  {
2979
3005
  this.actions['Backspace'].callback( lidx, cursor, e );
2980
3006
  lidx = cursor.line;
@@ -3308,20 +3334,20 @@ class CodeEditor
3308
3334
  }
3309
3335
  }
3310
3336
 
3311
- action( key, deleteSelection, fn, eventSkipDelete )
3337
+ action( key, deleteSelection, fn, eventSkipDeleteFn )
3312
3338
  {
3313
3339
  this.actions[ key ] = {
3314
3340
  "key": key,
3315
3341
  "callback": fn,
3316
3342
  "deleteSelection": deleteSelection,
3317
- "eventSkipDelete": eventSkipDelete
3343
+ "eventSkipDeleteFn": eventSkipDeleteFn
3318
3344
  };
3319
3345
  }
3320
3346
 
3321
3347
  _actionMustDelete( cursor, action, e )
3322
3348
  {
3323
3349
  return cursor.selection && action.deleteSelection &&
3324
- ( action.eventSkipDelete ? !e[ action.eventSkipDelete ] : true );
3350
+ !( action.eventSkipDeleteFn ? action.eventSkipDeleteFn( cursor, e ) : false );
3325
3351
  }
3326
3352
 
3327
3353
  scanWordSuggestions()
@@ -4542,35 +4568,43 @@ class CodeEditor
4542
4568
  const tokenSet = new Set( this._getTokensFromLine( text, true ) );
4543
4569
  const scores = {};
4544
4570
 
4545
- for( let [ lang, wordList ] of Object.entries( CodeEditor.keywords ) )
4546
- {
4547
- scores[ lang ] = 0;
4548
- for( let kw of wordList )
4549
- if( tokenSet.has( kw ) ) scores[ lang ]++;
4550
- }
4551
-
4552
- for( let [ lang, wordList ] of Object.entries( CodeEditor.statements ) )
4553
- {
4554
- for( let kw of wordList )
4555
- if( tokenSet.has( kw ) ) scores[ lang ]++;
4556
- }
4571
+ // Check strong indicators first
4572
+ const strongIndicators = {
4573
+ "JavaScript": ["import ", "export default", "console.", "=>", "document.", "window."],
4574
+ "TypeScript": ["import ", "export default", "console.", "=>", "document.", "window."],
4575
+ "C++": ["#include", "::", "std::", "template <", "using namespace"],
4576
+ "Python": ["def ", "import ", "print(", "self", "None", "True", "False"],
4577
+ "HTML": ["<html", "<div", "<body", "<script", "<style"],
4578
+ "CSS": ["@media"],
4579
+ "Markdown": ["#", "##", "###", "](", "![", "**"],
4580
+ };
4557
4581
 
4558
- for( let [ lang, wordList ] of Object.entries( CodeEditor.utils ) )
4582
+ for( const [ lang, indicators ] of Object.entries( strongIndicators ) )
4559
4583
  {
4560
- for( let kw of wordList )
4561
- if( tokenSet.has( kw ) ) scores[ lang ]++;
4584
+ scores[ lang ] = scores[ lang ] ?? 0;
4585
+ for( const key of indicators )
4586
+ {
4587
+ if( text.includes( key ) ) scores[ lang ] += 20;
4588
+ }
4562
4589
  }
4563
4590
 
4564
- for( let [ lang, wordList ] of Object.entries( CodeEditor.types ) )
4565
- {
4566
- for( let kw of wordList )
4567
- if( tokenSet.has( kw ) ) scores[ lang ]++;
4568
- }
4591
+ // Check groups' words now with less importance score
4592
+ const groups = [
4593
+ CodeEditor.keywords,
4594
+ CodeEditor.statements,
4595
+ CodeEditor.utils,
4596
+ CodeEditor.types,
4597
+ CodeEditor.builtIn,
4598
+ ];
4569
4599
 
4570
- for( let [ lang, wordList ] of Object.entries( CodeEditor.builtIn ) )
4600
+ for( const group of groups )
4571
4601
  {
4572
- for( let kw of wordList )
4573
- if( tokenSet.has( kw ) ) scores[ lang ]++;
4602
+ for( let [ lang, wordList ] of Object.entries( group ) )
4603
+ {
4604
+ scores[ lang ] = scores[ lang ] ?? 0;
4605
+ for( let kw of wordList )
4606
+ if( tokenSet.has( kw ) ) scores[ lang ]++;
4607
+ }
4574
4608
  }
4575
4609
 
4576
4610
  const sorted = Object.entries( scores ).sort( ( a, b ) => b[ 1 ] - a[ 1 ] );
@@ -4601,6 +4635,33 @@ class CodeEditor
4601
4635
  return true;
4602
4636
  }
4603
4637
 
4638
+ swapLines( lidx, offset, cursor )
4639
+ {
4640
+ if( this.code.lines[ lidx + offset ] == undefined )
4641
+ {
4642
+ return;
4643
+ }
4644
+
4645
+ this._addUndoStep( cursor, true );
4646
+
4647
+ swapArrayElements( this.code.lines, lidx + offset, lidx );
4648
+
4649
+ // Process both lines
4650
+ this.processLine( lidx + offset );
4651
+ this.processLine( lidx );
4652
+
4653
+ if( offset > 0 )
4654
+ {
4655
+ this.lineDown( cursor );
4656
+ }
4657
+ else
4658
+ {
4659
+ this.lineUp( cursor );
4660
+ }
4661
+
4662
+ this.hideAutoCompleteBox();
4663
+ }
4664
+
4604
4665
  restartBlink()
4605
4666
  {
4606
4667
  if( !this.code ) return;
@@ -4675,11 +4736,13 @@ class CodeEditor
4675
4736
  LX.deleteElement( this.selections[ cursor.name ] );
4676
4737
  delete this.selections[ cursor.name ];
4677
4738
  delete cursor.selection;
4739
+ cursor.line = cursor.line; // Update current line
4678
4740
  }
4679
4741
  else
4680
4742
  {
4681
4743
  for( let cursor of this.cursors.children )
4682
4744
  {
4745
+ cursor.line = cursor.line; // Update current line
4683
4746
  LX.deleteElement( this.selections[ cursor.name ] );
4684
4747
  delete this.selections[ cursor.name ];
4685
4748
  delete cursor.selection;
@@ -4695,7 +4758,7 @@ class CodeEditor
4695
4758
  this._removeSecondaryCursors();
4696
4759
 
4697
4760
  var cursor = this.getCurrentCursor();
4698
- this.resetCursorPos( CodeEditor.CURSOR_LEFT_TOP, cursor );
4761
+ this.resetCursorPos( CodeEditor.CURSOR_LEFT_TOP, cursor, true );
4699
4762
 
4700
4763
  this.startSelection( cursor );
4701
4764
 
@@ -4724,18 +4787,7 @@ class CodeEditor
4724
4787
 
4725
4788
  this.restartBlink();
4726
4789
 
4727
- // Add horizontal scroll
4728
- const rightMargin = this.charWidth;
4729
- const cursorX = ( cursor.position * this.charWidth );
4730
- const currentScrollLeft = this.getScrollLeft();
4731
- const viewportSizeX = this.codeScroller.clientWidth - CodeEditor.LINE_GUTTER_WIDTH; // Gutter offset
4732
- const viewportX = viewportSizeX + currentScrollLeft;
4733
-
4734
- if( cursorX >= ( viewportX - rightMargin ) )
4735
- {
4736
- const scroll = Math.max( cursorX - ( viewportSizeX - rightMargin ), 0 );
4737
- this.setScrollLeft( scroll );
4738
- }
4790
+ this.updateScrollLeft( cursor );
4739
4791
  }
4740
4792
 
4741
4793
  cursorToLeft( text, cursor )
@@ -4753,15 +4805,18 @@ class CodeEditor
4753
4805
 
4754
4806
  this.restartBlink();
4755
4807
 
4756
- // Add horizontal scroll
4757
- const leftMargin = this.charWidth;
4758
- const cursorX = ( cursor.position * this.charWidth );
4759
- const currentScrollLeft = this.getScrollLeft();
4760
-
4761
- if( cursorX < ( currentScrollLeft + leftMargin ) )
4808
+ // Check if we need to add scroll; if not then we might have to reduce it
4809
+ if( !this.updateScrollLeft( cursor ) )
4762
4810
  {
4763
- const scroll = Math.max( cursorX - leftMargin, 0 );
4764
- this.setScrollLeft( scroll );
4811
+ const leftMargin = this.charWidth;
4812
+ const cursorX = ( cursor.position * this.charWidth );
4813
+ const currentScrollLeft = this.getScrollLeft();
4814
+
4815
+ if( cursorX < ( currentScrollLeft + leftMargin ) )
4816
+ {
4817
+ const scroll = Math.max( cursorX - leftMargin, 0 );
4818
+ this.setScrollLeft( scroll );
4819
+ }
4765
4820
  }
4766
4821
  }
4767
4822
 
@@ -4774,7 +4829,7 @@ class CodeEditor
4774
4829
 
4775
4830
  if( resetLeft )
4776
4831
  {
4777
- this.resetCursorPos( CodeEditor.CURSOR_LEFT, cursor );
4832
+ this.resetCursorPos( CodeEditor.CURSOR_LEFT, cursor, true );
4778
4833
  }
4779
4834
 
4780
4835
  const currentScrollTop = this.getScrollTop();
@@ -4794,7 +4849,7 @@ class CodeEditor
4794
4849
 
4795
4850
  if( resetLeft )
4796
4851
  {
4797
- this.resetCursorPos( CodeEditor.CURSOR_LEFT, cursor );
4852
+ this.resetCursorPos( CodeEditor.CURSOR_LEFT, cursor, true );
4798
4853
  }
4799
4854
 
4800
4855
  const currentScrollTop = this.getScrollTop();
@@ -4823,11 +4878,16 @@ class CodeEditor
4823
4878
  }
4824
4879
  }
4825
4880
 
4826
- cursorToPosition( cursor, position )
4881
+ cursorToPosition( cursor, position, updateScroll = false )
4827
4882
  {
4828
4883
  cursor.position = position;
4829
4884
  cursor._left = position * this.charWidth;
4830
4885
  cursor.style.left = `calc( ${ cursor._left }px + ${ this.xPadding } )`;
4886
+
4887
+ if( updateScroll )
4888
+ {
4889
+ this.updateScrollLeft( cursor );
4890
+ }
4831
4891
  }
4832
4892
 
4833
4893
  cursorToLine( cursor, line, resetLeft = false )
@@ -4918,7 +4978,7 @@ class CodeEditor
4918
4978
  LX.deleteElement( cursor );
4919
4979
  }
4920
4980
 
4921
- resetCursorPos( flag, cursor )
4981
+ resetCursorPos( flag, cursor, resetScroll = false )
4922
4982
  {
4923
4983
  cursor = cursor ?? this.getCurrentCursor();
4924
4984
 
@@ -4927,7 +4987,11 @@ class CodeEditor
4927
4987
  cursor._left = 0;
4928
4988
  cursor.style.left = "calc(" + this.xPadding + ")";
4929
4989
  cursor.position = 0;
4930
- this.setScrollLeft( 0 );
4990
+
4991
+ if( resetScroll )
4992
+ {
4993
+ this.setScrollLeft( 0 );
4994
+ }
4931
4995
  }
4932
4996
 
4933
4997
  if( flag & CodeEditor.CURSOR_TOP )
@@ -4935,7 +4999,11 @@ class CodeEditor
4935
4999
  cursor._top = 0;
4936
5000
  cursor.style.top = "0px";
4937
5001
  cursor.line = 0;
4938
- this.setScrollTop( 0 )
5002
+
5003
+ if( resetScroll )
5004
+ {
5005
+ this.setScrollTop( 0 );
5006
+ }
4939
5007
  }
4940
5008
  }
4941
5009
 
@@ -5024,8 +5092,56 @@ class CodeEditor
5024
5092
  }
5025
5093
  }
5026
5094
 
5027
- _addSpaces( n )
5095
+ _addSpaces( cursor, n )
5028
5096
  {
5097
+ if( cursor.selection && !cursor.selection.sameLine() )
5098
+ {
5099
+ cursor.selection.invertIfNecessary();
5100
+
5101
+ for( let lidx = cursor.selection.fromY; lidx <= cursor.selection.toY; ++lidx )
5102
+ {
5103
+ // Remove indentation
5104
+ let lineStart = firstNonspaceIndex( this.code.lines[ lidx ] );
5105
+
5106
+ // Only tabs/spaces in the line...
5107
+ if( lineStart == -1 )
5108
+ {
5109
+ lineStart = this.code.lines[ lidx ].length;
5110
+ }
5111
+
5112
+ let indentSpaces = lineStart % this.tabSpaces;
5113
+ indentSpaces = indentSpaces == 0 ? this.tabSpaces : this.tabSpaces - indentSpaces;
5114
+
5115
+ const spacesString = " ".repeat( indentSpaces );
5116
+
5117
+ this.code.lines[ lidx ] = [
5118
+ this.code.lines[ lidx ].slice( 0, lineStart ),
5119
+ spacesString,
5120
+ this.code.lines[ lidx ].slice( lineStart )
5121
+ ].join('');
5122
+
5123
+ this.processLine( lidx );
5124
+
5125
+ if( cursor.line === lidx )
5126
+ {
5127
+ this.cursorToString( cursor, spacesString );
5128
+ }
5129
+
5130
+ if( cursor.selection.fromY === lidx )
5131
+ {
5132
+ cursor.selection.fromX = Math.max( cursor.selection.fromX + indentSpaces, 0 );
5133
+ }
5134
+ if( cursor.selection.toY === lidx )
5135
+ {
5136
+ cursor.selection.toX = Math.max( cursor.selection.toX + indentSpaces, 0 );
5137
+ }
5138
+
5139
+ this._processSelection( cursor, undefined, true );
5140
+ }
5141
+
5142
+ return;
5143
+ }
5144
+
5029
5145
  for( var i = 0; i < n; ++i )
5030
5146
  {
5031
5147
  this.root.dispatchEvent( new CustomEvent( 'keydown', { 'detail': {
@@ -5038,41 +5154,79 @@ class CodeEditor
5038
5154
 
5039
5155
  _removeSpaces( cursor )
5040
5156
  {
5041
- const lidx = cursor.line;
5042
-
5043
- // Remove indentation
5044
- let lineStart = firstNonspaceIndex( this.code.lines[ lidx ] );
5045
-
5046
- // Nothing to remove... we are at the start of the line
5047
- if( lineStart == 0 )
5157
+ if( cursor.selection )
5048
5158
  {
5049
- return;
5159
+ cursor.selection.invertIfNecessary();
5050
5160
  }
5051
5161
 
5052
- // Only tabs/spaces in the line...
5053
- if( lineStart == -1 )
5162
+ const lCount = cursor.selection ? 1 + ( cursor.selection.toY - cursor.selection.fromY ) : 1;
5163
+
5164
+ for( let i = 0; i < lCount; ++i )
5054
5165
  {
5055
- lineStart = this.code.lines[ lidx ].length;
5056
- }
5166
+ const lidx = ( cursor.selection ? cursor.selection.fromY : cursor.line ) + i;
5057
5167
 
5058
- let indentSpaces = lineStart % this.tabSpaces;
5059
- indentSpaces = indentSpaces == 0 ? this.tabSpaces : indentSpaces;
5060
- const newStart = Math.max( lineStart - indentSpaces, 0 );
5168
+ // Remove indentation
5169
+ let lineStart = firstNonspaceIndex( this.code.lines[ lidx ] );
5061
5170
 
5062
- this.code.lines[ lidx ] = [
5063
- this.code.lines[ lidx ].slice( 0, newStart ),
5064
- this.code.lines[ lidx ].slice( lineStart )
5065
- ].join('');
5171
+ // Nothing to remove... we are at the start of the line
5172
+ if( lineStart == 0 )
5173
+ {
5174
+ continue;
5175
+ }
5066
5176
 
5067
- this.processLine( lidx );
5177
+ // Only tabs/spaces in the line...
5178
+ if( lineStart == -1 )
5179
+ {
5180
+ lineStart = this.code.lines[ lidx ].length;
5181
+ }
5068
5182
 
5069
- this.cursorToString( cursor, " ".repeat( indentSpaces ), true );
5183
+ let indentSpaces = lineStart % this.tabSpaces;
5184
+ indentSpaces = indentSpaces == 0 ? this.tabSpaces : indentSpaces;
5185
+ const newStart = Math.max( lineStart - indentSpaces, 0 );
5070
5186
 
5071
- if( cursor.selection )
5187
+ this.code.lines[ lidx ] = [
5188
+ this.code.lines[ lidx ].slice( 0, newStart ),
5189
+ this.code.lines[ lidx ].slice( lineStart )
5190
+ ].join('');
5191
+
5192
+ this.processLine( lidx );
5193
+
5194
+ if( cursor.line === lidx )
5195
+ {
5196
+ this.cursorToString( cursor, " ".repeat( indentSpaces ), true );
5197
+ }
5198
+
5199
+ if( cursor.selection )
5200
+ {
5201
+ if( cursor.selection.fromY === lidx )
5202
+ {
5203
+ cursor.selection.fromX = Math.max( cursor.selection.fromX - indentSpaces, 0 );
5204
+ }
5205
+ if( cursor.selection.toY === lidx )
5206
+ {
5207
+ cursor.selection.toX = Math.max( cursor.selection.toX - indentSpaces, 0 );
5208
+ }
5209
+
5210
+ this._processSelection( cursor, undefined, true );
5211
+ }
5212
+ }
5213
+ }
5214
+
5215
+ updateScrollLeft( cursor )
5216
+ {
5217
+ cursor = cursor ?? this.getCurrentCursor();
5218
+
5219
+ const rightMargin = this.charWidth;
5220
+ const cursorX = ( cursor.position * this.charWidth );
5221
+ const currentScrollLeft = this.getScrollLeft();
5222
+ const viewportSizeX = this.codeScroller.clientWidth - CodeEditor.LINE_GUTTER_WIDTH; // Gutter offset
5223
+ const viewportX = viewportSizeX + currentScrollLeft;
5224
+
5225
+ if( cursorX >= ( viewportX - rightMargin ) )
5072
5226
  {
5073
- cursor.selection.invertIfNecessary();
5074
- cursor.selection.fromX = Math.max( cursor.selection.fromX - indentSpaces, 0 );
5075
- this._processSelection( cursor );
5227
+ const scroll = Math.max( cursorX - ( viewportSizeX - rightMargin ), 0 );
5228
+ this.setScrollLeft( scroll );
5229
+ return true;
5076
5230
  }
5077
5231
  }
5078
5232
 
@@ -5190,14 +5344,16 @@ class CodeEditor
5190
5344
  {
5191
5345
  if( type == 'vertical' )
5192
5346
  {
5193
- const scrollBarHeight = this.vScrollbar.thumb.parentElement.offsetHeight;
5194
- const scrollThumbHeight = this.vScrollbar.thumb.offsetHeight;
5195
-
5196
5347
  const scrollHeight = this.codeScroller.scrollHeight - this.codeScroller.clientHeight;
5197
- const currentScroll = this.codeScroller.scrollTop;
5198
5348
 
5199
- this.vScrollbar.thumb._top = ( currentScroll / scrollHeight ) * ( scrollBarHeight - scrollThumbHeight );
5200
- this.vScrollbar.thumb.style.top = this.vScrollbar.thumb._top + "px";
5349
+ if( scrollHeight > 0 )
5350
+ {
5351
+ const scrollBarHeight = this.vScrollbar.thumb.parentElement.offsetHeight;
5352
+ const scrollThumbHeight = this.vScrollbar.thumb.offsetHeight;
5353
+ const currentScroll = this.codeScroller.scrollTop;
5354
+ this.vScrollbar.thumb._top = ( currentScroll / scrollHeight ) * ( scrollBarHeight - scrollThumbHeight );
5355
+ this.vScrollbar.thumb.style.top = this.vScrollbar.thumb._top + "px";
5356
+ }
5201
5357
  }
5202
5358
  else
5203
5359
  {
@@ -5206,14 +5362,16 @@ class CodeEditor
5206
5362
  this.codeScroller.scrollLeft += value;
5207
5363
  }
5208
5364
 
5209
- const scrollBarWidth = this.hScrollbar.thumb.parentElement.offsetWidth;
5210
- const scrollThumbWidth = this.hScrollbar.thumb.offsetWidth;
5211
-
5365
+ // Only when scroll is needed
5212
5366
  const scrollWidth = this.codeScroller.scrollWidth - this.codeScroller.clientWidth;
5213
- const currentScroll = this.codeScroller.scrollLeft;
5214
-
5215
- this.hScrollbar.thumb._left = ( currentScroll / scrollWidth ) * ( scrollBarWidth - scrollThumbWidth );
5216
- this.hScrollbar.thumb.style.left = this.hScrollbar.thumb._left + "px";
5367
+ if( scrollWidth > 0 )
5368
+ {
5369
+ const scrollBarWidth = this.hScrollbar.thumb.parentElement.offsetWidth;
5370
+ const scrollThumbWidth = this.hScrollbar.thumb.offsetWidth;
5371
+ const currentScroll = this.codeScroller.scrollLeft;
5372
+ this.hScrollbar.thumb._left = ( currentScroll / scrollWidth ) * ( scrollBarWidth - scrollThumbWidth );
5373
+ this.hScrollbar.thumb.style.left = this.hScrollbar.thumb._left + "px";
5374
+ }
5217
5375
  }
5218
5376
  }
5219
5377
 
@@ -5235,7 +5393,6 @@ class CodeEditor
5235
5393
  const currentScroll = (this.hScrollbar.thumb._left * scrollWidth) / ( scrollBarWidth - scrollThumbWidth );
5236
5394
  this.codeScroller.scrollLeft = currentScroll;
5237
5395
 
5238
-
5239
5396
  this._discardScroll = true;
5240
5397
  }
5241
5398
 
@@ -5313,7 +5470,7 @@ class CodeEditor
5313
5470
  return [ word, from, to ];
5314
5471
  }
5315
5472
 
5316
- _measureChar( char = "a", useFloating = false, getBB = false )
5473
+ _measureChar( char = "M", useFloating = true, getBB = false )
5317
5474
  {
5318
5475
  const parentContainer = LX.makeContainer( null, "lexcodeeditor", "", document.body );
5319
5476
  const container = LX.makeContainer( null, "code", "", parentContainer );
@@ -5500,14 +5657,16 @@ class CodeEditor
5500
5657
  return;
5501
5658
  }
5502
5659
 
5660
+ const maxX = this.codeScroller.clientWidth - 256; // Viewport - box width
5661
+
5503
5662
  // Select always first option
5504
5663
  this.autocomplete.firstChild.classList.add( 'selected' );
5505
5664
 
5506
5665
  // Show box
5507
5666
  this.autocomplete.classList.toggle( 'show', true );
5508
5667
  this.autocomplete.classList.toggle( 'no-scrollbar', !( this.autocomplete.scrollHeight > this.autocomplete.offsetHeight ) );
5509
- this.autocomplete.style.left = (cursor._left + CodeEditor.LINE_GUTTER_WIDTH - this.getScrollLeft()) + "px";
5510
- this.autocomplete.style.top = (cursor._top + 28 + this.lineHeight - this.getScrollTop()) + "px";
5668
+ this.autocomplete.style.left = `${ Math.min( cursor._left + CodeEditor.LINE_GUTTER_WIDTH - this.getScrollLeft(), maxX ) }px`;
5669
+ this.autocomplete.style.top = `${ ( cursor._top + this._verticalTopOffset + this.lineHeight - this.getScrollTop() ) }px`;
5511
5670
 
5512
5671
  this.isAutoCompleteActive = true;
5513
5672
  }
@@ -5588,21 +5747,33 @@ class CodeEditor
5588
5747
 
5589
5748
  const [ word, idx ] = this._getSelectedAutoComplete();
5590
5749
  const offset = dir == 'down' ? 1 : -1;
5750
+ const fIdx = idx + offset;
5751
+
5752
+ const autocompleteRowHeight = 22;
5753
+ const autocompleteHeight = 132;
5591
5754
 
5592
5755
  if( dir == 'down' )
5593
5756
  {
5594
- if( ( idx + offset ) >= this.autocomplete.childElementCount ) return;
5757
+ if( fIdx >= this.autocomplete.childElementCount ) return;
5758
+
5759
+ if( ( ( idx + offset * 2 ) * autocompleteRowHeight ) - this.autocomplete.scrollTop > autocompleteHeight )
5760
+ {
5761
+ this.autocomplete.scrollTop += autocompleteRowHeight;
5762
+ }
5595
5763
  }
5596
5764
  else if( dir == 'up')
5597
5765
  {
5598
- if( ( idx + offset ) < 0 ) return;
5599
- }
5766
+ if( fIdx < 0 ) return;
5600
5767
 
5601
- this.autocomplete.scrollTop += offset * 20;
5768
+ if( ( fIdx * autocompleteRowHeight ) < this.autocomplete.scrollTop )
5769
+ {
5770
+ this.autocomplete.scrollTop -= autocompleteRowHeight;
5771
+ }
5772
+ }
5602
5773
 
5603
5774
  // Remove selected from the current word and add it to the next one
5604
- this.autocomplete.childNodes[ idx ].classList.remove('selected');
5605
- this.autocomplete.childNodes[ idx + offset ].classList.add('selected');
5775
+ this.autocomplete.childNodes[ idx ].classList.remove( 'selected' );
5776
+ this.autocomplete.childNodes[ idx + offset ].classList.add( 'selected' );
5606
5777
  }
5607
5778
 
5608
5779
  showSearchBox( clear )
@@ -5904,7 +6075,7 @@ class CodeEditor
5904
6075
  this.fontSize = size;
5905
6076
  const r = document.querySelector( ':root' );
5906
6077
  r.style.setProperty( "--code-editor-font-size", `${ this.fontSize }px` );
5907
- this.charWidth = this._measureChar( "a", true );
6078
+ this.charWidth = this._measureChar();
5908
6079
 
5909
6080
  window.localStorage.setItem( "lexcodeeditor-font-size", this.fontSize );
5910
6081
 
@@ -6019,9 +6190,9 @@ CodeEditor.declarationKeywords =
6019
6190
  CodeEditor.keywords =
6020
6191
  {
6021
6192
  'JavaScript': ['var', 'let', 'const', 'this', 'in', 'of', 'true', 'false', 'new', 'function', 'NaN', 'static', 'class', 'constructor', 'null', 'typeof', 'debugger', 'abstract',
6022
- 'arguments', 'extends', 'instanceof', 'Infinity'],
6193
+ 'arguments', 'extends', 'instanceof', 'Infinity', 'get'],
6023
6194
  'TypeScript': ['var', 'let', 'const', 'this', 'in', 'of', 'true', 'false', 'new', 'function', 'class', 'extends', 'instanceof', 'Infinity', 'private', 'public', 'protected', 'interface',
6024
- 'enum', 'type'],
6195
+ 'enum', 'type', 'get'],
6025
6196
  'C': ['int', 'float', 'double', 'long', 'short', 'char', 'const', 'void', 'true', 'false', 'auto', 'struct', 'typedef', 'signed', 'volatile', 'unsigned', 'static', 'extern', 'enum', 'register',
6026
6197
  'union'],
6027
6198
  'C++': [...CodeEditor.nativeTypes["C++"], 'const', 'static_cast', 'dynamic_cast', 'new', 'delete', 'true', 'false', 'auto', 'class', 'struct', 'typedef', 'nullptr',
@@ -6071,7 +6242,8 @@ CodeEditor.types =
6071
6242
  'JavaScript': ['Object', 'String', 'Function', 'Boolean', 'Symbol', 'Error', 'Number', 'TextEncoder', 'TextDecoder', 'Array', 'ArrayBuffer', 'InputEvent', 'MouseEvent',
6072
6243
  'Int8Array', 'Int16Array', 'Int32Array', 'Float32Array', 'Float64Array', 'Element'],
6073
6244
  'TypeScript': ['arguments', 'constructor', 'null', 'typeof', 'debugger', 'abstract', 'Object', 'string', 'String', 'Function', 'Boolean', 'boolean', 'Error', 'Number', 'number', 'TextEncoder',
6074
- 'TextDecoder', 'Array', 'ArrayBuffer', 'InputEvent', 'MouseEvent', 'Int8Array', 'Int16Array', 'Int32Array', 'Float32Array', 'Float64Array', 'Element'],
6245
+ 'TextDecoder', 'Array', 'ArrayBuffer', 'InputEvent', 'MouseEvent', 'Int8Array', 'Int16Array', 'Int32Array', 'Float32Array', 'Float64Array', 'Element', 'bigint', 'unknown', 'any',
6246
+ 'Record'],
6075
6247
  'Rust': ['u128'],
6076
6248
  'Python': ['int', 'type', 'float', 'map', 'list', 'ArithmeticError', 'AssertionError', 'AttributeError', 'Exception', 'EOFError', 'FloatingPointError', 'GeneratorExit',
6077
6249
  'ImportError', 'IndentationError', 'IndexError', 'KeyError', 'KeyboardInterrupt', 'LookupError', 'MemoryError', 'NameError', 'NotImplementedError', 'OSError',
@@ -6094,8 +6266,8 @@ CodeEditor.builtIn =
6094
6266
 
6095
6267
  CodeEditor.statements =
6096
6268
  {
6097
- 'JavaScript': ['for', 'if', 'else', 'case', 'switch', 'return', 'while', 'continue', 'break', 'do', 'import', 'from', 'throw', 'async', 'try', 'catch', 'await'],
6098
- 'TypeScript': ['for', 'if', 'else', 'case', 'switch', 'return', 'while', 'continue', 'break', 'do', 'import', 'from', 'throw', 'async', 'try', 'catch', 'await', 'as'],
6269
+ 'JavaScript': ['for', 'if', 'else', 'case', 'switch', 'return', 'while', 'continue', 'break', 'do', 'import', 'default', 'export', 'from', 'throw', 'async', 'try', 'catch', 'await', 'as'],
6270
+ 'TypeScript': ['for', 'if', 'else', 'case', 'switch', 'return', 'while', 'continue', 'break', 'do', 'import', 'default', 'export', 'from', 'throw', 'async', 'try', 'catch', 'await', 'as'],
6099
6271
  'CSS': ['@', 'import'],
6100
6272
  'C': ['for', 'if', 'else', 'return', 'continue', 'break', 'case', 'switch', 'while', 'using', 'default', 'goto', 'do'],
6101
6273
  'C++': ['std', 'for', 'if', 'else', 'return', 'continue', 'break', 'case', 'switch', 'while', 'using', 'glm', 'spdlog', 'default'],