lexgui 8.0.0 → 8.1.1

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.
Files changed (56) hide show
  1. package/README.md +3 -3
  2. package/build/components/AlertDialog.d.ts +7 -0
  3. package/build/components/Counter.d.ts +1 -0
  4. package/build/components/Dialog.d.ts +1 -1
  5. package/build/components/Footer.d.ts +1 -1
  6. package/build/components/Menubar.d.ts +2 -2
  7. package/build/core/Area.d.ts +22 -22
  8. package/build/core/Namespace.js +34 -34
  9. package/build/core/Namespace.js.map +1 -1
  10. package/build/core/Panel.d.ts +2 -3
  11. package/build/extensions/AssetView.d.ts +136 -134
  12. package/build/extensions/AssetView.js +1367 -1320
  13. package/build/extensions/AssetView.js.map +1 -1
  14. package/build/extensions/Audio.js +19 -19
  15. package/build/extensions/Audio.js.map +1 -1
  16. package/build/extensions/CodeEditor.js +867 -647
  17. package/build/extensions/CodeEditor.js.map +1 -1
  18. package/build/extensions/DocMaker.d.ts +1 -1
  19. package/build/extensions/DocMaker.js +73 -61
  20. package/build/extensions/DocMaker.js.map +1 -1
  21. package/build/extensions/GraphEditor.js +406 -305
  22. package/build/extensions/GraphEditor.js.map +1 -1
  23. package/build/extensions/ImUi.js +21 -20
  24. package/build/extensions/ImUi.js.map +1 -1
  25. package/build/extensions/Timeline.d.ts +29 -36
  26. package/build/extensions/Timeline.js +421 -424
  27. package/build/extensions/Timeline.js.map +1 -1
  28. package/build/extensions/VideoEditor.js +101 -97
  29. package/build/extensions/VideoEditor.js.map +1 -1
  30. package/build/extensions/index.d.ts +8 -8
  31. package/build/extensions/index.js +1 -1
  32. package/build/index.all.d.ts +2 -2
  33. package/build/index.css.d.ts +1 -1
  34. package/build/index.d.ts +56 -55
  35. package/build/lexgui.all.js +28488 -27640
  36. package/build/lexgui.all.js.map +1 -1
  37. package/build/lexgui.all.min.js +1 -1
  38. package/build/lexgui.all.module.js +28412 -27565
  39. package/build/lexgui.all.module.js.map +1 -1
  40. package/build/lexgui.all.module.min.js +1 -1
  41. package/build/lexgui.css +176 -69
  42. package/build/lexgui.js +13796 -13330
  43. package/build/lexgui.js.map +1 -1
  44. package/build/lexgui.min.css +1 -1
  45. package/build/lexgui.min.js +1 -1
  46. package/build/lexgui.module.js +13733 -13268
  47. package/build/lexgui.module.js.map +1 -1
  48. package/build/lexgui.module.min.js +1 -1
  49. package/changelog.md +22 -1
  50. package/demo.js +6 -5
  51. package/examples/all-components.html +3 -0
  52. package/examples/asset-view.html +52 -6
  53. package/examples/dialogs.html +3 -3
  54. package/examples/editor.html +1 -1
  55. package/examples/index.html +1 -1
  56. package/package.json +4 -1
@@ -3,7 +3,7 @@ import { LX } from '../core/Namespace.js';
3
3
 
4
4
  // CodeEditor.ts @jxarco
5
5
  if (!LX) {
6
- throw ("Missing LX namespace!");
6
+ throw ('Missing LX namespace!');
7
7
  }
8
8
  LX.extensions.push('CodeEditor');
9
9
  const g = globalThis;
@@ -13,20 +13,36 @@ LX.Panel;
13
13
  LX.Tree;
14
14
  LX.Tabs;
15
15
  LX.ContextMenu;
16
- function swapElements(obj, a, b) { [obj[a], obj[b]] = [obj[b], obj[a]]; }
17
- function swapArrayElements(array, id0, id1) { [array[id0], array[id1]] = [array[id1], array[id0]]; }
18
- function sliceChars(str, idx, n = 1) { return str.substr(0, idx) + str.substr(idx + n); }
19
- function firstNonspaceIndex(str) { const index = str.search(/\S|$/); return index < str.length ? index : -1; }
20
- function strReverse(str) { return str.split("").reverse().join(""); }
21
- function isLetter(c) { return /[a-zA-Z]/.test(c); }
22
- function isSymbol(c) { return /[^\w\s]/.test(c); }
16
+ function swapElements(obj, a, b) {
17
+ [obj[a], obj[b]] = [obj[b], obj[a]];
18
+ }
19
+ function swapArrayElements(array, id0, id1) {
20
+ [array[id0], array[id1]] = [array[id1], array[id0]];
21
+ }
22
+ function sliceChars(str, idx, n = 1) {
23
+ return str.substr(0, idx) + str.substr(idx + n);
24
+ }
25
+ function firstNonspaceIndex(str) {
26
+ const index = str.search(/\S|$/);
27
+ return index < str.length ? index : -1;
28
+ }
29
+ function strReverse(str) {
30
+ return str.split('').reverse().join('');
31
+ }
32
+ function isLetter(c) {
33
+ return /[a-zA-Z]/.test(c);
34
+ }
35
+ function isSymbol(c) {
36
+ return /[^\w\s]/.test(c);
37
+ }
23
38
  function indexOfFrom(str, reg, from, reverse = false) {
24
39
  from = from ?? 0;
25
40
  if (reverse) {
26
41
  str = str.substring(0, from);
27
42
  var k = from - 1;
28
- while (str[k] && str[k] != reg)
43
+ while (str[k] && str[k] != reg) {
29
44
  k--;
45
+ }
30
46
  return str[k] ? k : -1;
31
47
  }
32
48
  else {
@@ -45,24 +61,28 @@ function codeScopesEqual(a, b) {
45
61
  }
46
62
  class Cursor {
47
63
  root;
48
- name = "";
64
+ name = '';
49
65
  editor;
50
66
  isMain = false;
51
67
  selection = null;
52
68
  _line = 0;
53
69
  _position = 0;
54
- get line() { return this._line; }
70
+ get line() {
71
+ return this._line;
72
+ }
55
73
  set line(v) {
56
74
  this._line = v;
57
75
  if (this.isMain)
58
76
  this.editor._setActiveLine(v);
59
77
  }
60
- get position() { return this._position; }
78
+ get position() {
79
+ return this._position;
80
+ }
61
81
  set position(v) {
62
82
  this._position = v;
63
83
  if (this.isMain) {
64
84
  const activeLine = this.editor.state.activeLine;
65
- this.editor._updateDataInfoPanel("@cursor-data", `Ln ${activeLine + 1}, Col ${v + 1}`);
85
+ this.editor._updateDataInfoPanel('@cursor-data', `Ln ${activeLine + 1}, Col ${v + 1}`);
66
86
  }
67
87
  }
68
88
  left = 0;
@@ -73,8 +93,8 @@ class Cursor {
73
93
  this.isMain = isMain;
74
94
  this.root = document.createElement('div');
75
95
  this.root.name = name;
76
- this.root.className = "cursor";
77
- this.root.innerHTML = "&nbsp;";
96
+ this.root.className = 'cursor';
97
+ this.root.innerHTML = '&nbsp;';
78
98
  this.set(position, line, false);
79
99
  }
80
100
  set(position = 0, line = 0, updateEditor = true) {
@@ -107,7 +127,7 @@ class CodeSelection {
107
127
  editor;
108
128
  cursor;
109
129
  className;
110
- constructor(editor, cursor, className = "lexcodeselection") {
130
+ constructor(editor, cursor, className = 'lexcodeselection') {
111
131
  this.editor = editor;
112
132
  this.cursor = cursor;
113
133
  this.className = className;
@@ -142,10 +162,10 @@ class CodeSelection {
142
162
  var domEl = document.createElement('div');
143
163
  domEl.className = this.className;
144
164
  domEl._top = y * this.editor.lineHeight;
145
- domEl.style.top = domEl._top + "px";
165
+ domEl.style.top = domEl._top + 'px';
146
166
  domEl._left = x * this.editor.charWidth;
147
- domEl.style.left = "calc(" + domEl._left + "px + " + this.editor.xPadding + ")";
148
- domEl.style.width = width + "px";
167
+ domEl.style.left = 'calc(' + domEl._left + 'px + ' + this.editor.xPadding + ')';
168
+ domEl.style.width = width + 'px';
149
169
  if (isSearchResult) {
150
170
  this.editor.searchResultSelections.appendChild(domEl);
151
171
  }
@@ -190,40 +210,44 @@ class ScrollBar {
190
210
  this.editor = editor;
191
211
  this.type = type;
192
212
  this.root = document.createElement('div');
193
- this.root.className = "lexcodescrollbar hidden";
194
- if (type & ScrollBar.SCROLLBAR_VERTICAL)
213
+ this.root.className = 'lexcodescrollbar hidden';
214
+ if (type & ScrollBar.SCROLLBAR_VERTICAL) {
195
215
  this.root.classList.add('vertical');
196
- else if (type & ScrollBar.SCROLLBAR_HORIZONTAL)
216
+ }
217
+ else if (type & ScrollBar.SCROLLBAR_HORIZONTAL) {
197
218
  this.root.classList.add('horizontal');
219
+ }
198
220
  this.thumb = document.createElement('div');
199
221
  this.thumb._top = 0;
200
222
  this.thumb._left = 0;
201
223
  this.root.appendChild(this.thumb);
202
- this.thumb.addEventListener("mousedown", inner_mousedown);
224
+ this.thumb.addEventListener('mousedown', inner_mousedown);
203
225
  this.lastPosition = new LX.vec2(0, 0);
204
226
  let that = this;
205
227
  function inner_mousedown(e) {
206
228
  var doc = editor.root.ownerDocument;
207
- doc.addEventListener("mousemove", inner_mousemove);
208
- doc.addEventListener("mouseup", inner_mouseup);
229
+ doc.addEventListener('mousemove', inner_mousemove);
230
+ doc.addEventListener('mouseup', inner_mouseup);
209
231
  that.lastPosition.set(e.x, e.y);
210
232
  e.stopPropagation();
211
233
  e.preventDefault();
212
234
  }
213
235
  function inner_mousemove(e) {
214
236
  var dt = that.lastPosition.sub(new LX.vec2(e.x, e.y));
215
- if (that.type & ScrollBar.SCROLLBAR_VERTICAL)
237
+ if (that.type & ScrollBar.SCROLLBAR_VERTICAL) {
216
238
  editor.updateVerticalScrollFromScrollBar(dt.y);
217
- else
239
+ }
240
+ else {
218
241
  editor.updateHorizontalScrollFromScrollBar(dt.x);
242
+ }
219
243
  that.lastPosition.set(e.x, e.y);
220
244
  e.stopPropagation();
221
245
  e.preventDefault();
222
246
  }
223
247
  function inner_mouseup(e) {
224
248
  var doc = editor.root.ownerDocument;
225
- doc.removeEventListener("mousemove", inner_mousemove);
226
- doc.removeEventListener("mouseup", inner_mouseup);
249
+ doc.removeEventListener('mousemove', inner_mousemove);
250
+ doc.removeEventListener('mouseup', inner_mouseup);
227
251
  }
228
252
  }
229
253
  }
@@ -236,58 +260,106 @@ class ScrollBar {
236
260
  */
237
261
  const HighlightRules = {
238
262
  common: [
239
- { test: (ctx) => ctx.inBlockComment, className: "cm-com" },
240
- { test: (ctx) => ctx.inString, action: (ctx, editor) => editor._appendStringToken(ctx.token), discard: true },
241
- { test: (ctx) => ctx.token.substr(0, ctx.singleLineCommentToken.length) == ctx.singleLineCommentToken, className: "cm-com" },
242
- { test: (ctx, editor) => editor._isKeyword(ctx), className: "cm-kwd" },
243
- { test: (ctx, editor) => editor._mustHightlightWord(ctx.token, CE.builtIn, ctx.lang) && (ctx.lang.tags ?? false ? (editor._enclosedByTokens(ctx.token, ctx.tokenIndex, '<', '>')) : true), className: "cm-bln" },
244
- { test: (ctx, editor) => editor._mustHightlightWord(ctx.token, CE.statements, ctx.lang), className: "cm-std" },
245
- { test: (ctx, editor) => editor._mustHightlightWord(ctx.token, CE.symbols, ctx.lang), className: "cm-sym" },
246
- { test: (ctx, editor) => editor._mustHightlightWord(ctx.token, CE.types, ctx.lang), className: "cm-typ" },
247
- { test: (ctx, editor) => editor._isNumber(ctx.token) || editor._isNumber(ctx.token.replace(/[px]|[em]|%/g, '')), className: "cm-dec" },
248
- { test: (ctx) => ctx.lang.usePreprocessor && ctx.token.includes('#'), className: "cm-ppc" },
263
+ { test: (ctx) => ctx.inBlockComment, className: 'cm-com' },
264
+ { test: (ctx) => ctx.inString,
265
+ action: (ctx, editor) => editor._appendStringToken(ctx.token), discard: true },
266
+ { test: (ctx) => ctx.token.substr(0, ctx.singleLineCommentToken.length) == ctx.singleLineCommentToken,
267
+ className: 'cm-com' },
268
+ { test: (ctx, editor) => editor._isKeyword(ctx), className: 'cm-kwd' },
269
+ {
270
+ test: (ctx, editor) => editor._mustHightlightWord(ctx.token, CE.builtIn, ctx.lang) && (ctx.lang.tags ?? false
271
+ ? (editor._enclosedByTokens(ctx.token, ctx.tokenIndex, '<', '>'))
272
+ : true),
273
+ className: 'cm-bln'
274
+ },
275
+ { test: (ctx, editor) => editor._mustHightlightWord(ctx.token, CE.statements, ctx.lang),
276
+ className: 'cm-std' },
277
+ { test: (ctx, editor) => editor._mustHightlightWord(ctx.token, CE.symbols, ctx.lang),
278
+ className: 'cm-sym' },
279
+ { test: (ctx, editor) => editor._mustHightlightWord(ctx.token, CE.types, ctx.lang),
280
+ className: 'cm-typ' },
281
+ {
282
+ test: (ctx, editor) => editor._isNumber(ctx.token) || editor._isNumber(ctx.token.replace(/[px]|[em]|%/g, '')),
283
+ className: 'cm-dec'
284
+ },
285
+ { test: (ctx) => ctx.lang.usePreprocessor && ctx.token.includes('#'), className: 'cm-ppc' }
249
286
  ],
250
287
  javascript: [
251
- { test: (ctx) => (ctx.prev === 'class' && ctx.next === '{'), className: "cm-typ" },
288
+ { test: (ctx) => (ctx.prev === 'class' && ctx.next === '{'), className: 'cm-typ' }
252
289
  ],
253
290
  typescript: [
254
- { test: (ctx) => ctx.scope && (ctx.token !== ',' && ctx.scope.type == "enum"), className: "cm-enu" },
255
- { test: (ctx) => (ctx.prev === ':' && ctx.next !== undefined && isLetter(ctx.token)) || (ctx.prev === 'interface' && ctx.next === '{') || (ctx.prev === 'enum' && ctx.next === '{'), className: "cm-typ" },
256
- { test: (ctx) => (ctx.prev === 'class' && ctx.next === '{') || (ctx.prev === 'class' && ctx.next === '<') || (ctx.prev === 'new' && ctx.next === '(') || (ctx.prev === 'new' && ctx.next === '<'), className: "cm-typ" },
257
- { test: (ctx, editor) => ctx.token !== ',' && editor._enclosedByTokens(ctx.token, ctx.tokenIndex, '<', '>'), className: "cm-typ" },
291
+ { test: (ctx) => ctx.scope && (ctx.token !== ',' && ctx.scope.type == 'enum'), className: 'cm-enu' },
292
+ {
293
+ test: (ctx) => (ctx.prev === ':' && ctx.next !== undefined && isLetter(ctx.token))
294
+ || (ctx.prev === 'interface' && ctx.next === '{') || (ctx.prev === 'enum' && ctx.next === '{'),
295
+ className: 'cm-typ'
296
+ },
297
+ {
298
+ test: (ctx) => (ctx.prev === 'class' && ctx.next === '{') || (ctx.prev === 'class' && ctx.next === '<')
299
+ || (ctx.prev === 'new' && ctx.next === '(') || (ctx.prev === 'new' && ctx.next === '<'),
300
+ className: 'cm-typ'
301
+ },
302
+ {
303
+ test: (ctx, editor) => ctx.token !== ',' && editor._enclosedByTokens(ctx.token, ctx.tokenIndex, '<', '>'),
304
+ className: 'cm-typ'
305
+ }
258
306
  ],
259
307
  cpp: [
260
- { test: (ctx) => ctx.scope && (ctx.token !== ',' && ctx.scope.type == "enum"), className: "cm-enu" },
261
- { test: (ctx) => ctx.isEnumValueSymbol(ctx.token), className: "cm-enu" },
262
- { test: (ctx) => (ctx.prev === 'class' && ctx.next === '{') || (ctx.prev === 'struct' && ctx.next === '{'), className: "cm-typ" },
263
- { test: (ctx) => ctx.prev === "<" && (ctx.next === ">" || ctx.next === "*"), className: "cm-typ" }, // Defining template type in C++
264
- { test: (ctx) => ctx.next === "::" || (ctx.prev === "::" && ctx.next !== "("), className: "cm-typ" }, // C++ Class
265
- { test: (ctx) => ctx.isClassSymbol(ctx.token) || ctx.isStructSymbol(ctx.token), className: "cm-typ" },
308
+ { test: (ctx) => ctx.scope && (ctx.token !== ',' && ctx.scope.type == 'enum'), className: 'cm-enu' },
309
+ { test: (ctx) => ctx.isEnumValueSymbol(ctx.token), className: 'cm-enu' },
310
+ {
311
+ test: (ctx) => (ctx.prev === 'class' && ctx.next === '{') || (ctx.prev === 'struct' && ctx.next === '{'),
312
+ className: 'cm-typ'
313
+ },
314
+ { test: (ctx) => ctx.prev === '<' && (ctx.next === '>' || ctx.next === '*'), className: 'cm-typ' }, // Defining template type in C++
315
+ { test: (ctx) => ctx.next === '::' || (ctx.prev === '::' && ctx.next !== '('), className: 'cm-typ' }, // C++ Class
316
+ { test: (ctx) => ctx.isClassSymbol(ctx.token) || ctx.isStructSymbol(ctx.token), className: 'cm-typ' }
266
317
  ],
267
318
  wgsl: [
268
- { test: (ctx) => ctx.prev === '>' && (!ctx.next || ctx.next === '{'), className: "cm-typ" }, // Function return type
269
- { test: (ctx) => (ctx.prev === ':' && ctx.next !== undefined) || (ctx.prev === 'struct' && ctx.next === '{'), className: "cm-typ" },
270
- { test: (ctx, editor) => ctx.token !== ',' && editor._enclosedByTokens(ctx.token, ctx.tokenIndex, '<', '>'), className: "cm-typ" },
319
+ { test: (ctx) => ctx.prev === '>' && (!ctx.next || ctx.next === '{'), className: 'cm-typ' }, // Function return type
320
+ {
321
+ test: (ctx) => (ctx.prev === ':' && ctx.next !== undefined) || (ctx.prev === 'struct' && ctx.next === '{'),
322
+ className: 'cm-typ'
323
+ },
324
+ {
325
+ test: (ctx, editor) => ctx.token !== ',' && editor._enclosedByTokens(ctx.token, ctx.tokenIndex, '<', '>'),
326
+ className: 'cm-typ'
327
+ }
271
328
  ],
272
329
  css: [
273
- { test: (ctx) => (ctx.prev == '.' || ctx.prev == '::' || (ctx.prev == ':' && ctx.next == '{') || (ctx.token[0] == '#' && ctx.prev != ':')), className: "cm-kwd" },
274
- { test: (ctx) => ctx.prev === ':' && (ctx.next === ';' || ctx.next === '!important'), className: "cm-str" }, // CSS value
275
- { test: (ctx) => (ctx.prev === undefined || ctx.prev === '{' || ctx.prev === ';') && ctx.next === ":", className: "cm-typ" }, // CSS attribute
276
- { test: (ctx) => ctx.prev === "(" && ctx.next === ")" && ctx.token.startsWith("--"), className: "cm-typ" }, // CSS vars
330
+ {
331
+ test: (ctx) => (ctx.prev == '.' || ctx.prev == '::' || (ctx.prev == ':' && ctx.next == '{')
332
+ || (ctx.token[0] == '#' && ctx.prev != ':')),
333
+ className: 'cm-kwd'
334
+ },
335
+ { test: (ctx) => ctx.prev === ':' && (ctx.next === ';' || ctx.next === '!important'),
336
+ className: 'cm-str' }, // CSS value
337
+ { test: (ctx) => (ctx.prev === undefined || ctx.prev === '{' || ctx.prev === ';') && ctx.next === ':',
338
+ className: 'cm-typ' }, // CSS attribute
339
+ { test: (ctx) => ctx.prev === '(' && ctx.next === ')' && ctx.token.startsWith('--'),
340
+ className: 'cm-typ' } // CSS vars
277
341
  ],
278
342
  batch: [
279
- { test: (ctx) => ctx.token === '@' || ctx.prev === ':' || ctx.prev === '@', className: "cm-kwd" }
343
+ { test: (ctx) => ctx.token === '@' || ctx.prev === ':' || ctx.prev === '@', className: 'cm-kwd' }
280
344
  ],
281
345
  markdown: [
282
- { test: (ctx) => ctx.isFirstToken && ctx.token.replaceAll('#', '').length != ctx.token.length, action: (ctx, editor) => editor._markdownHeader = true, className: "cm-kwd" }
346
+ { test: (ctx) => ctx.isFirstToken && ctx.token.replaceAll('#', '').length != ctx.token.length,
347
+ action: (ctx, editor) => editor._markdownHeader = true, className: 'cm-kwd' }
283
348
  ],
284
349
  php: [
285
- { test: (ctx) => ctx.token.startsWith('$'), className: "cm-var" },
286
- { test: (ctx) => (ctx.prev === 'class' && (ctx.next === '{' || ctx.next === 'implements')) || (ctx.prev === 'enum'), className: "cm-typ" },
350
+ { test: (ctx) => ctx.token.startsWith('$'), className: 'cm-var' },
351
+ {
352
+ test: (ctx) => (ctx.prev === 'class' && (ctx.next === '{' || ctx.next === 'implements'))
353
+ || (ctx.prev === 'enum'),
354
+ className: 'cm-typ'
355
+ }
287
356
  ],
288
357
  post_common: [
289
- { test: (ctx) => isLetter(ctx.token) && (ctx.token[0] != '@') && (ctx.token[0] != ',') && (ctx.next === '('), className: "cm-mtd" }
290
- ],
358
+ {
359
+ test: (ctx) => isLetter(ctx.token) && (ctx.token[0] != '@') && (ctx.token[0] != ',') && (ctx.next === '('),
360
+ className: 'cm-mtd'
361
+ }
362
+ ]
291
363
  };
292
364
  /**
293
365
  * @class CodeEditor
@@ -331,7 +403,7 @@ class CodeEditor {
331
403
  explorerArea;
332
404
  code;
333
405
  gutter;
334
- xPadding = "0px";
406
+ xPadding = '0px';
335
407
  hScrollbar;
336
408
  vScrollbar;
337
409
  codeScroller;
@@ -385,8 +457,8 @@ class CodeEditor {
385
457
  useAutoComplete = true;
386
458
  allowClosingTabs = true;
387
459
  allowLoadingFiles = true;
388
- highlight = "Plain Text";
389
- explorerName = "EXPLORER";
460
+ highlight = 'Plain Text';
461
+ explorerName = 'EXPLORER';
390
462
  newTabOptions;
391
463
  customSuggestions = [];
392
464
  // Editor callbacks
@@ -408,7 +480,7 @@ class CodeEditor {
408
480
  _lastProcessedCursorIndex = null;
409
481
  _lastMaxLineLength = undefined;
410
482
  _lastMouseDown = 0;
411
- _lastTextFound = "";
483
+ _lastTextFound = '';
412
484
  _lastBaseareaWidth = undefined;
413
485
  _blockCommentCache = [];
414
486
  _pendingString = undefined;
@@ -471,7 +543,7 @@ class CodeEditor {
471
543
  this.onSelectTab = options.onSelectTab;
472
544
  // File explorer
473
545
  if (this.useFileExplorer) {
474
- let [explorerArea, editorArea] = area.split({ sizes: ["15%", "85%"] });
546
+ let [explorerArea, editorArea] = area.split({ sizes: ['15%', '85%'] });
475
547
  // explorerArea.setLimitBox( 180, 20, 512 );
476
548
  this.explorerArea = explorerArea;
477
549
  let panel = new LX.Panel();
@@ -512,7 +584,7 @@ class CodeEditor {
512
584
  area = editorArea;
513
585
  }
514
586
  this.baseArea = area;
515
- this.area = new LX.Area({ className: "lexcodeeditor", height: "100%", skipAppend: true });
587
+ this.area = new LX.Area({ className: 'lexcodeeditor', height: '100%', skipAppend: true });
516
588
  if (!this.skipTabs) {
517
589
  this.tabs = this.area.addTabs({ onclose: (name) => {
518
590
  delete this.openedTabs[name];
@@ -521,7 +593,7 @@ class CodeEditor {
521
593
  LX.removeClas(this.cursorsDOM, 'show');
522
594
  }
523
595
  } });
524
- LX.addClass(this.tabs.root.parentElement, "rounded-t-lg");
596
+ LX.addClass(this.tabs.root.parentElement, 'rounded-t-lg');
525
597
  if (!this.disableEdition) {
526
598
  this.tabs.root.parentElement.addEventListener('dblclick', (e) => {
527
599
  if (options.allowAddScripts ?? true) {
@@ -535,12 +607,13 @@ class CodeEditor {
535
607
  else {
536
608
  this.codeArea = new LX.Area({ skipAppend: true });
537
609
  this.area.attach(this.codeArea);
538
- const loadFileButton = LX.makeElement("button", "grid absolute self-center z-100 p-3 rounded-full bg-secondary hover:bg-tertiary cursor-pointer border", LX.makeIcon("FolderOpen").innerHTML, this.area, {
539
- bottom: "8px"
610
+ const loadFileButton = LX.makeElement('button', 'grid absolute self-center z-100 p-3 rounded-full bg-secondary hover:bg-tertiary cursor-pointer border', LX.makeIcon('FolderOpen').innerHTML, this.area, {
611
+ bottom: '8px'
540
612
  });
541
- loadFileButton.addEventListener("click", (e) => {
613
+ loadFileButton.addEventListener('click', (e) => {
542
614
  const dropdownOptions = [];
543
- for (const [key, value] of [...Object.entries(this.loadedTabs).slice(1), ...Object.entries(this._tabStorage)]) {
615
+ for (const [key, value] of [...Object.entries(this.loadedTabs).slice(1),
616
+ ...Object.entries(this._tabStorage)]) {
544
617
  const icon = this._getFileIcon(key);
545
618
  const classes = icon ? icon.split(' ') : [];
546
619
  dropdownOptions.push({
@@ -552,11 +625,11 @@ class CodeEditor {
552
625
  }
553
626
  });
554
627
  }
555
- new LX.DropdownMenu(loadFileButton, dropdownOptions, { side: "top", align: "center" });
628
+ new LX.DropdownMenu(loadFileButton, dropdownOptions, { side: 'top', align: 'center' });
556
629
  });
557
630
  }
558
631
  this.codeArea.root.classList.add('lexcodearea');
559
- const codeResizeObserver = new ResizeObserver(entries => {
632
+ const codeResizeObserver = new ResizeObserver((entries) => {
560
633
  if (!this.code) {
561
634
  return;
562
635
  }
@@ -566,13 +639,13 @@ class CodeEditor {
566
639
  // Full editor
567
640
  area.root.classList.add('codebasearea');
568
641
  const observer = new MutationObserver((e) => {
569
- if (e[0].attributeName == "style") {
642
+ if (e[0].attributeName == 'style') {
570
643
  this.resize();
571
644
  }
572
645
  });
573
646
  observer.observe(area.root.parentNode, {
574
647
  attributes: true,
575
- attributeFilter: ['class', 'style'],
648
+ attributeFilter: ['class', 'style']
576
649
  });
577
650
  this.root = this.area.root;
578
651
  this.root.tabIndex = -1;
@@ -583,7 +656,7 @@ class CodeEditor {
583
656
  this.root.addEventListener('focusout', this.processFocus.bind(this, false));
584
657
  }
585
658
  else {
586
- this.root.classList.add("disabled");
659
+ this.root.classList.add('disabled');
587
660
  }
588
661
  this.root.addEventListener('mousedown', this.processMouse.bind(this));
589
662
  this.root.addEventListener('mouseup', this.processMouse.bind(this));
@@ -603,7 +676,7 @@ class CodeEditor {
603
676
  // Store here selections per cursor
604
677
  this.selections = {};
605
678
  // Css char synchronization
606
- this.xPadding = CodeEditor.LINE_GUTTER_WIDTH + "px";
679
+ this.xPadding = CodeEditor.LINE_GUTTER_WIDTH + 'px';
607
680
  // Add main cursor
608
681
  this._addCursor(0, 0, true, true);
609
682
  // Scroll stuff
@@ -625,8 +698,10 @@ class CodeEditor {
625
698
  // Scroll down...
626
699
  if (scrollTop > lastScrollTopValue) {
627
700
  if (this.visibleLinesViewport.y < (this.code.lines.length - 1)) {
628
- const totalLinesInViewport = ((this.codeScroller.offsetHeight) / this.lineHeight) | 0;
629
- const scrollDownBoundary = (Math.max(this.visibleLinesViewport.y - totalLinesInViewport, 0) - 1) * this.lineHeight;
701
+ const totalLinesInViewport = ((this.codeScroller.offsetHeight) / this.lineHeight)
702
+ | 0;
703
+ const scrollDownBoundary = (Math.max(this.visibleLinesViewport.y - totalLinesInViewport, 0) - 1)
704
+ * this.lineHeight;
630
705
  if (scrollTop >= scrollDownBoundary) {
631
706
  this.processLines(CodeEditor.UPDATE_VISIBLE_LINES);
632
707
  }
@@ -650,7 +725,7 @@ class CodeEditor {
650
725
  if (e.ctrlKey) {
651
726
  e.preventDefault();
652
727
  e.stopPropagation();
653
- (e.deltaY > 0.0 ? this._decreaseFontSize() : this._increaseFontSize());
728
+ e.deltaY > 0.0 ? this._decreaseFontSize() : this._increaseFontSize();
654
729
  }
655
730
  });
656
731
  this.codeScroller.addEventListener('wheel', (e) => {
@@ -666,7 +741,7 @@ class CodeEditor {
666
741
  {
667
742
  // This is only the container, line numbers are in the same line div
668
743
  this.gutter = document.createElement('div');
669
- this.gutter.className = "lexcodegutter";
744
+ this.gutter.className = 'lexcodegutter';
670
745
  area.attach(this.gutter);
671
746
  // Add custom vertical scroll bar
672
747
  this.vScrollbar = new ScrollBar(this, ScrollBar.SCROLLBAR_VERTICAL);
@@ -680,22 +755,25 @@ class CodeEditor {
680
755
  // Add autocomplete box
681
756
  {
682
757
  this.autocomplete = document.createElement('div');
683
- this.autocomplete.className = "autocomplete";
758
+ this.autocomplete.className = 'autocomplete';
684
759
  this.codeArea.attach(this.autocomplete);
685
760
  }
686
761
  // Add search box
687
762
  {
688
763
  const box = document.createElement('div');
689
- box.className = "searchbox";
764
+ box.className = 'searchbox';
690
765
  const searchPanel = new LX.Panel();
691
766
  box.appendChild(searchPanel.root);
692
767
  searchPanel.sameLine(4);
693
- searchPanel.addText(null, "", null, { placeholder: "Find", inputClass: "bg-secondary" });
694
- searchPanel.addButton(null, "up", () => this.search(null, true), { icon: "ArrowUp", title: "Previous Match", tooltip: true });
695
- searchPanel.addButton(null, "down", () => this.search(), { icon: "ArrowDown", title: "Next Match", tooltip: true });
696
- searchPanel.addButton(null, "x", this.hideSearchBox.bind(this), { icon: "X", title: "Close", tooltip: true });
768
+ searchPanel.addText(null, '', null, { placeholder: 'Find', inputClass: 'bg-secondary' });
769
+ searchPanel.addButton(null, 'up', () => this.search(null, true), { icon: 'ArrowUp',
770
+ title: 'Previous Match', tooltip: true });
771
+ searchPanel.addButton(null, 'down', () => this.search(), { icon: 'ArrowDown', title: 'Next Match',
772
+ tooltip: true });
773
+ searchPanel.addButton(null, 'x', this.hideSearchBox.bind(this), { icon: 'X', title: 'Close',
774
+ tooltip: true });
697
775
  const searchInput = box.querySelector('input');
698
- searchInput?.addEventListener('keyup', e => {
776
+ searchInput?.addEventListener('keyup', (e) => {
699
777
  if (e.key == 'Escape')
700
778
  this.hideSearchBox();
701
779
  else if (e.key == 'Enter')
@@ -707,15 +785,16 @@ class CodeEditor {
707
785
  // Add search LINE box
708
786
  {
709
787
  const box = document.createElement('div');
710
- box.className = "searchbox";
788
+ box.className = 'searchbox';
711
789
  const searchPanel = new LX.Panel();
712
790
  box.appendChild(searchPanel.root);
713
791
  searchPanel.sameLine(2);
714
- searchPanel.addText(null, "", (value) => {
715
- input.value = ":" + value.replaceAll(':', '');
792
+ searchPanel.addText(null, '', (value) => {
793
+ input.value = ':' + value.replaceAll(':', '');
716
794
  this.goToLine(input.value.slice(1));
717
- }, { placeholder: "Go to line", trigger: "input" });
718
- searchPanel.addButton(null, "x", this.hideSearchLineBox.bind(this), { icon: "X", title: "Close", tooltip: true });
795
+ }, { placeholder: 'Go to line', trigger: 'input' });
796
+ searchPanel.addButton(null, 'x', this.hideSearchLineBox.bind(this), { icon: 'X', title: 'Close',
797
+ tooltip: true });
719
798
  let input = box.querySelector('input');
720
799
  input.addEventListener('keyup', (e) => {
721
800
  if (e.key == 'Escape')
@@ -728,7 +807,7 @@ class CodeEditor {
728
807
  // Add code-sizer
729
808
  {
730
809
  this.codeSizer = document.createElement('div');
731
- this.codeSizer.className = "code-sizer pseudoparent-tabs";
810
+ this.codeSizer.className = 'code-sizer pseudoparent-tabs';
732
811
  // Append all childs
733
812
  while (this.codeScroller.firstChild) {
734
813
  this.codeSizer.appendChild(this.codeScroller.firstChild);
@@ -744,22 +823,30 @@ class CodeEditor {
744
823
  };
745
824
  // Code
746
825
  this.pairKeys = {
747
- "\"": "\"",
826
+ '"': '"',
748
827
  "'": "'",
749
- "(": ")",
750
- "{": "}",
751
- "[": "]"
828
+ '(': ')',
829
+ '{': '}',
830
+ '[': ']'
752
831
  };
753
832
  this.stringKeys = {
754
- "@\"": "\"",
833
+ '@"': '"',
755
834
  "@'": "'"
756
835
  };
757
836
  // Scan tokens..
758
837
  // setInterval( this.scanWordSuggestions.bind( this ), 2000 );
759
838
  this.specialKeys = [
760
- 'Backspace', 'Enter', 'ArrowUp', 'ArrowDown',
761
- 'ArrowRight', 'ArrowLeft', 'Delete', 'Home',
762
- 'End', 'Tab', 'Escape'
839
+ 'Backspace',
840
+ 'Enter',
841
+ 'ArrowUp',
842
+ 'ArrowDown',
843
+ 'ArrowRight',
844
+ 'ArrowLeft',
845
+ 'Delete',
846
+ 'Home',
847
+ 'End',
848
+ 'Tab',
849
+ 'Escape'
763
850
  ];
764
851
  // Convert reserved word arrays to maps so we can search tokens faster
765
852
  if (!CodeEditor._staticReady) {
@@ -771,8 +858,9 @@ class CodeEditor {
771
858
  CodeEditor.types[lang] = new Set(CodeEditor.types[lang]);
772
859
  for (let lang in CodeEditor.builtIn)
773
860
  CodeEditor.builtIn[lang] = new Set(CodeEditor.builtIn[lang]);
774
- for (let lang in CodeEditor.statements)
861
+ for (let lang in CodeEditor.statements) {
775
862
  CodeEditor.statements[lang] = new Set(CodeEditor.statements[lang]);
863
+ }
776
864
  for (let lang in CodeEditor.symbols)
777
865
  CodeEditor.symbols[lang] = new Set(CodeEditor.symbols[lang]);
778
866
  CodeEditor._staticReady = true;
@@ -780,10 +868,12 @@ class CodeEditor {
780
868
  // Action keys
781
869
  {
782
870
  this.action('Escape', false, (ln, cursor, e) => {
783
- if (this.hideAutoCompleteBox())
871
+ if (this.hideAutoCompleteBox()) {
784
872
  return;
785
- if (this.hideSearchBox())
873
+ }
874
+ if (this.hideSearchBox()) {
786
875
  return;
876
+ }
787
877
  // Remove selections and cursors
788
878
  this.endSelection();
789
879
  this._removeSecondaryCursors();
@@ -912,23 +1002,28 @@ class CodeEditor {
912
1002
  this.action('End', false, (ln, cursor, e) => {
913
1003
  if ((e.shiftKey || e._shiftKey) && !e.cancelShift) {
914
1004
  var string = this.code.lines[ln].substring(cursor.position);
915
- if (!cursor.selection)
1005
+ if (!cursor.selection) {
916
1006
  this.startSelection(cursor);
917
- if (cursor.selection.sameLine())
1007
+ }
1008
+ if (cursor.selection.sameLine()) {
918
1009
  cursor.selection.selectInline(cursor, cursor.position, cursor.line, this.measureString(string));
1010
+ }
919
1011
  else {
920
1012
  this.resetCursorPos(CodeEditor.CURSOR_LEFT, cursor);
921
1013
  this.cursorToString(cursor, this.code.lines[ln]);
922
1014
  this._processSelection(cursor, e);
923
1015
  }
924
1016
  }
925
- else if (!e.keepSelection)
1017
+ else if (!e.keepSelection) {
926
1018
  this.endSelection();
1019
+ }
927
1020
  this.resetCursorPos(CodeEditor.CURSOR_LEFT, cursor);
928
1021
  this.cursorToString(cursor, this.code.lines[ln]);
929
- var viewportSizeX = (this.codeScroller.clientWidth + this.getScrollLeft()) - CodeEditor.LINE_GUTTER_WIDTH; // Gutter offset
930
- if ((cursor.position * this.charWidth) >= viewportSizeX)
1022
+ var viewportSizeX = (this.codeScroller.clientWidth + this.getScrollLeft())
1023
+ - CodeEditor.LINE_GUTTER_WIDTH; // Gutter offset
1024
+ if ((cursor.position * this.charWidth) >= viewportSizeX) {
931
1025
  this.setScrollLeft(this.code.lines[ln].length * this.charWidth);
1026
+ }
932
1027
  // Merge cursors
933
1028
  this.mergeCursors(ln);
934
1029
  });
@@ -945,7 +1040,7 @@ class CodeEditor {
945
1040
  this._addUndoStep(cursor, true);
946
1041
  var _c0 = this.getCharAtPos(cursor, -1);
947
1042
  var _c1 = this.getCharAtPos(cursor);
948
- this.code.lines.splice(cursor.line + 1, 0, "");
1043
+ this.code.lines.splice(cursor.line + 1, 0, '');
949
1044
  this.code.lines[cursor.line + 1] = this.code.lines[ln].substr(cursor.position); // new line (below)
950
1045
  this.code.lines[ln] = this.code.lines[ln].substr(0, cursor.position); // line above
951
1046
  this.lineDown(cursor, true);
@@ -953,9 +1048,9 @@ class CodeEditor {
953
1048
  var spaces = firstNonspaceIndex(this.code.lines[ln]);
954
1049
  var tabs = Math.floor(spaces / this.tabSpaces);
955
1050
  if (_c0 == '{' && _c1 == '}') {
956
- this.code.lines.splice(cursor.line, 0, "");
1051
+ this.code.lines.splice(cursor.line, 0, '');
957
1052
  this._addSpaceTabs(cursor, tabs + 1);
958
- this.code.lines[cursor.line + 1] = " ".repeat(spaces) + this.code.lines[cursor.line + 1];
1053
+ this.code.lines[cursor.line + 1] = ' '.repeat(spaces) + this.code.lines[cursor.line + 1];
959
1054
  }
960
1055
  else {
961
1056
  this._addSpaceTabs(cursor, tabs);
@@ -966,8 +1061,9 @@ class CodeEditor {
966
1061
  // Move cursor..
967
1062
  if (!this.isAutoCompleteActive) {
968
1063
  if (e.shiftKey) {
969
- if (!cursor.selection)
1064
+ if (!cursor.selection) {
970
1065
  this.startSelection(cursor);
1066
+ }
971
1067
  this.lineUp(cursor);
972
1068
  var letter = this.getCharAtPos(cursor);
973
1069
  if (!letter) {
@@ -993,8 +1089,9 @@ class CodeEditor {
993
1089
  // Move cursor..
994
1090
  if (!this.isAutoCompleteActive) {
995
1091
  if (e.shiftKey) {
996
- if (!cursor.selection)
1092
+ if (!cursor.selection) {
997
1093
  this.startSelection(cursor);
1094
+ }
998
1095
  }
999
1096
  else {
1000
1097
  this.endSelection();
@@ -1017,8 +1114,9 @@ class CodeEditor {
1017
1114
  });
1018
1115
  this.action('ArrowLeft', false, (ln, cursor, e) => {
1019
1116
  // Nothing to do..
1020
- if (cursor.line == 0 && cursor.position == 0)
1117
+ if (cursor.line == 0 && cursor.position == 0) {
1021
1118
  return;
1119
+ }
1022
1120
  if (e.metaKey) { // Apple devices (Command)
1023
1121
  e.preventDefault();
1024
1122
  this.actions['Home'].callback(ln, cursor, e);
@@ -1039,14 +1137,17 @@ class CodeEditor {
1039
1137
  var substr = word.substr(0, diff);
1040
1138
  // Selections...
1041
1139
  if (e.shiftKey) {
1042
- if (!cursor.selection)
1140
+ if (!cursor.selection) {
1043
1141
  this.startSelection(cursor);
1142
+ }
1044
1143
  }
1045
- else
1144
+ else {
1046
1145
  this.endSelection();
1146
+ }
1047
1147
  this.cursorToString(cursor, substr, true);
1048
- if (e.shiftKey)
1148
+ if (e.shiftKey) {
1049
1149
  this._processSelection(cursor, e);
1150
+ }
1050
1151
  }
1051
1152
  else {
1052
1153
  var letter = this.getCharAtPos(cursor, -1);
@@ -1060,8 +1161,9 @@ class CodeEditor {
1060
1161
  else {
1061
1162
  if (!cursor.selection) {
1062
1163
  this.cursorToLeft(letter, cursor);
1063
- if (this.useAutoComplete && this.isAutoCompleteActive)
1164
+ if (this.useAutoComplete && this.isAutoCompleteActive) {
1064
1165
  this.showAutoCompleteBox('foo', cursor);
1166
+ }
1065
1167
  }
1066
1168
  else {
1067
1169
  cursor.selection.invertIfNecessary();
@@ -1087,16 +1189,15 @@ class CodeEditor {
1087
1189
  });
1088
1190
  this.action('ArrowRight', false, (ln, cursor, e) => {
1089
1191
  // Nothing to do..
1090
- if (cursor.line == this.code.lines.length - 1 &&
1091
- cursor.position == this.code.lines[cursor.line].length)
1192
+ if (cursor.line == this.code.lines.length - 1
1193
+ && cursor.position == this.code.lines[cursor.line].length) {
1092
1194
  return;
1093
- if (e.metaKey) // Apple devices (Command)
1094
- {
1195
+ }
1196
+ if (e.metaKey) { // Apple devices (Command)
1095
1197
  e.preventDefault();
1096
1198
  this.actions['End'].callback(ln, cursor, e);
1097
1199
  }
1098
- else if (e.ctrlKey) // Next word
1099
- {
1200
+ else if (e.ctrlKey) { // Next word
1100
1201
  // Get next word
1101
1202
  const [word, from, to] = this.getWordAtPos(cursor);
1102
1203
  // If no length, we change line..
@@ -1106,31 +1207,36 @@ class CodeEditor {
1106
1207
  var substr = word.substr(diff);
1107
1208
  // Selections...
1108
1209
  if (e.shiftKey) {
1109
- if (!cursor.selection)
1210
+ if (!cursor.selection) {
1110
1211
  this.startSelection(cursor);
1212
+ }
1111
1213
  }
1112
- else
1214
+ else {
1113
1215
  this.endSelection();
1216
+ }
1114
1217
  this.cursorToString(cursor, substr);
1115
- if (e.shiftKey)
1218
+ if (e.shiftKey) {
1116
1219
  this._processSelection(cursor, e);
1220
+ }
1117
1221
  }
1118
- else // Next char
1119
- {
1222
+ // Next char
1223
+ else {
1120
1224
  var letter = this.getCharAtPos(cursor);
1121
1225
  if (letter) {
1122
1226
  // Selecting chars
1123
1227
  if (e.shiftKey) {
1124
- if (!cursor.selection)
1228
+ if (!cursor.selection) {
1125
1229
  this.startSelection(cursor);
1230
+ }
1126
1231
  this.cursorToRight(letter, cursor);
1127
1232
  this._processSelection(cursor, e, false, CodeEditor.SELECTION_X);
1128
1233
  }
1129
1234
  else {
1130
1235
  if (!cursor.selection) {
1131
1236
  this.cursorToRight(letter, cursor);
1132
- if (this.useAutoComplete && this.isAutoCompleteActive)
1237
+ if (this.useAutoComplete && this.isAutoCompleteActive) {
1133
1238
  this.showAutoCompleteBox('foo', cursor);
1239
+ }
1134
1240
  }
1135
1241
  else {
1136
1242
  cursor.selection.invertIfNecessary();
@@ -1165,22 +1271,22 @@ class CodeEditor {
1165
1271
  if (this.statusPanel) {
1166
1272
  area.attach(this.statusPanel);
1167
1273
  }
1168
- if (document.fonts.status == "loading") {
1274
+ if (document.fonts.status == 'loading') {
1169
1275
  await document.fonts.ready;
1170
1276
  }
1171
1277
  // Load any font size from local storage
1172
- const savedFontSize = window.localStorage.getItem("lexcodeeditor-font-size");
1278
+ const savedFontSize = window.localStorage.getItem('lexcodeeditor-font-size');
1173
1279
  if (savedFontSize) {
1174
1280
  this._setFontSize(parseInt(savedFontSize));
1175
1281
  }
1176
- else // Use default size
1177
- {
1282
+ // Use default size
1283
+ else {
1178
1284
  const r = document.querySelector(':root');
1179
1285
  const s = getComputedStyle(r);
1180
- this.fontSize = parseInt(s.getPropertyValue("--code-editor-font-size"));
1286
+ this.fontSize = parseInt(s.getPropertyValue('--code-editor-font-size'));
1181
1287
  this.charWidth = this._measureChar();
1182
1288
  }
1183
- LX.emitSignal("@font-size", this.fontSize);
1289
+ LX.emitSignal('@font-size', this.fontSize);
1184
1290
  // Get final sizes for editor elements based on Tabs and status bar offsets
1185
1291
  LX.doAsync(() => {
1186
1292
  this._verticalTopOffset = this.tabs?.root.getBoundingClientRect().height ?? 0;
@@ -1202,17 +1308,18 @@ class CodeEditor {
1202
1308
  };
1203
1309
  if (options.allowAddScripts ?? true) {
1204
1310
  this.onCreateFile = options.onCreateFile;
1205
- this.addTab("+", false, "Create file");
1311
+ this.addTab('+', false, 'Create file');
1206
1312
  }
1207
1313
  if (options.files) {
1208
- console.assert(options.files.constructor === Array, "_files_ must be an Array!");
1314
+ console.assert(options.files.constructor === Array, '_files_ must be an Array!');
1209
1315
  const numFiles = options.files.length;
1210
- const loadAsync = (options.filesAsync !== undefined);
1316
+ const loadAsync = options.filesAsync !== undefined;
1211
1317
  let filesLoaded = 0;
1212
1318
  for (let url of options.files) {
1213
1319
  const finalUrl = url.constructor === Array ? url[0] : url;
1214
1320
  const finalFileName = url.constructor === Array ? url[1] : undefined;
1215
- await this.loadFile(finalUrl, { filename: finalFileName, async: loadAsync, callback: (name, text) => {
1321
+ await this.loadFile(finalUrl, { filename: finalFileName, async: loadAsync,
1322
+ callback: (name, text) => {
1216
1323
  filesLoaded++;
1217
1324
  if (filesLoaded == numFiles) {
1218
1325
  onLoadAll();
@@ -1225,14 +1332,16 @@ class CodeEditor {
1225
1332
  }
1226
1333
  else {
1227
1334
  if (options.defaultTab ?? true) {
1228
- this.addTab(options.name || "untitled", true, options.title, { language: options.highlight ?? "Plain Text" });
1335
+ this.addTab(options.name || 'untitled', true, options.title, {
1336
+ language: options.highlight ?? 'Plain Text'
1337
+ });
1229
1338
  }
1230
1339
  onLoadAll();
1231
1340
  }
1232
1341
  }
1233
1342
  // Clear signals
1234
1343
  clear() {
1235
- console.assert(this.rightStatusPanel && this.leftStatusPanel, "No panels to clear.");
1344
+ console.assert(this.rightStatusPanel && this.leftStatusPanel, 'No panels to clear.');
1236
1345
  this.rightStatusPanel.clear();
1237
1346
  this.leftStatusPanel.clear();
1238
1347
  }
@@ -1243,14 +1352,14 @@ class CodeEditor {
1243
1352
  onKeyPressed(e) {
1244
1353
  // Toggle visibility of the file explorer
1245
1354
  if (e.key == 'b' && e.ctrlKey && this.useFileExplorer) {
1246
- this.explorerArea.root.classList.toggle("hidden");
1355
+ this.explorerArea.root.classList.toggle('hidden');
1247
1356
  if (this._lastBaseareaWidth) {
1248
1357
  this.baseArea.root.style.width = this._lastBaseareaWidth;
1249
1358
  delete this._lastBaseareaWidth;
1250
1359
  }
1251
1360
  else {
1252
1361
  this._lastBaseareaWidth = this.baseArea.root.style.width;
1253
- this.baseArea.root.style.width = "100%";
1362
+ this.baseArea.root.style.width = '100%';
1254
1363
  }
1255
1364
  }
1256
1365
  }
@@ -1258,7 +1367,7 @@ class CodeEditor {
1258
1367
  return this.code.lines.join(min ? ' ' : '\n');
1259
1368
  }
1260
1369
  // This can be used to empty all text...
1261
- setText(text = "", langString) {
1370
+ setText(text = '', langString) {
1262
1371
  let newLines = text.split('\n');
1263
1372
  this.code.lines = [].concat(newLines);
1264
1373
  this._removeSecondaryCursors();
@@ -1292,15 +1401,16 @@ class CodeEditor {
1292
1401
  this.code.lines[lidx].slice(0, cursor.position),
1293
1402
  firstLine
1294
1403
  ].join('');
1295
- this.cursorToPosition(cursor, (cursor.position + (firstLine?.length ?? 0)));
1404
+ this.cursorToPosition(cursor, cursor.position + (firstLine?.length ?? 0));
1296
1405
  // Enter next lines...
1297
1406
  let _text = null;
1298
1407
  for (var i = 0; i < newLines.length; ++i) {
1299
1408
  _text = newLines[i];
1300
1409
  this.cursorToLine(cursor, cursor.line++, true);
1301
1410
  // Add remaining...
1302
- if (i == (newLines.length - 1))
1411
+ if (i == (newLines.length - 1)) {
1303
1412
  _text += remaining;
1413
+ }
1304
1414
  this.code.lines.splice(1 + lidx + i, 0, _text);
1305
1415
  }
1306
1416
  if (_text)
@@ -1315,7 +1425,7 @@ class CodeEditor {
1315
1425
  newLines[0],
1316
1426
  this.code.lines[lidx].slice(cursor.position)
1317
1427
  ].join('');
1318
- this.cursorToPosition(cursor, (cursor.position + newLines[0].length));
1428
+ this.cursorToPosition(cursor, cursor.position + newLines[0].length);
1319
1429
  this.processLine(lidx);
1320
1430
  }
1321
1431
  this.resize(CodeEditor.RESIZE_SCROLLBAR_H_V, undefined, () => {
@@ -1365,7 +1475,7 @@ class CodeEditor {
1365
1475
  const filename = file;
1366
1476
  const name = options.filename ?? filename.substring(filename.lastIndexOf('/') + 1);
1367
1477
  if (options.async ?? false) {
1368
- const text = await this._requestFileAsync(filename, "text");
1478
+ const text = await this._requestFileAsync(filename, 'text');
1369
1479
  _innerAddTab(text, name, options.filename ?? filename);
1370
1480
  }
1371
1481
  else {
@@ -1374,11 +1484,11 @@ class CodeEditor {
1374
1484
  } });
1375
1485
  }
1376
1486
  }
1377
- else // File Blob
1378
- {
1487
+ // File Blob
1488
+ else {
1379
1489
  const fr = new FileReader();
1380
1490
  fr.readAsText(file);
1381
- fr.onload = e => {
1491
+ fr.onload = (e) => {
1382
1492
  const text = e.currentTarget.result;
1383
1493
  _innerAddTab(text, file.name);
1384
1494
  };
@@ -1386,8 +1496,9 @@ class CodeEditor {
1386
1496
  }
1387
1497
  _addUndoStep(cursor, force = false, deleteRedo = true) {
1388
1498
  // Only the mainc cursor stores undo steps
1389
- if (!cursor.isMain)
1499
+ if (!cursor.isMain) {
1390
1500
  return;
1501
+ }
1391
1502
  const d = new Date();
1392
1503
  const current = d.getTime();
1393
1504
  if (!force) {
@@ -1471,7 +1582,7 @@ class CodeEditor {
1471
1582
  if (override) {
1472
1583
  this.code.languageOverride = langString;
1473
1584
  }
1474
- this._updateDataInfoPanel("@highlight", langString);
1585
+ this._updateDataInfoPanel('@highlight', langString);
1475
1586
  this.mustProcessLines = true;
1476
1587
  const ext = langExtension ?? CodeEditor.languages[langString].ext;
1477
1588
  const icon = this._getFileIcon(null, ext);
@@ -1481,14 +1592,13 @@ class CodeEditor {
1481
1592
  tab.firstChild.remove();
1482
1593
  console.assert(tab != undefined);
1483
1594
  var iconEl;
1484
- if (!icon.includes('.')) // Not a file
1485
- {
1595
+ if (!icon.includes('.')) { // Not a file
1486
1596
  const classes = icon.split(' ');
1487
1597
  iconEl = LX.makeIcon(classes[0], { svgClass: classes.slice(0).join(' ') });
1488
1598
  }
1489
1599
  else {
1490
1600
  iconEl = document.createElement('img');
1491
- iconEl.src = "https://raw.githubusercontent.com/jxarco/lexgui.js/master/" + icon;
1601
+ iconEl.src = 'https://raw.githubusercontent.com/jxarco/lexgui.js/master/' + icon;
1492
1602
  }
1493
1603
  tab.prepend(iconEl);
1494
1604
  }
@@ -1523,37 +1633,47 @@ class CodeEditor {
1523
1633
  if (this.skipInfo) {
1524
1634
  return;
1525
1635
  }
1526
- let panel = new LX.Panel({ className: "lexcodetabinfo flex flex-row", height: "auto" });
1636
+ let panel = new LX.Panel({ className: 'lexcodetabinfo flex flex-row', height: 'auto' });
1527
1637
  if (this.onCreateStatusPanel) {
1528
1638
  this.onCreateStatusPanel(panel, this);
1529
1639
  }
1530
- let leftStatusPanel = this.leftStatusPanel = new LX.Panel({ id: "FontSizeZoomStatusComponent", height: "auto" });
1640
+ let leftStatusPanel = this.leftStatusPanel = new LX.Panel({ id: 'FontSizeZoomStatusComponent',
1641
+ height: 'auto' });
1531
1642
  leftStatusPanel.sameLine();
1532
1643
  if (this.skipTabs) {
1533
- leftStatusPanel.addButton(null, "ZoomOutButton", this._decreaseFontSize.bind(this), { icon: "ZoomOut", width: "32px", title: "Zoom Out", tooltip: true });
1534
- }
1535
- leftStatusPanel.addButton(null, "ZoomOutButton", this._decreaseFontSize.bind(this), { icon: "ZoomOut", width: "32px", title: "Zoom Out", tooltip: true });
1536
- leftStatusPanel.addLabel(this.fontSize, { fit: true, signal: "@font-size" });
1537
- leftStatusPanel.addButton(null, "ZoomInButton", this._increaseFontSize.bind(this), { icon: "ZoomIn", width: "32px", title: "Zoom In", tooltip: true });
1538
- leftStatusPanel.endLine("justify-start");
1644
+ leftStatusPanel.addButton(null, 'ZoomOutButton', this._decreaseFontSize.bind(this), { icon: 'ZoomOut',
1645
+ width: '32px', title: 'Zoom Out', tooltip: true });
1646
+ }
1647
+ leftStatusPanel.addButton(null, 'ZoomOutButton', this._decreaseFontSize.bind(this), { icon: 'ZoomOut',
1648
+ width: '32px', title: 'Zoom Out', tooltip: true });
1649
+ leftStatusPanel.addLabel(this.fontSize, { fit: true, signal: '@font-size' });
1650
+ leftStatusPanel.addButton(null, 'ZoomInButton', this._increaseFontSize.bind(this), { icon: 'ZoomIn',
1651
+ width: '32px', title: 'Zoom In', tooltip: true });
1652
+ leftStatusPanel.endLine('justify-start');
1539
1653
  panel.attach(leftStatusPanel.root);
1540
- let rightStatusPanel = this.rightStatusPanel = new LX.Panel({ height: "auto" });
1654
+ let rightStatusPanel = this.rightStatusPanel = new LX.Panel({ height: 'auto' });
1541
1655
  rightStatusPanel.sameLine();
1542
- rightStatusPanel.addLabel(this.code?.title ?? "", { id: "EditorFilenameStatusComponent", fit: true, signal: "@tab-name" });
1543
- rightStatusPanel.addButton(null, "Ln 1, Col 1", this.showSearchLineBox.bind(this), { id: "EditorSelectionStatusComponent", fit: true, signal: "@cursor-data" });
1544
- rightStatusPanel.addButton(null, "Spaces: " + this.tabSpaces, (value, event) => {
1545
- LX.addContextMenu("Spaces", event, (m) => {
1656
+ rightStatusPanel.addLabel(this.code?.title ?? '', { id: 'EditorFilenameStatusComponent', fit: true,
1657
+ signal: '@tab-name' });
1658
+ rightStatusPanel.addButton(null, 'Ln 1, Col 1', this.showSearchLineBox.bind(this), {
1659
+ id: 'EditorSelectionStatusComponent',
1660
+ fit: true,
1661
+ signal: '@cursor-data'
1662
+ });
1663
+ rightStatusPanel.addButton(null, 'Spaces: ' + this.tabSpaces, (value, event) => {
1664
+ LX.addContextMenu('Spaces', event, (m) => {
1546
1665
  const options = [2, 4, 8];
1547
- for (const n of options)
1666
+ for (const n of options) {
1548
1667
  m.add(n, (v) => {
1549
1668
  this.tabSpaces = v;
1550
1669
  this.processLines();
1551
- this._updateDataInfoPanel("@tab-spaces", "Spaces: " + this.tabSpaces);
1670
+ this._updateDataInfoPanel('@tab-spaces', 'Spaces: ' + this.tabSpaces);
1552
1671
  });
1672
+ }
1553
1673
  });
1554
- }, { id: "EditorIndentationStatusComponent", nameWidth: "15%", signal: "@tab-spaces" });
1555
- rightStatusPanel.addButton("<b>{ }</b>", this.highlight, (value, event) => {
1556
- LX.addContextMenu("Language", event, (m) => {
1674
+ }, { id: 'EditorIndentationStatusComponent', nameWidth: '15%', signal: '@tab-spaces' });
1675
+ rightStatusPanel.addButton('<b>{ }</b>', this.highlight, (value, event) => {
1676
+ LX.addContextMenu('Language', event, (m) => {
1557
1677
  for (const lang of Object.keys(CodeEditor.languages)) {
1558
1678
  m.add(lang, (v) => {
1559
1679
  this._changeLanguage(v, undefined, true);
@@ -1561,32 +1681,34 @@ class CodeEditor {
1561
1681
  });
1562
1682
  }
1563
1683
  });
1564
- }, { id: "EditorLanguageStatusComponent", nameWidth: "15%", signal: "@highlight" });
1565
- rightStatusPanel.endLine("justify-end");
1684
+ }, { id: 'EditorLanguageStatusComponent', nameWidth: '15%', signal: '@highlight' });
1685
+ rightStatusPanel.endLine('justify-end');
1566
1686
  panel.attach(rightStatusPanel.root);
1567
1687
  const itemVisibilityMap = {
1568
- "Font Size Zoom": options.statusShowFontSizeZoom ?? true,
1569
- "Editor Filename": options.statusShowEditorFilename ?? true,
1570
- "Editor Selection": options.statusShowEditorSelection ?? true,
1571
- "Editor Indentation": options.statusShowEditorIndentation ?? true,
1572
- "Editor Language": options.statusShowEditorLanguage ?? true,
1688
+ 'Font Size Zoom': options.statusShowFontSizeZoom ?? true,
1689
+ 'Editor Filename': options.statusShowEditorFilename ?? true,
1690
+ 'Editor Selection': options.statusShowEditorSelection ?? true,
1691
+ 'Editor Indentation': options.statusShowEditorIndentation ?? true,
1692
+ 'Editor Language': options.statusShowEditorLanguage ?? true
1573
1693
  };
1574
1694
  const _setVisibility = (itemName) => {
1575
- const b = panel.root.querySelector(`#${itemName.replaceAll(" ", "")}StatusComponent`);
1695
+ const b = panel.root.querySelector(`#${itemName.replaceAll(' ', '')}StatusComponent`);
1576
1696
  console.assert(b, `${itemName} has no status button!`);
1577
- b.classList.toggle("hidden", !itemVisibilityMap[itemName]);
1697
+ b.classList.toggle('hidden', !itemVisibilityMap[itemName]);
1578
1698
  };
1579
1699
  for (const [itemName, v] of Object.entries(itemVisibilityMap)) {
1580
1700
  _setVisibility(itemName);
1581
1701
  }
1582
- panel.root.addEventListener("contextmenu", (e) => {
1583
- if (e.target && (e.target.classList.contains("lexpanel") || e.target.classList.contains("lexinlinecomponents"))) {
1702
+ panel.root.addEventListener('contextmenu', (e) => {
1703
+ if (e.target
1704
+ && (e.target.classList.contains('lexpanel')
1705
+ || e.target.classList.contains('lexinlinecomponents'))) {
1584
1706
  return;
1585
1707
  }
1586
1708
  const menuOptions = Object.keys(itemVisibilityMap).map((itemName, idx) => {
1587
1709
  const item = {
1588
1710
  name: itemName,
1589
- icon: "Check",
1711
+ icon: 'Check',
1590
1712
  callback: () => {
1591
1713
  itemVisibilityMap[itemName] = !itemVisibilityMap[itemName];
1592
1714
  _setVisibility(itemName);
@@ -1596,7 +1718,7 @@ class CodeEditor {
1596
1718
  delete item.icon;
1597
1719
  return item;
1598
1720
  });
1599
- new LX.DropdownMenu(e.target, menuOptions, { side: "top", align: "start" });
1721
+ new LX.DropdownMenu(e.target, menuOptions, { side: 'top', align: 'start' });
1600
1722
  });
1601
1723
  return panel;
1602
1724
  }
@@ -1631,13 +1753,13 @@ class CodeEditor {
1631
1753
  }
1632
1754
  }
1633
1755
  if (langString === undefined) {
1634
- return "AlignLeft fg-neutral-500";
1756
+ return 'AlignLeft fg-neutral-500';
1635
1757
  }
1636
1758
  const iconPlusClasses = CodeEditor.languages[langString]?.icon;
1637
1759
  if (iconPlusClasses) {
1638
1760
  return iconPlusClasses[extension] ?? iconPlusClasses;
1639
1761
  }
1640
- return "AlignLeft fg-neutral-500";
1762
+ return 'AlignLeft fg-neutral-500';
1641
1763
  }
1642
1764
  _onNewTab(e) {
1643
1765
  this.processFocus(false);
@@ -1646,22 +1768,23 @@ class CodeEditor {
1646
1768
  return;
1647
1769
  }
1648
1770
  const dmOptions = this.newTabOptions ?? [
1649
- { name: "Create file", icon: "FilePlus", callback: this._onCreateNewFile.bind(this) },
1650
- { name: "Load file", icon: "FileUp", disabled: !this.allowLoadingFiles, callback: this.loadTabFromFile.bind(this) }
1771
+ { name: 'Create file', icon: 'FilePlus', callback: this._onCreateNewFile.bind(this) },
1772
+ { name: 'Load file', icon: 'FileUp', disabled: !this.allowLoadingFiles,
1773
+ callback: this.loadTabFromFile.bind(this) }
1651
1774
  ];
1652
- new LX.DropdownMenu(e.target, dmOptions, { side: "bottom", align: "start" });
1775
+ new LX.DropdownMenu(e.target, dmOptions, { side: 'bottom', align: 'start' });
1653
1776
  }
1654
1777
  _onCreateNewFile() {
1655
1778
  let options = {};
1656
1779
  if (this.onCreateFile) {
1657
1780
  options = this.onCreateFile(this);
1658
- if (!options) // Skip adding new file
1659
- {
1781
+ if (!options) { // Skip adding new file
1660
1782
  return;
1661
1783
  }
1662
1784
  }
1663
- const name = options.name ?? "unnamed.js";
1664
- this.addTab(name, true, name, { indexOffset: options.indexOffset, language: options.language ?? "JavaScript" });
1785
+ const name = options.name ?? 'unnamed.js';
1786
+ this.addTab(name, true, name, { indexOffset: options.indexOffset,
1787
+ language: options.language ?? 'JavaScript' });
1665
1788
  }
1666
1789
  _onSelectTab(isNewTabButton, event, name) {
1667
1790
  if (this.disableEdition) {
@@ -1681,7 +1804,7 @@ class CodeEditor {
1681
1804
  this.restoreCursor(cursor, this.code.cursorState);
1682
1805
  this.endSelection();
1683
1806
  this.hideAutoCompleteBox();
1684
- this._updateDataInfoPanel("@tab-name", name);
1807
+ this._updateDataInfoPanel('@tab-name', name);
1685
1808
  if (this.code.languageOverride) {
1686
1809
  this._changeLanguage(this.code.languageOverride);
1687
1810
  }
@@ -1698,15 +1821,17 @@ class CodeEditor {
1698
1821
  return;
1699
1822
  }
1700
1823
  new LX.DropdownMenu(event.target, [
1701
- { name: "Close", kbd: "MWB", disabled: !this.allowClosingTabs, callback: () => { this.closeTab(name); } },
1702
- { name: "Close Others", disabled: !this.allowClosingTabs, callback: () => {
1824
+ { name: 'Close', kbd: 'MWB', disabled: !this.allowClosingTabs, callback: () => {
1825
+ this.closeTab(name);
1826
+ } },
1827
+ { name: 'Close Others', disabled: !this.allowClosingTabs, callback: () => {
1703
1828
  for (const [key, data] of Object.entries(this.tabs.tabs)) {
1704
1829
  if (key === '+' || key === name)
1705
1830
  continue;
1706
1831
  this.closeTab(key);
1707
1832
  }
1708
1833
  } },
1709
- { name: "Close All", disabled: !this.allowClosingTabs, callback: () => {
1834
+ { name: 'Close All', disabled: !this.allowClosingTabs, callback: () => {
1710
1835
  for (const [key, data] of Object.entries(this.tabs.tabs)) {
1711
1836
  if (key === '+')
1712
1837
  continue;
@@ -1714,10 +1839,10 @@ class CodeEditor {
1714
1839
  }
1715
1840
  } },
1716
1841
  null,
1717
- { name: "Copy Path", icon: "Copy", callback: () => {
1718
- navigator.clipboard.writeText(this.openedTabs[name].path ?? "");
1842
+ { name: 'Copy Path', icon: 'Copy', callback: () => {
1843
+ navigator.clipboard.writeText(this.openedTabs[name].path ?? '');
1719
1844
  } }
1720
- ], { side: "bottom", align: "start", event });
1845
+ ], { side: 'bottom', align: 'start', event });
1721
1846
  }
1722
1847
  addTab(name, selected, title, options = {}) {
1723
1848
  // If already loaded, set new name...
@@ -1728,15 +1853,15 @@ class CodeEditor {
1728
1853
  if (repeats > 0) {
1729
1854
  name = name.split('.').join('_' + repeats + '.');
1730
1855
  }
1731
- const isNewTabButton = (name === '+');
1856
+ const isNewTabButton = name === '+';
1732
1857
  // Create code content
1733
1858
  let code = document.createElement('div');
1734
1859
  let codeAny = code;
1735
1860
  Object.assign(code, {
1736
- path: options.path ?? "",
1861
+ path: options.path ?? '',
1737
1862
  className: 'code',
1738
- lines: [""],
1739
- language: options.language ?? "Plain Text",
1863
+ lines: [''],
1864
+ language: options.language ?? 'Plain Text',
1740
1865
  cursorState: {},
1741
1866
  undoSteps: [],
1742
1867
  redoSteps: [],
@@ -1748,17 +1873,15 @@ class CodeEditor {
1748
1873
  title: title ?? name,
1749
1874
  tokens: {}
1750
1875
  });
1751
- code.style.left = "0px",
1752
- code.style.top = "0px",
1753
- code.addEventListener('dragenter', function (e) {
1754
- e.preventDefault();
1755
- this.parentElement?.classList.add('dragging');
1756
- });
1876
+ code.style.left = '0px', code.style.top = '0px', code.addEventListener('dragenter', function (e) {
1877
+ e.preventDefault();
1878
+ this.parentElement?.classList.add('dragging');
1879
+ });
1757
1880
  code.addEventListener('dragleave', function (e) {
1758
1881
  e.preventDefault();
1759
1882
  this.parentElement?.classList.remove('dragging');
1760
1883
  });
1761
- code.addEventListener('drop', e => {
1884
+ code.addEventListener('drop', (e) => {
1762
1885
  e.preventDefault();
1763
1886
  code.parentElement?.classList.remove('dragging');
1764
1887
  if (e.dataTransfer?.files) {
@@ -1808,17 +1931,17 @@ class CodeEditor {
1808
1931
  this.code = lastCode;
1809
1932
  }
1810
1933
  this._processLinesIfNecessary();
1811
- this._updateDataInfoPanel("@tab-name", name);
1934
+ this._updateDataInfoPanel('@tab-name', name);
1812
1935
  // Bc it could be overrided..
1813
1936
  return name;
1814
1937
  }
1815
1938
  loadCode(name) {
1816
1939
  // Hide all others
1817
- this.codeSizer.querySelectorAll(".code").forEach((c) => c.classList.add("hidden"));
1940
+ this.codeSizer.querySelectorAll('.code').forEach((c) => c.classList.add('hidden'));
1818
1941
  // Already open...
1819
1942
  if (this.openedTabs[name]) {
1820
1943
  let code = this.openedTabs[name];
1821
- code.classList.remove("hidden");
1944
+ code.classList.remove('hidden');
1822
1945
  return;
1823
1946
  }
1824
1947
  let code = this.loadedTabs[name];
@@ -1850,7 +1973,7 @@ class CodeEditor {
1850
1973
  this.processLines();
1851
1974
  this._changeLanguageFromExtension(LX.getExtension(name));
1852
1975
  this._processLinesIfNecessary();
1853
- this._updateDataInfoPanel("@tab-name", code.tabName);
1976
+ this._updateDataInfoPanel('@tab-name', code.tabName);
1854
1977
  }
1855
1978
  loadTab(name) {
1856
1979
  // Already open...
@@ -1877,9 +2000,9 @@ class CodeEditor {
1877
2000
  return;
1878
2001
  }
1879
2002
  // Reset visibility
1880
- code.style.display = "block";
2003
+ code.style.display = 'block';
1881
2004
  this.openedTabs[name] = code;
1882
- const isNewTabButton = (name === '+');
2005
+ const isNewTabButton = name === '+';
1883
2006
  const tabIcon = this._getFileIcon(name);
1884
2007
  this.tabs.add(name, code, {
1885
2008
  selected: true,
@@ -1897,7 +2020,7 @@ class CodeEditor {
1897
2020
  this.code = code;
1898
2021
  this.resetCursorPos(CodeEditor.CURSOR_LEFT_TOP, undefined, true);
1899
2022
  this._changeLanguageFromExtension(LX.getExtension(name));
1900
- this._updateDataInfoPanel("@tab-name", code.tabName);
2023
+ this._updateDataInfoPanel('@tab-name', code.tabName);
1901
2024
  this.processLines();
1902
2025
  }
1903
2026
  closeTab(name, eraseAll = false) {
@@ -1919,7 +2042,7 @@ class CodeEditor {
1919
2042
  input.type = 'file';
1920
2043
  document.body.appendChild(input);
1921
2044
  input.click();
1922
- input.addEventListener('change', e => {
2045
+ input.addEventListener('change', (e) => {
1923
2046
  const target = e.target;
1924
2047
  if (target.files && target.files[0]) {
1925
2048
  this.loadFile(target.files[0]);
@@ -1944,7 +2067,7 @@ class CodeEditor {
1944
2067
  return;
1945
2068
  var cursor = this.getCurrentCursor();
1946
2069
  var code_rect = this.code.getBoundingClientRect();
1947
- var mouse_pos = [(e.clientX - code_rect.x), (e.clientY - code_rect.y)];
2070
+ var mouse_pos = [e.clientX - code_rect.x, e.clientY - code_rect.y];
1948
2071
  // Discard out of lines click...
1949
2072
  var ln = (mouse_pos[1] / this.lineHeight) | 0;
1950
2073
  if (ln < 0)
@@ -1955,10 +2078,12 @@ class CodeEditor {
1955
2078
  this.processClick(e);
1956
2079
  this.canOpenContextMenu = !cursor.selection;
1957
2080
  if (cursor.selection) {
1958
- this.canOpenContextMenu = this.canOpenContextMenu || ((cursor.line >= cursor.selection.fromY && cursor.line <= cursor.selection.toY
1959
- && cursor.position >= cursor.selection.fromX && cursor.position <= cursor.selection.toX));
1960
- if (this.canOpenContextMenu)
2081
+ this.canOpenContextMenu = this.canOpenContextMenu
2082
+ || (cursor.line >= cursor.selection.fromY && cursor.line <= cursor.selection.toY
2083
+ && cursor.position >= cursor.selection.fromX && cursor.position <= cursor.selection.toX);
2084
+ if (this.canOpenContextMenu) {
1961
2085
  return;
2086
+ }
1962
2087
  }
1963
2088
  }
1964
2089
  this._mouseDown = true;
@@ -1975,8 +2100,7 @@ class CodeEditor {
1975
2100
  this.processSelections(e);
1976
2101
  }
1977
2102
  }
1978
- else if (e.type == 'click') // trip
1979
- {
2103
+ else if (e.type == 'click') { // trip
1980
2104
  switch (e.detail) {
1981
2105
  case LX.MOUSE_DOUBLE_CLICK:
1982
2106
  const [word, from, to] = this.getWordAtPos(cursor);
@@ -2001,10 +2125,16 @@ class CodeEditor {
2001
2125
  return;
2002
2126
  }
2003
2127
  LX.addContextMenu(null, e, (m) => {
2004
- m.add("Copy", () => { this._copyContent(cursor); });
2128
+ m.add('Copy', () => {
2129
+ this._copyContent(cursor);
2130
+ });
2005
2131
  if (!this.disableEdition) {
2006
- m.add("Cut", () => { this._cutContent(cursor); });
2007
- m.add("Paste", () => { this._pasteContent(cursor); });
2132
+ m.add('Cut', () => {
2133
+ this._cutContent(cursor);
2134
+ });
2135
+ m.add('Paste', () => {
2136
+ this._pasteContent(cursor);
2137
+ });
2008
2138
  }
2009
2139
  if (!this.onContextMenu) {
2010
2140
  return;
@@ -2014,21 +2144,22 @@ class CodeEditor {
2014
2144
  // Some selections don't depend on mouse up..
2015
2145
  if (cursor.selection)
2016
2146
  cursor.selection.invertIfNecessary();
2017
- const separator = "_NEWLINE_";
2147
+ const separator = '_NEWLINE_';
2018
2148
  let code = this.code.lines.join(separator);
2019
2149
  // Get linear start index
2020
2150
  let index = 0;
2021
2151
  for (let i = 0; i <= cursor.selection.fromY; i++) {
2022
- index += (i == cursor.selection.fromY ? cursor.selection.fromX : this.code.lines[i].length);
2152
+ index += i == cursor.selection.fromY ? cursor.selection.fromX : this.code.lines[i].length;
2023
2153
  }
2024
2154
  index += cursor.selection.fromY * separator.length;
2025
- const num_chars = cursor.selection.chars + (cursor.selection.toY - cursor.selection.fromY) * separator.length;
2155
+ const num_chars = cursor.selection.chars
2156
+ + (cursor.selection.toY - cursor.selection.fromY) * separator.length;
2026
2157
  const text = code.substr(index, num_chars);
2027
2158
  content = text.split(separator).join('\n');
2028
2159
  }
2029
2160
  const options = this.onContextMenu(this, content, e);
2030
2161
  if (options.length) {
2031
- m.add("");
2162
+ m.add('');
2032
2163
  for (const o of options) {
2033
2164
  m.add(o.path, { disabled: o.disabled, callback: o.callback });
2034
2165
  }
@@ -2065,7 +2196,8 @@ class CodeEditor {
2065
2196
  processClick(e) {
2066
2197
  var cursor = this.getCurrentCursor();
2067
2198
  var code_rect = this.codeScroller.getBoundingClientRect();
2068
- var position = [(e.clientX - code_rect.x) + this.getScrollLeft(), (e.clientY - code_rect.y) + this.getScrollTop()];
2199
+ var position = [(e.clientX - code_rect.x) + this.getScrollLeft(),
2200
+ (e.clientY - code_rect.y) + this.getScrollTop()];
2069
2201
  var ln = (position[1] / this.lineHeight) | 0;
2070
2202
  // Check out of range line
2071
2203
  const outOfRange = ln > this.code.lines.length - 1;
@@ -2112,9 +2244,10 @@ class CodeEditor {
2112
2244
  if (!keepRange) {
2113
2245
  let ccw = true;
2114
2246
  // Check if we must change ccw or not ... (not with mouse)
2115
- if (!isMouseEvent && cursor.line >= selection.fromY &&
2116
- (cursor.line == selection.fromY ? cursor.position >= selection.fromX : true)) {
2117
- ccw = (e && this._lastSelectionKeyDir && (e.key == 'ArrowRight' || e.key == 'ArrowDown' || e.key == 'End'));
2247
+ if (!isMouseEvent && cursor.line >= selection.fromY
2248
+ && (cursor.line == selection.fromY ? cursor.position >= selection.fromX : true)) {
2249
+ ccw = e && this._lastSelectionKeyDir
2250
+ && (e.key == 'ArrowRight' || e.key == 'ArrowDown' || e.key == 'End');
2118
2251
  }
2119
2252
  if (ccw) {
2120
2253
  if (flags & CodeEditor.SELECTION_X)
@@ -2141,8 +2274,9 @@ class CodeEditor {
2141
2274
  let cursorSelections = this.selections[cursor.name];
2142
2275
  // Selection goes down...
2143
2276
  if (deltaY >= 0) {
2144
- while (deltaY < (cursorSelections.childElementCount - 1))
2277
+ while (deltaY < (cursorSelections.childElementCount - 1)) {
2145
2278
  LX.deleteElement(cursorSelections.lastChild);
2279
+ }
2146
2280
  for (let i = fromY; i <= toY; i++) {
2147
2281
  const sId = i - fromY;
2148
2282
  const isVisible = i >= this.visibleLinesViewport.x && i <= this.visibleLinesViewport.y;
@@ -2152,17 +2286,19 @@ class CodeEditor {
2152
2286
  domEl = cursorSelections.childNodes[sId];
2153
2287
  if (!domEl) {
2154
2288
  domEl = document.createElement('div');
2155
- domEl.className = "lexcodeselection";
2289
+ domEl.className = 'lexcodeselection';
2156
2290
  cursorSelections.appendChild(domEl);
2157
2291
  }
2158
2292
  }
2159
2293
  // Compute new width and selection margins
2160
- let string = "";
2161
- if (sId == 0) // First line 2 cases (single line, multiline)
2162
- {
2294
+ let string = '';
2295
+ if (sId == 0) { // First line 2 cases (single line, multiline)
2163
2296
  const reverse = fromX > toX;
2164
- if (deltaY == 0)
2165
- string = !reverse ? this.code.lines[i].substring(fromX, toX) : this.code.lines[i].substring(toX, fromX);
2297
+ if (deltaY == 0) {
2298
+ string = !reverse
2299
+ ? this.code.lines[i].substring(fromX, toX)
2300
+ : this.code.lines[i].substring(toX, fromX);
2301
+ }
2166
2302
  else
2167
2303
  string = this.code.lines[i].substr(fromX);
2168
2304
  const pixels = (reverse && deltaY == 0 ? toX : fromX) * this.charWidth;
@@ -2177,16 +2313,17 @@ class CodeEditor {
2177
2313
  const stringWidth = this.measureString(string);
2178
2314
  selection.chars += stringWidth / this.charWidth;
2179
2315
  if (isVisible) {
2180
- domEl.style.width = (stringWidth || (deltaY == 0 ? 0 : 8)) + "px";
2316
+ domEl.style.width = (stringWidth || (deltaY == 0 ? 0 : 8)) + 'px';
2181
2317
  domEl._top = i * this.lineHeight;
2182
- domEl.style.top = domEl._top + "px";
2318
+ domEl.style.top = domEl._top + 'px';
2183
2319
  }
2184
2320
  }
2185
2321
  }
2186
- else // Selection goes up...
2187
- {
2188
- while (Math.abs(deltaY) < (cursorSelections.childElementCount - 1))
2322
+ // Selection goes up...
2323
+ else {
2324
+ while (Math.abs(deltaY) < (cursorSelections.childElementCount - 1)) {
2189
2325
  LX.deleteElement(cursorSelections.firstChild);
2326
+ }
2190
2327
  for (let i = toY; i <= fromY; i++) {
2191
2328
  const sId = i - toY;
2192
2329
  const isVisible = i >= this.visibleLinesViewport.x && i <= this.visibleLinesViewport.y;
@@ -2196,7 +2333,7 @@ class CodeEditor {
2196
2333
  domEl = cursorSelections.childNodes[sId];
2197
2334
  if (!domEl) {
2198
2335
  domEl = document.createElement('div');
2199
- domEl.className = "lexcodeselection";
2336
+ domEl.className = 'lexcodeselection';
2200
2337
  cursorSelections.appendChild(domEl);
2201
2338
  }
2202
2339
  }
@@ -2206,7 +2343,7 @@ class CodeEditor {
2206
2343
  string = this.code.lines[i].substr(toX);
2207
2344
  const pixels = toX * this.charWidth;
2208
2345
  if (isVisible)
2209
- domEl.style.left = "calc(" + pixels + "px + " + this.xPadding + ")";
2346
+ domEl.style.left = 'calc(' + pixels + 'px + ' + this.xPadding + ')';
2210
2347
  }
2211
2348
  else {
2212
2349
  string = (i == fromY) ? this.code.lines[i].substring(0, fromX) : this.code.lines[i]; // Last line, any multiple line...
@@ -2216,17 +2353,18 @@ class CodeEditor {
2216
2353
  const stringWidth = this.measureString(string);
2217
2354
  selection.chars += stringWidth / this.charWidth;
2218
2355
  if (isVisible) {
2219
- domEl.style.width = (stringWidth || 8) + "px";
2356
+ domEl.style.width = (stringWidth || 8) + 'px';
2220
2357
  domEl._top = i * this.lineHeight;
2221
- domEl.style.top = domEl._top + "px";
2358
+ domEl.style.top = domEl._top + 'px';
2222
2359
  }
2223
2360
  }
2224
2361
  }
2225
2362
  }
2226
2363
  async processKey(e) {
2227
2364
  const numCursors = this.cursors.length;
2228
- if (!this.code || e.srcElement?.constructor != HTMLDivElement)
2365
+ if (!this.code || e.srcElement?.constructor != HTMLDivElement) {
2229
2366
  return;
2367
+ }
2230
2368
  const detail = e.detail ?? {};
2231
2369
  const key = e.key ?? detail.key;
2232
2370
  // Do not propagate "space to scroll" event
@@ -2251,8 +2389,9 @@ class CodeEditor {
2251
2389
  for (var i = 0; i < numCursors; i++) {
2252
2390
  let cursor = this.cursors[i];
2253
2391
  // We could delete secondary cursor while iterating..
2254
- if (!cursor)
2392
+ if (!cursor) {
2255
2393
  break;
2394
+ }
2256
2395
  // Arrows don't modify code lines.. And only add offset if in the same line
2257
2396
  if (lastProcessedCursor && lastProcessedCursor.line == cursor.line && !key.includes('Arrow')) {
2258
2397
  cursor.position += cursorOffset.x;
@@ -2262,8 +2401,8 @@ class CodeEditor {
2262
2401
  lastProcessedCursor = this.saveCursor(cursor);
2263
2402
  this._lastProcessedCursorIndex = i;
2264
2403
  this._processKeyAtCursor(e, key, cursor);
2265
- cursorOffset.x += (cursor.position - lastProcessedCursor.position);
2266
- cursorOffset.y += (cursor.line - lastProcessedCursor.line);
2404
+ cursorOffset.x += cursor.position - lastProcessedCursor.position;
2405
+ cursorOffset.y += cursor.line - lastProcessedCursor.line;
2267
2406
  // Set active line in case it's blurred
2268
2407
  if (!cursor.selection) {
2269
2408
  cursor.line = cursor.line;
@@ -2275,8 +2414,9 @@ class CodeEditor {
2275
2414
  async processKeyAtTargetCursor(e, key, targetIdx) {
2276
2415
  let cursor = this.cursors[targetIdx];
2277
2416
  // We could delete secondary cursor while iterating..
2278
- if (!cursor)
2417
+ if (!cursor) {
2279
2418
  return;
2419
+ }
2280
2420
  this._processKeyAtCursor(e, key, cursor);
2281
2421
  this._processGlobalKeys(e, key);
2282
2422
  }
@@ -2367,7 +2507,7 @@ class CodeEditor {
2367
2507
  return;
2368
2508
  }
2369
2509
  let lidx = cursor.line;
2370
- this.code.lines[lidx] = this.code.lines[lidx] ?? "";
2510
+ this.code.lines[lidx] = this.code.lines[lidx] ?? '';
2371
2511
  // Check combinations
2372
2512
  const isLastCursor = cursor.isLast();
2373
2513
  if (e.ctrlKey || e.metaKey) {
@@ -2409,8 +2549,9 @@ class CodeEditor {
2409
2549
  }
2410
2550
  // Apply binded actions...
2411
2551
  for (const actKey in this.actions) {
2412
- if (key != actKey)
2552
+ if (key != actKey) {
2413
2553
  continue;
2554
+ }
2414
2555
  e.preventDefault();
2415
2556
  if (this._actionMustDelete(cursor, this.actions[key], e)) {
2416
2557
  this.actions['Backspace'].callback(lidx, cursor, e);
@@ -2418,17 +2559,19 @@ class CodeEditor {
2418
2559
  return this.actions[key].callback(lidx, cursor, e);
2419
2560
  }
2420
2561
  // From now on, don't allow ctrl, shift or meta (mac) combinations
2421
- if (e.ctrlKey || e.metaKey)
2562
+ if (e.ctrlKey || e.metaKey) {
2422
2563
  return;
2564
+ }
2423
2565
  // Add undo steps
2424
2566
  if (!skipUndo && this.code.lines.length) {
2425
2567
  this._addUndoStep(cursor);
2426
2568
  }
2427
2569
  // Some custom cases for word enclosing (), {}, "", '', ...
2428
- const enclosableKeys = ["\"", "'", "(", "{"];
2570
+ const enclosableKeys = ['"', "'", '(', '{'];
2429
2571
  if (enclosableKeys.indexOf(key) > -1) {
2430
- if (this._encloseSelectedWordWithKey(key, lidx, cursor))
2572
+ if (this._encloseSelectedWordWithKey(key, lidx, cursor)) {
2431
2573
  return;
2574
+ }
2432
2575
  }
2433
2576
  // Until this point, if there was a selection, we need
2434
2577
  // to delete the content..
@@ -2448,7 +2591,7 @@ class CodeEditor {
2448
2591
  }
2449
2592
  this.cursorToRight(key, cursor);
2450
2593
  // Some custom cases for auto key pair (), {}, "", '', ...
2451
- const keyMustPair = (this.pairKeys[key] !== undefined);
2594
+ const keyMustPair = this.pairKeys[key] !== undefined;
2452
2595
  if (keyMustPair && !this.wasKeyPaired) {
2453
2596
  // Make sure to detect later that the key is paired automatically to avoid loops...
2454
2597
  this.wasKeyPaired = true;
@@ -2470,7 +2613,7 @@ class CodeEditor {
2470
2613
  }
2471
2614
  }
2472
2615
  async _pasteContent(cursor) {
2473
- const mustDetectLanguage = (!this.getText().length);
2616
+ const mustDetectLanguage = !this.getText().length;
2474
2617
  let text = await navigator.clipboard.readText();
2475
2618
  // Remove any possible tabs (\t) and add spaces
2476
2619
  text = text.replaceAll(/\t|\\t/g, ' '.repeat(this.tabSpaces));
@@ -2489,23 +2632,24 @@ class CodeEditor {
2489
2632
  }
2490
2633
  }
2491
2634
  async _copyContent(cursor) {
2492
- let textToCopy = "";
2635
+ let textToCopy = '';
2493
2636
  if (!cursor.selection) {
2494
- textToCopy = "\n" + this.code.lines[cursor.line];
2637
+ textToCopy = '\n' + this.code.lines[cursor.line];
2495
2638
  }
2496
2639
  else {
2497
2640
  // Some selections don't depend on mouse up..
2498
2641
  if (cursor.selection)
2499
2642
  cursor.selection.invertIfNecessary();
2500
- const separator = "_NEWLINE_";
2643
+ const separator = '_NEWLINE_';
2501
2644
  let code = this.code.lines.join(separator);
2502
2645
  // Get linear start index
2503
2646
  let index = 0;
2504
2647
  for (let i = 0; i <= cursor.selection.fromY; i++) {
2505
- index += (i == cursor.selection.fromY ? cursor.selection.fromX : this.code.lines[i].length);
2648
+ index += i == cursor.selection.fromY ? cursor.selection.fromX : this.code.lines[i].length;
2506
2649
  }
2507
2650
  index += cursor.selection.fromY * separator.length;
2508
- const num_chars = cursor.selection.chars + (cursor.selection.toY - cursor.selection.fromY) * separator.length;
2651
+ const num_chars = cursor.selection.chars
2652
+ + (cursor.selection.toY - cursor.selection.fromY) * separator.length;
2509
2653
  const text = code.substr(index, num_chars);
2510
2654
  const lines = text.split(separator);
2511
2655
  textToCopy = lines.join('\n');
@@ -2515,10 +2659,10 @@ class CodeEditor {
2515
2659
  }
2516
2660
  async _cutContent(cursor) {
2517
2661
  let lidx = cursor.line;
2518
- let textToCut = "";
2662
+ let textToCut = '';
2519
2663
  this._addUndoStep(cursor, true);
2520
2664
  if (!cursor.selection) {
2521
- textToCut = "\n" + this.code.lines[cursor.line];
2665
+ textToCut = '\n' + this.code.lines[cursor.line];
2522
2666
  this.code.lines.splice(lidx, 1);
2523
2667
  this.processLines();
2524
2668
  this.resetCursorPos(CodeEditor.CURSOR_LEFT, cursor);
@@ -2530,15 +2674,16 @@ class CodeEditor {
2530
2674
  // Some selections don't depend on mouse up..
2531
2675
  if (cursor.selection)
2532
2676
  cursor.selection.invertIfNecessary();
2533
- const separator = "_NEWLINE_";
2677
+ const separator = '_NEWLINE_';
2534
2678
  let code = this.code.lines.join(separator);
2535
2679
  // Get linear start index
2536
2680
  let index = 0;
2537
2681
  for (let i = 0; i <= cursor.selection.fromY; i++) {
2538
- index += (i == cursor.selection.fromY ? cursor.selection.fromX : this.code.lines[i].length);
2682
+ index += i == cursor.selection.fromY ? cursor.selection.fromX : this.code.lines[i].length;
2539
2683
  }
2540
2684
  index += cursor.selection.fromY * separator.length;
2541
- const numChars = cursor.selection.chars + (cursor.selection.toY - cursor.selection.fromY) * separator.length;
2685
+ const numChars = cursor.selection.chars
2686
+ + (cursor.selection.toY - cursor.selection.fromY) * separator.length;
2542
2687
  const text = code.substr(index, numChars);
2543
2688
  const lines = text.split(separator);
2544
2689
  textToCut = lines.join('\n');
@@ -2570,7 +2715,7 @@ class CodeEditor {
2570
2715
  return idx < 0 ? 1e10 : idx;
2571
2716
  }));
2572
2717
  if (useCommentBlock) {
2573
- const tokens = (lang.blockCommentsTokens ?? this.defaultBlockCommentTokens);
2718
+ const tokens = lang.blockCommentsTokens ?? this.defaultBlockCommentTokens;
2574
2719
  const fromString = this.code.lines[cursor.selection.fromY];
2575
2720
  let fromIdx = firstNonspaceIndex(fromString);
2576
2721
  if (fromIdx == -1) {
@@ -2578,11 +2723,11 @@ class CodeEditor {
2578
2723
  }
2579
2724
  this.code.lines[cursor.selection.fromY] = [
2580
2725
  fromString.substring(0, fromIdx),
2581
- tokens[0] + " ",
2726
+ tokens[0] + ' ',
2582
2727
  fromString.substring(fromIdx)
2583
2728
  ].join('');
2584
- this.code.lines[cursor.selection.toY] += " " + tokens[1];
2585
- cursor.selection.fromX += (tokens[0].length + 1);
2729
+ this.code.lines[cursor.selection.toY] += ' ' + tokens[1];
2730
+ cursor.selection.fromX += tokens[0].length + 1;
2586
2731
  this._processSelection(cursor);
2587
2732
  }
2588
2733
  else {
@@ -2610,8 +2755,9 @@ class CodeEditor {
2610
2755
  }
2611
2756
  _commentLine(cursor, line, minNonspaceIdx, updateCursor = true) {
2612
2757
  const lang = CodeEditor.languages[this.highlight];
2613
- if (!(lang.singleLineComments ?? true))
2758
+ if (!(lang.singleLineComments ?? true)) {
2614
2759
  return;
2760
+ }
2615
2761
  const token = (lang.singleLineCommentToken ?? this.defaultSingleLineCommentToken) + ' ';
2616
2762
  const string = this.code.lines[line];
2617
2763
  let idx = firstNonspaceIndex(string);
@@ -2649,29 +2795,31 @@ class CodeEditor {
2649
2795
  }
2650
2796
  _uncommentLine(cursor, line) {
2651
2797
  const lang = CodeEditor.languages[this.highlight];
2652
- if (!(lang.singleLineComments ?? true))
2798
+ if (!(lang.singleLineComments ?? true)) {
2653
2799
  return;
2800
+ }
2654
2801
  const token = lang.singleLineCommentToken ?? this.defaultSingleLineCommentToken;
2655
2802
  const string = this.code.lines[line];
2656
2803
  if (string.includes(token)) {
2657
2804
  this.code.lines[line] = string.replace(token + ' ', '');
2658
2805
  // try deleting token + space, and then if not, delete only the token
2659
- if (string.length == this.code.lines[line].length)
2806
+ if (string.length == this.code.lines[line].length) {
2660
2807
  this.code.lines[line] = string.replace(token, '');
2808
+ }
2661
2809
  this.cursorToString(cursor, 'X'.repeat(Math.abs(string.length - this.code.lines[line].length)), true);
2662
2810
  }
2663
2811
  }
2664
2812
  action(key, deleteSelection = false, fn, eventSkipDeleteFn) {
2665
2813
  this.actions[key] = {
2666
- "key": key,
2667
- "callback": fn,
2668
- "deleteSelection": deleteSelection,
2669
- "eventSkipDeleteFn": eventSkipDeleteFn
2814
+ 'key': key,
2815
+ 'callback': fn,
2816
+ 'deleteSelection': deleteSelection,
2817
+ 'eventSkipDeleteFn': eventSkipDeleteFn
2670
2818
  };
2671
2819
  }
2672
2820
  _actionMustDelete(cursor, action, e) {
2673
- return cursor.selection && action.deleteSelection &&
2674
- !(action.eventSkipDeleteFn ? action.eventSkipDeleteFn(cursor, e) : false);
2821
+ return cursor.selection && action.deleteSelection
2822
+ && !(action.eventSkipDeleteFn ? action.eventSkipDeleteFn(cursor, e) : false);
2675
2823
  }
2676
2824
  scanWordSuggestions() {
2677
2825
  this.code.tokens = {};
@@ -2698,15 +2846,16 @@ class CodeEditor {
2698
2846
  if (!this.code) {
2699
2847
  return;
2700
2848
  }
2701
- var htmlCode = "";
2849
+ var htmlCode = '';
2702
2850
  this._blockCommentCache.length = 0;
2703
2851
  this.mustProcessLines = false;
2704
2852
  // Reset all lines content
2705
- this.code.innerHTML = "";
2853
+ this.code.innerHTML = '';
2706
2854
  // Get info about lines in viewport
2707
2855
  const lastScrollTop = this.getScrollTop();
2708
- this.firstLineInViewport = (mode ?? CodeEditor.KEEP_VISIBLE_LINES) & CodeEditor.UPDATE_VISIBLE_LINES ?
2709
- ((lastScrollTop / this.lineHeight) | 0) : this.firstLineInViewport;
2856
+ this.firstLineInViewport = (mode ?? CodeEditor.KEEP_VISIBLE_LINES) & CodeEditor.UPDATE_VISIBLE_LINES
2857
+ ? ((lastScrollTop / this.lineHeight) | 0)
2858
+ : this.firstLineInViewport;
2710
2859
  const totalLinesInViewport = ((this.codeScroller.offsetHeight) / this.lineHeight) | 0;
2711
2860
  this.visibleLinesViewport = new LX.vec2(Math.max(this.firstLineInViewport - this.lineScrollMargin.x, 0), Math.min(this.firstLineInViewport + totalLinesInViewport + this.lineScrollMargin.y, this.code.lines.length));
2712
2861
  // Add remaining lines if we are near the end of the scroll
@@ -2716,7 +2865,7 @@ class CodeEditor {
2716
2865
  this.visibleLinesViewport.y += diff;
2717
2866
  }
2718
2867
  }
2719
- this._scopeStack = [{ name: "", type: "global" }];
2868
+ this._scopeStack = [{ name: '', type: 'global' }];
2720
2869
  // Process visible lines
2721
2870
  for (let i = this.visibleLinesViewport.x; i < this.visibleLinesViewport.y; ++i) {
2722
2871
  htmlCode += this.processLine(i, true);
@@ -2724,7 +2873,7 @@ class CodeEditor {
2724
2873
  this.code.innerHTML = htmlCode;
2725
2874
  // Update scroll data
2726
2875
  this.codeScroller.scrollTop = lastScrollTop;
2727
- this.code.style.top = (this.visibleLinesViewport.x * this.lineHeight) + "px";
2876
+ this.code.style.top = (this.visibleLinesViewport.x * this.lineHeight) + 'px';
2728
2877
  // Update selections
2729
2878
  this.updateSelections(null, true);
2730
2879
  this._clearTmpVariables();
@@ -2764,9 +2913,9 @@ class CodeEditor {
2764
2913
  this._currentLineString = lineString;
2765
2914
  const tokensToEvaluate = this._getTokensFromLine(lineString);
2766
2915
  if (!tokensToEvaluate.length) {
2767
- return this._updateLine(force, lineNumber, "", skipPropagation);
2916
+ return this._updateLine(force, lineNumber, '', skipPropagation);
2768
2917
  }
2769
- let lineInnerHtml = "";
2918
+ let lineInnerHtml = '';
2770
2919
  let pushedScope = false;
2771
2920
  const newSignature = this._getLineSignatureFromTokens(tokensToEvaluate);
2772
2921
  const cachedSignature = this.code.lineSignatures[lineNumber];
@@ -2775,7 +2924,7 @@ class CodeEditor {
2775
2924
  const blockCommentsTokens = lang.blockCommentsTokens ?? this.defaultBlockCommentTokens;
2776
2925
  // Reset scope stack if structural changes in current line
2777
2926
  if (mustUpdateScopes) {
2778
- this._scopeStack = [{ name: "", type: "global" }];
2927
+ this._scopeStack = [{ name: '', type: 'global' }];
2779
2928
  }
2780
2929
  // Process all tokens
2781
2930
  for (let i = 0; i < tokensToEvaluate.length; ++i) {
@@ -2801,7 +2950,7 @@ class CodeEditor {
2801
2950
  }
2802
2951
  // Compare line signature for structural changes
2803
2952
  // to pop current scope if necessary
2804
- if (token === "}" && this._scopeStack.length > 1) {
2953
+ if (token === '}' && this._scopeStack.length > 1) {
2805
2954
  this._scopeStack.pop();
2806
2955
  }
2807
2956
  lineInnerHtml += this._evaluateToken({
@@ -2818,10 +2967,11 @@ class CodeEditor {
2818
2967
  if (blockComments && this._buildingBlockComment != undefined
2819
2968
  && token.substr(0, blockCommentsTokens[1].length) == blockCommentsTokens[1]) {
2820
2969
  const [commentLineNumber, tokenPos] = this._buildingBlockComment;
2821
- this._blockCommentCache.push([new LX.vec2(commentLineNumber, lineNumber), new LX.vec2(tokenPos, tokenStartIndex)]);
2970
+ this._blockCommentCache.push([new LX.vec2(commentLineNumber, lineNumber),
2971
+ new LX.vec2(tokenPos, tokenStartIndex)]);
2822
2972
  delete this._buildingBlockComment;
2823
2973
  }
2824
- if (token !== "{") {
2974
+ if (token !== '{') {
2825
2975
  continue;
2826
2976
  }
2827
2977
  // Store current scopes
@@ -2850,10 +3000,10 @@ class CodeEditor {
2850
3000
  }
2851
3001
  }
2852
3002
  }
2853
- contextTokens = contextTokens.reverse().filter(v => v.length && v != ' ');
3003
+ contextTokens = contextTokens.reverse().filter((v) => v.length && v != ' ');
2854
3004
  // Keywords that can open a *named* scope
2855
3005
  // TODO: Do this per language
2856
- const scopeKeywords = ["class", "enum", "function", "interface", "type", "struct", "namespace"];
3006
+ const scopeKeywords = ['class', 'enum', 'function', 'interface', 'type', 'struct', 'namespace'];
2857
3007
  let scopeType = null; // This is the type of scope (function, class, enum, etc)
2858
3008
  let scopeName = null;
2859
3009
  for (let i = 0; i < contextTokens.length; i++) {
@@ -2865,21 +3015,21 @@ class CodeEditor {
2865
3015
  }
2866
3016
  }
2867
3017
  // Special case: enum type specification `enum Foo : int {`
2868
- if (scopeType === "enum" && contextTokens.includes(":")) {
2869
- const colonIndex = contextTokens.indexOf(":");
3018
+ if (scopeType === 'enum' && contextTokens.includes(':')) {
3019
+ const colonIndex = contextTokens.indexOf(':');
2870
3020
  scopeName = contextTokens[colonIndex + 1] || scopeName;
2871
3021
  }
2872
3022
  if (!scopeType) {
2873
- const parOpenIndex = contextTokens.indexOf("(");
3023
+ const parOpenIndex = contextTokens.indexOf('(');
2874
3024
  scopeName = contextTokens[parOpenIndex + 1] || scopeName;
2875
3025
  if (scopeName) {
2876
- scopeType = "method";
3026
+ scopeType = 'method';
2877
3027
  }
2878
3028
  }
2879
3029
  // Only push if it's not already reflected in the cached scopes
2880
3030
  const lastScope = this._scopeStack.at(-1);
2881
3031
  if (lastScope?.lineNumber !== lineNumber) {
2882
- this._scopeStack.push({ name: scopeName ?? "", type: scopeType ?? "anonymous", lineNumber });
3032
+ this._scopeStack.push({ name: scopeName ?? '', type: scopeType ?? 'anonymous', lineNumber });
2883
3033
  }
2884
3034
  pushedScope = true;
2885
3035
  }
@@ -2890,14 +3040,14 @@ class CodeEditor {
2890
3040
  }
2891
3041
  _getLineSignatureFromTokens(tokens) {
2892
3042
  const structuralChars = new Set(['{', '}']);
2893
- const sign = tokens.filter(t => structuralChars.has(t));
2894
- return sign.join("_");
3043
+ const sign = tokens.filter((t) => structuralChars.has(t));
3044
+ return sign.join('_');
2895
3045
  }
2896
3046
  _updateBlockComments(section, lineNumber, tokens) {
2897
3047
  const lang = CodeEditor.languages[this.highlight];
2898
3048
  const blockCommentsTokens = lang.blockCommentsTokens ?? this.defaultBlockCommentTokens;
2899
- const lineOpensBlock = (section[0].x === lineNumber);
2900
- const lineClosesBlock = (section[0].y === lineNumber);
3049
+ const lineOpensBlock = section[0].x === lineNumber;
3050
+ const lineClosesBlock = section[0].y === lineNumber;
2901
3051
  (section[0].x !== lineNumber) && (section[0].y !== lineNumber);
2902
3052
  delete this._buildingBlockComment;
2903
3053
  /*
@@ -2905,7 +3055,7 @@ class CodeEditor {
2905
3055
  until reaching new delimiters
2906
3056
  */
2907
3057
  if (lineOpensBlock) {
2908
- const r = tokens.filter(t => t.substr(0, blockCommentsTokens[0].length) == blockCommentsTokens[0]);
3058
+ const r = tokens.filter((t) => t.substr(0, blockCommentsTokens[0].length) == blockCommentsTokens[0]);
2909
3059
  if (!r.length) {
2910
3060
  this._buildingBlockComment = [lineNumber - 1, 0];
2911
3061
  this.mustProcessPreviousLine = (tokens) => {
@@ -2927,7 +3077,7 @@ class CodeEditor {
2927
3077
  }
2928
3078
  }
2929
3079
  else if (lineClosesBlock) {
2930
- const r = tokens.filter(t => t.substr(0, blockCommentsTokens[1].length) == blockCommentsTokens[1]);
3080
+ const r = tokens.filter((t) => t.substr(0, blockCommentsTokens[1].length) == blockCommentsTokens[1]);
2931
3081
  if (!r.length) {
2932
3082
  this._buildingBlockComment = [section[0].x, section[1].x];
2933
3083
  this.mustProcessNextLine = (tokens) => {
@@ -2952,7 +3102,7 @@ class CodeEditor {
2952
3102
  }
2953
3103
  _processExtraLineIfNecessary(lineNumber, tokens, oldSymbols, skipPropagation = false) {
2954
3104
  if (!this._scopeStack) {
2955
- console.warn("CodeEditor: No scope available");
3105
+ console.warn('CodeEditor: No scope available');
2956
3106
  return;
2957
3107
  }
2958
3108
  // Update block comments if necessary
@@ -2969,7 +3119,7 @@ class CodeEditor {
2969
3119
  }
2970
3120
  const newSignature = this._getLineSignatureFromTokens(tokens);
2971
3121
  const cachedSignature = this.code.lineSignatures[lineNumber];
2972
- const mustUpdateScopes = (cachedSignature !== newSignature);
3122
+ const mustUpdateScopes = cachedSignature !== newSignature;
2973
3123
  const sameScopes = codeScopesEqual(this._scopeStack, this.code.lineScopes[lineNumber + 1]);
2974
3124
  // Only update scope stack if something changed when editing a single line
2975
3125
  // Compare line signature for structural changes
@@ -3000,12 +3150,15 @@ class CodeEditor {
3000
3150
  _updateLine(force = false, lineNumber, html, skipPropagation = false, symbols = [], tokens = []) {
3001
3151
  const gutterLineHtml = `<span class='line-gutter'>${lineNumber + 1}</span>`;
3002
3152
  const oldSymbols = this._updateLineSymbols(lineNumber, symbols);
3003
- const lineScope = CodeEditor.debugScopes && this.code.lineScopes[lineNumber] ? this.code.lineScopes[lineNumber].map((s) => `${s.type}`).join(", ") : "";
3004
- const lineSymbols = CodeEditor.debugSymbols && this.code.lineSymbols[lineNumber] ? this.code.lineSymbols[lineNumber].map((s) => `${s.name}(${s.kind})`).join(", ") : "";
3005
- const debugString = lineScope + (lineScope.length ? " - " : "") + lineSymbols;
3006
- if (!force) // Single line update
3007
- {
3008
- this.code.childNodes[this.toLocalLine(lineNumber)].innerHTML = (gutterLineHtml + html + debugString);
3153
+ const lineScope = CodeEditor.debugScopes && this.code.lineScopes[lineNumber]
3154
+ ? this.code.lineScopes[lineNumber].map((s) => `${s.type}`).join(', ')
3155
+ : '';
3156
+ const lineSymbols = CodeEditor.debugSymbols && this.code.lineSymbols[lineNumber]
3157
+ ? this.code.lineSymbols[lineNumber].map((s) => `${s.name}(${s.kind})`).join(', ')
3158
+ : '';
3159
+ const debugString = lineScope + (lineScope.length ? ' - ' : '') + lineSymbols;
3160
+ if (!force) { // Single line update
3161
+ this.code.childNodes[this.toLocalLine(lineNumber)].innerHTML = gutterLineHtml + html + debugString;
3009
3162
  if (!skipPropagation) {
3010
3163
  this._processExtraLineIfNecessary(lineNumber, tokens, oldSymbols, skipPropagation);
3011
3164
  }
@@ -3026,7 +3179,7 @@ class CodeEditor {
3026
3179
  }
3027
3180
  }
3028
3181
  if (CodeEditor.debugProcessedLines) {
3029
- this.code.childNodes[lineNumber]?.classList.add("debug");
3182
+ this.code.childNodes[lineNumber]?.classList.add('debug');
3030
3183
  }
3031
3184
  this._setActiveLine(lineNumber);
3032
3185
  this._clearTmpVariables();
@@ -3058,31 +3211,34 @@ class CodeEditor {
3058
3211
  symbols.push(s);
3059
3212
  };
3060
3213
  // Don't make symbols from preprocessor lines
3061
- if (text.startsWith("#")) {
3214
+ if (text.startsWith('#')) {
3062
3215
  return [];
3063
3216
  }
3064
3217
  const nativeTypes = CodeEditor.nativeTypes[this.highlight];
3065
3218
  const topLevelRegexes = [
3066
- [/^class\s+([A-Za-z0-9_]+)/, "class"],
3067
- [/^struct\s+([A-Za-z0-9_]+)/, "struct"],
3068
- [/^enum\s+([A-Za-z0-9_]+)/, "enum"],
3069
- [/^interface\s+([A-Za-z0-9_]+)/, "interface"],
3070
- [/^type\s+([A-Za-z0-9_]+)/, "type"],
3071
- [/^function\s+([A-Za-z0-9_]+)/, "method"],
3072
- [/^fn\s+([A-Za-z0-9_]+)/, "method"],
3073
- [/^def\s+([A-Za-z0-9_]+)/, "method"],
3074
- [/^([A-Za-z0-9_]+)\s*=\s*\(?.*\)?\s*=>/, "method"] // arrow functions
3219
+ [/^class\s+([A-Za-z0-9_]+)/, 'class'],
3220
+ [/^struct\s+([A-Za-z0-9_]+)/, 'struct'],
3221
+ [/^enum\s+([A-Za-z0-9_]+)/, 'enum'],
3222
+ [/^interface\s+([A-Za-z0-9_]+)/, 'interface'],
3223
+ [/^type\s+([A-Za-z0-9_]+)/, 'type'],
3224
+ [/^function\s+([A-Za-z0-9_]+)/, 'method'],
3225
+ [/^fn\s+([A-Za-z0-9_]+)/, 'method'],
3226
+ [/^def\s+([A-Za-z0-9_]+)/, 'method'],
3227
+ [/^([A-Za-z0-9_]+)\s*=\s*\(?.*\)?\s*=>/, 'method'] // arrow functions
3075
3228
  ];
3076
3229
  // Add regexes to detect methods, variables ( including "id : nativeType" )
3077
3230
  {
3078
3231
  if (nativeTypes) {
3079
- topLevelRegexes.push([new RegExp(`^(?:${nativeTypes.join('|')})\\s+([A-Za-z0-9_]+)\s*[\(]+`), 'method']);
3080
- if (this.highlight === "WGSL") {
3081
- topLevelRegexes.push([new RegExp(`[A-Za-z0-9]+(\\s*)+:(\\s*)+(${nativeTypes.join('|')})`), 'variable', (m) => m[0].split(":")[0].trim()]);
3232
+ topLevelRegexes.push([new RegExp(`^(?:${nativeTypes.join('|')})\\s+([A-Za-z0-9_]+)\s*[\(]+`),
3233
+ 'method']);
3234
+ if (this.highlight === 'WGSL') {
3235
+ topLevelRegexes.push([new RegExp(`[A-Za-z0-9]+(\\s*)+:(\\s*)+(${nativeTypes.join('|')})`),
3236
+ 'variable', (m) => m[0].split(':')[0].trim()]);
3082
3237
  }
3083
3238
  }
3084
- const declarationKeywords = CodeEditor.declarationKeywords[this.highlight] ?? ["const", "let", "var"];
3085
- topLevelRegexes.push([new RegExp(`^(?:${declarationKeywords.join('|')})\\s+([A-Za-z0-9_]+)`), 'variable']);
3239
+ const declarationKeywords = CodeEditor.declarationKeywords[this.highlight] ?? ['const', 'let', 'var'];
3240
+ topLevelRegexes.push([new RegExp(`^(?:${declarationKeywords.join('|')})\\s+([A-Za-z0-9_]+)`),
3241
+ 'variable']);
3086
3242
  }
3087
3243
  for (let [regex, kind, fn] of topLevelRegexes) {
3088
3244
  const m = text.match(regex);
@@ -3091,8 +3247,8 @@ class CodeEditor {
3091
3247
  }
3092
3248
  }
3093
3249
  const usageRegexes = [
3094
- [/new\s+([A-Za-z0-9_]+)\s*\(/, "constructor-call"],
3095
- [/this.([A-Za-z_][A-Za-z0-9_]*)\s*\=/, "class-property"],
3250
+ [/new\s+([A-Za-z0-9_]+)\s*\(/, 'constructor-call'],
3251
+ [/this.([A-Za-z_][A-Za-z0-9_]*)\s*\=/, 'class-property']
3096
3252
  ];
3097
3253
  for (let [regex, kind, fn] of usageRegexes) {
3098
3254
  const m = text.match(regex);
@@ -3108,31 +3264,32 @@ class CodeEditor {
3108
3264
  const before = text.slice(0, match.index);
3109
3265
  if (/(new|function|fn|def)\s+$/.test(before))
3110
3266
  continue; // skip constructor calls
3111
- if (["constructor", "location", ...(nativeTypes ?? [])].indexOf(name) > -1)
3267
+ if (['constructor', 'location', ...(nativeTypes ?? [])].indexOf(name) > -1)
3112
3268
  continue; // skip hardcoded non method symbol
3113
- if (previousLineScope && previousLineScope.at(-1)?.type === "class")
3269
+ if (previousLineScope && previousLineScope.at(-1)?.type === 'class')
3114
3270
  continue; // skip class methods
3115
- _pushSymbol({ name, kind: "method-call", scope: scopeName, line: lineNumber });
3271
+ _pushSymbol({ name, kind: 'method-call', scope: scopeName, line: lineNumber });
3116
3272
  }
3117
3273
  // Stop after matches for top-level declarations and usage symbols
3118
3274
  if (symbols.length) {
3119
3275
  return symbols;
3120
3276
  }
3121
- const nonWhiteSpaceTokens = tokens.filter(t => t.trim().length);
3277
+ const nonWhiteSpaceTokens = tokens.filter((t) => t.trim().length);
3122
3278
  for (let i = 0; i < nonWhiteSpaceTokens.length; i++) {
3123
3279
  const prev = nonWhiteSpaceTokens[i - 1];
3124
3280
  const token = nonWhiteSpaceTokens[i];
3125
3281
  const next = nonWhiteSpaceTokens[i + 1];
3126
- if (scopeType.startsWith("class")) {
3127
- if (next === "(" && /^[a-zA-Z_]\w*$/.test(token) && prev === undefined) {
3128
- if (token === "constructor")
3282
+ if (scopeType.startsWith('class')) {
3283
+ if (next === '(' && /^[a-zA-Z_]\w*$/.test(token) && prev === undefined) {
3284
+ if (token === 'constructor')
3129
3285
  continue; // skip constructor symbol
3130
- _pushSymbol({ name: token, kind: "method", scope: scopeName, line: lineNumber });
3286
+ _pushSymbol({ name: token, kind: 'method', scope: scopeName, line: lineNumber });
3131
3287
  }
3132
3288
  }
3133
- else if (scopeType.startsWith("enum")) {
3134
- if (!isSymbol(token) && !this._isNumber(token) && !this._mustHightlightWord(token, CodeEditor.statements)) {
3135
- _pushSymbol({ name: token, kind: "enum_value", scope: scopeName, line: lineNumber });
3289
+ else if (scopeType.startsWith('enum')) {
3290
+ if (!isSymbol(token) && !this._isNumber(token)
3291
+ && !this._mustHightlightWord(token, CodeEditor.statements)) {
3292
+ _pushSymbol({ name: token, kind: 'enum_value', scope: scopeName, line: lineNumber });
3136
3293
  }
3137
3294
  }
3138
3295
  }
@@ -3182,8 +3339,8 @@ class CodeEditor {
3182
3339
  // Count times we started a string BEFORE the comment
3183
3340
  var err = false;
3184
3341
  err = err || (stringKeys.some(function (v) {
3185
- var re = new RegExp(v, "g");
3186
- var matches = (lineString.substring(0, idx).match(re) || []);
3342
+ var re = new RegExp(v, 'g');
3343
+ var matches = lineString.substring(0, idx).match(re) || [];
3187
3344
  return (matches.length % 2) !== 0;
3188
3345
  }));
3189
3346
  return err ? undefined : idx;
@@ -3203,8 +3360,9 @@ class CodeEditor {
3203
3360
  let charCounterList = [];
3204
3361
  let charCounter = 0;
3205
3362
  const pushToken = function (t) {
3206
- if ((skipNonWords && (t.includes('"') || t.length < 3)))
3363
+ if ((skipNonWords && (t.includes('"') || t.length < 3))) {
3207
3364
  return;
3365
+ }
3208
3366
  tokensToEvaluate.push(t);
3209
3367
  charCounterList.push(charCounter);
3210
3368
  // Update positions
@@ -3252,7 +3410,7 @@ class CodeEditor {
3252
3410
  }
3253
3411
  const importantIdx = tokens.indexOf('important');
3254
3412
  if (this.highlight == 'CSS' && importantIdx > -1 && tokens[importantIdx - 1] === '!') {
3255
- tokens[importantIdx - 1] = "!important";
3413
+ tokens[importantIdx - 1] = '!important';
3256
3414
  tokens.splice(importantIdx, 1);
3257
3415
  }
3258
3416
  }
@@ -3262,11 +3420,11 @@ class CodeEditor {
3262
3420
  while (dollarIdx > -1) {
3263
3421
  const offsetIdx = dollarIdx + offset;
3264
3422
  if (tokens[offsetIdx + 1] === 'this-') {
3265
- tokens[offsetIdx] = "$this";
3266
- tokens[offsetIdx + 1] = "-";
3423
+ tokens[offsetIdx] = '$this';
3424
+ tokens[offsetIdx + 1] = '-';
3267
3425
  }
3268
3426
  else {
3269
- tokens[offsetIdx] += (tokens[offsetIdx + 1] ?? "");
3427
+ tokens[offsetIdx] += tokens[offsetIdx + 1] ?? '';
3270
3428
  tokens.splice(offsetIdx + 1, 1);
3271
3429
  }
3272
3430
  dollarIdx = tokens.slice(offsetIdx).indexOf('$');
@@ -3278,7 +3436,7 @@ class CodeEditor {
3278
3436
  let atIdx = tokens.indexOf('@');
3279
3437
  while (atIdx > -1) {
3280
3438
  const offsetIdx = atIdx + offset;
3281
- tokens[offsetIdx] += (tokens[offsetIdx + 1] ?? "");
3439
+ tokens[offsetIdx] += tokens[offsetIdx + 1] ?? '';
3282
3440
  tokens.splice(offsetIdx + 1, 1);
3283
3441
  atIdx = tokens.slice(offsetIdx).indexOf('$');
3284
3442
  offset = offsetIdx;
@@ -3297,7 +3455,8 @@ class CodeEditor {
3297
3455
  return wordCategory[this.highlight] && wordCategory[this.highlight].has(t);
3298
3456
  }
3299
3457
  _getTokenHighlighting(ctx, highlight) {
3300
- const rules = [...HighlightRules.common, ...(HighlightRules[highlight] || []), ...HighlightRules.post_common];
3458
+ const rules = [...HighlightRules.common, ...(HighlightRules[highlight] || []),
3459
+ ...HighlightRules.post_common];
3301
3460
  for (const rule of rules) {
3302
3461
  if (!rule.test(ctx, this)) {
3303
3462
  continue;
@@ -3312,14 +3471,14 @@ class CodeEditor {
3312
3471
  _evaluateToken(ctxData) {
3313
3472
  let { token, prev, next, tokenIndex, isFirstToken, isLastToken } = ctxData;
3314
3473
  const lang = CodeEditor.languages[this.highlight];
3315
- const highlight = this.highlight.replace(/\s/g, '').replaceAll("+", "p").toLowerCase();
3474
+ const highlight = this.highlight.replace(/\s/g, '').replaceAll('+', 'p').toLowerCase();
3316
3475
  const customStringKeys = Object.assign({}, this.stringKeys);
3317
3476
  const lineNumber = this._currentLineNumber;
3318
3477
  const tokenStartIndex = this._currentTokenPositions[tokenIndex];
3319
- const inBlockComment = (this._buildingBlockComment ?? this._inBlockCommentSection(lineNumber, tokenStartIndex, token.length)) !== undefined;
3478
+ const inBlockComment = (this._buildingBlockComment ?? this._inBlockCommentSection(lineNumber, tokenStartIndex, token.length))
3479
+ !== undefined;
3320
3480
  var usePreviousTokenToCheckString = false;
3321
- if (['cpp', 'c'].indexOf(highlight) > -1 && prev && prev.includes('#')) // preprocessor code..
3322
- {
3481
+ if (['cpp', 'c'].indexOf(highlight) > -1 && prev && prev.includes('#')) { // preprocessor code..
3323
3482
  customStringKeys['@<'] = '>';
3324
3483
  }
3325
3484
  else if (highlight == 'markdown' && (ctxData.prevWithSpaces == '[' || ctxData.nextWithSpaces == ']')) {
@@ -3328,14 +3487,16 @@ class CodeEditor {
3328
3487
  customStringKeys['@['] = ']';
3329
3488
  }
3330
3489
  else if (highlight == 'javascript' || highlight == 'typescript') {
3331
- customStringKeys["@`"] = "`";
3490
+ customStringKeys['@`'] = '`';
3332
3491
  }
3333
3492
  // Manage strings
3334
3493
  this._stringEnded = false;
3335
- if (usePreviousTokenToCheckString || (!inBlockComment && (lang.tags ?? false ? (this._enclosedByTokens(token, tokenIndex, '<', '>')) : true))) {
3494
+ if (usePreviousTokenToCheckString
3495
+ || (!inBlockComment
3496
+ && (lang.tags ?? false ? (this._enclosedByTokens(token, tokenIndex, '<', '>')) : true))) {
3336
3497
  const _checkIfStringEnded = (t) => {
3337
3498
  if (this._stringInterpolation) {
3338
- if (token == "$" && next == "{") {
3499
+ if (token == '$' && next == '{') {
3339
3500
  delete this._stringInterpolation;
3340
3501
  this._stringInterpolationOpened = true;
3341
3502
  this._stringEnded = true;
@@ -3343,15 +3504,17 @@ class CodeEditor {
3343
3504
  }
3344
3505
  }
3345
3506
  const idx = Object.values(customStringKeys).indexOf(t);
3346
- this._stringEnded = (idx > -1) && (idx == Object.values(customStringKeys).indexOf(customStringKeys['@' + this._buildingString]));
3507
+ this._stringEnded = (idx > -1)
3508
+ && (idx
3509
+ == Object.values(customStringKeys).indexOf(customStringKeys['@' + this._buildingString]));
3347
3510
  };
3348
3511
  if (this._buildingString != undefined) {
3349
3512
  _checkIfStringEnded(usePreviousTokenToCheckString ? ctxData.nextWithSpaces : token);
3350
3513
  }
3351
3514
  else if (customStringKeys['@' + (usePreviousTokenToCheckString ? ctxData.prevWithSpaces : token)]) {
3352
3515
  // Start new string
3353
- this._buildingString = (usePreviousTokenToCheckString ? ctxData.prevWithSpaces : token);
3354
- if ((highlight == 'javascript' || highlight == 'typescript') && token == "`") {
3516
+ this._buildingString = usePreviousTokenToCheckString ? ctxData.prevWithSpaces : token;
3517
+ if ((highlight == 'javascript' || highlight == 'typescript') && token == '`') {
3355
3518
  this._stringInterpolation = true;
3356
3519
  }
3357
3520
  // Check if string ended in same token using next...
@@ -3359,47 +3522,47 @@ class CodeEditor {
3359
3522
  _checkIfStringEnded(ctxData.nextWithSpaces);
3360
3523
  }
3361
3524
  }
3362
- else if (this._stringInterpolationOpened && prev == "}") {
3525
+ else if (this._stringInterpolationOpened && prev == '}') {
3363
3526
  delete this._stringInterpolationOpened;
3364
3527
  this._stringInterpolation = true;
3365
- this._buildingString = "`";
3528
+ this._buildingString = '`';
3366
3529
  }
3367
3530
  }
3368
3531
  // Update context data for next tests
3369
3532
  ctxData.discardToken = false;
3370
3533
  ctxData.inBlockComment = inBlockComment;
3371
3534
  ctxData.markdownHeader = this._markdownHeader;
3372
- ctxData.inString = (this._buildingString !== undefined);
3535
+ ctxData.inString = this._buildingString !== undefined;
3373
3536
  ctxData.singleLineCommentToken = lang.singleLineCommentToken ?? this.defaultSingleLineCommentToken;
3374
3537
  ctxData.lang = lang;
3375
3538
  ctxData.scope = this._scopeStack.at(-1);
3376
3539
  // Add utils functions for the rules
3377
- ctxData.isVariableSymbol = (token) => this.code.symbolsTable.has(token) && this.code.symbolsTable.get(token)[0].kind === "variable";
3378
- ctxData.isEnumValueSymbol = (token) => this.code.symbolsTable.has(token) && this.code.symbolsTable.get(token)[0].kind === "enum_value";
3379
- ctxData.isClassSymbol = (token) => this.code.symbolsTable.has(token) && this.code.symbolsTable.get(token)[0].kind === "class";
3380
- ctxData.isStructSymbol = (token) => this.code.symbolsTable.has(token) && this.code.symbolsTable.get(token)[0].kind === "struct";
3381
- ctxData.isEnumSymbol = (token) => this.code.symbolsTable.has(token) && this.code.symbolsTable.get(token)[0].kind === "enum";
3540
+ ctxData.isVariableSymbol = (token) => this.code.symbolsTable.has(token) && this.code.symbolsTable.get(token)[0].kind === 'variable';
3541
+ ctxData.isEnumValueSymbol = (token) => this.code.symbolsTable.has(token) && this.code.symbolsTable.get(token)[0].kind === 'enum_value';
3542
+ ctxData.isClassSymbol = (token) => this.code.symbolsTable.has(token) && this.code.symbolsTable.get(token)[0].kind === 'class';
3543
+ ctxData.isStructSymbol = (token) => this.code.symbolsTable.has(token) && this.code.symbolsTable.get(token)[0].kind === 'struct';
3544
+ ctxData.isEnumSymbol = (token) => this.code.symbolsTable.has(token) && this.code.symbolsTable.get(token)[0].kind === 'enum';
3382
3545
  // Get highlighting class based on language common and specific rules
3383
3546
  let tokenClass = this._getTokenHighlighting(ctxData, highlight);
3384
3547
  if (this._stringInterpolationOpened && this._pendingString) {
3385
- this._pendingString = this._pendingString.substring(0, this._pendingString.indexOf("$"));
3386
- if (ctxData.tokens[tokenIndex + 1] == "{") {
3387
- ctxData.tokens[tokenIndex + 1] = "${";
3548
+ this._pendingString = this._pendingString.substring(0, this._pendingString.indexOf('$'));
3549
+ if (ctxData.tokens[tokenIndex + 1] == '{') {
3550
+ ctxData.tokens[tokenIndex + 1] = '${';
3388
3551
  }
3389
3552
  }
3390
3553
  // We finished constructing a string
3391
3554
  if (this._buildingString && (this._stringEnded || isLastToken) && !inBlockComment) {
3392
3555
  token = this._getCurrentString();
3393
- tokenClass = "cm-str";
3556
+ tokenClass = 'cm-str';
3394
3557
  ctxData.discardToken = false;
3395
3558
  }
3396
3559
  // Update state
3397
3560
  this._buildingString = this._stringEnded ? undefined : this._buildingString;
3398
3561
  if (ctxData.discardToken) {
3399
- return "";
3562
+ return '';
3400
3563
  }
3401
3564
  // Replace html chars
3402
- token = token.replace("<", "&lt;").replace(">", "&gt;");
3565
+ token = token.replace('<', '&lt;').replace('>', '&gt;');
3403
3566
  // No highlighting, no need to put it inside another span..
3404
3567
  if (!tokenClass) {
3405
3568
  return token;
@@ -3408,7 +3571,7 @@ class CodeEditor {
3408
3571
  }
3409
3572
  _appendStringToken(token) {
3410
3573
  if (!this._pendingString) {
3411
- this._pendingString = "";
3574
+ this._pendingString = '';
3412
3575
  }
3413
3576
  this._pendingString += token;
3414
3577
  return true;
@@ -3421,15 +3584,19 @@ class CodeEditor {
3421
3584
  _enclosedByTokens(token, tokenIndex, tagStart, tagEnd) {
3422
3585
  const tokenStartIndex = this._currentTokenPositions[tokenIndex];
3423
3586
  const tagStartIndex = indexOfFrom(this._currentLineString, tagStart, tokenStartIndex, true);
3424
- if (tagStartIndex < 0) // Not found..
3587
+ if (tagStartIndex < 0) { // Not found..
3425
3588
  return;
3589
+ }
3426
3590
  const tagStartIndexOpposite = indexOfFrom(this._currentLineString, tagEnd, tokenStartIndex, true);
3427
- if (tagStartIndexOpposite >= 0 && tagStartIndexOpposite > tagStartIndex) // Found the opposite first while reversing..
3591
+ if (tagStartIndexOpposite >= 0 && tagStartIndexOpposite > tagStartIndex) { // Found the opposite first while reversing..
3428
3592
  return;
3593
+ }
3429
3594
  const tagEndIndex = indexOfFrom(this._currentLineString, tagEnd, tokenStartIndex);
3430
- if (tagEndIndex < 0) // Not found..
3595
+ if (tagEndIndex < 0) { // Not found..
3431
3596
  return;
3432
- if ((tagStartIndex < tokenStartIndex) && (tagEndIndex >= (tokenStartIndex + token.length)) && !this._mustHightlightWord(token, CodeEditor.symbols)) {
3597
+ }
3598
+ if ((tagStartIndex < tokenStartIndex) && (tagEndIndex >= (tokenStartIndex + token.length))
3599
+ && !this._mustHightlightWord(token, CodeEditor.symbols)) {
3433
3600
  return [tagStartIndex, tagEndIndex];
3434
3601
  }
3435
3602
  }
@@ -3440,15 +3607,18 @@ class CodeEditor {
3440
3607
  const lineRange = section[0];
3441
3608
  const posRange = section[1];
3442
3609
  // Outside the lines range
3443
- const meetsLineRange = (lineNumber >= lineRange.x && lineNumber <= lineRange.y);
3610
+ const meetsLineRange = lineNumber >= lineRange.x && lineNumber <= lineRange.y;
3444
3611
  if (!meetsLineRange) {
3445
3612
  continue;
3446
3613
  }
3447
- if ((lineNumber != lineRange.x && lineNumber != lineRange.y) || // Inside the block, not first nor last line
3448
- (lineNumber == lineRange.x && tokenPosition >= posRange.x &&
3449
- ((lineNumber == lineRange.y && (tokenPosition + tokenLength) <= (posRange.y + blockCommentsTokens[1].length)) || lineNumber !== lineRange.y)) ||
3450
- (lineNumber == lineRange.y && ((tokenPosition + tokenLength) <= (posRange.y + blockCommentsTokens[1].length))) &&
3451
- ((lineNumber == lineRange.x && tokenPosition >= posRange.x) || lineNumber !== lineRange.x)) {
3614
+ if ((lineNumber != lineRange.x && lineNumber != lineRange.y) // Inside the block, not first nor last line
3615
+ || (lineNumber == lineRange.x && tokenPosition >= posRange.x
3616
+ && ((lineNumber == lineRange.y
3617
+ && (tokenPosition + tokenLength) <= (posRange.y + blockCommentsTokens[1].length))
3618
+ || lineNumber !== lineRange.y))
3619
+ || (lineNumber == lineRange.y
3620
+ && ((tokenPosition + tokenLength) <= (posRange.y + blockCommentsTokens[1].length)))
3621
+ && ((lineNumber == lineRange.x && tokenPosition >= posRange.x) || lineNumber !== lineRange.x)) {
3452
3622
  return section;
3453
3623
  }
3454
3624
  }
@@ -3467,7 +3637,7 @@ class CodeEditor {
3467
3637
  }
3468
3638
  }
3469
3639
  if (this.highlight == 'Markdown') {
3470
- isKwd = (this._markdownHeader !== undefined);
3640
+ isKwd = this._markdownHeader !== undefined;
3471
3641
  }
3472
3642
  else if (lang.tags) {
3473
3643
  isKwd = isKwd && (this._enclosedByTokens(token, tokenIndex, '<', '>') != undefined);
@@ -3516,13 +3686,13 @@ class CodeEditor {
3516
3686
  // Change next key?
3517
3687
  switch (key) {
3518
3688
  case "'":
3519
- case "\"":
3689
+ case '"':
3520
3690
  break;
3521
- case "(":
3522
- key = ")";
3691
+ case '(':
3692
+ key = ')';
3523
3693
  break;
3524
- case "{":
3525
- key = "}";
3694
+ case '{':
3695
+ key = '}';
3526
3696
  break;
3527
3697
  }
3528
3698
  // Insert the other
@@ -3544,13 +3714,13 @@ class CodeEditor {
3544
3714
  const scores = {};
3545
3715
  // Check strong indicators first
3546
3716
  const strongIndicators = {
3547
- "JavaScript": ["import ", "export default", "console.", "=>", "document.", "window."],
3548
- "TypeScript": ["import ", "export default", "console.", "=>", "document.", "window."],
3549
- "C++": ["#include", "::", "std::", "template <", "using namespace"],
3550
- "Python": ["def ", "import ", "print(", "self", "None", "True", "False"],
3551
- "HTML": ["<html", "<div", "<body", "<script", "<style"],
3552
- "CSS": ["@media"],
3553
- "Markdown": ["#", "##", "###", "](", "![", "**"],
3717
+ 'JavaScript': ['import ', 'export default', 'console.', '=>', 'document.', 'window.'],
3718
+ 'TypeScript': ['import ', 'export default', 'console.', '=>', 'document.', 'window.'],
3719
+ 'C++': ['#include', '::', 'std::', 'template <', 'using namespace'],
3720
+ 'Python': ['def ', 'import ', 'print(', 'self', 'None', 'True', 'False'],
3721
+ 'HTML': ['<html', '<div', '<body', '<script', '<style'],
3722
+ 'CSS': ['@media'],
3723
+ 'Markdown': ['#', '##', '###', '](', '![', '**']
3554
3724
  };
3555
3725
  for (const [lang, indicators] of Object.entries(strongIndicators)) {
3556
3726
  scores[lang] = scores[lang] ?? 0;
@@ -3565,30 +3735,33 @@ class CodeEditor {
3565
3735
  CodeEditor.statements,
3566
3736
  CodeEditor.utils,
3567
3737
  CodeEditor.types,
3568
- CodeEditor.builtIn,
3738
+ CodeEditor.builtIn
3569
3739
  ];
3570
3740
  for (const group of groups) {
3571
3741
  for (let [lang, wordList] of Object.entries(group)) {
3572
3742
  scores[lang] = scores[lang] ?? 0;
3573
- for (let kw of wordList)
3743
+ for (let kw of wordList) {
3574
3744
  if (tokenSet.has(kw))
3575
3745
  scores[lang]++;
3746
+ }
3576
3747
  }
3577
3748
  }
3578
3749
  const sorted = Object.entries(scores).sort((a, b) => b[1] - a[1]);
3579
3750
  return sorted[0][1] > 0 ? sorted[0][0] : undefined;
3580
3751
  }
3581
3752
  lineUp(cursor, resetLeft = false) {
3582
- if (this.code.lines[cursor.line - 1] == undefined)
3753
+ if (this.code.lines[cursor.line - 1] == undefined) {
3583
3754
  return false;
3755
+ }
3584
3756
  cursor.line--;
3585
3757
  cursor.line = Math.max(0, cursor.line);
3586
3758
  this.cursorToTop(cursor, resetLeft);
3587
3759
  return true;
3588
3760
  }
3589
3761
  lineDown(cursor, resetLeft = false) {
3590
- if (this.code.lines[cursor.line + 1] == undefined)
3762
+ if (this.code.lines[cursor.line + 1] == undefined) {
3591
3763
  return false;
3764
+ }
3592
3765
  cursor.line++;
3593
3766
  this.cursorToBottom(cursor, resetLeft);
3594
3767
  return true;
@@ -3615,12 +3788,14 @@ class CodeEditor {
3615
3788
  return;
3616
3789
  clearInterval(this.blinker);
3617
3790
  LX.addClass(this.cursorsDOM, 'show');
3618
- if (this.cursorBlinkRate > 0)
3791
+ if (this.cursorBlinkRate > 0) {
3619
3792
  this.blinker = setInterval(() => {
3620
3793
  LX.toggleClass(this.cursorsDOM, 'show');
3621
3794
  }, this.cursorBlinkRate);
3622
- else if (this.cursorBlinkRate < 0)
3795
+ }
3796
+ else if (this.cursorBlinkRate < 0) {
3623
3797
  LX.removeClass(this.cursorsDOM, 'show');
3798
+ }
3624
3799
  }
3625
3800
  startSelection(cursor) {
3626
3801
  // Show elements
@@ -3641,12 +3816,13 @@ class CodeEditor {
3641
3816
  if (cursor.selection)
3642
3817
  cursor.selection.invertIfNecessary();
3643
3818
  const selection = cursor.selection;
3644
- const separator = "_NEWLINE_";
3819
+ const separator = '_NEWLINE_';
3645
3820
  let code = this.code.lines.join(separator);
3646
3821
  // Get linear start index
3647
3822
  let index = 0;
3648
- for (let i = 0; i <= selection.fromY; i++)
3649
- index += (i == selection.fromY ? selection.fromX : this.code.lines[i].length);
3823
+ for (let i = 0; i <= selection.fromY; i++) {
3824
+ index += i == selection.fromY ? selection.fromX : this.code.lines[i].length;
3825
+ }
3650
3826
  index += selection.fromY * separator.length;
3651
3827
  const num_chars = selection.chars + (selection.toY - selection.fromY) * separator.length;
3652
3828
  const pre = code.slice(0, index);
@@ -3718,7 +3894,7 @@ class CodeEditor {
3718
3894
  // Check if we need to add scroll; if not then we might have to reduce it
3719
3895
  if (!this.updateScrollLeft(cursor)) {
3720
3896
  const leftMargin = this.charWidth;
3721
- const cursorX = (cursor.position * this.charWidth);
3897
+ const cursorX = cursor.position * this.charWidth;
3722
3898
  const currentScrollLeft = this.getScrollLeft();
3723
3899
  if (cursorX < (currentScrollLeft + leftMargin)) {
3724
3900
  const scroll = Math.max(cursorX - leftMargin, 0);
@@ -3776,7 +3952,7 @@ class CodeEditor {
3776
3952
  cursorToLine(cursor, line, resetLeft = false) {
3777
3953
  cursor.line = line;
3778
3954
  cursor.top = this.lineHeight * line;
3779
- cursor.root.style.top = cursor.top + "px";
3955
+ cursor.root.style.top = cursor.top + 'px';
3780
3956
  if (resetLeft)
3781
3957
  this.resetCursorPos(CodeEditor.CURSOR_LEFT, cursor);
3782
3958
  }
@@ -3832,7 +4008,7 @@ class CodeEditor {
3832
4008
  cursor = cursor ?? this.getCurrentCursor();
3833
4009
  if (flag & CodeEditor.CURSOR_LEFT) {
3834
4010
  cursor.left = 0;
3835
- cursor.root.style.left = "calc(" + this.xPadding + ")";
4011
+ cursor.root.style.left = 'calc(' + this.xPadding + ')';
3836
4012
  cursor.position = 0;
3837
4013
  if (resetScroll) {
3838
4014
  this.setScrollLeft(0);
@@ -3840,7 +4016,7 @@ class CodeEditor {
3840
4016
  }
3841
4017
  if (flag & CodeEditor.CURSOR_TOP) {
3842
4018
  cursor.top = 0;
3843
- cursor.root.style.top = "0px";
4019
+ cursor.root.style.top = '0px';
3844
4020
  cursor.line = 0;
3845
4021
  if (resetScroll) {
3846
4022
  this.setScrollTop(0);
@@ -3851,11 +4027,12 @@ class CodeEditor {
3851
4027
  // If cursor in that position exists, remove it instead..
3852
4028
  const exists = this.cursors.find((v) => v.position == position && v.line == line);
3853
4029
  if (exists && !force) {
3854
- if (!exists.isMain)
4030
+ if (!exists.isMain) {
3855
4031
  exists.remove();
4032
+ }
3856
4033
  return null;
3857
4034
  }
3858
- let cursor = new Cursor("cursor" + this.cursors.length, position, line, isMain, this);
4035
+ let cursor = new Cursor('cursor' + this.cursors.length, position, line, isMain, this);
3859
4036
  this.cursors.push(cursor);
3860
4037
  this.cursorsDOM.appendChild(cursor.root);
3861
4038
  return cursor;
@@ -3898,7 +4075,7 @@ class CodeEditor {
3898
4075
  }
3899
4076
  let indentSpaces = lineStart % this.tabSpaces;
3900
4077
  indentSpaces = indentSpaces == 0 ? this.tabSpaces : this.tabSpaces - indentSpaces;
3901
- const spacesString = " ".repeat(indentSpaces);
4078
+ const spacesString = ' '.repeat(indentSpaces);
3902
4079
  this.code.lines[lidx] = [
3903
4080
  lineString.slice(0, lineStart),
3904
4081
  spacesString,
@@ -3953,7 +4130,7 @@ class CodeEditor {
3953
4130
  ].join('');
3954
4131
  this.processLine(lidx);
3955
4132
  if (cursor.line === lidx) {
3956
- this.cursorToString(cursor, " ".repeat(indentSpaces), true);
4133
+ this.cursorToString(cursor, ' '.repeat(indentSpaces), true);
3957
4134
  }
3958
4135
  if (cursor.selection) {
3959
4136
  if (cursor.selection.fromY === lidx) {
@@ -3969,7 +4146,7 @@ class CodeEditor {
3969
4146
  updateScrollLeft(cursor) {
3970
4147
  cursor = cursor ?? this.getCurrentCursor();
3971
4148
  const rightMargin = this.charWidth;
3972
- const cursorX = (cursor.position * this.charWidth);
4149
+ const cursorX = cursor.position * this.charWidth;
3973
4150
  const currentScrollLeft = this.getScrollLeft();
3974
4151
  const viewportSizeX = this.codeScroller.clientWidth - CodeEditor.LINE_GUTTER_WIDTH; // Gutter offset
3975
4152
  const viewportX = viewportSizeX + currentScrollLeft;
@@ -4013,11 +4190,11 @@ class CodeEditor {
4013
4190
  const maxLineLength = pMaxLength ?? this.getMaxLineLength();
4014
4191
  this._lastMaxLineLength = maxLineLength;
4015
4192
  scrollWidth = maxLineLength * this.charWidth + CodeEditor.LINE_GUTTER_WIDTH;
4016
- this.codeSizer.style.minWidth = scrollWidth + "px";
4193
+ this.codeSizer.style.minWidth = scrollWidth + 'px';
4017
4194
  }
4018
4195
  if (flag & CodeEditor.RESIZE_SCROLLBAR_V) {
4019
4196
  scrollHeight = this.code.lines.length * this.lineHeight;
4020
- this.codeSizer.style.minHeight = scrollHeight + "px";
4197
+ this.codeSizer.style.minHeight = scrollHeight + 'px';
4021
4198
  }
4022
4199
  this.resizeScrollBars(flag);
4023
4200
  if (onResize) {
@@ -4039,10 +4216,10 @@ class CodeEditor {
4039
4216
  resizeScrollBars(flag = CodeEditor.RESIZE_SCROLLBAR_H_V) {
4040
4217
  if (flag & CodeEditor.RESIZE_SCROLLBAR_V) {
4041
4218
  const totalLinesInViewport = ((this.codeScroller.offsetHeight) / this.lineHeight) | 0;
4042
- const needsVerticalScrollbar = (this.code.lines.length >= totalLinesInViewport);
4219
+ const needsVerticalScrollbar = this.code.lines.length >= totalLinesInViewport;
4043
4220
  if (needsVerticalScrollbar) {
4044
- this.vScrollbar.thumb.size = (totalLinesInViewport / this.code.lines.length);
4045
- this.vScrollbar.thumb.style.height = (this.vScrollbar.thumb.size * 100.0) + "%";
4221
+ this.vScrollbar.thumb.size = totalLinesInViewport / this.code.lines.length;
4222
+ this.vScrollbar.thumb.style.height = (this.vScrollbar.thumb.size * 100.0) + '%';
4046
4223
  }
4047
4224
  this.vScrollbar.root.classList.toggle('hidden', !needsVerticalScrollbar);
4048
4225
  this.hScrollbar.root.style.width = `calc(100% - ${48 + (needsVerticalScrollbar ? ScrollBar.SCROLLBAR_VERTICAL_WIDTH : 0)}px)`; // 48 is the line gutter
@@ -4053,8 +4230,8 @@ class CodeEditor {
4053
4230
  const maxLineLength = this._lastMaxLineLength;
4054
4231
  const needsHorizontalScrollbar = maxLineLength >= numViewportChars;
4055
4232
  if (needsHorizontalScrollbar) {
4056
- this.hScrollbar.thumb.size = (numViewportChars / maxLineLength);
4057
- this.hScrollbar.thumb.style.width = (this.hScrollbar.thumb.size * 100.0) + "%";
4233
+ this.hScrollbar.thumb.size = numViewportChars / maxLineLength;
4234
+ this.hScrollbar.thumb.style.width = (this.hScrollbar.thumb.size * 100.0) + '%';
4058
4235
  }
4059
4236
  this.hScrollbar.root.classList.toggle('hidden', !needsHorizontalScrollbar);
4060
4237
  this.codeArea.root.style.height = `calc(100% - ${this._fullVerticalOffset + (needsHorizontalScrollbar ? ScrollBar.SCROLLBAR_HORIZONTAL_HEIGHT : 0)}px)`;
@@ -4068,7 +4245,7 @@ class CodeEditor {
4068
4245
  const scrollThumbHeight = this.vScrollbar.thumb.offsetHeight;
4069
4246
  const currentScroll = this.codeScroller.scrollTop;
4070
4247
  this.vScrollbar.thumb._top = (currentScroll / scrollHeight) * (scrollBarHeight - scrollThumbHeight);
4071
- this.vScrollbar.thumb.style.top = this.vScrollbar.thumb._top + "px";
4248
+ this.vScrollbar.thumb.style.top = this.vScrollbar.thumb._top + 'px';
4072
4249
  }
4073
4250
  }
4074
4251
  else {
@@ -4082,7 +4259,7 @@ class CodeEditor {
4082
4259
  const scrollThumbWidth = this.hScrollbar.thumb.offsetWidth;
4083
4260
  const currentScroll = this.codeScroller.scrollLeft;
4084
4261
  this.hScrollbar.thumb._left = (currentScroll / scrollWidth) * (scrollBarWidth - scrollThumbWidth);
4085
- this.hScrollbar.thumb.style.left = this.hScrollbar.thumb._left + "px";
4262
+ this.hScrollbar.thumb.style.left = this.hScrollbar.thumb._left + 'px';
4086
4263
  }
4087
4264
  }
4088
4265
  }
@@ -4091,8 +4268,8 @@ class CodeEditor {
4091
4268
  // Move scrollbar thumb
4092
4269
  const scrollBarWidth = this.hScrollbar.thumb.parentElement.offsetWidth;
4093
4270
  const scrollThumbWidth = this.hScrollbar.thumb.offsetWidth;
4094
- this.hScrollbar.thumb._left = LX.clamp(value, 0, (scrollBarWidth - scrollThumbWidth));
4095
- this.hScrollbar.thumb.style.left = this.hScrollbar.thumb._left + "px";
4271
+ this.hScrollbar.thumb._left = LX.clamp(value, 0, scrollBarWidth - scrollThumbWidth);
4272
+ this.hScrollbar.thumb.style.left = this.hScrollbar.thumb._left + 'px';
4096
4273
  // Scroll code
4097
4274
  const scrollWidth = this.codeScroller.scrollWidth - this.codeScroller.clientWidth;
4098
4275
  const currentScroll = (this.hScrollbar.thumb._left * scrollWidth) / (scrollBarWidth - scrollThumbWidth);
@@ -4104,8 +4281,8 @@ class CodeEditor {
4104
4281
  // Move scrollbar thumb
4105
4282
  const scrollBarHeight = this.vScrollbar.thumb.parentElement.offsetHeight;
4106
4283
  const scrollThumbHeight = this.vScrollbar.thumb.offsetHeight;
4107
- this.vScrollbar.thumb._top = LX.clamp(value, 0, (scrollBarHeight - scrollThumbHeight));
4108
- this.vScrollbar.thumb.style.top = this.vScrollbar.thumb._top + "px";
4284
+ this.vScrollbar.thumb._top = LX.clamp(value, 0, scrollBarHeight - scrollThumbHeight);
4285
+ this.vScrollbar.thumb.style.top = this.vScrollbar.thumb._top + 'px';
4109
4286
  // Scroll code
4110
4287
  const scrollHeight = this.codeScroller.scrollHeight - this.codeScroller.clientHeight;
4111
4288
  const currentScroll = (this.vScrollbar.thumb._top * scrollHeight) / (scrollBarHeight - scrollThumbHeight);
@@ -4120,46 +4297,52 @@ class CodeEditor {
4120
4297
  const isChar = (char) => {
4121
4298
  const exceptions = ['_', '#', '!'];
4122
4299
  const code = char.charCodeAt(0);
4123
- return (exceptions.indexOf(char) > -1) || (code > 47 && code < 58) || (code > 64 && code < 91) || (code > 96 && code < 123);
4300
+ return (exceptions.indexOf(char) > -1) || (code > 47 && code < 58) || (code > 64 && code < 91)
4301
+ || (code > 96 && code < 123);
4124
4302
  };
4125
4303
  let from = cursor.position + offset;
4126
4304
  let to = cursor.position + offset;
4127
4305
  // Check left ...
4128
- while (words[from] && isChar(words[from]))
4306
+ while (words[from] && isChar(words[from])) {
4129
4307
  from--;
4308
+ }
4130
4309
  from++;
4131
4310
  // Check right ...
4132
- while (words[to] && isChar(words[to]))
4311
+ while (words[to] && isChar(words[to])) {
4133
4312
  to++;
4313
+ }
4134
4314
  // Skip spaces ...
4135
4315
  let word = words.substring(from, to);
4136
4316
  if (word == ' ') {
4137
4317
  if (offset < 0) {
4138
- while (words[from - 1] != undefined && words[from - 1] == ' ')
4318
+ while (words[from - 1] != undefined && words[from - 1] == ' ') {
4139
4319
  from--;
4320
+ }
4140
4321
  to++;
4141
4322
  word = words.substring(from, to + 1);
4142
4323
  }
4143
4324
  else {
4144
- while (words[to] != undefined && words[to] == ' ')
4325
+ while (words[to] != undefined && words[to] == ' ') {
4145
4326
  to++;
4327
+ }
4146
4328
  from--;
4147
4329
  word = words.substring(from, to);
4148
4330
  }
4149
4331
  }
4150
4332
  return [word, from, to];
4151
4333
  }
4152
- _measureChar(char = "M", useFloating = true, getBB = false) {
4153
- const parentContainer = LX.makeContainer(null, "lexcodeeditor", "", document.body);
4154
- const container = LX.makeContainer(null, "code", "", parentContainer);
4155
- const line = document.createElement("pre");
4334
+ _measureChar(char = 'M', useFloating = true, getBB = false) {
4335
+ const parentContainer = LX.makeContainer(null, 'lexcodeeditor', '', document.body);
4336
+ const container = LX.makeContainer(null, 'code', '', parentContainer);
4337
+ const line = document.createElement('pre');
4156
4338
  container.appendChild(line);
4157
- const text = document.createElement("span");
4339
+ const text = document.createElement('span');
4158
4340
  line.appendChild(text);
4159
4341
  text.innerText = char;
4160
4342
  var rect = text.getBoundingClientRect();
4161
4343
  LX.deleteElement(parentContainer);
4162
- const bb = [useFloating ? rect.width : Math.floor(rect.width), useFloating ? rect.height : Math.floor(rect.height)];
4344
+ const bb = [useFloating ? rect.width : Math.floor(rect.width),
4345
+ useFloating ? rect.height : Math.floor(rect.height)];
4163
4346
  return getBB ? bb : bb[0];
4164
4347
  }
4165
4348
  measureString(str) {
@@ -4179,14 +4362,17 @@ class CodeEditor {
4179
4362
  for (let i = 0; i < params.length; i++) {
4180
4363
  let key = params[i].split(',');
4181
4364
  if (key.length > 1) {
4182
- if (key[key.length - 1].includes(']'))
4365
+ if (key[key.length - 1].includes(']')) {
4183
4366
  continue;
4367
+ }
4184
4368
  key = key[key.length - 1];
4185
4369
  }
4186
- else if (key[0].includes('}'))
4370
+ else if (key[0].includes('}')) {
4187
4371
  continue;
4188
- else
4372
+ }
4373
+ else {
4189
4374
  key = key[0];
4375
+ }
4190
4376
  key = key.replaceAll(/[{}\n\r]/g, '').replaceAll(' ', '');
4191
4377
  if (key[0] != '"' && key[key.length - 1] != '"') {
4192
4378
  params[i] = params[i].replace(key, '"' + key + '"');
@@ -4198,7 +4384,7 @@ class CodeEditor {
4198
4384
  return JSON.stringify(json, undefined, 4);
4199
4385
  }
4200
4386
  catch (e) {
4201
- alert("Invalid JSON format");
4387
+ alert('Invalid JSON format');
4202
4388
  return;
4203
4389
  }
4204
4390
  }
@@ -4211,7 +4397,7 @@ class CodeEditor {
4211
4397
  this.hideAutoCompleteBox();
4212
4398
  return;
4213
4399
  }
4214
- this.autocomplete.innerHTML = ""; // Clear all suggestions
4400
+ this.autocomplete.innerHTML = ''; // Clear all suggestions
4215
4401
  // Add language special keys...
4216
4402
  let suggestions = [
4217
4403
  ...Array.from(CodeEditor.keywords[this.highlight] ?? []),
@@ -4222,8 +4408,8 @@ class CodeEditor {
4222
4408
  ];
4223
4409
  const scopeStack = [...this.code.lineScopes[cursor.line]];
4224
4410
  const scope = scopeStack.at(-1);
4225
- if (scope.type.startsWith("enum")) {
4226
- const enumValues = Array.from(this.code.symbolsTable).filter((s) => s[1][0].kind === "enum_value" && s[1][0].scope === scope.name).map((s) => s[0]);
4411
+ if (scope.type.startsWith('enum')) {
4412
+ const enumValues = Array.from(this.code.symbolsTable).filter((s) => s[1][0].kind === 'enum_value' && s[1][0].scope === scope.name).map((s) => s[0]);
4227
4413
  suggestions = suggestions.concat(enumValues.slice(0, -1));
4228
4414
  }
4229
4415
  else {
@@ -4248,34 +4434,36 @@ class CodeEditor {
4248
4434
  const pre = document.createElement('pre');
4249
4435
  this.autocomplete.appendChild(pre);
4250
4436
  const symbol = this.code.symbolsTable.get(s);
4251
- let iconName = "CaseLower";
4252
- let iconClass = "foo";
4437
+ let iconName = 'CaseLower';
4438
+ let iconClass = 'foo';
4253
4439
  if (symbol) {
4254
- switch (symbol[0].kind) // Get first occurrence
4255
- {
4256
- case "variable":
4257
- iconName = "Cuboid";
4258
- iconClass = "fg-blue-400";
4440
+ switch (symbol[0].kind)
4441
+ // Get first occurrence
4442
+ {
4443
+ case 'variable':
4444
+ iconName = 'Cuboid';
4445
+ iconClass = 'fg-blue-400';
4259
4446
  break;
4260
- case "method":
4261
- iconName = "Box";
4262
- iconClass = "fg-fuchsia-500";
4447
+ case 'method':
4448
+ iconName = 'Box';
4449
+ iconClass = 'fg-fuchsia-500';
4263
4450
  break;
4264
- case "class":
4265
- iconName = "CircleNodes";
4266
- iconClass = "fg-orange-500";
4451
+ case 'class':
4452
+ iconName = 'CircleNodes';
4453
+ iconClass = 'fg-orange-500';
4267
4454
  break;
4268
4455
  }
4269
4456
  }
4270
4457
  else {
4271
- if (this._mustHightlightWord(currSuggestion, CodeEditor.utils))
4272
- iconName = "ToolCase";
4458
+ if (this._mustHightlightWord(currSuggestion, CodeEditor.utils)) {
4459
+ iconName = 'ToolCase';
4460
+ }
4273
4461
  else if (this._mustHightlightWord(currSuggestion, CodeEditor.types)) {
4274
- iconName = "Type";
4275
- iconClass = "fg-blue-400";
4462
+ iconName = 'Type';
4463
+ iconClass = 'fg-blue-400';
4276
4464
  }
4277
4465
  }
4278
- pre.appendChild(LX.makeIcon(iconName, { iconClass: "mr-1", svgClass: "sm " + iconClass }));
4466
+ pre.appendChild(LX.makeIcon(iconName, { iconClass: 'mr-1', svgClass: 'sm ' + iconClass }));
4279
4467
  pre.addEventListener('click', () => {
4280
4468
  this.autoCompleteWord(currSuggestion);
4281
4469
  });
@@ -4303,7 +4491,8 @@ class CodeEditor {
4303
4491
  this.autocomplete.classList.toggle('show', true);
4304
4492
  this.autocomplete.classList.toggle('no-scrollbar', !(this.autocomplete.scrollHeight > this.autocomplete.offsetHeight));
4305
4493
  this.autocomplete.style.left = `${Math.min(cursor.left + CodeEditor.LINE_GUTTER_WIDTH - this.getScrollLeft(), maxX)}px`;
4306
- this.autocomplete.style.top = `${(cursor.top + this._verticalTopOffset + this.lineHeight - this.getScrollTop())}px`;
4494
+ this.autocomplete.style.top =
4495
+ `${(cursor.top + this._verticalTopOffset + this.lineHeight - this.getScrollTop())}px`;
4307
4496
  this.isAutoCompleteActive = true;
4308
4497
  }
4309
4498
  hideAutoCompleteBox() {
@@ -4313,19 +4502,19 @@ class CodeEditor {
4313
4502
  const isActive = this.isAutoCompleteActive;
4314
4503
  this.isAutoCompleteActive = false;
4315
4504
  this.autocomplete.classList.remove('show');
4316
- this.autocomplete.innerHTML = ""; // Clear all suggestions
4505
+ this.autocomplete.innerHTML = ''; // Clear all suggestions
4317
4506
  return isActive != this.isAutoCompleteActive;
4318
4507
  }
4319
4508
  autoCompleteWord(suggestion) {
4320
- if (!this.isAutoCompleteActive)
4509
+ if (!this.isAutoCompleteActive) {
4321
4510
  return;
4511
+ }
4322
4512
  let [suggestedWord, idx] = this._getSelectedAutoComplete();
4323
4513
  suggestedWord = suggestion ?? suggestedWord;
4324
4514
  for (let cursor of this.cursors) {
4325
4515
  const [word, start, end] = this.getWordAtPos(cursor, -1);
4326
4516
  const lineString = this.code.lines[cursor.line];
4327
- this.code.lines[cursor.line] =
4328
- lineString.slice(0, start) + suggestedWord + lineString.slice(end);
4517
+ this.code.lines[cursor.line] = lineString.slice(0, start) + suggestedWord + lineString.slice(end);
4329
4518
  // Process lines and remove suggestion box
4330
4519
  this.cursorToPosition(cursor, start + suggestedWord.length);
4331
4520
  this.processLine(cursor.line);
@@ -4338,7 +4527,7 @@ class CodeEditor {
4338
4527
  for (let i = 0; i < this.autocomplete.childElementCount; ++i) {
4339
4528
  const child = this.autocomplete.childNodes[i];
4340
4529
  if (child.classList.contains('selected')) {
4341
- var word = "";
4530
+ var word = '';
4342
4531
  for (let childSpan of child.childNodes) {
4343
4532
  if (childSpan.constructor != HTMLSpanElement) {
4344
4533
  continue;
@@ -4351,8 +4540,9 @@ class CodeEditor {
4351
4540
  return [null, -1];
4352
4541
  }
4353
4542
  _moveArrowSelectedAutoComplete(dir) {
4354
- if (!this.isAutoCompleteActive)
4543
+ if (!this.isAutoCompleteActive) {
4355
4544
  return;
4545
+ }
4356
4546
  const [word, idx] = this._getSelectedAutoComplete();
4357
4547
  const offset = dir == 'down' ? 1 : -1;
4358
4548
  const fIdx = idx + offset;
@@ -4373,8 +4563,8 @@ class CodeEditor {
4373
4563
  }
4374
4564
  }
4375
4565
  // Remove selected from the current word and add it to the next one
4376
- LX.removeClass(this.autocomplete.childNodes[idx], "selected");
4377
- LX.addClass(this.autocomplete.childNodes[idx + offset], "selected");
4566
+ LX.removeClass(this.autocomplete.childNodes[idx], 'selected');
4567
+ LX.addClass(this.autocomplete.childNodes[idx + offset], 'selected');
4378
4568
  }
4379
4569
  showSearchBox(clear = false) {
4380
4570
  this.hideSearchLineBox();
@@ -4382,7 +4572,7 @@ class CodeEditor {
4382
4572
  this.isSearchboxActive = true;
4383
4573
  const input = this.searchbox.querySelector('input');
4384
4574
  if (clear) {
4385
- input.value = "";
4575
+ input.value = '';
4386
4576
  }
4387
4577
  else {
4388
4578
  const cursor = this.getCurrentCursor();
@@ -4454,7 +4644,7 @@ class CodeEditor {
4454
4644
  }
4455
4645
  if (line == null) {
4456
4646
  if (!skipAlert) {
4457
- alert("No results!");
4647
+ alert('No results!');
4458
4648
  }
4459
4649
  const lastLine = this.code.lines.length - 1;
4460
4650
  this._lastResult = {
@@ -4469,7 +4659,7 @@ class CodeEditor {
4469
4659
  have to add the length of the substring (0, first_ocurrence)
4470
4660
  */
4471
4661
  if (!reverse) {
4472
- char += (line == cursorData.y ? cursorData.x : 0);
4662
+ char += line == cursorData.y ? cursorData.x : 0;
4473
4663
  }
4474
4664
  // Text found..
4475
4665
  this._lastTextFound = text;
@@ -4481,7 +4671,7 @@ class CodeEditor {
4481
4671
  // Show elements
4482
4672
  this.searchResultSelections.classList.add('show');
4483
4673
  // Create new selection instance
4484
- cursor.selection = new CodeSelection(this, cursor, "lexcodesearchresult");
4674
+ cursor.selection = new CodeSelection(this, cursor, 'lexcodesearchresult');
4485
4675
  cursor.selection.selectInline(cursor, char, line, this.measureString(text), true);
4486
4676
  }
4487
4677
  this._lastResult = {
@@ -4500,7 +4690,7 @@ class CodeEditor {
4500
4690
  this.searchlinebox.classList.add('opened');
4501
4691
  this.isSearchlineboxActive = true;
4502
4692
  const input = this.searchlinebox.querySelector('input');
4503
- input.value = ":";
4693
+ input.value = ':';
4504
4694
  input.focus();
4505
4695
  }
4506
4696
  hideSearchLineBox() {
@@ -4510,19 +4700,22 @@ class CodeEditor {
4510
4700
  }
4511
4701
  }
4512
4702
  goToLine(line) {
4513
- if (!this._isNumber(line))
4703
+ if (!this._isNumber(line)) {
4514
4704
  return;
4705
+ }
4515
4706
  this.codeScroller.scrollTo(0, Math.max(line - 15) * this.lineHeight);
4516
4707
  // Select line ?
4517
4708
  var cursor = this.getCurrentCursor(true);
4518
4709
  this.cursorToLine(cursor, line - 1, true);
4519
4710
  }
4520
4711
  selectNextOcurrence(cursor) {
4521
- if (!cursor.selection)
4712
+ if (!cursor.selection) {
4522
4713
  return;
4714
+ }
4523
4715
  const text = cursor.selection.getText();
4524
- if (!text)
4716
+ if (!text) {
4525
4717
  return;
4718
+ }
4526
4719
  if (!this._currentOcurrences) {
4527
4720
  const currentKey = [cursor.position - text.length, cursor.line].join('_');
4528
4721
  this._currentOcurrences = {};
@@ -4545,7 +4738,7 @@ class CodeEditor {
4545
4738
  _updateDataInfoPanel(signal, value) {
4546
4739
  if (!this.skipInfo) {
4547
4740
  if (this.cursors.length > 1) {
4548
- value = "";
4741
+ value = '';
4549
4742
  }
4550
4743
  LX.emitSignal(signal, value);
4551
4744
  }
@@ -4556,7 +4749,7 @@ class CodeEditor {
4556
4749
  return;
4557
4750
  }
4558
4751
  const cursor = this.getCurrentCursor();
4559
- this._updateDataInfoPanel("@cursor-data", `Ln ${n + 1}, Col ${cursor.position + 1}`);
4752
+ this._updateDataInfoPanel('@cursor-data', `Ln ${n + 1}, Col ${cursor.position + 1}`);
4560
4753
  const oldLocal = this.toLocalLine(this.state.activeLine);
4561
4754
  let line = this.code.childNodes[oldLocal];
4562
4755
  if (!line) {
@@ -4579,19 +4772,19 @@ class CodeEditor {
4579
4772
  // Change font size
4580
4773
  this.fontSize = size;
4581
4774
  const r = document.querySelector(':root');
4582
- r.style.setProperty("--code-editor-font-size", `${this.fontSize}px`);
4775
+ r.style.setProperty('--code-editor-font-size', `${this.fontSize}px`);
4583
4776
  this.charWidth = this._measureChar();
4584
- window.localStorage.setItem("lexcodeeditor-font-size", `${this.fontSize}`);
4777
+ window.localStorage.setItem('lexcodeeditor-font-size', `${this.fontSize}`);
4585
4778
  // Change row size
4586
4779
  const rowPixels = this.fontSize + 6;
4587
- r.style.setProperty("--code-editor-row-height", `${rowPixels}px`);
4780
+ r.style.setProperty('--code-editor-row-height', `${rowPixels}px`);
4588
4781
  this.lineHeight = rowPixels;
4589
4782
  // Relocate cursors
4590
4783
  this.relocateCursors();
4591
4784
  // Resize the code area
4592
4785
  this.processLines();
4593
4786
  // Emit event
4594
- LX.emitSignal("@font-size", this.fontSize);
4787
+ LX.emitSignal('@font-size', this.fontSize);
4595
4788
  }
4596
4789
  _applyFontSizeOffset(offset = 0) {
4597
4790
  const newFontSize = LX.clamp(this.fontSize + offset, CodeEditor.CODE_MIN_FONT_SIZE, CodeEditor.CODE_MAX_FONT_SIZE);
@@ -4615,19 +4808,21 @@ class CodeEditor {
4615
4808
  }
4616
4809
  async _requestFileAsync(url, dataType, nocache = false) {
4617
4810
  return new Promise((resolve, reject) => {
4618
- dataType = dataType ?? "arraybuffer";
4619
- const mimeType = dataType === "arraybuffer" ? "application/octet-stream" : undefined;
4811
+ dataType = dataType ?? 'arraybuffer';
4812
+ const mimeType = dataType === 'arraybuffer' ? 'application/octet-stream' : undefined;
4620
4813
  var xhr = new XMLHttpRequest();
4621
4814
  xhr.open('GET', url, true);
4622
4815
  xhr.responseType = dataType;
4623
- if (mimeType)
4816
+ if (mimeType) {
4624
4817
  xhr.overrideMimeType(mimeType);
4625
- if (nocache)
4818
+ }
4819
+ if (nocache) {
4626
4820
  xhr.setRequestHeader('Cache-Control', 'no-cache');
4821
+ }
4627
4822
  xhr.onload = function () {
4628
4823
  var response = this.response;
4629
4824
  if (this.status != 200) {
4630
- var err = "Error " + this.status;
4825
+ var err = 'Error ' + this.status;
4631
4826
  reject(err);
4632
4827
  return;
4633
4828
  }
@@ -4642,143 +4837,168 @@ class CodeEditor {
4642
4837
  }
4643
4838
  }
4644
4839
  const CE = CodeEditor;
4645
- CE.languages =
4646
- {
4647
- 'Plain Text': { ext: "txt", blockComments: false, singleLineComments: false, numbers: false, icon: "AlignLeft fg-neutral-500" },
4648
- 'JavaScript': { ext: "js", icon: "Js fg-yellow-500" },
4649
- 'TypeScript': { ext: "ts", icon: "Ts fg-blue-600" },
4650
- 'C': { ext: ['c', 'h'], usePreprocessor: true, icon: { 'c': "C fg-sky-400", 'h': "C fg-fuchsia-500" } },
4651
- 'C++': { ext: ["cpp", "hpp"], usePreprocessor: true, icon: { 'cpp': "CPlusPlus fg-sky-400", 'hpp': "CPlusPlus fg-fuchsia-500" } },
4652
- 'CSS': { ext: "css", icon: "Hash fg-blue-700" },
4653
- 'CMake': { ext: "cmake", singleLineCommentToken: '#', blockComments: false, ignoreCase: true },
4654
- 'GLSL': { ext: "glsl", usePreprocessor: true },
4655
- 'WGSL': { ext: "wgsl", usePreprocessor: true },
4656
- 'JSON': { ext: "json", blockComments: false, singleLineComments: false, icon: "Json fg-yellow-400" },
4657
- 'XML': { ext: "xml", tags: true, icon: "Rss fg-orange-500" },
4658
- 'Rust': { ext: "rs", icon: "Rust fg-primary" },
4659
- 'Python': { ext: "py", singleLineCommentToken: '#', icon: "Python fg-cyan-600" },
4660
- 'HTML': { ext: "html", tags: true, singleLineComments: false, blockCommentsTokens: ['<!--', '-->'], numbers: false, icon: "Code fg-orange-500" },
4661
- 'Batch': { ext: "bat", blockComments: false, singleLineCommentToken: '::', ignoreCase: true, icon: "Windows fg-blue-400" },
4662
- 'Markdown': { ext: "md", blockComments: false, singleLineCommentToken: '::', tags: true, numbers: false, icon: "Markdown fg-primary" },
4663
- 'PHP': { ext: "php", icon: "Php fg-purple-700" },
4664
- };
4665
- CE.nativeTypes =
4666
- {
4667
- 'C++': ['int', 'float', 'double', 'bool', 'long', 'short', 'char', 'wchar_t', 'void'],
4668
- 'WGSL': ['bool', 'u32', 'i32', 'f16', 'f32', 'vec2', 'vec3', 'vec4', 'vec2f', 'vec3f', 'vec4f', 'mat2x2f', 'mat3x3f', 'mat4x4f', 'array', 'vec2u', 'vec3u', 'vec4u', 'ptr', 'sampler']
4669
- };
4670
- CE.declarationKeywords =
4671
- {
4672
- 'JavaScript': ['var', 'let', 'const', 'this', 'static', 'class'],
4673
- 'C++': [...CE.nativeTypes["C++"], 'const', 'auto', 'class', 'struct', 'namespace', 'enum', 'extern']
4674
- };
4675
- CE.keywords =
4676
- {
4677
- 'JavaScript': ['var', 'let', 'const', 'this', 'in', 'of', 'true', 'false', 'new', 'function', 'NaN', 'static', 'class', 'constructor', 'null', 'typeof', 'debugger', 'abstract',
4678
- 'arguments', 'extends', 'instanceof', 'Infinity', 'get'],
4679
- 'TypeScript': ['var', 'let', 'const', 'this', 'in', 'of', 'true', 'false', 'new', 'function', 'class', 'extends', 'instanceof', 'Infinity', 'private', 'public', 'protected', 'interface',
4680
- 'enum', 'type', 'get'],
4681
- 'C': ['int', 'float', 'double', 'long', 'short', 'char', 'const', 'void', 'true', 'false', 'auto', 'struct', 'typedef', 'signed', 'volatile', 'unsigned', 'static', 'extern', 'enum', 'register',
4682
- 'union'],
4683
- 'C++': [...CE.nativeTypes["C++"], 'const', 'static_cast', 'dynamic_cast', 'new', 'delete', 'true', 'false', 'auto', 'class', 'struct', 'typedef', 'nullptr',
4684
- 'NULL', 'signed', 'unsigned', 'namespace', 'enum', 'extern', 'union', 'sizeof', 'static', 'private', 'public'],
4685
- 'CMake': ['cmake_minimum_required', 'set', 'not', 'if', 'endif', 'exists', 'string', 'strequal', 'add_definitions', 'macro', 'endmacro', 'file', 'list', 'source_group', 'add_executable',
4686
- 'target_include_directories', 'set_target_properties', 'set_property', 'add_compile_options', 'add_link_options', 'include_directories', 'add_library', 'target_link_libraries',
4687
- 'target_link_options', 'add_subdirectory', 'add_compile_definitions', 'project', 'cache'],
4688
- 'JSON': ['true', 'false'],
4689
- 'GLSL': ['true', 'false', 'function', 'int', 'float', 'vec2', 'vec3', 'vec4', 'mat2x2', 'mat3x3', 'mat4x4', 'struct'],
4690
- 'CSS': ['body', 'html', 'canvas', 'div', 'input', 'span', '.', 'table', 'tr', 'td', 'th', 'label', 'video', 'img', 'code', 'button', 'select', 'option', 'svg', 'media', 'all',
4691
- 'i', 'a', 'li', 'h1', 'h2', 'h3', 'h4', 'h5', 'last-child', 'tbody', 'pre', 'monospace', 'font-face'],
4692
- 'WGSL': [...CE.nativeTypes["WGSL"], 'var', 'let', 'true', 'false', 'fn', 'atomic', 'struct', 'sampler_comparison', 'texture_depth_2d', 'texture_depth_2d_array', 'texture_depth_cube',
4693
- 'texture_depth_cube_array', 'texture_depth_multisampled_2d', 'texture_external', 'texture_1d', 'texture_2d', 'texture_2d_array', 'texture_3d', 'texture_cube', 'texture_cube_array',
4694
- 'texture_storage_1d', 'texture_storage_2d', 'texture_storage_2d_array', 'texture_storage_3d'],
4695
- 'Rust': ['as', 'const', 'crate', 'enum', 'extern', 'false', 'fn', 'impl', 'in', 'let', 'mod', 'move', 'mut', 'pub', 'ref', 'self', 'Self', 'static', 'struct', 'super', 'trait', 'true',
4696
- 'type', 'unsafe', 'use', 'where', 'abstract', 'become', 'box', 'final', 'macro', 'override', 'priv', 'typeof', 'unsized', 'virtual'],
4697
- 'Python': ['False', 'def', 'None', 'True', 'in', 'is', 'and', 'lambda', 'nonlocal', 'not', 'or'],
4698
- 'Batch': ['set', 'echo', 'off', 'del', 'defined', 'setlocal', 'enabledelayedexpansion', 'driverquery', 'print'],
4699
- 'HTML': ['html', 'meta', 'title', 'link', 'script', 'body', 'DOCTYPE', 'head', 'br', 'i', 'a', 'li', 'img', 'tr', 'td', 'h1', 'h2', 'h3', 'h4', 'h5'],
4700
- 'Markdown': ['br', 'i', 'a', 'li', 'img', 'table', 'title', 'tr', 'td', 'h1', 'h2', 'h3', 'h4', 'h5'],
4701
- 'PHP': ['const', 'function', 'array', 'new', 'int', 'string', '$this', 'public', 'null', 'private', 'protected', 'implements', 'class', 'use', 'namespace', 'abstract', 'clone', 'final',
4702
- 'enum'],
4703
- };
4840
+ CE.languages = {
4841
+ 'Plain Text': { ext: 'txt', blockComments: false, singleLineComments: false, numbers: false,
4842
+ icon: 'AlignLeft fg-neutral-500' },
4843
+ 'JavaScript': { ext: 'js', icon: 'Js fg-yellow-500' },
4844
+ 'TypeScript': { ext: 'ts', icon: 'Ts fg-blue-600' },
4845
+ 'C': { ext: ['c', 'h'], usePreprocessor: true, icon: { 'c': 'C fg-sky-400', 'h': 'C fg-fuchsia-500' } },
4846
+ 'C++': { ext: ['cpp', 'hpp'], usePreprocessor: true,
4847
+ icon: { 'cpp': 'CPlusPlus fg-sky-400', 'hpp': 'CPlusPlus fg-fuchsia-500' } },
4848
+ 'CSS': { ext: 'css', icon: 'Hash fg-blue-700' },
4849
+ 'CMake': { ext: 'cmake', singleLineCommentToken: '#', blockComments: false, ignoreCase: true },
4850
+ 'GLSL': { ext: 'glsl', usePreprocessor: true },
4851
+ 'WGSL': { ext: 'wgsl', usePreprocessor: true },
4852
+ 'JSON': { ext: 'json', blockComments: false, singleLineComments: false, icon: 'Json fg-yellow-400' },
4853
+ 'XML': { ext: 'xml', tags: true, icon: 'Rss fg-orange-500' },
4854
+ 'Rust': { ext: 'rs', icon: 'Rust fg-primary' },
4855
+ 'Python': { ext: 'py', singleLineCommentToken: '#', icon: 'Python fg-cyan-600' },
4856
+ 'HTML': { ext: 'html', tags: true, singleLineComments: false, blockCommentsTokens: ['<!--', '-->'],
4857
+ numbers: false, icon: 'Code fg-orange-500' },
4858
+ 'Batch': { ext: 'bat', blockComments: false, singleLineCommentToken: '::', ignoreCase: true,
4859
+ icon: 'Windows fg-blue-400' },
4860
+ 'Markdown': { ext: 'md', blockComments: false, singleLineCommentToken: '::', tags: true, numbers: false,
4861
+ icon: 'Markdown fg-primary' },
4862
+ 'PHP': { ext: 'php', icon: 'Php fg-purple-700' }
4863
+ };
4864
+ CE.nativeTypes = {
4865
+ 'C++': ['int', 'float', 'double', 'bool', 'long', 'short', 'char', 'wchar_t', 'void'],
4866
+ 'WGSL': ['bool', 'u32', 'i32', 'f16', 'f32', 'vec2', 'vec3', 'vec4', 'vec2f', 'vec3f', 'vec4f', 'mat2x2f',
4867
+ 'mat3x3f', 'mat4x4f', 'array', 'vec2u', 'vec3u', 'vec4u', 'ptr', 'sampler']
4868
+ };
4869
+ CE.declarationKeywords = {
4870
+ 'JavaScript': ['var', 'let', 'const', 'this', 'static', 'class'],
4871
+ 'C++': [...CE.nativeTypes['C++'], 'const', 'auto', 'class', 'struct', 'namespace', 'enum', 'extern']
4872
+ };
4873
+ CE.keywords = {
4874
+ 'JavaScript': ['var', 'let', 'const', 'this', 'in', 'of', 'true', 'false', 'new', 'function', 'NaN', 'static',
4875
+ 'class', 'constructor', 'null', 'typeof', 'debugger', 'abstract', 'arguments', 'extends', 'instanceof',
4876
+ 'Infinity', 'get'],
4877
+ 'TypeScript': ['var', 'let', 'const', 'this', 'in', 'of', 'true', 'false', 'new', 'function', 'class', 'extends',
4878
+ 'instanceof', 'Infinity', 'private', 'public', 'protected', 'interface', 'enum', 'type', 'get'],
4879
+ 'C': ['int', 'float', 'double', 'long', 'short', 'char', 'const', 'void', 'true', 'false', 'auto', 'struct',
4880
+ 'typedef', 'signed', 'volatile', 'unsigned', 'static', 'extern', 'enum', 'register', 'union'],
4881
+ 'C++': [...CE.nativeTypes['C++'], 'const', 'static_cast', 'dynamic_cast', 'new', 'delete', 'true', 'false', 'auto',
4882
+ 'class', 'struct', 'typedef', 'nullptr', 'NULL', 'signed', 'unsigned', 'namespace', 'enum', 'extern', 'union',
4883
+ 'sizeof', 'static', 'private', 'public'],
4884
+ 'CMake': ['cmake_minimum_required', 'set', 'not', 'if', 'endif', 'exists', 'string', 'strequal', 'add_definitions',
4885
+ 'macro', 'endmacro', 'file', 'list', 'source_group', 'add_executable', 'target_include_directories',
4886
+ 'set_target_properties', 'set_property', 'add_compile_options', 'add_link_options', 'include_directories',
4887
+ 'add_library', 'target_link_libraries', 'target_link_options', 'add_subdirectory', 'add_compile_definitions',
4888
+ 'project', 'cache'],
4889
+ 'JSON': ['true', 'false'],
4890
+ 'GLSL': ['true', 'false', 'function', 'int', 'float', 'vec2', 'vec3', 'vec4', 'mat2x2', 'mat3x3', 'mat4x4',
4891
+ 'struct'],
4892
+ 'CSS': ['body', 'html', 'canvas', 'div', 'input', 'span', '.', 'table', 'tr', 'td', 'th', 'label', 'video', 'img',
4893
+ 'code', 'button', 'select', 'option', 'svg', 'media', 'all', 'i', 'a', 'li', 'h1', 'h2', 'h3', 'h4', 'h5',
4894
+ 'last-child', 'tbody', 'pre', 'monospace', 'font-face'],
4895
+ 'WGSL': [...CE.nativeTypes['WGSL'], 'var', 'let', 'true', 'false', 'fn', 'atomic', 'struct', 'sampler_comparison',
4896
+ 'texture_depth_2d', 'texture_depth_2d_array', 'texture_depth_cube', 'texture_depth_cube_array',
4897
+ 'texture_depth_multisampled_2d', 'texture_external', 'texture_1d', 'texture_2d', 'texture_2d_array',
4898
+ 'texture_3d', 'texture_cube', 'texture_cube_array', 'texture_storage_1d', 'texture_storage_2d',
4899
+ 'texture_storage_2d_array', 'texture_storage_3d'],
4900
+ 'Rust': ['as', 'const', 'crate', 'enum', 'extern', 'false', 'fn', 'impl', 'in', 'let', 'mod', 'move', 'mut', 'pub',
4901
+ 'ref', 'self', 'Self', 'static', 'struct', 'super', 'trait', 'true', 'type', 'unsafe', 'use', 'where',
4902
+ 'abstract', 'become', 'box', 'final', 'macro', 'override', 'priv', 'typeof', 'unsized', 'virtual'],
4903
+ 'Python': ['False', 'def', 'None', 'True', 'in', 'is', 'and', 'lambda', 'nonlocal', 'not', 'or'],
4904
+ 'Batch': ['set', 'echo', 'off', 'del', 'defined', 'setlocal', 'enabledelayedexpansion', 'driverquery', 'print'],
4905
+ 'HTML': ['html', 'meta', 'title', 'link', 'script', 'body', 'DOCTYPE', 'head', 'br', 'i', 'a', 'li', 'img', 'tr',
4906
+ 'td', 'h1', 'h2', 'h3', 'h4', 'h5'],
4907
+ 'Markdown': ['br', 'i', 'a', 'li', 'img', 'table', 'title', 'tr', 'td', 'h1', 'h2', 'h3', 'h4', 'h5'],
4908
+ 'PHP': ['const', 'function', 'array', 'new', 'int', 'string', '$this', 'public', 'null', 'private', 'protected',
4909
+ 'implements', 'class', 'use', 'namespace', 'abstract', 'clone', 'final', 'enum']
4910
+ };
4704
4911
  // These ones don't have hightlight, used as suggestions to autocomplete only...
4705
- CE.utils =
4706
- {
4707
- 'JavaScript': ['querySelector', 'body', 'addEventListener', 'removeEventListener', 'remove', 'sort', 'keys', 'filter', 'isNaN', 'parseFloat', 'parseInt', 'EPSILON', 'isFinite',
4708
- 'bind', 'prototype', 'length', 'assign', 'entries', 'values', 'concat', 'substring', 'substr', 'splice', 'slice', 'buffer', 'appendChild', 'createElement', 'prompt',
4709
- 'alert'],
4710
- 'WGSL': ['textureSample'],
4711
- 'Python': ['abs', 'all', 'any', 'ascii', 'bin', 'bool', 'bytearray', 'bytes', 'callable', 'chr', 'classmethod', 'compile', 'complex', 'delattr', 'dict', 'dir', 'divmod',
4712
- 'enumerate', 'eval', 'exec', 'filter', 'float', 'format', 'frozenset', 'getattr', 'globals', 'hasattr', 'hash', 'help', 'hex', 'id', 'input', 'int', 'isinstance',
4713
- 'issubclass', 'iter', 'len', 'list', 'locals', 'map', 'max', 'memoryview', 'min', 'next', 'object', 'oct', 'open', 'ord', 'pow', 'print', 'property', 'range', 'repr',
4714
- 'reversed', 'round', 'set', 'setattr', 'slice', 'sorted', 'staticmethod', 'str', 'sum', 'super', 'tuple', 'type', 'vars', 'zip'],
4715
- 'CSS': [...Object.keys(document.body.style).map(LX.toKebabCase), 'block', 'inline', 'inline-block', 'flex', 'grid', 'none', 'inherit', 'initial', 'unset', 'revert', 'sticky',
4716
- 'relative', 'absolute', 'fixed', 'static', 'auto', 'visible', 'hidden', 'scroll', 'clip', 'ellipsis', 'nowrap', 'wrap', 'break-word', 'solid', 'dashed', 'dotted', 'double',
4717
- 'groove', 'ridge', 'inset', 'outset', 'left', 'right', 'center', 'top', 'bottom', 'start', 'end', 'justify', 'stretch', 'space-between', 'space-around', 'space-evenly',
4718
- 'baseline', 'middle', 'normal', 'bold', 'lighter', 'bolder', 'italic', 'blur', 'uppercase', 'lowercase', 'capitalize', 'transparent', 'currentColor', 'pointer', 'default',
4719
- 'move', 'grab', 'grabbing', 'not-allowed', 'none', 'cover', 'contain', 'repeat', 'no-repeat', 'repeat-x', 'repeat-y', 'round', 'space', 'linear-gradient', 'radial-gradient',
4720
- 'conic-gradient', 'url', 'calc', 'min', 'max', 'clamp', 'red', 'blue', 'green', 'black', 'white', 'gray', 'silver', 'yellow', 'orange', 'purple', 'pink', 'cyan', 'magenta',
4721
- 'lime', 'teal', 'navy', 'transparent', 'currentcolor', 'inherit', 'initial', 'unset', 'revert', 'none', 'auto', 'fit-content', 'min-content', 'max-content']
4722
- };
4723
- CE.types =
4724
- {
4725
- 'JavaScript': ['Object', 'String', 'Function', 'Boolean', 'Symbol', 'Error', 'Number', 'TextEncoder', 'TextDecoder', 'Array', 'ArrayBuffer', 'InputEvent', 'MouseEvent',
4726
- 'Int8Array', 'Int16Array', 'Int32Array', 'Float32Array', 'Float64Array', 'Element'],
4727
- 'TypeScript': ['arguments', 'constructor', 'null', 'typeof', 'debugger', 'abstract', 'Object', 'string', 'String', 'Function', 'Boolean', 'boolean', 'Error', 'Number', 'number', 'TextEncoder',
4728
- 'TextDecoder', 'Array', 'ArrayBuffer', 'InputEvent', 'MouseEvent', 'Int8Array', 'Int16Array', 'Int32Array', 'Float32Array', 'Float64Array', 'Element', 'bigint', 'unknown', 'any',
4729
- 'Record'],
4730
- 'Rust': ['u128'],
4731
- 'Python': ['int', 'type', 'float', 'map', 'list', 'ArithmeticError', 'AssertionError', 'AttributeError', 'Exception', 'EOFError', 'FloatingPointError', 'GeneratorExit',
4732
- 'ImportError', 'IndentationError', 'IndexError', 'KeyError', 'KeyboardInterrupt', 'LookupError', 'MemoryError', 'NameError', 'NotImplementedError', 'OSError',
4733
- 'OverflowError', 'ReferenceError', 'RuntimeError', 'StopIteration', 'SyntaxError', 'TabError', 'SystemError', 'SystemExit', 'TypeError', 'UnboundLocalError',
4734
- 'UnicodeError', 'UnicodeEncodeError', 'UnicodeDecodeError', 'UnicodeTranslateError', 'ValueError', 'ZeroDivisionError'],
4735
- 'C++': ['uint8_t', 'uint16_t', 'uint32_t'],
4736
- 'PHP': ['Exception', 'DateTime', 'JsonSerializable'],
4737
- };
4738
- CE.builtIn =
4739
- {
4740
- 'JavaScript': ['document', 'console', 'window', 'navigator', 'performance'],
4741
- 'CSS': ['*', '!important'],
4742
- 'C++': ['vector', 'list', 'map'],
4743
- 'WGSL': ['@vertex', '@fragment'],
4744
- 'HTML': ['type', 'xmlns', 'PUBLIC', 'http-equiv', 'src', 'style', 'lang', 'href', 'rel', 'content', 'xml', 'alt'], // attributes
4745
- 'Markdown': ['type', 'src', 'style', 'lang', 'href', 'rel', 'content', 'valign', 'alt'], // attributes
4746
- 'PHP': ['echo', 'print'],
4747
- };
4748
- CE.statements =
4749
- {
4750
- 'JavaScript': ['for', 'if', 'else', 'case', 'switch', 'return', 'while', 'continue', 'break', 'do', 'import', 'default', 'export', 'from', 'throw', 'async', 'try', 'catch', 'await', 'as'],
4751
- 'TypeScript': ['for', 'if', 'else', 'case', 'switch', 'return', 'while', 'continue', 'break', 'do', 'import', 'default', 'export', 'from', 'throw', 'async', 'try', 'catch', 'await', 'as'],
4752
- 'CSS': ['@', 'import'],
4753
- 'C': ['for', 'if', 'else', 'return', 'continue', 'break', 'case', 'switch', 'while', 'using', 'default', 'goto', 'do'],
4754
- 'C++': ['std', 'for', 'if', 'else', 'return', 'continue', 'break', 'case', 'switch', 'while', 'using', 'glm', 'spdlog', 'default'],
4755
- 'GLSL': ['for', 'if', 'else', 'return', 'continue', 'break'],
4756
- 'WGSL': ['const', 'for', 'if', 'else', 'return', 'continue', 'break', 'storage', 'read', 'read_write', 'uniform', 'function', 'workgroup', 'bitcast'],
4757
- 'Rust': ['break', 'else', 'continue', 'for', 'if', 'loop', 'match', 'return', 'while', 'do', 'yield'],
4758
- 'Python': ['if', 'raise', 'del', 'import', 'return', 'elif', 'try', 'else', 'while', 'as', 'except', 'with', 'assert', 'finally', 'yield', 'break', 'for', 'class', 'continue',
4759
- 'global', 'pass', 'from'],
4760
- 'Batch': ['if', 'IF', 'for', 'FOR', 'in', 'IN', 'do', 'DO', 'call', 'CALL', 'goto', 'GOTO', 'exit', 'EXIT'],
4761
- 'PHP': ['declare', 'enddeclare', 'foreach', 'endforeach', 'if', 'else', 'elseif', 'endif', 'for', 'endfor', 'while', 'endwhile', 'switch', 'case', 'default', 'endswitch', 'return', 'break', 'continue',
4762
- 'try', 'catch', 'die', 'do', 'exit', 'finally'],
4763
- };
4764
- CE.symbols =
4765
- {
4766
- 'JavaScript': ['<', '>', '[', ']', '{', '}', '(', ')', ';', '=', '|', '||', '&', '&&', '?', '??'],
4767
- 'TypeScript': ['<', '>', '[', ']', '{', '}', '(', ')', ';', '=', '|', '||', '&', '&&', '?', '??'],
4768
- 'C': ['<', '>', '[', ']', '{', '}', '(', ')', ';', '=', '|', '||', '&', '&&', '?', '*', '-', '+'],
4769
- 'C++': ['<', '>', '[', ']', '{', '}', '(', ')', ';', '=', '|', '||', '&', '&&', '?', '::', '*', '-', '+'],
4770
- 'CMake': ['{', '}'],
4771
- 'JSON': ['[', ']', '{', '}', '(', ')'],
4772
- 'GLSL': ['[', ']', '{', '}', '(', ')'],
4773
- 'WGSL': ['[', ']', '{', '}', '(', ')', '->'],
4774
- 'CSS': ['{', '}', '(', ')', '*'],
4775
- 'Rust': ['<', '>', '[', ']', '(', ')', '='],
4776
- 'Python': ['<', '>', '[', ']', '(', ')', '='],
4777
- 'Batch': ['[', ']', '(', ')', '%'],
4778
- 'HTML': ['<', '>', '/'],
4779
- 'XML': ['<', '>', '/'],
4780
- 'PHP': ['[', ']', '{', '}', '(', ')'],
4781
- };
4912
+ CE.utils = {
4913
+ 'JavaScript': ['querySelector', 'body', 'addEventListener', 'removeEventListener', 'remove', 'sort', 'keys',
4914
+ 'filter', 'isNaN', 'parseFloat', 'parseInt', 'EPSILON', 'isFinite', 'bind', 'prototype', 'length', 'assign',
4915
+ 'entries', 'values', 'concat', 'substring', 'substr', 'splice', 'slice', 'buffer', 'appendChild',
4916
+ 'createElement', 'prompt', 'alert'],
4917
+ 'WGSL': ['textureSample'],
4918
+ 'Python': ['abs', 'all', 'any', 'ascii', 'bin', 'bool', 'bytearray', 'bytes', 'callable', 'chr', 'classmethod',
4919
+ 'compile', 'complex', 'delattr', 'dict', 'dir', 'divmod', 'enumerate', 'eval', 'exec', 'filter', 'float',
4920
+ 'format', 'frozenset', 'getattr', 'globals', 'hasattr', 'hash', 'help', 'hex', 'id', 'input', 'int',
4921
+ 'isinstance', 'issubclass', 'iter', 'len', 'list', 'locals', 'map', 'max', 'memoryview', 'min', 'next',
4922
+ 'object', 'oct', 'open', 'ord', 'pow', 'print', 'property', 'range', 'repr', 'reversed', 'round', 'set',
4923
+ 'setattr', 'slice', 'sorted', 'staticmethod', 'str', 'sum', 'super', 'tuple', 'type', 'vars', 'zip'],
4924
+ 'CSS': [...Object.keys(document.body.style).map(LX.toKebabCase), 'block', 'inline', 'inline-block', 'flex',
4925
+ 'grid', 'none', 'inherit', 'initial', 'unset', 'revert', 'sticky', 'relative', 'absolute', 'fixed', 'static',
4926
+ 'auto', 'visible', 'hidden', 'scroll', 'clip', 'ellipsis', 'nowrap', 'wrap', 'break-word', 'solid', 'dashed',
4927
+ 'dotted', 'double', 'groove', 'ridge', 'inset', 'outset', 'left', 'right', 'center', 'top', 'bottom', 'start',
4928
+ 'end', 'justify', 'stretch', 'space-between', 'space-around', 'space-evenly', 'baseline', 'middle', 'normal',
4929
+ 'bold', 'lighter', 'bolder', 'italic', 'blur', 'uppercase', 'lowercase', 'capitalize', 'transparent',
4930
+ 'currentColor', 'pointer', 'default', 'move', 'grab', 'grabbing', 'not-allowed', 'none', 'cover', 'contain',
4931
+ 'repeat', 'no-repeat', 'repeat-x', 'repeat-y', 'round', 'space', 'linear-gradient', 'radial-gradient',
4932
+ 'conic-gradient', 'url', 'calc', 'min', 'max', 'clamp', 'red', 'blue', 'green', 'black', 'white', 'gray',
4933
+ 'silver', 'yellow', 'orange', 'purple', 'pink', 'cyan', 'magenta', 'lime', 'teal', 'navy', 'transparent',
4934
+ 'currentcolor', 'inherit', 'initial', 'unset', 'revert', 'none', 'auto', 'fit-content', 'min-content',
4935
+ 'max-content']
4936
+ };
4937
+ CE.types = {
4938
+ 'JavaScript': ['Object', 'String', 'Function', 'Boolean', 'Symbol', 'Error', 'Number', 'TextEncoder',
4939
+ 'TextDecoder', 'Array', 'ArrayBuffer', 'InputEvent', 'MouseEvent', 'Int8Array', 'Int16Array', 'Int32Array',
4940
+ 'Float32Array', 'Float64Array', 'Element'],
4941
+ 'TypeScript': ['arguments', 'constructor', 'null', 'typeof', 'debugger', 'abstract', 'Object', 'string', 'String',
4942
+ 'Function', 'Boolean', 'boolean', 'Error', 'Number', 'number', 'TextEncoder', 'TextDecoder', 'Array',
4943
+ 'ArrayBuffer', 'InputEvent', 'MouseEvent', 'Int8Array', 'Int16Array', 'Int32Array', 'Float32Array',
4944
+ 'Float64Array', 'Element', 'bigint', 'unknown', 'any', 'Record'],
4945
+ 'Rust': ['u128'],
4946
+ 'Python': ['int', 'type', 'float', 'map', 'list', 'ArithmeticError', 'AssertionError', 'AttributeError',
4947
+ 'Exception', 'EOFError', 'FloatingPointError', 'GeneratorExit', 'ImportError', 'IndentationError', 'IndexError',
4948
+ 'KeyError', 'KeyboardInterrupt', 'LookupError', 'MemoryError', 'NameError', 'NotImplementedError', 'OSError',
4949
+ 'OverflowError', 'ReferenceError', 'RuntimeError', 'StopIteration', 'SyntaxError', 'TabError', 'SystemError',
4950
+ 'SystemExit', 'TypeError', 'UnboundLocalError', 'UnicodeError', 'UnicodeEncodeError', 'UnicodeDecodeError',
4951
+ 'UnicodeTranslateError', 'ValueError', 'ZeroDivisionError'],
4952
+ 'C++': ['uint8_t', 'uint16_t', 'uint32_t'],
4953
+ 'PHP': ['Exception', 'DateTime', 'JsonSerializable']
4954
+ };
4955
+ CE.builtIn = {
4956
+ 'JavaScript': ['document', 'console', 'window', 'navigator', 'performance'],
4957
+ 'CSS': ['*', '!important'],
4958
+ 'C++': ['vector', 'list', 'map'],
4959
+ 'WGSL': ['@vertex', '@fragment'],
4960
+ 'HTML': ['type', 'xmlns', 'PUBLIC', 'http-equiv', 'src', 'style', 'lang', 'href', 'rel', 'content', 'xml', 'alt'], // attributes
4961
+ 'Markdown': ['type', 'src', 'style', 'lang', 'href', 'rel', 'content', 'valign', 'alt'], // attributes
4962
+ 'PHP': ['echo', 'print']
4963
+ };
4964
+ CE.statements = {
4965
+ 'JavaScript': ['for', 'if', 'else', 'case', 'switch', 'return', 'while', 'continue', 'break', 'do', 'import',
4966
+ 'default', 'export', 'from', 'throw', 'async', 'try', 'catch', 'await', 'as'],
4967
+ 'TypeScript': ['for', 'if', 'else', 'case', 'switch', 'return', 'while', 'continue', 'break', 'do', 'import',
4968
+ 'default', 'export', 'from', 'throw', 'async', 'try', 'catch', 'await', 'as'],
4969
+ 'CSS': ['@', 'import'],
4970
+ 'C': ['for', 'if', 'else', 'return', 'continue', 'break', 'case', 'switch', 'while', 'using', 'default', 'goto',
4971
+ 'do'],
4972
+ 'C++': ['std', 'for', 'if', 'else', 'return', 'continue', 'break', 'case', 'switch', 'while', 'using', 'glm',
4973
+ 'spdlog', 'default'],
4974
+ 'GLSL': ['for', 'if', 'else', 'return', 'continue', 'break'],
4975
+ 'WGSL': ['const', 'for', 'if', 'else', 'return', 'continue', 'break', 'storage', 'read', 'read_write', 'uniform',
4976
+ 'function', 'workgroup', 'bitcast'],
4977
+ 'Rust': ['break', 'else', 'continue', 'for', 'if', 'loop', 'match', 'return', 'while', 'do', 'yield'],
4978
+ 'Python': ['if', 'raise', 'del', 'import', 'return', 'elif', 'try', 'else', 'while', 'as', 'except', 'with',
4979
+ 'assert', 'finally', 'yield', 'break', 'for', 'class', 'continue', 'global', 'pass', 'from'],
4980
+ 'Batch': ['if', 'IF', 'for', 'FOR', 'in', 'IN', 'do', 'DO', 'call', 'CALL', 'goto', 'GOTO', 'exit', 'EXIT'],
4981
+ 'PHP': ['declare', 'enddeclare', 'foreach', 'endforeach', 'if', 'else', 'elseif', 'endif', 'for', 'endfor',
4982
+ 'while', 'endwhile', 'switch', 'case', 'default', 'endswitch', 'return', 'break', 'continue', 'try', 'catch',
4983
+ 'die', 'do', 'exit', 'finally']
4984
+ };
4985
+ CE.symbols = {
4986
+ 'JavaScript': ['<', '>', '[', ']', '{', '}', '(', ')', ';', '=', '|', '||', '&', '&&', '?', '??'],
4987
+ 'TypeScript': ['<', '>', '[', ']', '{', '}', '(', ')', ';', '=', '|', '||', '&', '&&', '?', '??'],
4988
+ 'C': ['<', '>', '[', ']', '{', '}', '(', ')', ';', '=', '|', '||', '&', '&&', '?', '*', '-', '+'],
4989
+ 'C++': ['<', '>', '[', ']', '{', '}', '(', ')', ';', '=', '|', '||', '&', '&&', '?', '::', '*', '-', '+'],
4990
+ 'CMake': ['{', '}'],
4991
+ 'JSON': ['[', ']', '{', '}', '(', ')'],
4992
+ 'GLSL': ['[', ']', '{', '}', '(', ')'],
4993
+ 'WGSL': ['[', ']', '{', '}', '(', ')', '->'],
4994
+ 'CSS': ['{', '}', '(', ')', '*'],
4995
+ 'Rust': ['<', '>', '[', ']', '(', ')', '='],
4996
+ 'Python': ['<', '>', '[', ']', '(', ')', '='],
4997
+ 'Batch': ['[', ']', '(', ')', '%'],
4998
+ 'HTML': ['<', '>', '/'],
4999
+ 'XML': ['<', '>', '/'],
5000
+ 'PHP': ['[', ']', '{', '}', '(', ')']
5001
+ };
4782
5002
  CE.REGISTER_LANGUAGE = function (name, options = {}, def, rules) {
4783
5003
  CE.languages[name] = options;
4784
5004
  if (def?.keywords)