lexgui 0.1.14 → 0.1.16
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.
- package/build/components/codeeditor.js +607 -208
- package/build/lexgui.css +90 -18
- package/build/lexgui.js +30 -29
- package/build/lexgui.module.js +20 -19
- package/demo.js +0 -3
- package/examples/code_editor.html +13 -4
- package/package.json +1 -1
|
@@ -29,6 +29,10 @@ function firstNonspaceIndex(str) {
|
|
|
29
29
|
return str.search(/\S|$/);
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
+
function deleteElement(el) {
|
|
33
|
+
if(el) el.remove();
|
|
34
|
+
}
|
|
35
|
+
|
|
32
36
|
let ASYNC_ENABLED = true;
|
|
33
37
|
|
|
34
38
|
function doAsync( fn, ms ) {
|
|
@@ -102,10 +106,31 @@ class CodeEditor {
|
|
|
102
106
|
|
|
103
107
|
constructor( area, options = {} ) {
|
|
104
108
|
|
|
109
|
+
// var a = [];
|
|
110
|
+
|
|
111
|
+
// var map = {};
|
|
112
|
+
|
|
113
|
+
// for( var i = 0; i < 1000000; ++i )
|
|
114
|
+
// map[i] = 1;
|
|
115
|
+
|
|
116
|
+
// const start = performance.now();
|
|
117
|
+
|
|
118
|
+
// for( var i = 0; i < 3000; ++i ) {
|
|
119
|
+
// const b = map[Math.floor( Math.random() * 1000000 )];
|
|
120
|
+
// }
|
|
121
|
+
|
|
122
|
+
// console.log( performance.now() - start );
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
// debugger;
|
|
126
|
+
|
|
127
|
+
|
|
105
128
|
window.editor = this;
|
|
106
129
|
|
|
107
130
|
CodeEditor.__instances.push( this );
|
|
108
131
|
|
|
132
|
+
var that = this;
|
|
133
|
+
|
|
109
134
|
this.base_area = area;
|
|
110
135
|
this.area = new LX.Area( { className: "lexcodeeditor", height: "auto", no_append: true } );
|
|
111
136
|
|
|
@@ -142,6 +167,9 @@ class CodeEditor {
|
|
|
142
167
|
this.root.addEventListener( 'click', this.processMouse.bind(this) );
|
|
143
168
|
this.root.addEventListener( 'contextmenu', this.processMouse.bind(this) );
|
|
144
169
|
|
|
170
|
+
// Take into account the scrollbar..
|
|
171
|
+
this.tabs.area.root.classList.add( 'codetabsarea' );
|
|
172
|
+
|
|
145
173
|
// Cursors and selection
|
|
146
174
|
|
|
147
175
|
this.cursors = document.createElement('div');
|
|
@@ -170,6 +198,96 @@ class CodeEditor {
|
|
|
170
198
|
this.cursors.appendChild(cursor);
|
|
171
199
|
}
|
|
172
200
|
|
|
201
|
+
// Add custom vertical scroll bar
|
|
202
|
+
{
|
|
203
|
+
var scrollbar = document.createElement('div');
|
|
204
|
+
scrollbar.className = "lexcodescrollbar";
|
|
205
|
+
this.scrollbar = scrollbar;
|
|
206
|
+
area.attach(this.scrollbar);
|
|
207
|
+
|
|
208
|
+
var scrollbarThumb = document.createElement('div');
|
|
209
|
+
this.scrollbarThumb = scrollbarThumb;
|
|
210
|
+
this.scrollbarThumb._top = 0;
|
|
211
|
+
scrollbar.appendChild(scrollbarThumb);
|
|
212
|
+
|
|
213
|
+
this.scrollbarThumb.addEventListener("mousedown", inner_mousedown);
|
|
214
|
+
|
|
215
|
+
var last_pos = 0;
|
|
216
|
+
|
|
217
|
+
function inner_mousedown(e)
|
|
218
|
+
{
|
|
219
|
+
var doc = that.root.ownerDocument;
|
|
220
|
+
doc.addEventListener("mousemove",inner_mousemove);
|
|
221
|
+
doc.addEventListener("mouseup",inner_mouseup);
|
|
222
|
+
last_pos = e.y;
|
|
223
|
+
e.stopPropagation();
|
|
224
|
+
e.preventDefault();
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
function inner_mousemove(e)
|
|
228
|
+
{
|
|
229
|
+
var dt = (last_pos - e.y);
|
|
230
|
+
|
|
231
|
+
that.applyVerticalScrollFromScrollBar( that.scrollbarThumb._top - dt )
|
|
232
|
+
|
|
233
|
+
last_pos = e.y;
|
|
234
|
+
e.stopPropagation();
|
|
235
|
+
e.preventDefault();
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
function inner_mouseup(e)
|
|
239
|
+
{
|
|
240
|
+
var doc = that.root.ownerDocument;
|
|
241
|
+
doc.removeEventListener("mousemove", inner_mousemove);
|
|
242
|
+
doc.removeEventListener("mouseup", inner_mouseup);
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
// Add custom horizontal scroll bar
|
|
247
|
+
{
|
|
248
|
+
var hScrollbar = document.createElement('div');
|
|
249
|
+
hScrollbar.className = "lexcodescrollbar horizontal";
|
|
250
|
+
this.hScrollbar = hScrollbar;
|
|
251
|
+
area.attach(this.hScrollbar);
|
|
252
|
+
|
|
253
|
+
var hScrollbarThumb = document.createElement('div');
|
|
254
|
+
this.hScrollbarThumb = hScrollbarThumb;
|
|
255
|
+
this.hScrollbarThumb._left = 0;
|
|
256
|
+
hScrollbar.appendChild(hScrollbarThumb);
|
|
257
|
+
|
|
258
|
+
this.hScrollbarThumb.addEventListener("mousedown", inner_mousedown);
|
|
259
|
+
|
|
260
|
+
var last_pos = 0;
|
|
261
|
+
|
|
262
|
+
function inner_mousedown(e)
|
|
263
|
+
{
|
|
264
|
+
var doc = that.root.ownerDocument;
|
|
265
|
+
doc.addEventListener("mousemove",inner_mousemove);
|
|
266
|
+
doc.addEventListener("mouseup",inner_mouseup);
|
|
267
|
+
last_pos = e.x;
|
|
268
|
+
e.stopPropagation();
|
|
269
|
+
e.preventDefault();
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
function inner_mousemove(e)
|
|
273
|
+
{
|
|
274
|
+
var dt = (last_pos - e.x);
|
|
275
|
+
|
|
276
|
+
that.applyHorizontalScrollFromScrollBar( that.hScrollbarThumb._left - dt )
|
|
277
|
+
|
|
278
|
+
last_pos = e.x;
|
|
279
|
+
e.stopPropagation();
|
|
280
|
+
e.preventDefault();
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
function inner_mouseup(e)
|
|
284
|
+
{
|
|
285
|
+
var doc = that.root.ownerDocument;
|
|
286
|
+
doc.removeEventListener("mousemove", inner_mousemove);
|
|
287
|
+
doc.removeEventListener("mouseup", inner_mouseup);
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
|
|
173
291
|
// Add autocomplete box
|
|
174
292
|
{
|
|
175
293
|
var box = document.createElement('div');
|
|
@@ -199,6 +317,7 @@ class CodeEditor {
|
|
|
199
317
|
this.tabSpaces = 4;
|
|
200
318
|
this.maxUndoSteps = 16;
|
|
201
319
|
this.lineHeight = 20;
|
|
320
|
+
this.defaultSingleLineCommentToken = "//";
|
|
202
321
|
this.charWidth = 8; //this.measureChar();
|
|
203
322
|
this._lastTime = null;
|
|
204
323
|
|
|
@@ -210,28 +329,48 @@ class CodeEditor {
|
|
|
210
329
|
"[": "]"
|
|
211
330
|
};
|
|
212
331
|
|
|
332
|
+
this.stringKeys = { // adding @ because some words are always true in (e.g. constructor..)
|
|
333
|
+
"@\"": "\"",
|
|
334
|
+
"@'": "'"
|
|
335
|
+
};
|
|
336
|
+
|
|
213
337
|
// Scan tokens..
|
|
214
338
|
setInterval( this.scanWordSuggestions.bind(this), 2000 );
|
|
215
339
|
|
|
216
|
-
this.languages =
|
|
217
|
-
'Plain Text'
|
|
218
|
-
|
|
340
|
+
this.languages = {
|
|
341
|
+
'Plain Text': { },
|
|
342
|
+
'JavaScript': { },
|
|
343
|
+
'C++': { },
|
|
344
|
+
'CSS': { },
|
|
345
|
+
'GLSL': { },
|
|
346
|
+
'WGSL': { },
|
|
347
|
+
'JSON': { },
|
|
348
|
+
'XML': { },
|
|
349
|
+
'Python': { },
|
|
350
|
+
'Batch': { blockComments: false, singleLineCommentToken: '::' }
|
|
351
|
+
};
|
|
352
|
+
|
|
219
353
|
this.specialKeys = [
|
|
220
354
|
'Backspace', 'Enter', 'ArrowUp', 'ArrowDown',
|
|
221
355
|
'ArrowRight', 'ArrowLeft', 'Delete', 'Home',
|
|
222
356
|
'End', 'Tab', 'Escape'
|
|
223
357
|
];
|
|
358
|
+
|
|
224
359
|
this.keywords = {
|
|
225
360
|
'JavaScript': ['var', 'let', 'const', 'this', 'in', 'of', 'true', 'false', 'new', 'function', 'NaN', 'static', 'class', 'constructor', 'null', 'typeof', 'debugger', 'abstract',
|
|
226
361
|
'arguments', 'extends', 'instanceof'],
|
|
227
|
-
'C++': ['int', 'float', 'bool', 'const', 'static_cast', 'dynamic_cast', 'new', 'delete', 'void', 'true', 'false', 'auto', 'struct', 'typedef'
|
|
362
|
+
'C++': ['int', 'float', 'double', 'bool', 'char', 'wchar_t', 'const', 'static_cast', 'dynamic_cast', 'new', 'delete', 'void', 'true', 'false', 'auto', 'struct', 'typedef', 'nullptr',
|
|
363
|
+
'NULL', 'unsigned'],
|
|
364
|
+
'JSON': ['true', 'false'],
|
|
228
365
|
'GLSL': ['true', 'false', 'function', 'int', 'float', 'vec2', 'vec3', 'vec4', 'mat2x2', 'mat3x3', 'mat4x4', 'struct'],
|
|
229
366
|
'CSS': ['body', 'html', 'canvas', 'div', 'input', 'span', '.'],
|
|
230
367
|
'WGSL': ['var', 'let', 'true', 'false', 'fn', 'bool', 'u32', 'i32', 'f16', 'f32', 'vec2f', 'vec3f', 'vec4f', 'mat2x2f', 'mat3x3f', 'mat4x4f', 'array', 'atomic', 'struct',
|
|
231
368
|
'sampler', 'sampler_comparison', 'texture_depth_2d', 'texture_depth_2d_array', 'texture_depth_cube', 'texture_depth_cube_array', 'texture_depth_multisampled_2d',
|
|
232
369
|
'texture_external', 'texture_1d', 'texture_2d', 'texture_2d_array', 'texture_3d', 'texture_cube', 'texture_cube_array', 'texture_storage_1d', 'texture_storage_2d',
|
|
233
370
|
'texture_storage_2d_array', 'texture_storage_3d'],
|
|
234
|
-
'Python': ['False', 'def', 'None', 'True', 'in', 'is', 'and', 'lambda', 'nonlocal', 'not', 'or']
|
|
371
|
+
'Python': ['False', 'def', 'None', 'True', 'in', 'is', 'and', 'lambda', 'nonlocal', 'not', 'or'],
|
|
372
|
+
'Batch': ['set', 'SET', 'echo', 'ECHO', 'off', 'OFF', 'del', 'DEL', 'defined', 'DEFINED', 'setlocal', 'SETLOCAL', 'enabledelayedexpansion', 'ENABLEDELAYEDEXPANSION', 'driverquery',
|
|
373
|
+
'DRIVERQUERY', 'print', 'PRINT']
|
|
235
374
|
};
|
|
236
375
|
this.utils = { // These ones don't have hightlight, used as suggestions to autocomplete only...
|
|
237
376
|
'JavaScript': ['querySelector', 'body', 'addEventListener', 'removeEventListener', 'remove', 'sort', 'keys', 'filter', 'isNaN', 'parseFloat', 'parseInt', 'EPSILON', 'isFinite',
|
|
@@ -248,7 +387,8 @@ class CodeEditor {
|
|
|
248
387
|
'Python': ['int', 'type', 'float', 'map', 'list', 'ArithmeticError', 'AssertionError', 'AttributeError', 'Exception', 'EOFError', 'FloatingPointError', 'GeneratorExit',
|
|
249
388
|
'ImportError', 'IndentationError', 'IndexError', 'KeyError', 'KeyboardInterrupt', 'LookupError', 'MemoryError', 'NameError', 'NotImplementedError', 'OSError',
|
|
250
389
|
'OverflowError', 'ReferenceError', 'RuntimeError', 'StopIteration', 'SyntaxError', 'TabError', 'SystemError', 'SystemExit', 'TypeError', 'UnboundLocalError',
|
|
251
|
-
'UnicodeError', 'UnicodeEncodeError', 'UnicodeDecodeError', 'UnicodeTranslateError', 'ValueError', 'ZeroDivisionError' ]
|
|
390
|
+
'UnicodeError', 'UnicodeEncodeError', 'UnicodeDecodeError', 'UnicodeTranslateError', 'ValueError', 'ZeroDivisionError' ],
|
|
391
|
+
'C++': ['uint8_t', 'uint16_t', 'uint32_t']
|
|
252
392
|
};
|
|
253
393
|
this.builtin = {
|
|
254
394
|
'JavaScript': ['document', 'console', 'window', 'navigator', 'performance'],
|
|
@@ -257,21 +397,33 @@ class CodeEditor {
|
|
|
257
397
|
};
|
|
258
398
|
this.statementsAndDeclarations = {
|
|
259
399
|
'JavaScript': ['for', 'if', 'else', 'case', 'switch', 'return', 'while', 'continue', 'break', 'do', 'import', 'from', 'throw', 'async', 'try', 'catch', 'await'],
|
|
260
|
-
'C++': ['std', 'for', 'if', 'else', 'return', 'continue', 'break', 'case', 'switch', 'while', 'glm'],
|
|
400
|
+
'C++': ['std', 'for', 'if', 'else', 'return', 'continue', 'break', 'case', 'switch', 'while', 'glm', 'spdlog'],
|
|
261
401
|
'GLSL': ['for', 'if', 'else', 'return', 'continue', 'break'],
|
|
262
402
|
'WGSL': ['const','for', 'if', 'else', 'return', 'continue', 'break', 'storage', 'read', 'uniform'],
|
|
263
|
-
'Python': ['if', 'raise', 'del', 'import', 'return', 'elif', 'try', 'else', 'while', 'as', 'except', 'with', 'assert', 'finally', 'yield', 'break', 'for', 'class', 'continue',
|
|
403
|
+
'Python': ['if', 'raise', 'del', 'import', 'return', 'elif', 'try', 'else', 'while', 'as', 'except', 'with', 'assert', 'finally', 'yield', 'break', 'for', 'class', 'continue',
|
|
404
|
+
'global', 'pass'],
|
|
405
|
+
'Batch': ['if', 'IF', 'for', 'FOR', 'in', 'IN', 'do', 'DO', 'call', 'CALL', 'goto', 'GOTO', 'exit', 'EXIT']
|
|
264
406
|
};
|
|
265
407
|
this.symbols = {
|
|
266
408
|
'JavaScript': ['<', '>', '[', ']', '{', '}', '(', ')', ';', '=', '|', '||', '&', '&&', '?', '??'],
|
|
267
|
-
'C++': ['<', '>', '[', ']', '{', '}', '(', ')', ';', '=', '|', '||', '&', '&&', '?', '::'],
|
|
409
|
+
'C++': ['<', '>', '[', ']', '{', '}', '(', ')', ';', '=', '|', '||', '&', '&&', '?', '::', '*', '-', '+'],
|
|
268
410
|
'JSON': ['[', ']', '{', '}', '(', ')'],
|
|
269
411
|
'GLSL': ['[', ']', '{', '}', '(', ')'],
|
|
270
412
|
'WGSL': ['[', ']', '{', '}', '(', ')', '->'],
|
|
271
413
|
'CSS': ['{', '}', '(', ')', '*'],
|
|
272
|
-
'Python': ['<', '>', '[', ']', '(', ')', '=']
|
|
414
|
+
'Python': ['<', '>', '[', ']', '(', ')', '='],
|
|
415
|
+
'Batch': ['[', ']', '(', ')', '%'],
|
|
273
416
|
};
|
|
274
417
|
|
|
418
|
+
// Convert reserved word arrays to maps so we can search tokens faster
|
|
419
|
+
|
|
420
|
+
for( let lang in this.keywords ) this.keywords[lang] = this.keywords[lang].reduce((a, v) => ({ ...a, [v]: true}), {});
|
|
421
|
+
for( let lang in this.utils ) this.utils[lang] = this.utils[lang].reduce((a, v) => ({ ...a, [v]: true}), {});
|
|
422
|
+
for( let lang in this.types ) this.types[lang] = this.types[lang].reduce((a, v) => ({ ...a, [v]: true}), {});
|
|
423
|
+
for( let lang in this.builtin ) this.builtin[lang] = this.builtin[lang].reduce((a, v) => ({ ...a, [v]: true}), {});
|
|
424
|
+
for( let lang in this.statementsAndDeclarations ) this.statementsAndDeclarations[lang] = this.statementsAndDeclarations[lang].reduce((a, v) => ({ ...a, [v]: true}), {});
|
|
425
|
+
for( let lang in this.symbols ) this.symbols[lang] = this.symbols[lang].reduce((a, v) => ({ ...a, [v]: true}), {});
|
|
426
|
+
|
|
275
427
|
// Action keys
|
|
276
428
|
|
|
277
429
|
this.action('Escape', false, ( ln, cursor, e ) => {
|
|
@@ -355,7 +507,7 @@ class CodeEditor {
|
|
|
355
507
|
this.resetCursorPos( CodeEditor.CURSOR_LEFT );
|
|
356
508
|
if(idx > 0) this.cursorToString(cursor, prestring);
|
|
357
509
|
this._refreshCodeInfo(cursor.line, cursor.position);
|
|
358
|
-
this.
|
|
510
|
+
this.setScrollLeft( 0 );
|
|
359
511
|
|
|
360
512
|
if( e.shiftKey && !e.cancelShift )
|
|
361
513
|
{
|
|
@@ -366,7 +518,7 @@ class CodeEditor {
|
|
|
366
518
|
this.startSelection(cursor);
|
|
367
519
|
var string = this.code.lines[ln].substring(idx, last_pos);
|
|
368
520
|
this.selection.selectInline(idx, cursor.line, this.measureString(string));
|
|
369
|
-
} else
|
|
521
|
+
} else if( !e.keepSelection )
|
|
370
522
|
this.endSelection();
|
|
371
523
|
});
|
|
372
524
|
|
|
@@ -384,8 +536,8 @@ class CodeEditor {
|
|
|
384
536
|
this.resetCursorPos( CodeEditor.CURSOR_LEFT );
|
|
385
537
|
this.cursorToString( cursor, this.code.lines[ln] );
|
|
386
538
|
|
|
387
|
-
const last_char = (
|
|
388
|
-
this.
|
|
539
|
+
const last_char = (this.code.clientWidth / this.charWidth)|0;
|
|
540
|
+
this.setScrollLeft( cursor.position >= last_char ? (cursor.position - last_char) * this.charWidth : 0 );
|
|
389
541
|
});
|
|
390
542
|
|
|
391
543
|
this.action('Enter', true, ( ln, cursor, e ) => {
|
|
@@ -442,7 +594,7 @@ class CodeEditor {
|
|
|
442
594
|
|
|
443
595
|
var letter = this.getCharAtPos( cursor );
|
|
444
596
|
if(!letter) {
|
|
445
|
-
this.selection.toX =
|
|
597
|
+
this.selection.toX = this.code.lines[cursor.line].length;
|
|
446
598
|
this.cursorToPosition(cursor, this.selection.toX);
|
|
447
599
|
}
|
|
448
600
|
|
|
@@ -504,7 +656,7 @@ class CodeEditor {
|
|
|
504
656
|
|
|
505
657
|
if(e.metaKey) { // Apple devices (Command)
|
|
506
658
|
e.preventDefault();
|
|
507
|
-
this.actions[ 'Home' ].callback( ln, cursor );
|
|
659
|
+
this.actions[ 'Home' ].callback( ln, cursor, e );
|
|
508
660
|
}
|
|
509
661
|
else if(e.ctrlKey) {
|
|
510
662
|
// Get next word
|
|
@@ -548,13 +700,15 @@ class CodeEditor {
|
|
|
548
700
|
}
|
|
549
701
|
}
|
|
550
702
|
else if( cursor.line > 0 ) {
|
|
551
|
-
|
|
703
|
+
|
|
704
|
+
if( e.shiftKey ) {
|
|
705
|
+
if(!this.selection) this.startSelection(cursor);
|
|
706
|
+
}
|
|
707
|
+
|
|
552
708
|
this.lineUp( cursor );
|
|
553
|
-
this.
|
|
554
|
-
this.cursorToPosition( cursor, this.code.lines[cursor.line].length );
|
|
709
|
+
this.actions[ 'End' ].callback( cursor.line, cursor, e );
|
|
555
710
|
|
|
556
711
|
if( e.shiftKey ) {
|
|
557
|
-
if(!this.selection) this.startSelection(cursor);
|
|
558
712
|
this.selection.toX = cursor.position;
|
|
559
713
|
this.selection.toY--;
|
|
560
714
|
this.processSelection(null, true);
|
|
@@ -613,17 +767,22 @@ class CodeEditor {
|
|
|
613
767
|
}
|
|
614
768
|
else if( this.code.lines[ cursor.line + 1 ] !== undefined ) {
|
|
615
769
|
|
|
770
|
+
if( e.shiftKey ) {
|
|
771
|
+
if(!this.selection) this.startSelection(cursor);
|
|
772
|
+
e.cancelShift = true;
|
|
773
|
+
e.keepSelection = true;
|
|
774
|
+
}
|
|
775
|
+
|
|
616
776
|
this.lineDown( cursor );
|
|
617
|
-
e.cancelShift = true;
|
|
618
777
|
this.actions['Home'].callback(cursor.line, cursor, e);
|
|
619
|
-
|
|
620
|
-
|
|
778
|
+
|
|
621
779
|
if( e.shiftKey ) {
|
|
622
|
-
if(!this.selection) this.startSelection(cursor);
|
|
623
780
|
this.selection.toX = cursor.position;
|
|
624
781
|
this.selection.toY++;
|
|
625
782
|
this.processSelection(null, true);
|
|
626
783
|
}
|
|
784
|
+
|
|
785
|
+
this.hideAutoCompleteBox();
|
|
627
786
|
}
|
|
628
787
|
}
|
|
629
788
|
});
|
|
@@ -652,7 +811,7 @@ class CodeEditor {
|
|
|
652
811
|
}
|
|
653
812
|
|
|
654
813
|
// This can be used to empty all text...
|
|
655
|
-
setText( text = "" ) {
|
|
814
|
+
setText( text = "", lang ) {
|
|
656
815
|
|
|
657
816
|
let new_lines = text.split('\n');
|
|
658
817
|
this.code.lines = [].concat(new_lines);
|
|
@@ -663,6 +822,11 @@ class CodeEditor {
|
|
|
663
822
|
this.cursorToLine(cursor, new_lines.length); // Already substracted 1
|
|
664
823
|
this.cursorToPosition(cursor, lastLine.length);
|
|
665
824
|
this.processLines();
|
|
825
|
+
|
|
826
|
+
if( lang )
|
|
827
|
+
{
|
|
828
|
+
this._changeLanguage( lang );
|
|
829
|
+
}
|
|
666
830
|
}
|
|
667
831
|
|
|
668
832
|
appendText( text ) {
|
|
@@ -731,11 +895,13 @@ class CodeEditor {
|
|
|
731
895
|
loadFile( file ) {
|
|
732
896
|
|
|
733
897
|
const inner_add_tab = ( text, name, title ) => {
|
|
734
|
-
this.addTab(name, true, title);
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
898
|
+
const existing = this.addTab(name, true, title);
|
|
899
|
+
if( !existing )
|
|
900
|
+
{
|
|
901
|
+
text = text.replaceAll('\r', '');
|
|
902
|
+
this.code.lines = text.split('\n');
|
|
903
|
+
this._changeLanguageFromExtension( LX.getExtension(name) );
|
|
904
|
+
}
|
|
739
905
|
};
|
|
740
906
|
|
|
741
907
|
if(file.constructor == String)
|
|
@@ -744,7 +910,6 @@ class CodeEditor {
|
|
|
744
910
|
LX.request({ url: filename, success: text => {
|
|
745
911
|
|
|
746
912
|
const name = filename.substring(filename.lastIndexOf('/') + 1);
|
|
747
|
-
this._changeLanguageFromExtension( LX.getExtension(name) );
|
|
748
913
|
inner_add_tab( text, name, filename );
|
|
749
914
|
} });
|
|
750
915
|
}
|
|
@@ -753,12 +918,10 @@ class CodeEditor {
|
|
|
753
918
|
const fr = new FileReader();
|
|
754
919
|
fr.readAsText( file );
|
|
755
920
|
fr.onload = e => {
|
|
756
|
-
this._changeLanguageFromExtension( LX.getExtension(file.name) );
|
|
757
921
|
const text = e.currentTarget.result;
|
|
758
922
|
inner_add_tab( text, file.name );
|
|
759
923
|
};
|
|
760
924
|
}
|
|
761
|
-
|
|
762
925
|
}
|
|
763
926
|
|
|
764
927
|
_addUndoStep( cursor ) {
|
|
@@ -773,6 +936,8 @@ class CodeEditor {
|
|
|
773
936
|
}
|
|
774
937
|
|
|
775
938
|
_changeLanguage( lang ) {
|
|
939
|
+
|
|
940
|
+
this.code.lang = lang;
|
|
776
941
|
this.highlight = lang;
|
|
777
942
|
this._refreshCodeInfo();
|
|
778
943
|
this.processLines();
|
|
@@ -780,6 +945,9 @@ class CodeEditor {
|
|
|
780
945
|
|
|
781
946
|
_changeLanguageFromExtension( ext ) {
|
|
782
947
|
|
|
948
|
+
if( !ext )
|
|
949
|
+
return this._changeLanguage( this.code.lang );
|
|
950
|
+
|
|
783
951
|
switch(ext.toLowerCase())
|
|
784
952
|
{
|
|
785
953
|
case 'js': return this._changeLanguage('JavaScript');
|
|
@@ -791,6 +959,7 @@ class CodeEditor {
|
|
|
791
959
|
case 'xml': return this._changeLanguage('XML');
|
|
792
960
|
case 'wgsl': return this._changeLanguage('WGSL');
|
|
793
961
|
case 'py': return this._changeLanguage('Python');
|
|
962
|
+
case 'bat': return this._changeLanguage('Batch');
|
|
794
963
|
case 'txt':
|
|
795
964
|
default:
|
|
796
965
|
this._changeLanguage('Plain Text');
|
|
@@ -815,7 +984,7 @@ class CodeEditor {
|
|
|
815
984
|
panel.addLabel("Col " + panel.col, { width: "64px" });
|
|
816
985
|
panel.addButton("<b>{ }</b>", this.highlight, (value, event) => {
|
|
817
986
|
LX.addContextMenu( "Language", event, m => {
|
|
818
|
-
for( const lang of this.languages )
|
|
987
|
+
for( const lang of Object.keys(this.languages) )
|
|
819
988
|
m.add( lang, this._changeLanguage.bind(this) );
|
|
820
989
|
});
|
|
821
990
|
}, { width: "25%", nameWidth: "15%" });
|
|
@@ -856,48 +1025,48 @@ class CodeEditor {
|
|
|
856
1025
|
if(this.openedTabs[name])
|
|
857
1026
|
{
|
|
858
1027
|
this.tabs.select( this.code.tabName );
|
|
859
|
-
return;
|
|
1028
|
+
return true;
|
|
860
1029
|
}
|
|
861
1030
|
|
|
862
1031
|
// Create code content
|
|
863
1032
|
let code = document.createElement('div');
|
|
864
1033
|
code.className = 'code';
|
|
865
1034
|
code.lines = [""];
|
|
1035
|
+
code.lang = "Plain Text";
|
|
866
1036
|
code.cursorState = {};
|
|
867
1037
|
code.undoSteps = [];
|
|
868
1038
|
code.tabName = name;
|
|
869
1039
|
code.title = title ?? name;
|
|
870
|
-
code.tokens = {};
|
|
1040
|
+
code.tokens = {};
|
|
1041
|
+
code.customScroll = new LX.vec2;
|
|
871
1042
|
|
|
872
1043
|
code.addEventListener('dragenter', function(e) {
|
|
873
1044
|
e.preventDefault();
|
|
874
|
-
this.classList.add('dragging');
|
|
1045
|
+
this.parentElement.classList.add('dragging');
|
|
875
1046
|
});
|
|
876
1047
|
code.addEventListener('dragleave', function(e) {
|
|
877
1048
|
e.preventDefault();
|
|
878
|
-
this.
|
|
1049
|
+
this.parentElement.remove('dragging');
|
|
879
1050
|
});
|
|
880
1051
|
code.addEventListener('drop', (e) => {
|
|
881
1052
|
e.preventDefault();
|
|
882
|
-
code.classList.remove('dragging');
|
|
1053
|
+
code.parentElement.classList.remove('dragging');
|
|
883
1054
|
for( let i = 0; i < e.dataTransfer.files.length; ++i )
|
|
884
1055
|
this.loadFile( e.dataTransfer.files[i] );
|
|
885
1056
|
});
|
|
1057
|
+
code.addEventListener('wheel', (e) => {
|
|
886
1058
|
|
|
887
|
-
|
|
888
|
-
this.gutter.scrollTop = code.scrollTop;
|
|
889
|
-
this.gutter.scrollLeft = code.scrollLeft;
|
|
1059
|
+
// Get scroll data
|
|
890
1060
|
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
cursor.style.top = (cursor._top - code.scrollTop) + "px";
|
|
894
|
-
cursor.style.left = "calc( " + (cursor._left - code.scrollLeft) + "px + " + this.xPadding + ")";
|
|
1061
|
+
const dX = (e.deltaY > 0.0 ? 1.0 : -1.0) * 20.0 * ( e.shiftKey ? 1.0 : 0.0 );
|
|
1062
|
+
const dY = (e.deltaY > 0.0 ? 1.0 : -1.0) * 40.0 * ( e.shiftKey ? 0.0 : 1.0 );
|
|
895
1063
|
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
1064
|
+
var new_scroll = code.customScroll.add( new LX.vec2( dX, dY ), new LX.vec2() );
|
|
1065
|
+
|
|
1066
|
+
// Update state
|
|
1067
|
+
|
|
1068
|
+
if( new_scroll.x != this.getScrollLeft()) this.setScrollLeft( new_scroll.x );
|
|
1069
|
+
if( new_scroll.y != this.getScrollTop()) this.setScrollTop( new_scroll.y );
|
|
901
1070
|
});
|
|
902
1071
|
|
|
903
1072
|
this.openedTabs[name] = code;
|
|
@@ -919,13 +1088,14 @@ class CodeEditor {
|
|
|
919
1088
|
this._refreshCodeInfo(cursor.line, cursor.position);
|
|
920
1089
|
|
|
921
1090
|
// Restore scroll
|
|
922
|
-
this.gutter.
|
|
923
|
-
this.gutter.
|
|
1091
|
+
this.gutter.scrollLeft = this.getScrollLeft();
|
|
1092
|
+
this.gutter.scrollTop = this.getScrollTop();
|
|
924
1093
|
}});
|
|
925
1094
|
|
|
926
1095
|
this.endSelection();
|
|
927
1096
|
|
|
928
|
-
if(selected)
|
|
1097
|
+
if( selected )
|
|
1098
|
+
{
|
|
929
1099
|
this.code = code;
|
|
930
1100
|
this.resetCursorPos(CodeEditor.CURSOR_LEFT | CodeEditor.CURSOR_TOP);
|
|
931
1101
|
this.processLines();
|
|
@@ -963,7 +1133,7 @@ class CodeEditor {
|
|
|
963
1133
|
|
|
964
1134
|
var cursor = this.cursors.children[0];
|
|
965
1135
|
var code_rect = this.code.getBoundingClientRect();
|
|
966
|
-
var mouse_pos = [(e.clientX - code_rect.x)
|
|
1136
|
+
var mouse_pos = [(e.clientX - code_rect.x), (e.clientY - code_rect.y)];
|
|
967
1137
|
|
|
968
1138
|
// Discard out of lines click...
|
|
969
1139
|
if( e.type != 'contextmenu' )
|
|
@@ -974,9 +1144,6 @@ class CodeEditor {
|
|
|
974
1144
|
|
|
975
1145
|
if( e.type == 'mousedown' )
|
|
976
1146
|
{
|
|
977
|
-
if( mouse_pos[0] > this.code.scrollWidth || mouse_pos[1] > this.code.scrollHeight )
|
|
978
|
-
return; // Scrollbar click
|
|
979
|
-
|
|
980
1147
|
// Left click only...
|
|
981
1148
|
if( e.button === 2 )
|
|
982
1149
|
{
|
|
@@ -1067,7 +1234,7 @@ class CodeEditor {
|
|
|
1067
1234
|
processClick(e, skip_refresh = false) {
|
|
1068
1235
|
|
|
1069
1236
|
var code_rect = this.code.getBoundingClientRect();
|
|
1070
|
-
var position = [(e.clientX - code_rect.x)
|
|
1237
|
+
var position = [(e.clientX - code_rect.x), (e.clientY - code_rect.y)];
|
|
1071
1238
|
var ln = (position[1] / this.lineHeight)|0;
|
|
1072
1239
|
|
|
1073
1240
|
if(this.code.lines[ln] == undefined) return;
|
|
@@ -1079,7 +1246,6 @@ class CodeEditor {
|
|
|
1079
1246
|
|
|
1080
1247
|
var ch = (position[0] / this.charWidth)|0;
|
|
1081
1248
|
var string = this.code.lines[ln].slice(0, ch);
|
|
1082
|
-
// this.cursorToString(cursor, string);
|
|
1083
1249
|
this.cursorToPosition(cursor, string.length);
|
|
1084
1250
|
|
|
1085
1251
|
this.hideAutoCompleteBox();
|
|
@@ -1115,7 +1281,7 @@ class CodeEditor {
|
|
|
1115
1281
|
if( deltaY >= 0 )
|
|
1116
1282
|
{
|
|
1117
1283
|
while( deltaY < (this.selections.childElementCount - 1) )
|
|
1118
|
-
this.selections.lastChild
|
|
1284
|
+
deleteElement( this.selections.lastChild );
|
|
1119
1285
|
|
|
1120
1286
|
for(let i = fromY; i <= toY; i++){
|
|
1121
1287
|
|
|
@@ -1158,7 +1324,7 @@ class CodeEditor {
|
|
|
1158
1324
|
else // Selection goes up...
|
|
1159
1325
|
{
|
|
1160
1326
|
while( Math.abs(deltaY) < (this.selections.childElementCount - 1) )
|
|
1161
|
-
this.selections.firstChild
|
|
1327
|
+
deleteElement( this.selections.firstChild );
|
|
1162
1328
|
|
|
1163
1329
|
for(let i = toY; i <= fromY; i++){
|
|
1164
1330
|
|
|
@@ -1470,216 +1636,299 @@ class CodeEditor {
|
|
|
1470
1636
|
}
|
|
1471
1637
|
}
|
|
1472
1638
|
|
|
1473
|
-
processLines(
|
|
1639
|
+
processLines( from__legacy ) {
|
|
1474
1640
|
|
|
1475
|
-
|
|
1641
|
+
const start = performance.now();
|
|
1642
|
+
|
|
1643
|
+
var gutter_html = "";
|
|
1644
|
+
var code_html = "";
|
|
1645
|
+
|
|
1646
|
+
this.resizeScrollBars();
|
|
1476
1647
|
|
|
1477
|
-
this.gutter.innerHTML = "";
|
|
1478
1648
|
this.code.innerHTML = "";
|
|
1649
|
+
this.gutter.innerHTML = "";
|
|
1479
1650
|
|
|
1480
|
-
|
|
1651
|
+
// Get info about lines in viewport
|
|
1652
|
+
const margin = 20;
|
|
1653
|
+
const firstLineInViewport = (this.getScrollTop() / this.lineHeight)|0;
|
|
1654
|
+
const totalLinesInViewport = ((this.code.parentElement.offsetHeight - 36) / this.lineHeight)|0;
|
|
1655
|
+
const viewportRange = new LX.vec2(
|
|
1656
|
+
Math.max( firstLineInViewport - margin, 0 ),
|
|
1657
|
+
Math.min( firstLineInViewport + totalLinesInViewport + margin, this.code.lines.length )
|
|
1658
|
+
);
|
|
1659
|
+
|
|
1660
|
+
for( let i = viewportRange.x; i < viewportRange.y; ++i )
|
|
1481
1661
|
{
|
|
1482
|
-
|
|
1662
|
+
gutter_html += "<span>" + (i + 1) + "</span>";
|
|
1663
|
+
code_html += this.processLine( i, true );
|
|
1483
1664
|
}
|
|
1484
1665
|
|
|
1485
|
-
|
|
1666
|
+
this.code.innerHTML = code_html;
|
|
1667
|
+
this.gutter.innerHTML = gutter_html;
|
|
1668
|
+
|
|
1669
|
+
console.log( "Num lines processed: " + (viewportRange.y - viewportRange.x), performance.now() - start );
|
|
1486
1670
|
}
|
|
1487
1671
|
|
|
1488
1672
|
processLine( linenum, force ) {
|
|
1489
1673
|
|
|
1490
|
-
//
|
|
1491
|
-
// {
|
|
1492
|
-
// this.processLines();
|
|
1493
|
-
// return;
|
|
1494
|
-
// }
|
|
1495
|
-
|
|
1496
|
-
delete this._building_string; // multi-line strings not supported by now
|
|
1674
|
+
delete this._buildingString; // multi-line strings not supported by now
|
|
1497
1675
|
|
|
1498
1676
|
// It's allowed to process only 1 line to optimize
|
|
1499
1677
|
let linestring = this.code.lines[ linenum ];
|
|
1500
1678
|
|
|
1501
|
-
|
|
1502
|
-
pre.dataset['linenum'] = linenum;
|
|
1503
|
-
|
|
1504
|
-
// Line gutter
|
|
1505
|
-
var linenumspan = document.createElement('span');
|
|
1506
|
-
linenumspan.innerHTML = (linenum + 1);
|
|
1507
|
-
|
|
1508
|
-
if( force )
|
|
1509
|
-
{
|
|
1510
|
-
this.gutter.appendChild(linenumspan);
|
|
1511
|
-
this.code.appendChild( pre );
|
|
1512
|
-
} else
|
|
1679
|
+
if( !force )
|
|
1513
1680
|
{
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1681
|
+
var pre = document.createElement('pre');
|
|
1682
|
+
|
|
1683
|
+
// Single code line
|
|
1684
|
+
deleteElement( this.code.childNodes[ linenum ] );
|
|
1517
1685
|
this.code.insertChildAtIndex( pre, linenum );
|
|
1686
|
+
|
|
1687
|
+
// Gutter
|
|
1688
|
+
deleteElement( this.gutter.childNodes[ linenum ] );
|
|
1689
|
+
var linenumspan = document.createElement('span');
|
|
1690
|
+
linenumspan.innerHTML = (linenum + 1);
|
|
1691
|
+
this.gutter.insertChildAtIndex( linenumspan, linenum );
|
|
1518
1692
|
}
|
|
1519
1693
|
|
|
1520
|
-
|
|
1521
|
-
pre.appendChild(linespan);
|
|
1694
|
+
const tokensToEvaluate = this._getTokensFromString( linestring );
|
|
1522
1695
|
|
|
1523
|
-
|
|
1696
|
+
if( !tokensToEvaluate.length )
|
|
1697
|
+
return "<pre></pre>";
|
|
1524
1698
|
|
|
1525
|
-
|
|
1699
|
+
var line_inner_html = "";
|
|
1526
1700
|
|
|
1527
1701
|
// Process all tokens
|
|
1528
|
-
for( var i = 0; i <
|
|
1702
|
+
for( var i = 0; i < tokensToEvaluate.length; ++i )
|
|
1529
1703
|
{
|
|
1530
1704
|
let it = i - 1;
|
|
1531
|
-
let prev =
|
|
1705
|
+
let prev = tokensToEvaluate[it];
|
|
1532
1706
|
while( prev == ' ' ) {
|
|
1533
1707
|
it--;
|
|
1534
|
-
prev =
|
|
1708
|
+
prev = tokensToEvaluate[it];
|
|
1535
1709
|
}
|
|
1536
1710
|
|
|
1537
1711
|
it = i + 1;
|
|
1538
|
-
let next =
|
|
1539
|
-
while( next == ' ' || next == '"') {
|
|
1712
|
+
let next = tokensToEvaluate[it];
|
|
1713
|
+
while( next == ' ' || next == '"' ) {
|
|
1540
1714
|
it++;
|
|
1541
|
-
next =
|
|
1715
|
+
next = tokensToEvaluate[it];
|
|
1542
1716
|
}
|
|
1543
1717
|
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1718
|
+
const token = tokensToEvaluate[i];
|
|
1719
|
+
|
|
1720
|
+
if( this.languages[ this.highlight ].blockComments ?? true )
|
|
1721
|
+
{
|
|
1722
|
+
if( token.substr(0, 2) == '/*' )
|
|
1723
|
+
this._buildingBlockComment = true;
|
|
1724
|
+
if( token.substr(token.length - 2) == '*/' )
|
|
1725
|
+
delete this._buildingBlockComment;
|
|
1726
|
+
}
|
|
1727
|
+
|
|
1728
|
+
line_inner_html += this.evaluateToken(token, prev, next);
|
|
1729
|
+
}
|
|
1730
|
+
|
|
1731
|
+
// Single line update
|
|
1732
|
+
if( !force )
|
|
1733
|
+
{
|
|
1734
|
+
this.code.childNodes[ linenum ].innerHTML = line_inner_html;
|
|
1735
|
+
}
|
|
1736
|
+
// Update all lines at once
|
|
1737
|
+
else
|
|
1738
|
+
{
|
|
1739
|
+
return "<pre>" + line_inner_html + "</pre>";
|
|
1740
|
+
}
|
|
1741
|
+
}
|
|
1742
|
+
|
|
1743
|
+
_processTokens( tokens, offset = 0 ) {
|
|
1744
|
+
|
|
1745
|
+
if( this.highlight == 'C++' )
|
|
1746
|
+
{
|
|
1747
|
+
var idx = tokens.slice(offset).findIndex( (value, index) => this.isNumber(value) );
|
|
1748
|
+
if( idx > -1 )
|
|
1749
|
+
{
|
|
1750
|
+
idx += offset; // Add offset to compute within the whole array of tokens
|
|
1751
|
+
let data = tokens[idx] + tokens[++idx];
|
|
1752
|
+
while( this.isNumber( data ) )
|
|
1753
|
+
{
|
|
1754
|
+
tokens[ idx - 1 ] += tokens[ idx ];
|
|
1755
|
+
tokens.splice( idx, 1 );
|
|
1756
|
+
data += tokens[idx];
|
|
1757
|
+
}
|
|
1758
|
+
// Scan for numbers again
|
|
1759
|
+
return this._processTokens( tokens, idx );
|
|
1760
|
+
}
|
|
1551
1761
|
}
|
|
1552
1762
|
|
|
1553
|
-
|
|
1763
|
+
return tokens;
|
|
1554
1764
|
}
|
|
1555
1765
|
|
|
1556
1766
|
_getTokensFromString( linestring, skipNonWords ) {
|
|
1557
1767
|
|
|
1558
1768
|
// Check if line comment
|
|
1559
|
-
const
|
|
1560
|
-
|
|
1769
|
+
const singleLineCommentToken = this.languages[ this.highlight ].singleLineCommentToken ?? this.defaultSingleLineCommentToken;
|
|
1770
|
+
const usesBlockComments = this.languages[ this.highlight ].blockComments ?? true;
|
|
1771
|
+
const has_comment = linestring.split(singleLineCommentToken);
|
|
1772
|
+
linestring = ( has_comment.length > 1 ) ? has_comment[0] : linestring;
|
|
1561
1773
|
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
for( let t of tokens )
|
|
1566
|
-
{
|
|
1567
|
-
if( !t.length || (skipNonWords && ( t.includes('"') || t.length < 3 )) )
|
|
1568
|
-
continue;
|
|
1774
|
+
// const tokens = linestring.split(' ').join('¬ ¬').split('¬'); // trick to split without losing spaces
|
|
1775
|
+
|
|
1776
|
+
let tokensToEvaluate = []; // store in a temp array so we know prev and next tokens...
|
|
1569
1777
|
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1778
|
+
const pushToken = function( t ) {
|
|
1779
|
+
if( (skipNonWords && ( t.includes('"') || t.length < 3 )) )
|
|
1780
|
+
return;
|
|
1781
|
+
tokensToEvaluate.push( t );
|
|
1782
|
+
};
|
|
1574
1783
|
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1784
|
+
let iter = linestring.matchAll(/(::|[\[\](){}<>.,;:*"'%@ ])/g);
|
|
1785
|
+
let subtokens = iter.next();
|
|
1786
|
+
if( subtokens.value )
|
|
1787
|
+
{
|
|
1788
|
+
let idx = 0;
|
|
1789
|
+
while( subtokens.value != undefined )
|
|
1578
1790
|
{
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
if(!subtokens.value) {
|
|
1588
|
-
const _at = t.substring(idx);
|
|
1589
|
-
if( _at.length ) to_process.push( _at );
|
|
1590
|
-
}
|
|
1791
|
+
const _pt = linestring.substring(idx, subtokens.value.index);
|
|
1792
|
+
if( _pt.length ) pushToken( _pt );
|
|
1793
|
+
pushToken( subtokens.value[0] );
|
|
1794
|
+
idx = subtokens.value.index + subtokens.value[0].length;
|
|
1795
|
+
subtokens = iter.next();
|
|
1796
|
+
if(!subtokens.value) {
|
|
1797
|
+
const _at = linestring.substring(idx);
|
|
1798
|
+
if( _at.length ) pushToken( _at );
|
|
1591
1799
|
}
|
|
1592
1800
|
}
|
|
1593
|
-
else to_process.push( t );
|
|
1594
1801
|
}
|
|
1802
|
+
else tokensToEvaluate.push( linestring );
|
|
1595
1803
|
|
|
1596
|
-
if(
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1804
|
+
// if( usesBlockComments )
|
|
1805
|
+
// {
|
|
1806
|
+
// var block = false;
|
|
1807
|
+
|
|
1808
|
+
// if( t.includes('/*') )
|
|
1809
|
+
// {
|
|
1810
|
+
// const idx = t.indexOf( '/*' );
|
|
1811
|
+
// tokensToEvaluate.push( t.substring( 0, idx ), '/*', t.substring( idx + 2 ) );
|
|
1812
|
+
// block |= true;
|
|
1813
|
+
// }
|
|
1814
|
+
// else if( t.includes('*/') )
|
|
1815
|
+
// {
|
|
1816
|
+
// const idx = t.indexOf( '*/' );
|
|
1817
|
+
// tokensToEvaluate.push( t.substring( 0, idx ), '*/', t.substring( idx + 2 ) );
|
|
1818
|
+
// block |= true;
|
|
1819
|
+
// }
|
|
1820
|
+
|
|
1821
|
+
// if( block ) continue;
|
|
1822
|
+
// }
|
|
1601
1823
|
|
|
1602
|
-
|
|
1824
|
+
if( has_comment.length > 1 && !skipNonWords )
|
|
1825
|
+
pushToken( singleLineCommentToken + has_comment[1] );
|
|
1603
1826
|
|
|
1604
|
-
|
|
1827
|
+
// console.log( tokensToEvaluate );
|
|
1828
|
+
|
|
1829
|
+
return this._processTokens( tokensToEvaluate );
|
|
1605
1830
|
}
|
|
1606
1831
|
|
|
1607
|
-
|
|
1832
|
+
_mustHightlightWord( token, kindArray ) {
|
|
1608
1833
|
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
let inner_html = "", token_classname = "";
|
|
1834
|
+
return kindArray[this.highlight] && kindArray[this.highlight][token] != undefined;
|
|
1835
|
+
}
|
|
1612
1836
|
|
|
1613
|
-
|
|
1614
|
-
{
|
|
1615
|
-
sString = (this._building_string == token); // stop string if i was building it
|
|
1616
|
-
this._building_string = this._building_string ? this._building_string : token;
|
|
1617
|
-
}
|
|
1837
|
+
evaluateToken( token, prev, next ) {
|
|
1618
1838
|
|
|
1619
1839
|
if(token == ' ')
|
|
1620
1840
|
{
|
|
1621
|
-
|
|
1841
|
+
return token;
|
|
1622
1842
|
}
|
|
1623
1843
|
else
|
|
1624
1844
|
{
|
|
1625
|
-
|
|
1626
|
-
|
|
1845
|
+
let stringEnded = false;
|
|
1846
|
+
let highlight = this.highlight.replace(/\s/g, '').replaceAll("+", "p").toLowerCase();
|
|
1847
|
+
|
|
1848
|
+
const singleLineCommentToken = this.languages[ this.highlight ].singleLineCommentToken ?? this.defaultSingleLineCommentToken;
|
|
1849
|
+
const usesBlockComments = this.languages[ this.highlight ].blockComments ?? true;
|
|
1850
|
+
const customStringKeys = Object.assign( {}, this.stringKeys );
|
|
1851
|
+
|
|
1852
|
+
if( highlight == 'cpp' && prev && prev.includes('#') ) // preprocessor code..
|
|
1853
|
+
{
|
|
1854
|
+
customStringKeys['@<'] = '>';
|
|
1855
|
+
}
|
|
1856
|
+
|
|
1857
|
+
// Manage strings
|
|
1858
|
+
if( this._buildingString != undefined )
|
|
1859
|
+
{
|
|
1860
|
+
const idx = Object.values(customStringKeys).indexOf( token );
|
|
1861
|
+
stringEnded = (idx > -1) && (idx == Object.values(customStringKeys).indexOf( customStringKeys[ '@' + this._buildingString ] ));
|
|
1862
|
+
}
|
|
1863
|
+
else if( customStringKeys[ '@' + token ] )
|
|
1864
|
+
{
|
|
1865
|
+
// Start new string
|
|
1866
|
+
this._buildingString = token;
|
|
1867
|
+
}
|
|
1868
|
+
|
|
1869
|
+
let token_classname = "";
|
|
1870
|
+
|
|
1871
|
+
if( this._buildingBlockComment != undefined )
|
|
1872
|
+
token_classname = "cm-com";
|
|
1627
1873
|
|
|
1628
|
-
else if( this.
|
|
1629
|
-
token_classname
|
|
1874
|
+
else if( this._buildingString != undefined )
|
|
1875
|
+
token_classname = "cm-str";
|
|
1630
1876
|
|
|
1631
1877
|
else if( this._mustHightlightWord( token, this.keywords ) )
|
|
1632
|
-
token_classname
|
|
1878
|
+
token_classname = "cm-kwd";
|
|
1633
1879
|
|
|
1634
1880
|
else if( this._mustHightlightWord( token, this.builtin ) )
|
|
1635
|
-
token_classname
|
|
1881
|
+
token_classname = "cm-bln";
|
|
1636
1882
|
|
|
1637
1883
|
else if( this._mustHightlightWord( token, this.statementsAndDeclarations ) )
|
|
1638
|
-
token_classname
|
|
1884
|
+
token_classname = "cm-std";
|
|
1639
1885
|
|
|
1640
1886
|
else if( this._mustHightlightWord( token, this.symbols ) )
|
|
1641
|
-
token_classname
|
|
1887
|
+
token_classname = "cm-sym";
|
|
1642
1888
|
|
|
1643
|
-
else if( token.substr(0, 2) ==
|
|
1644
|
-
token_classname
|
|
1889
|
+
else if( token.substr(0, 2) == singleLineCommentToken )
|
|
1890
|
+
token_classname = "cm-com";
|
|
1645
1891
|
|
|
1646
|
-
else if( token.substr(0, 2) == '/*' )
|
|
1647
|
-
token_classname
|
|
1892
|
+
else if( usesBlockComments && token.substr(0, 2) == '/*' )
|
|
1893
|
+
token_classname = "cm-com";
|
|
1648
1894
|
|
|
1649
|
-
else if( token.substr(token.length - 2) == '*/' )
|
|
1650
|
-
token_classname
|
|
1895
|
+
else if( usesBlockComments && token.substr(token.length - 2) == '*/' )
|
|
1896
|
+
token_classname = "cm-com";
|
|
1651
1897
|
|
|
1652
|
-
else if(
|
|
1653
|
-
token_classname
|
|
1898
|
+
else if( this.isNumber(token) || this.isNumber( token.replace(/[px]|[em]|%/g,'') ) )
|
|
1899
|
+
token_classname = "cm-dec";
|
|
1654
1900
|
|
|
1655
1901
|
else if( this.isCSSClass(token, prev, next) )
|
|
1656
|
-
token_classname
|
|
1902
|
+
token_classname = "cm-kwd";
|
|
1657
1903
|
|
|
1658
1904
|
else if ( this.isType(token, prev, next) )
|
|
1659
|
-
token_classname
|
|
1905
|
+
token_classname = "cm-typ";
|
|
1660
1906
|
|
|
1661
|
-
else if ( token
|
|
1662
|
-
token_classname
|
|
1907
|
+
else if ( highlight == 'batch' && (token == '@' || prev == ':' || prev == '@') )
|
|
1908
|
+
token_classname = "cm-kwd";
|
|
1663
1909
|
|
|
1664
1910
|
else if ( highlight == 'cpp' && token.includes('#') ) // C++ preprocessor
|
|
1665
|
-
token_classname
|
|
1911
|
+
token_classname = "cm-ppc";
|
|
1666
1912
|
|
|
1667
|
-
else if ( highlight == 'cpp' && prev
|
|
1668
|
-
token_classname
|
|
1913
|
+
else if ( highlight == 'cpp' && prev == '<' && (next == '>' || next == '*') ) // Defining template type in C++
|
|
1914
|
+
token_classname = "cm-typ";
|
|
1915
|
+
|
|
1916
|
+
else if ( highlight == 'cpp' && (next == '::' || prev == '::' && next != '(' )) // C++ Class
|
|
1917
|
+
token_classname = "cm-typ";
|
|
1669
1918
|
|
|
1670
1919
|
else if ( highlight == 'css' && prev == ':' && (next == ';' || next == '!important') ) // CSS value
|
|
1671
|
-
token_classname
|
|
1920
|
+
token_classname = "cm-str";
|
|
1672
1921
|
|
|
1673
1922
|
else if ( highlight == 'css' && prev == undefined && next == ':' ) // CSS attribute
|
|
1674
|
-
token_classname
|
|
1923
|
+
token_classname = "cm-typ";
|
|
1675
1924
|
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
}
|
|
1925
|
+
else if ( token[0] != '@' && next == '(' )
|
|
1926
|
+
token_classname = "cm-mtd";
|
|
1679
1927
|
|
|
1680
|
-
|
|
1928
|
+
this._buildingString = stringEnded ? undefined : this._buildingString;
|
|
1681
1929
|
|
|
1682
|
-
|
|
1930
|
+
return "<span class='" + highlight + " " + token_classname + "'>" + token + "</span>";
|
|
1931
|
+
}
|
|
1683
1932
|
}
|
|
1684
1933
|
|
|
1685
1934
|
isCSSClass( token, prev, next ) {
|
|
@@ -1687,7 +1936,16 @@ class CodeEditor {
|
|
|
1687
1936
|
}
|
|
1688
1937
|
|
|
1689
1938
|
isNumber( token ) {
|
|
1690
|
-
|
|
1939
|
+
|
|
1940
|
+
if(this.highlight == 'C++')
|
|
1941
|
+
{
|
|
1942
|
+
if( token.lastChar == 'f' )
|
|
1943
|
+
return this.isNumber( token.substring(0, token.length - 1) )
|
|
1944
|
+
else if( token.lastChar == 'u' )
|
|
1945
|
+
return !(token.includes('.')) && this.isNumber( token.substring(0, token.length - 1) );
|
|
1946
|
+
}
|
|
1947
|
+
|
|
1948
|
+
return token.length && token != ' ' && !Number.isNaN(+token);
|
|
1691
1949
|
}
|
|
1692
1950
|
|
|
1693
1951
|
isType( token, prev, next ) {
|
|
@@ -1700,9 +1958,13 @@ class CodeEditor {
|
|
|
1700
1958
|
{
|
|
1701
1959
|
return (prev == 'class' && next == '{') || (prev == 'new' && next == '(');
|
|
1702
1960
|
}
|
|
1961
|
+
else if( this.highlight == 'C++' )
|
|
1962
|
+
{
|
|
1963
|
+
return (prev == 'class' && next == '{') || (prev == 'struct' && next == '{');
|
|
1964
|
+
}
|
|
1703
1965
|
else if ( this.highlight == 'WGSL' )
|
|
1704
1966
|
{
|
|
1705
|
-
const is_kwd =
|
|
1967
|
+
const is_kwd = !this._mustHightlightWord( token, this.keywords );
|
|
1706
1968
|
return (prev == 'struct' && next == '{') ||
|
|
1707
1969
|
( is_kwd &&
|
|
1708
1970
|
( prev == ':' && next == ')' || prev == ':' && next == ',' || prev == '>' && next == '{'
|
|
@@ -1715,7 +1977,7 @@ class CodeEditor {
|
|
|
1715
1977
|
if( !this.selection || (this.selection.fromY != this.selection.toY) )
|
|
1716
1978
|
return false;
|
|
1717
1979
|
|
|
1718
|
-
|
|
1980
|
+
this.selection.invertIfNecessary();
|
|
1719
1981
|
|
|
1720
1982
|
// Insert first..
|
|
1721
1983
|
this.code.lines[lidx] = [
|
|
@@ -1851,9 +2113,9 @@ class CodeEditor {
|
|
|
1851
2113
|
// Add horizontal scroll
|
|
1852
2114
|
|
|
1853
2115
|
doAsync(() => {
|
|
1854
|
-
var last_char = ((this.code.
|
|
2116
|
+
var last_char = ((this.code.clientWidth) / this.charWidth)|0;
|
|
1855
2117
|
if( cursor.position >= last_char )
|
|
1856
|
-
this.
|
|
2118
|
+
this.setScrollLeft( this.getScrollLeft() + this.charWidth );
|
|
1857
2119
|
});
|
|
1858
2120
|
}
|
|
1859
2121
|
|
|
@@ -1869,10 +2131,12 @@ class CodeEditor {
|
|
|
1869
2131
|
this.restartBlink();
|
|
1870
2132
|
this._refreshCodeInfo( cursor.line, cursor.position );
|
|
1871
2133
|
|
|
2134
|
+
// Add horizontal scroll
|
|
2135
|
+
|
|
1872
2136
|
doAsync(() => {
|
|
1873
|
-
var first_char = (this.
|
|
2137
|
+
var first_char = (this.getScrollLeft() / this.charWidth)|0;
|
|
1874
2138
|
if( (cursor.position - 1) < first_char )
|
|
1875
|
-
this.
|
|
2139
|
+
this.setScrollLeft( this.getScrollLeft() - this.charWidth );
|
|
1876
2140
|
});
|
|
1877
2141
|
}
|
|
1878
2142
|
|
|
@@ -1890,9 +2154,9 @@ class CodeEditor {
|
|
|
1890
2154
|
this._refreshCodeInfo( cursor.line, cursor.position );
|
|
1891
2155
|
|
|
1892
2156
|
doAsync(() => {
|
|
1893
|
-
var first_line = (this.
|
|
2157
|
+
var first_line = (this.getScrollTop() / this.lineHeight)|0;
|
|
1894
2158
|
if( (cursor.line - 1) < first_line )
|
|
1895
|
-
this.
|
|
2159
|
+
this.setScrollTop( this.getScrollTop() - this.lineHeight );
|
|
1896
2160
|
});
|
|
1897
2161
|
}
|
|
1898
2162
|
|
|
@@ -1909,9 +2173,9 @@ class CodeEditor {
|
|
|
1909
2173
|
this._refreshCodeInfo( cursor.line, cursor.position );
|
|
1910
2174
|
|
|
1911
2175
|
doAsync(() => {
|
|
1912
|
-
var last_line = ((this.code.
|
|
2176
|
+
var last_line = ((this.code.parentElement.offsetHeight - 32) / this.lineHeight)|0;
|
|
1913
2177
|
if( cursor.line >= last_line )
|
|
1914
|
-
this.
|
|
2178
|
+
this.setScrollTop( this.getScrollTop() + this.lineHeight );
|
|
1915
2179
|
});
|
|
1916
2180
|
}
|
|
1917
2181
|
|
|
@@ -1998,13 +2262,148 @@ class CodeEditor {
|
|
|
1998
2262
|
getScrollLeft() {
|
|
1999
2263
|
|
|
2000
2264
|
if(!this.code) return 0;
|
|
2001
|
-
return this.code.
|
|
2265
|
+
return this.code.customScroll.x;
|
|
2002
2266
|
}
|
|
2003
2267
|
|
|
2004
2268
|
getScrollTop() {
|
|
2005
2269
|
|
|
2006
2270
|
if(!this.code) return 0;
|
|
2007
|
-
return this.code.
|
|
2271
|
+
return this.code.customScroll.y;
|
|
2272
|
+
}
|
|
2273
|
+
|
|
2274
|
+
setScrollLeft( value, keepScrollBar ) {
|
|
2275
|
+
|
|
2276
|
+
if(!this.code) return;
|
|
2277
|
+
|
|
2278
|
+
const realClientWidth = (this.code.clientWidth - this.code.customScroll.x);
|
|
2279
|
+
const maxWidth = Math.max( this.code.scrollWidth - realClientWidth, 0 );
|
|
2280
|
+
|
|
2281
|
+
value = LX.UTILS.clamp( value, 0, maxWidth );
|
|
2282
|
+
|
|
2283
|
+
this.code.style.marginLeft = (-value) + "px";
|
|
2284
|
+
|
|
2285
|
+
if( !keepScrollBar )
|
|
2286
|
+
{
|
|
2287
|
+
const scrollWidth = this.hScrollbarThumb.parentElement.offsetWidth;
|
|
2288
|
+
const scrollBarWidth = this.hScrollbarThumb.offsetWidth;
|
|
2289
|
+
this.setScrollBarValue( ( scrollWidth - scrollBarWidth ) * ( value / maxWidth ), 'horizontal' );
|
|
2290
|
+
}
|
|
2291
|
+
|
|
2292
|
+
// Update cursor
|
|
2293
|
+
var cursor = this.cursors.children[0];
|
|
2294
|
+
cursor.style.left = "calc( " + (cursor._left - value) + "px + " + this.xPadding + ")";
|
|
2295
|
+
|
|
2296
|
+
// Update selection
|
|
2297
|
+
for( let s of this.selections.childNodes ) {
|
|
2298
|
+
s.style.left = "calc( " + (s._left - value) + "px + " + this.xPadding + ")";
|
|
2299
|
+
}
|
|
2300
|
+
|
|
2301
|
+
this.code.customScroll.x = value;
|
|
2302
|
+
}
|
|
2303
|
+
|
|
2304
|
+
setScrollTop( value, keepScrollBar ) {
|
|
2305
|
+
|
|
2306
|
+
if(!this.code) return;
|
|
2307
|
+
|
|
2308
|
+
const realClientHeight = this.code.parentElement.offsetHeight - 36;
|
|
2309
|
+
const maxHeight = Math.max( this.code.scrollHeight - realClientHeight, 0 );
|
|
2310
|
+
|
|
2311
|
+
value = LX.UTILS.clamp( value, 0, maxHeight );
|
|
2312
|
+
|
|
2313
|
+
this.gutter.scrollTop = value;
|
|
2314
|
+
|
|
2315
|
+
this.code.style.marginTop = (-value) + "px";
|
|
2316
|
+
|
|
2317
|
+
if( !keepScrollBar )
|
|
2318
|
+
{
|
|
2319
|
+
const scrollHeight = this.scrollbarThumb.parentElement.offsetHeight;
|
|
2320
|
+
const scrollBarHeight = this.scrollbarThumb.offsetHeight;
|
|
2321
|
+
// this.setScrollBarValue( ( scrollHeight - scrollBarHeight ) * ( value / maxHeight ) )
|
|
2322
|
+
const firstLineInViewport = (this.getScrollTop() / this.lineHeight)|0;
|
|
2323
|
+
this.setScrollBarValue( ( scrollHeight - scrollBarHeight ) * ( firstLineInViewport / this.code.lines.length ) )
|
|
2324
|
+
}
|
|
2325
|
+
|
|
2326
|
+
// Update cursor
|
|
2327
|
+
var cursor = this.cursors.children[0];
|
|
2328
|
+
cursor.style.top = (cursor._top - value) + "px";
|
|
2329
|
+
|
|
2330
|
+
// Update selection
|
|
2331
|
+
for( let s of this.selections.childNodes ) {
|
|
2332
|
+
s.style.top = (s._top - value) + "px";
|
|
2333
|
+
}
|
|
2334
|
+
|
|
2335
|
+
this.code.customScroll.y = value;
|
|
2336
|
+
}
|
|
2337
|
+
|
|
2338
|
+
resizeScrollBars() {
|
|
2339
|
+
|
|
2340
|
+
const numViewportLines = Math.floor( (this.code.parentElement.offsetHeight - 36) / this.lineHeight );
|
|
2341
|
+
|
|
2342
|
+
if( numViewportLines > this.code.lines.length )
|
|
2343
|
+
{
|
|
2344
|
+
this.scrollbar.classList.add( 'scrollbar-unused' );
|
|
2345
|
+
this.tabs.area.root.classList.remove( 'with-vscrollbar' );
|
|
2346
|
+
}
|
|
2347
|
+
else
|
|
2348
|
+
{
|
|
2349
|
+
this.scrollbar.classList.remove( 'scrollbar-unused' );
|
|
2350
|
+
this.tabs.area.root.classList.add( 'with-vscrollbar' );
|
|
2351
|
+
this.scrollbarThumb.size = (numViewportLines / this.code.lines.length);
|
|
2352
|
+
this.scrollbarThumb.style.height = (this.scrollbarThumb.size * 100.0) + "%";
|
|
2353
|
+
}
|
|
2354
|
+
|
|
2355
|
+
const numViewportChars = Math.floor( this.code.clientWidth / this.charWidth );
|
|
2356
|
+
const line_lengths = this.code.lines.map( value => value.length );
|
|
2357
|
+
const maxLineLength = Math.max(...line_lengths);
|
|
2358
|
+
|
|
2359
|
+
if( numViewportChars > maxLineLength )
|
|
2360
|
+
{
|
|
2361
|
+
this.hScrollbar.classList.add( 'scrollbar-unused' );
|
|
2362
|
+
this.tabs.area.root.classList.remove( 'with-hscrollbar' );
|
|
2363
|
+
}
|
|
2364
|
+
else
|
|
2365
|
+
{
|
|
2366
|
+
this.hScrollbar.classList.remove( 'scrollbar-unused' );
|
|
2367
|
+
this.tabs.area.root.classList.add( 'with-hscrollbar' );
|
|
2368
|
+
this.hScrollbarThumb.size = (numViewportChars / maxLineLength);
|
|
2369
|
+
this.hScrollbarThumb.style.width = (this.hScrollbarThumb.size * 100.0) + "%";
|
|
2370
|
+
}
|
|
2371
|
+
}
|
|
2372
|
+
|
|
2373
|
+
setScrollBarValue( value, type = 'vertical' ) {
|
|
2374
|
+
|
|
2375
|
+
if( type == 'vertical' )
|
|
2376
|
+
{
|
|
2377
|
+
const scrollHeight = this.scrollbarThumb.parentElement.offsetHeight;
|
|
2378
|
+
const scrollBarHeight = this.scrollbarThumb.offsetHeight;
|
|
2379
|
+
|
|
2380
|
+
value = LX.UTILS.clamp( value, 0, ( scrollHeight - scrollBarHeight ) );
|
|
2381
|
+
|
|
2382
|
+
this.scrollbarThumb._top = value;
|
|
2383
|
+
this.scrollbarThumb.style.top = this.scrollbarThumb._top + "px";
|
|
2384
|
+
}
|
|
2385
|
+
else
|
|
2386
|
+
{
|
|
2387
|
+
const scrollWidth = this.hScrollbarThumb.parentElement.offsetWidth;
|
|
2388
|
+
const scrollBarWidth = this.hScrollbarThumb.offsetWidth;
|
|
2389
|
+
|
|
2390
|
+
value = LX.UTILS.clamp( value, 0, ( scrollWidth - scrollBarWidth ) );
|
|
2391
|
+
|
|
2392
|
+
this.hScrollbarThumb._left = value;
|
|
2393
|
+
this.hScrollbarThumb.style.left = this.hScrollbarThumb._left + "px";
|
|
2394
|
+
}
|
|
2395
|
+
}
|
|
2396
|
+
|
|
2397
|
+
applyHorizontalScrollFromScrollBar( value ) {
|
|
2398
|
+
|
|
2399
|
+
this.setScrollBarValue( value, 'horizontal');
|
|
2400
|
+
this.setScrollLeft( value / this.hScrollbarThumb.size, true );
|
|
2401
|
+
}
|
|
2402
|
+
|
|
2403
|
+
applyVerticalScrollFromScrollBar( value ) {
|
|
2404
|
+
|
|
2405
|
+
this.setScrollBarValue( value );
|
|
2406
|
+
this.setScrollTop( value / this.scrollbarThumb.size, true );
|
|
2008
2407
|
}
|
|
2009
2408
|
|
|
2010
2409
|
getCharAtPos( cursor, offset = 0 ) {
|
|
@@ -2020,7 +2419,7 @@ class CodeEditor {
|
|
|
2020
2419
|
const words = this.code.lines[col];
|
|
2021
2420
|
|
|
2022
2421
|
const is_char = (char) => {
|
|
2023
|
-
const exceptions = ['_'];
|
|
2422
|
+
const exceptions = ['_', '#', '!'];
|
|
2024
2423
|
const code = char.charCodeAt(0);
|
|
2025
2424
|
return (exceptions.indexOf(char) > - 1) || (code > 47 && code < 58) || (code > 64 && code < 91) || (code > 96 && code < 123);
|
|
2026
2425
|
}
|
|
@@ -2048,7 +2447,7 @@ class CodeEditor {
|
|
|
2048
2447
|
test.innerHTML = char;
|
|
2049
2448
|
document.body.appendChild(test);
|
|
2050
2449
|
var rect = test.getBoundingClientRect();
|
|
2051
|
-
test
|
|
2450
|
+
deleteElement( test );
|
|
2052
2451
|
const bb = [Math.floor(rect.width), Math.floor(rect.height)];
|
|
2053
2452
|
return get_bb ? bb : bb[0];
|
|
2054
2453
|
}
|
|
@@ -2059,6 +2458,7 @@ class CodeEditor {
|
|
|
2059
2458
|
}
|
|
2060
2459
|
|
|
2061
2460
|
runScript( code ) {
|
|
2461
|
+
|
|
2062
2462
|
var script = document.createElement('script');
|
|
2063
2463
|
script.type = 'module';
|
|
2064
2464
|
script.innerHTML = code;
|
|
@@ -2115,15 +2515,15 @@ class CodeEditor {
|
|
|
2115
2515
|
|
|
2116
2516
|
// Add language special keys...
|
|
2117
2517
|
suggestions = suggestions.concat(
|
|
2118
|
-
this.builtin[ this.highlight ] ?? [],
|
|
2119
|
-
this.keywords[ this.highlight ] ?? [],
|
|
2120
|
-
this.statementsAndDeclarations[ this.highlight ] ?? [],
|
|
2121
|
-
this.types[ this.highlight ] ?? [],
|
|
2122
|
-
this.utils[ this.highlight ] ?? []
|
|
2518
|
+
Object.keys( this.builtin[ this.highlight ] ) ?? [],
|
|
2519
|
+
Object.keys( this.keywords[ this.highlight ] ) ?? [],
|
|
2520
|
+
Object.keys( this.statementsAndDeclarations[ this.highlight ] ) ?? [],
|
|
2521
|
+
Object.keys( this.types[ this.highlight ] ) ?? [],
|
|
2522
|
+
Object.keys( this.utils[ this.highlight ] ) ?? []
|
|
2123
2523
|
);
|
|
2124
2524
|
|
|
2125
2525
|
// Add words in current tab plus remove current word
|
|
2126
|
-
suggestions = suggestions.concat( Object.keys(this.code.tokens).filter( a => a != word ) );
|
|
2526
|
+
// suggestions = suggestions.concat( Object.keys(this.code.tokens).filter( a => a != word ) );
|
|
2127
2527
|
|
|
2128
2528
|
// Remove 1/2 char words and duplicates...
|
|
2129
2529
|
suggestions = suggestions.filter( (value, index) => value.length > 2 && suggestions.indexOf(value) === index );
|
|
@@ -2183,9 +2583,8 @@ class CodeEditor {
|
|
|
2183
2583
|
// Show box
|
|
2184
2584
|
this.autocomplete.classList.toggle('show', true);
|
|
2185
2585
|
this.autocomplete.classList.toggle('no-scrollbar', !(this.autocomplete.scrollHeight > this.autocomplete.offsetHeight));
|
|
2186
|
-
this.autocomplete.style.left = (cursor._left + 36) + "px";
|
|
2187
|
-
this.autocomplete.style.top = (cursor._top + 48) + "px";
|
|
2188
|
-
|
|
2586
|
+
this.autocomplete.style.left = (cursor._left + 36 - this.getScrollLeft()) + "px";
|
|
2587
|
+
this.autocomplete.style.top = (cursor._top + 48 - this.getScrollTop()) + "px";
|
|
2189
2588
|
|
|
2190
2589
|
this.isAutoCompleteActive = true;
|
|
2191
2590
|
}
|