lexgui 0.1.18 → 0.1.20
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/README.md +10 -13
- package/build/components/codeeditor.js +652 -304
- package/build/lexgui.css +73 -19
- package/build/lexgui.js +118 -66
- package/build/lexgui.module.js +108 -57
- package/changelog.md +15 -0
- package/examples/code_editor.html +44 -29
- package/examples/index.html +1 -2
- package/package.json +2 -1
- package/examples/overlay_area.html +0 -61
- package/examples/previews/overlay_area.png +0 -0
|
@@ -30,7 +30,7 @@ function firstNonspaceIndex( str ) {
|
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
function deleteElement( el ) {
|
|
33
|
-
if(el) el.remove();
|
|
33
|
+
if( el ) el.remove();
|
|
34
34
|
}
|
|
35
35
|
|
|
36
36
|
let ASYNC_ENABLED = true;
|
|
@@ -59,11 +59,25 @@ class CodeSelection {
|
|
|
59
59
|
return this.fromY === this.toY;
|
|
60
60
|
}
|
|
61
61
|
|
|
62
|
+
samePosition() {
|
|
63
|
+
return this.fromX === this.toX;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
isEmpty() {
|
|
67
|
+
return this.sameLine() && this.samePosition();
|
|
68
|
+
}
|
|
69
|
+
|
|
62
70
|
invertIfNecessary() {
|
|
63
|
-
if(this.fromX > this.toX)
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
swapElements(this, '
|
|
71
|
+
// if( this.fromX > this.toX )
|
|
72
|
+
if( this.fromY > this.toY )
|
|
73
|
+
{
|
|
74
|
+
swapElements( this, 'fromX', 'toX' );
|
|
75
|
+
swapElements( this, 'fromY', 'toY' );
|
|
76
|
+
}
|
|
77
|
+
else if( this.sameLine() && this.fromX > this.toX )
|
|
78
|
+
{
|
|
79
|
+
swapElements( this, 'fromX', 'toX' );
|
|
80
|
+
}
|
|
67
81
|
}
|
|
68
82
|
|
|
69
83
|
selectInline( x, y, width ) {
|
|
@@ -82,6 +96,9 @@ class CodeSelection {
|
|
|
82
96
|
domEl.style.left = "calc(" + domEl._left + "px + " + this.editor.xPadding + ")";
|
|
83
97
|
domEl.style.width = width + "px";
|
|
84
98
|
this.editor.selections.appendChild(domEl);
|
|
99
|
+
|
|
100
|
+
// Hide active line background
|
|
101
|
+
this.editor.code.childNodes.forEach( e => e.classList.remove( 'active-line' ) );
|
|
85
102
|
}
|
|
86
103
|
};
|
|
87
104
|
|
|
@@ -154,6 +171,10 @@ class CodeEditor {
|
|
|
154
171
|
static CURSOR_LEFT = 1;
|
|
155
172
|
static CURSOR_TOP = 2;
|
|
156
173
|
|
|
174
|
+
static SELECTION_X = 1;
|
|
175
|
+
static SELECTION_Y = 2
|
|
176
|
+
static SELECTION_X_Y = CodeEditor.SELECTION_X | CodeEditor.SELECTION_Y;
|
|
177
|
+
|
|
157
178
|
static KEEP_VISIBLE_LINES = 1;
|
|
158
179
|
static UPDATE_VISIBLE_LINES = 2;
|
|
159
180
|
|
|
@@ -170,11 +191,74 @@ class CodeEditor {
|
|
|
170
191
|
window.editor = this;
|
|
171
192
|
|
|
172
193
|
CodeEditor.__instances.push( this );
|
|
194
|
+
|
|
195
|
+
// File explorer
|
|
196
|
+
if( options.file_explorer ?? false )
|
|
197
|
+
{
|
|
198
|
+
var [explorerArea, codeArea] = area.split({ sizes:["15%","85%"] });
|
|
199
|
+
explorerArea.setLimitBox( 180, 20, 512 );
|
|
200
|
+
this.explorerArea = explorerArea;
|
|
201
|
+
|
|
202
|
+
let panel = new LX.Panel();
|
|
203
|
+
|
|
204
|
+
panel.addTitle( "EXPLORER" );
|
|
205
|
+
|
|
206
|
+
let sceneData = {
|
|
207
|
+
'id': 'WORKSPACE',
|
|
208
|
+
'skipVisibility': true,
|
|
209
|
+
'children': []
|
|
210
|
+
};
|
|
211
|
+
|
|
212
|
+
this.explorer = panel.addTree( null, sceneData, {
|
|
213
|
+
filter: false,
|
|
214
|
+
rename: false,
|
|
215
|
+
skip_default_icon: true,
|
|
216
|
+
onevent: (event) => {
|
|
217
|
+
switch(event.type) {
|
|
218
|
+
// case LX.TreeEvent.NODE_SELECTED:
|
|
219
|
+
// if( !this.tabs.tabDOMs[ event.node.id ] ) break;
|
|
220
|
+
case LX.TreeEvent.NODE_DBLCLICKED:
|
|
221
|
+
this.loadTab( event.node.id );
|
|
222
|
+
break;
|
|
223
|
+
case LX.TreeEvent.NODE_DELETED:
|
|
224
|
+
this.tabs.delete( event.node.id );
|
|
225
|
+
delete this.loadedTabs[ event.node.id ];
|
|
226
|
+
break;
|
|
227
|
+
// case LX.TreeEvent.NODE_CONTEXTMENU:
|
|
228
|
+
// LX.addContextMenu( event.multiple ? "Selected Nodes" : event.node.id, event.value, m => {
|
|
229
|
+
//
|
|
230
|
+
// });
|
|
231
|
+
// break;
|
|
232
|
+
// case LX.TreeEvent.NODE_DRAGGED:
|
|
233
|
+
// console.log(event.node.id + " is now child of " + event.value.id);
|
|
234
|
+
// break;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
this.addExplorerItem = function( item )
|
|
240
|
+
{
|
|
241
|
+
if( !this.explorer.data.children.find( (value, index) => value.id === item.id ) )
|
|
242
|
+
this.explorer.data.children.push( item );
|
|
243
|
+
};
|
|
244
|
+
|
|
245
|
+
explorerArea.attach( panel );
|
|
246
|
+
|
|
247
|
+
// Update area
|
|
248
|
+
area = codeArea;
|
|
249
|
+
}
|
|
173
250
|
|
|
174
251
|
this.base_area = area;
|
|
175
252
|
this.area = new LX.Area( { className: "lexcodeeditor", height: "auto", no_append: true } );
|
|
176
253
|
|
|
177
|
-
this.tabs = this.area.addTabs( { onclose: (name) =>
|
|
254
|
+
this.tabs = this.area.addTabs( { onclose: (name) => {
|
|
255
|
+
delete this.openedTabs[ name ];
|
|
256
|
+
if( Object.keys( this.openedTabs ).length < 2 )
|
|
257
|
+
{
|
|
258
|
+
clearInterval( this.blinker );
|
|
259
|
+
this.cursors.classList.remove( 'show' );
|
|
260
|
+
}
|
|
261
|
+
} } );
|
|
178
262
|
this.tabs.root.addEventListener( 'dblclick', (e) => {
|
|
179
263
|
if( options.allow_add_scripts ?? true ) {
|
|
180
264
|
e.preventDefault();
|
|
@@ -208,6 +292,9 @@ class CodeEditor {
|
|
|
208
292
|
this.root.addEventListener( 'click', this.processMouse.bind(this) );
|
|
209
293
|
this.root.addEventListener( 'contextmenu', this.processMouse.bind(this) );
|
|
210
294
|
|
|
295
|
+
// Add mouseup event to document as well to detect when selections end
|
|
296
|
+
document.body.addEventListener( 'mouseup', this._onMouseUp.bind(this) );
|
|
297
|
+
|
|
211
298
|
// Cursors and selection
|
|
212
299
|
|
|
213
300
|
this.cursors = document.createElement( 'div' );
|
|
@@ -230,13 +317,32 @@ class CodeEditor {
|
|
|
230
317
|
cursor.style.left = this.xPadding;
|
|
231
318
|
cursor._top = 0;
|
|
232
319
|
cursor.style.top = cursor._top + "px";
|
|
233
|
-
cursor.
|
|
320
|
+
cursor._position = 0;
|
|
234
321
|
cursor._line = 0;
|
|
235
322
|
cursor.print = (function() { console.log( this.line, this.position ) }).bind( cursor );
|
|
236
323
|
|
|
324
|
+
Object.defineProperty( this, 'line', {
|
|
325
|
+
get: (v) => { return cursor.line }
|
|
326
|
+
} );
|
|
327
|
+
|
|
328
|
+
Object.defineProperty( this, 'position', {
|
|
329
|
+
get: (v) => { return cursor.position }
|
|
330
|
+
} );
|
|
331
|
+
|
|
237
332
|
Object.defineProperty( cursor, 'line', {
|
|
238
333
|
get: (v) => { return this._line },
|
|
239
|
-
set: (v) => {
|
|
334
|
+
set: (v) => {
|
|
335
|
+
this._line = v;
|
|
336
|
+
this._setActiveLine( v );
|
|
337
|
+
}
|
|
338
|
+
} );
|
|
339
|
+
|
|
340
|
+
Object.defineProperty( cursor, 'position', {
|
|
341
|
+
get: (v) => { return this._position },
|
|
342
|
+
set: (v) => {
|
|
343
|
+
this._position = v;
|
|
344
|
+
this._updateDataInfoPanel( "@cursor-pos", "Col " + v );
|
|
345
|
+
}
|
|
240
346
|
} );
|
|
241
347
|
|
|
242
348
|
this.cursors.appendChild( cursor );
|
|
@@ -337,14 +443,15 @@ class CodeEditor {
|
|
|
337
443
|
|
|
338
444
|
this.state = {
|
|
339
445
|
focused: false,
|
|
340
|
-
selectingText: false
|
|
446
|
+
selectingText: false,
|
|
447
|
+
activeLine: null
|
|
341
448
|
}
|
|
342
449
|
|
|
343
450
|
// Code
|
|
344
451
|
|
|
345
452
|
this.useAutoComplete = options.autocomplete ?? true;
|
|
346
453
|
this.highlight = options.highlight ?? 'Plain Text';
|
|
347
|
-
this.onsave = options.onsave ?? ((code) => {
|
|
454
|
+
this.onsave = options.onsave ?? ((code) => { console.log( code, "save" ) });
|
|
348
455
|
this.onrun = options.onrun ?? ((code) => { this.runScript(code) });
|
|
349
456
|
this.actions = {};
|
|
350
457
|
this.cursorBlinkRate = 550;
|
|
@@ -352,7 +459,7 @@ class CodeEditor {
|
|
|
352
459
|
this.maxUndoSteps = 16;
|
|
353
460
|
this.lineHeight = 20;
|
|
354
461
|
this.defaultSingleLineCommentToken = "//";
|
|
355
|
-
this.charWidth =
|
|
462
|
+
this.charWidth = 7; //this._measureChar();
|
|
356
463
|
this._lastTime = null;
|
|
357
464
|
|
|
358
465
|
this.pairKeys = {
|
|
@@ -372,17 +479,18 @@ class CodeEditor {
|
|
|
372
479
|
// setInterval( this.scanWordSuggestions.bind( this ), 2000 );
|
|
373
480
|
|
|
374
481
|
this.languages = {
|
|
375
|
-
'Plain Text': { },
|
|
376
|
-
'JavaScript': { },
|
|
377
|
-
'C++': { },
|
|
378
|
-
'CSS': { },
|
|
379
|
-
'GLSL': { },
|
|
380
|
-
'WGSL': { },
|
|
381
|
-
'JSON': { },
|
|
382
|
-
'XML': { },
|
|
383
|
-
'
|
|
384
|
-
'
|
|
385
|
-
'
|
|
482
|
+
'Plain Text': { ext: 'txt' },
|
|
483
|
+
'JavaScript': { ext: 'js' },
|
|
484
|
+
'C++': { ext: 'cpp' },
|
|
485
|
+
'CSS': { ext: 'css' },
|
|
486
|
+
'GLSL': { ext: 'glsl' },
|
|
487
|
+
'WGSL': { ext: 'wgsl' },
|
|
488
|
+
'JSON': { ext: 'json' },
|
|
489
|
+
'XML': { ext: 'xml' },
|
|
490
|
+
'Rust': { ext: 'rs' },
|
|
491
|
+
'Python': { ext: 'py', singleLineCommentToken: '#' },
|
|
492
|
+
'HTML': { ext: 'html' },
|
|
493
|
+
'Batch': { ext: 'bat', blockComments: false, singleLineCommentToken: '::' }
|
|
386
494
|
};
|
|
387
495
|
|
|
388
496
|
this.specialKeys = [
|
|
@@ -395,7 +503,7 @@ class CodeEditor {
|
|
|
395
503
|
'JavaScript': ['var', 'let', 'const', 'this', 'in', 'of', 'true', 'false', 'new', 'function', 'NaN', 'static', 'class', 'constructor', 'null', 'typeof', 'debugger', 'abstract',
|
|
396
504
|
'arguments', 'extends', 'instanceof'],
|
|
397
505
|
'C++': ['int', 'float', 'double', 'bool', 'char', 'wchar_t', 'const', 'static_cast', 'dynamic_cast', 'new', 'delete', 'void', 'true', 'false', 'auto', 'struct', 'typedef', 'nullptr',
|
|
398
|
-
'NULL', 'unsigned'],
|
|
506
|
+
'NULL', 'unsigned', 'namespace'],
|
|
399
507
|
'JSON': ['true', 'false'],
|
|
400
508
|
'GLSL': ['true', 'false', 'function', 'int', 'float', 'vec2', 'vec3', 'vec4', 'mat2x2', 'mat3x3', 'mat4x4', 'struct'],
|
|
401
509
|
'CSS': ['body', 'html', 'canvas', 'div', 'input', 'span', '.'],
|
|
@@ -403,6 +511,8 @@ class CodeEditor {
|
|
|
403
511
|
'sampler', 'sampler_comparison', 'texture_depth_2d', 'texture_depth_2d_array', 'texture_depth_cube', 'texture_depth_cube_array', 'texture_depth_multisampled_2d',
|
|
404
512
|
'texture_external', 'texture_1d', 'texture_2d', 'texture_2d_array', 'texture_3d', 'texture_cube', 'texture_cube_array', 'texture_storage_1d', 'texture_storage_2d',
|
|
405
513
|
'texture_storage_2d_array', 'texture_storage_3d'],
|
|
514
|
+
'Rust': ['as', 'const', 'crate', 'enum', 'extern', 'false', 'fn', 'impl', 'in', 'let', 'mod', 'move', 'mut', 'pub', 'ref', 'self', 'Self', 'static', 'struct', 'super', 'trait', 'true',
|
|
515
|
+
'type', 'unsafe', 'use', 'where', 'abstract', 'become', 'box', 'final', 'macro', 'override', 'priv', 'typeof', 'unsized', 'virtual'],
|
|
406
516
|
'Python': ['False', 'def', 'None', 'True', 'in', 'is', 'and', 'lambda', 'nonlocal', 'not', 'or'],
|
|
407
517
|
'Batch': ['set', 'SET', 'echo', 'ECHO', 'off', 'OFF', 'del', 'DEL', 'defined', 'DEFINED', 'setlocal', 'SETLOCAL', 'enabledelayedexpansion', 'ENABLEDELAYEDEXPANSION', 'driverquery',
|
|
408
518
|
'DRIVERQUERY', 'print', 'PRINT'],
|
|
@@ -420,6 +530,7 @@ class CodeEditor {
|
|
|
420
530
|
};
|
|
421
531
|
this.types = {
|
|
422
532
|
'JavaScript': ['Object', 'String', 'Function', 'Boolean', 'Symbol', 'Error', 'Number', 'TextEncoder', 'TextDecoder'],
|
|
533
|
+
'Rust': ['u128'],
|
|
423
534
|
'Python': ['int', 'type', 'float', 'map', 'list', 'ArithmeticError', 'AssertionError', 'AttributeError', 'Exception', 'EOFError', 'FloatingPointError', 'GeneratorExit',
|
|
424
535
|
'ImportError', 'IndentationError', 'IndexError', 'KeyError', 'KeyboardInterrupt', 'LookupError', 'MemoryError', 'NameError', 'NotImplementedError', 'OSError',
|
|
425
536
|
'OverflowError', 'ReferenceError', 'RuntimeError', 'StopIteration', 'SyntaxError', 'TabError', 'SystemError', 'SystemExit', 'TypeError', 'UnboundLocalError',
|
|
@@ -434,9 +545,10 @@ class CodeEditor {
|
|
|
434
545
|
};
|
|
435
546
|
this.statementsAndDeclarations = {
|
|
436
547
|
'JavaScript': ['for', 'if', 'else', 'case', 'switch', 'return', 'while', 'continue', 'break', 'do', 'import', 'from', 'throw', 'async', 'try', 'catch', 'await'],
|
|
437
|
-
'C++': ['std', 'for', 'if', 'else', 'return', 'continue', 'break', 'case', 'switch', 'while', 'glm', 'spdlog'],
|
|
548
|
+
'C++': ['std', 'for', 'if', 'else', 'return', 'continue', 'break', 'case', 'switch', 'while', 'using', 'glm', 'spdlog'],
|
|
438
549
|
'GLSL': ['for', 'if', 'else', 'return', 'continue', 'break'],
|
|
439
550
|
'WGSL': ['const','for', 'if', 'else', 'return', 'continue', 'break', 'storage', 'read', 'uniform'],
|
|
551
|
+
'Rust': ['break', 'else', 'continue', 'for', 'if', 'loop', 'match', 'return', 'while', 'do', 'yield'],
|
|
440
552
|
'Python': ['if', 'raise', 'del', 'import', 'return', 'elif', 'try', 'else', 'while', 'as', 'except', 'with', 'assert', 'finally', 'yield', 'break', 'for', 'class', 'continue',
|
|
441
553
|
'global', 'pass'],
|
|
442
554
|
'Batch': ['if', 'IF', 'for', 'FOR', 'in', 'IN', 'do', 'DO', 'call', 'CALL', 'goto', 'GOTO', 'exit', 'EXIT']
|
|
@@ -448,6 +560,7 @@ class CodeEditor {
|
|
|
448
560
|
'GLSL': ['[', ']', '{', '}', '(', ')'],
|
|
449
561
|
'WGSL': ['[', ']', '{', '}', '(', ')', '->'],
|
|
450
562
|
'CSS': ['{', '}', '(', ')', '*'],
|
|
563
|
+
'Rust': ['<', '>', '[', ']', '(', ')', '='],
|
|
451
564
|
'Python': ['<', '>', '[', ']', '(', ')', '='],
|
|
452
565
|
'Batch': ['[', ']', '(', ')', '%'],
|
|
453
566
|
'HTML': ['<', '>', '/']
|
|
@@ -475,7 +588,7 @@ class CodeEditor {
|
|
|
475
588
|
if( this.selection ) {
|
|
476
589
|
this.deleteSelection( cursor );
|
|
477
590
|
// Remove entire line when selecting with triple click
|
|
478
|
-
if(
|
|
591
|
+
if( this._tripleClickSelection )
|
|
479
592
|
{
|
|
480
593
|
this.actions['Backspace'].callback( ln, cursor, e );
|
|
481
594
|
this.lineDown( cursor, true );
|
|
@@ -547,7 +660,6 @@ class CodeEditor {
|
|
|
547
660
|
|
|
548
661
|
this.resetCursorPos( CodeEditor.CURSOR_LEFT );
|
|
549
662
|
if(idx > 0) this.cursorToString( cursor, prestring );
|
|
550
|
-
this._refreshCodeInfo( cursor.line, cursor.position );
|
|
551
663
|
this.setScrollLeft( 0 );
|
|
552
664
|
|
|
553
665
|
if( e.shiftKey && !e.cancelShift )
|
|
@@ -563,7 +675,7 @@ class CodeEditor {
|
|
|
563
675
|
this.selection.selectInline( idx, cursor.line, this.measureString( string ) );
|
|
564
676
|
else
|
|
565
677
|
{
|
|
566
|
-
this.processSelection();
|
|
678
|
+
this.processSelection( e );
|
|
567
679
|
}
|
|
568
680
|
} else if( !e.keepSelection )
|
|
569
681
|
this.endSelection();
|
|
@@ -571,7 +683,7 @@ class CodeEditor {
|
|
|
571
683
|
|
|
572
684
|
this.action( 'End', false, ( ln, cursor, e ) => {
|
|
573
685
|
|
|
574
|
-
if( e.shiftKey || e._shiftKey ) {
|
|
686
|
+
if( ( e.shiftKey || e._shiftKey ) && !e.cancelShift ) {
|
|
575
687
|
|
|
576
688
|
var string = this.code.lines[ ln ].substring( cursor.position );
|
|
577
689
|
if( !this.selection )
|
|
@@ -582,9 +694,9 @@ class CodeEditor {
|
|
|
582
694
|
{
|
|
583
695
|
this.resetCursorPos( CodeEditor.CURSOR_LEFT );
|
|
584
696
|
this.cursorToString( cursor, this.code.lines[ ln ] );
|
|
585
|
-
this.processSelection();
|
|
697
|
+
this.processSelection( e );
|
|
586
698
|
}
|
|
587
|
-
} else
|
|
699
|
+
} else if( !e.keepSelection )
|
|
588
700
|
this.endSelection();
|
|
589
701
|
|
|
590
702
|
this.resetCursorPos( CodeEditor.CURSOR_LEFT );
|
|
@@ -643,16 +755,14 @@ class CodeEditor {
|
|
|
643
755
|
if( !this.selection )
|
|
644
756
|
this.startSelection( cursor );
|
|
645
757
|
|
|
646
|
-
this.
|
|
647
|
-
this.cursorToLine( cursor, this.selection.toY );
|
|
758
|
+
this.lineUp();
|
|
648
759
|
|
|
649
760
|
var letter = this.getCharAtPos( cursor );
|
|
650
761
|
if( !letter ) {
|
|
651
|
-
this.
|
|
652
|
-
this.cursorToPosition( cursor, this.selection.toX );
|
|
762
|
+
this.cursorToPosition( cursor, this.code.lines[ cursor.line ].length );
|
|
653
763
|
}
|
|
654
764
|
|
|
655
|
-
this.processSelection(
|
|
765
|
+
this.processSelection( e, false );
|
|
656
766
|
|
|
657
767
|
} else {
|
|
658
768
|
this.endSelection();
|
|
@@ -665,7 +775,7 @@ class CodeEditor {
|
|
|
665
775
|
// Move up autocomplete selection
|
|
666
776
|
else
|
|
667
777
|
{
|
|
668
|
-
this.
|
|
778
|
+
this._moveArrowSelectedAutoComplete('up');
|
|
669
779
|
}
|
|
670
780
|
});
|
|
671
781
|
|
|
@@ -678,16 +788,14 @@ class CodeEditor {
|
|
|
678
788
|
if( !this.selection )
|
|
679
789
|
this.startSelection( cursor );
|
|
680
790
|
|
|
681
|
-
this.
|
|
682
|
-
this.cursorToLine( cursor, this.selection.toY );
|
|
791
|
+
this.lineDown( cursor );
|
|
683
792
|
|
|
684
793
|
var letter = this.getCharAtPos( cursor );
|
|
685
794
|
if( !letter ) {
|
|
686
|
-
this.
|
|
687
|
-
this.cursorToPosition(cursor, this.selection.toX);
|
|
795
|
+
this.cursorToPosition( cursor, Math.max(this.code.lines[ cursor.line ].length - 1, 0) );
|
|
688
796
|
}
|
|
689
797
|
|
|
690
|
-
this.processSelection(
|
|
798
|
+
this.processSelection( e );
|
|
691
799
|
} else {
|
|
692
800
|
|
|
693
801
|
if( this.code.lines[ ln + 1 ] == undefined )
|
|
@@ -702,12 +810,16 @@ class CodeEditor {
|
|
|
702
810
|
// Move down autocomplete selection
|
|
703
811
|
else
|
|
704
812
|
{
|
|
705
|
-
this.
|
|
813
|
+
this._moveArrowSelectedAutoComplete('down');
|
|
706
814
|
}
|
|
707
815
|
});
|
|
708
816
|
|
|
709
817
|
this.action( 'ArrowLeft', false, ( ln, cursor, e ) => {
|
|
710
818
|
|
|
819
|
+
// Nothing to do..
|
|
820
|
+
if( cursor.line == 0 && cursor.position == 0 )
|
|
821
|
+
return;
|
|
822
|
+
|
|
711
823
|
if( e.metaKey ) { // Apple devices (Command)
|
|
712
824
|
e.preventDefault();
|
|
713
825
|
this.actions[ 'Home' ].callback( ln, cursor, e );
|
|
@@ -715,29 +827,29 @@ class CodeEditor {
|
|
|
715
827
|
else if( e.ctrlKey ) {
|
|
716
828
|
// Get next word
|
|
717
829
|
const [word, from, to] = this.getWordAtPos( cursor, -1 );
|
|
718
|
-
|
|
719
|
-
|
|
830
|
+
// If no length, we change line..
|
|
831
|
+
if( !word.length && this.lineUp( cursor, true ) ) {
|
|
832
|
+
e.cancelShift = true;
|
|
833
|
+
e.keepSelection = true;
|
|
834
|
+
this.actions[ 'End' ].callback( cursor.line, cursor, e );
|
|
835
|
+
delete e.cancelShift;
|
|
836
|
+
delete e.keepSelection;
|
|
837
|
+
}
|
|
838
|
+
var diff = Math.max( cursor.position - from, 1 );
|
|
839
|
+
var substr = word.substr( 0, diff );
|
|
720
840
|
// Selections...
|
|
721
841
|
if( e.shiftKey ) { if( !this.selection ) this.startSelection( cursor ); }
|
|
722
842
|
else this.endSelection();
|
|
723
|
-
this.cursorToString(cursor, substr, true);
|
|
724
|
-
if( e.shiftKey ) this.processSelection();
|
|
843
|
+
this.cursorToString( cursor, substr, true );
|
|
844
|
+
if( e.shiftKey ) this.processSelection( e, false, true );
|
|
725
845
|
}
|
|
726
846
|
else {
|
|
727
847
|
var letter = this.getCharAtPos( cursor, -1 );
|
|
728
848
|
if( letter ) {
|
|
729
849
|
if( e.shiftKey ) {
|
|
730
850
|
if( !this.selection ) this.startSelection( cursor );
|
|
731
|
-
if( ( ( cursor.position - 1 ) < this.selection.fromX ) && this.selection.sameLine() )
|
|
732
|
-
this.selection.fromX--;
|
|
733
|
-
else if( ( cursor.position - 1 ) == this.selection.fromX && this.selection.sameLine() ) {
|
|
734
|
-
this.cursorToLeft( letter, cursor );
|
|
735
|
-
this.endSelection();
|
|
736
|
-
return;
|
|
737
|
-
}
|
|
738
|
-
else this.selection.toX--;
|
|
739
851
|
this.cursorToLeft( letter, cursor );
|
|
740
|
-
this.processSelection(
|
|
852
|
+
this.processSelection( e, false, CodeEditor.SELECTION_X );
|
|
741
853
|
}
|
|
742
854
|
else {
|
|
743
855
|
if( !this.selection ) {
|
|
@@ -756,55 +868,48 @@ class CodeEditor {
|
|
|
756
868
|
}
|
|
757
869
|
else if( cursor.line > 0 ) {
|
|
758
870
|
|
|
759
|
-
if( e.shiftKey )
|
|
760
|
-
if( !this.selection ) this.startSelection( cursor );
|
|
761
|
-
}
|
|
871
|
+
if( e.shiftKey && !this.selection ) this.startSelection( cursor );
|
|
762
872
|
|
|
763
873
|
this.lineUp( cursor );
|
|
874
|
+
|
|
875
|
+
e.cancelShift = e.keepSelection = true;
|
|
764
876
|
this.actions[ 'End' ].callback( cursor.line, cursor, e );
|
|
877
|
+
delete e.cancelShift; delete e.keepSelection;
|
|
765
878
|
|
|
766
|
-
if( e.shiftKey )
|
|
767
|
-
this.selection.toX = cursor.position;
|
|
768
|
-
this.selection.toY--;
|
|
769
|
-
this.processSelection( null, true );
|
|
770
|
-
}
|
|
879
|
+
if( e.shiftKey ) this.processSelection( e, false );
|
|
771
880
|
}
|
|
772
881
|
}
|
|
773
882
|
});
|
|
774
883
|
|
|
775
884
|
this.action( 'ArrowRight', false, ( ln, cursor, e ) => {
|
|
776
885
|
|
|
886
|
+
// Nothing to do..
|
|
887
|
+
if( cursor.line == this.code.lines.length - 1 &&
|
|
888
|
+
cursor.position == this.code.lines[ cursor.line - 1 ].length )
|
|
889
|
+
return;
|
|
890
|
+
|
|
777
891
|
if( e.metaKey ) { // Apple devices (Command)
|
|
778
892
|
e.preventDefault();
|
|
779
893
|
this.actions[ 'End' ].callback( ln, cursor );
|
|
780
894
|
} else if( e.ctrlKey ) {
|
|
781
895
|
// Get next word
|
|
782
896
|
const [ word, from, to ] = this.getWordAtPos( cursor );
|
|
897
|
+
// If no length, we change line..
|
|
898
|
+
if( !word.length ) this.lineDown( cursor, true );
|
|
783
899
|
var diff = cursor.position - from;
|
|
784
900
|
var substr = word.substr( diff );
|
|
785
901
|
// Selections...
|
|
786
902
|
if( e.shiftKey ) { if( !this.selection ) this.startSelection( cursor ); }
|
|
787
903
|
else this.endSelection();
|
|
788
904
|
this.cursorToString( cursor, substr);
|
|
789
|
-
if( e.shiftKey ) this.processSelection();
|
|
905
|
+
if( e.shiftKey ) this.processSelection( e );
|
|
790
906
|
} else {
|
|
791
907
|
var letter = this.getCharAtPos( cursor );
|
|
792
908
|
if( letter ) {
|
|
793
909
|
if( e.shiftKey ) {
|
|
794
910
|
if( !this.selection ) this.startSelection( cursor );
|
|
795
|
-
var keep_range = false;
|
|
796
|
-
if( cursor.position == this.selection.fromX ) {
|
|
797
|
-
if( ( cursor.position + 1 ) == this.selection.toX && this.selection.sameLine() ) {
|
|
798
|
-
this.cursorToRight( letter, cursor );
|
|
799
|
-
this.endSelection();
|
|
800
|
-
return;
|
|
801
|
-
} else if( cursor.position < this.selection.toX ) {
|
|
802
|
-
this.selection.fromX++;
|
|
803
|
-
keep_range = true;
|
|
804
|
-
} else this.selection.toX++;
|
|
805
|
-
}
|
|
806
911
|
this.cursorToRight( letter, cursor );
|
|
807
|
-
this.processSelection(
|
|
912
|
+
this.processSelection( e, false, CodeEditor.SELECTION_X );
|
|
808
913
|
}else{
|
|
809
914
|
if( !this.selection ) {
|
|
810
915
|
this.cursorToRight( letter, cursor );
|
|
@@ -825,18 +930,11 @@ class CodeEditor {
|
|
|
825
930
|
|
|
826
931
|
if( e.shiftKey ) {
|
|
827
932
|
if( !this.selection ) this.startSelection( cursor );
|
|
828
|
-
e.cancelShift = true;
|
|
829
|
-
e.keepSelection = true;
|
|
830
933
|
}
|
|
831
934
|
|
|
832
|
-
this.lineDown( cursor );
|
|
833
|
-
this.actions['Home'].callback( cursor.line, cursor, e );
|
|
935
|
+
this.lineDown( cursor, true );
|
|
834
936
|
|
|
835
|
-
if( e.shiftKey )
|
|
836
|
-
this.selection.toX = cursor.position;
|
|
837
|
-
this.selection.toY++;
|
|
838
|
-
this.processSelection( null, true );
|
|
839
|
-
}
|
|
937
|
+
if( e.shiftKey ) this.processSelection( e, false );
|
|
840
938
|
|
|
841
939
|
this.hideAutoCompleteBox();
|
|
842
940
|
}
|
|
@@ -845,6 +943,7 @@ class CodeEditor {
|
|
|
845
943
|
|
|
846
944
|
// Default code tab
|
|
847
945
|
|
|
946
|
+
this.loadedTabs = { };
|
|
848
947
|
this.openedTabs = { };
|
|
849
948
|
|
|
850
949
|
if( options.allow_add_scripts ?? true )
|
|
@@ -855,6 +954,28 @@ class CodeEditor {
|
|
|
855
954
|
// Create inspector panel
|
|
856
955
|
let panel = this._createPanelInfo();
|
|
857
956
|
if( panel ) area.attach( panel );
|
|
957
|
+
|
|
958
|
+
const fontUrl = "https://raw.githubusercontent.com/jxarco/lexgui.js/master/" + "/data/CommitMono-400-Regular.otf";
|
|
959
|
+
const commitMono = new FontFace(
|
|
960
|
+
"CommitMono",
|
|
961
|
+
`url(${ fontUrl })`,
|
|
962
|
+
{
|
|
963
|
+
style: "normal",
|
|
964
|
+
weight: "400",
|
|
965
|
+
display: "swap"
|
|
966
|
+
}
|
|
967
|
+
);
|
|
968
|
+
|
|
969
|
+
// Add to the document.fonts (FontFaceSet)
|
|
970
|
+
document.fonts.add(commitMono);
|
|
971
|
+
|
|
972
|
+
// Load the font
|
|
973
|
+
commitMono.load();
|
|
974
|
+
|
|
975
|
+
// Wait until the fonts are all loaded
|
|
976
|
+
document.fonts.ready.then(() => {
|
|
977
|
+
console.log("commitMono loaded")
|
|
978
|
+
});
|
|
858
979
|
}
|
|
859
980
|
|
|
860
981
|
static getInstances()
|
|
@@ -862,6 +983,26 @@ class CodeEditor {
|
|
|
862
983
|
return CodeEditor.__instances;
|
|
863
984
|
}
|
|
864
985
|
|
|
986
|
+
// This received key inputs from the entire document...
|
|
987
|
+
onKeyPressed( e ) {
|
|
988
|
+
|
|
989
|
+
// Toggle visibility of the file explorer
|
|
990
|
+
if( e.key == 'b' && e.ctrlKey && this.explorer )
|
|
991
|
+
{
|
|
992
|
+
this.explorerArea.root.classList.toggle( "hidden" );
|
|
993
|
+
if( this._lastBaseareaWidth )
|
|
994
|
+
{
|
|
995
|
+
this.base_area.root.style.width = this._lastBaseareaWidth;
|
|
996
|
+
delete this._lastBaseareaWidth;
|
|
997
|
+
|
|
998
|
+
} else
|
|
999
|
+
{
|
|
1000
|
+
this._lastBaseareaWidth = this.base_area.root.style.width;
|
|
1001
|
+
this.base_area.root.style.width = "100%";
|
|
1002
|
+
}
|
|
1003
|
+
}
|
|
1004
|
+
}
|
|
1005
|
+
|
|
865
1006
|
getText( min ) {
|
|
866
1007
|
return this.code.lines.join(min ? ' ' : '\n');
|
|
867
1008
|
}
|
|
@@ -951,11 +1092,22 @@ class CodeEditor {
|
|
|
951
1092
|
loadFile( file ) {
|
|
952
1093
|
|
|
953
1094
|
const inner_add_tab = ( text, name, title ) => {
|
|
954
|
-
|
|
955
|
-
|
|
1095
|
+
|
|
1096
|
+
// Set current text and language
|
|
1097
|
+
const lines = text.replaceAll( '\r', '' ).split( '\n' );
|
|
1098
|
+
|
|
1099
|
+
// Add item in the explorer if used
|
|
1100
|
+
if( this.explorer )
|
|
1101
|
+
{
|
|
1102
|
+
this._storedLines = this._storedLines ?? {};
|
|
1103
|
+
this._storedLines[ name ] = lines;
|
|
1104
|
+
this.addExplorerItem( { 'id': name, 'skipVisibility': true, 'icon': this._getFileIcon( name ) } );
|
|
1105
|
+
this.explorer.frefresh( name );
|
|
1106
|
+
}
|
|
1107
|
+
else
|
|
956
1108
|
{
|
|
957
|
-
|
|
958
|
-
this.code.lines =
|
|
1109
|
+
this.addTab(name, true, title);
|
|
1110
|
+
this.code.lines = lines;
|
|
959
1111
|
this._changeLanguageFromExtension( LX.getExtension( name ) );
|
|
960
1112
|
}
|
|
961
1113
|
};
|
|
@@ -1011,8 +1163,37 @@ class CodeEditor {
|
|
|
1011
1163
|
|
|
1012
1164
|
this.code.language = lang;
|
|
1013
1165
|
this.highlight = lang;
|
|
1014
|
-
this.
|
|
1166
|
+
this._updateDataInfoPanel( "@highlight", lang );
|
|
1015
1167
|
this.processLines();
|
|
1168
|
+
|
|
1169
|
+
const ext = this.languages[ lang ].ext;
|
|
1170
|
+
const icon = this._getFileIcon( null, ext );
|
|
1171
|
+
|
|
1172
|
+
// Update tab icon
|
|
1173
|
+
{
|
|
1174
|
+
const tab = this.tabs.tabDOMs[ this.code.tabName ];
|
|
1175
|
+
tab.firstChild.remove();
|
|
1176
|
+
console.assert( tab != undefined );
|
|
1177
|
+
var iconEl;
|
|
1178
|
+
if( icon.includes( 'fa-' ) )
|
|
1179
|
+
{
|
|
1180
|
+
iconEl = document.createElement( 'i' );
|
|
1181
|
+
iconEl.className = icon;
|
|
1182
|
+
} else {
|
|
1183
|
+
iconEl = document.createElement( 'img' );
|
|
1184
|
+
iconEl.src = "https://raw.githubusercontent.com/jxarco/lexgui.js/master/" + icon;
|
|
1185
|
+
}
|
|
1186
|
+
tab.prepend( iconEl );
|
|
1187
|
+
}
|
|
1188
|
+
|
|
1189
|
+
// Update explorer icon
|
|
1190
|
+
if( this.explorer )
|
|
1191
|
+
{
|
|
1192
|
+
const item = this.explorer.data.children.filter( (v) => v.id === this.code.tabName )[ 0 ];
|
|
1193
|
+
console.assert( item != undefined );
|
|
1194
|
+
item.icon = icon;
|
|
1195
|
+
this.explorer.frefresh( this.code.tabName );
|
|
1196
|
+
}
|
|
1016
1197
|
}
|
|
1017
1198
|
|
|
1018
1199
|
_changeLanguageFromExtension( ext ) {
|
|
@@ -1020,23 +1201,13 @@ class CodeEditor {
|
|
|
1020
1201
|
if( !ext )
|
|
1021
1202
|
return this._changeLanguage( this.code.language );
|
|
1022
1203
|
|
|
1023
|
-
|
|
1204
|
+
for( let l in this.languages )
|
|
1024
1205
|
{
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
case 'h': return this._changeLanguage( 'C++' );
|
|
1028
|
-
case 'glsl': return this._changeLanguage( 'GLSL' );
|
|
1029
|
-
case 'css': return this._changeLanguage( 'CSS' );
|
|
1030
|
-
case 'json': return this._changeLanguage( 'JSON' );
|
|
1031
|
-
case 'xml': return this._changeLanguage( 'XML' );
|
|
1032
|
-
case 'wgsl': return this._changeLanguage( 'WGSL' );
|
|
1033
|
-
case 'py': return this._changeLanguage( 'Python' );
|
|
1034
|
-
case 'bat': return this._changeLanguage( 'Batch' );
|
|
1035
|
-
case 'html': return this._changeLanguage( 'HTML' );
|
|
1036
|
-
case 'txt':
|
|
1037
|
-
default:
|
|
1038
|
-
this._changeLanguage( 'Plain Text' );
|
|
1206
|
+
if( this.languages[l].ext == ext )
|
|
1207
|
+
return this._changeLanguage( l );
|
|
1039
1208
|
}
|
|
1209
|
+
|
|
1210
|
+
this._changeLanguage( 'Plain Text' );
|
|
1040
1211
|
}
|
|
1041
1212
|
|
|
1042
1213
|
_createPanelInfo() {
|
|
@@ -1044,34 +1215,23 @@ class CodeEditor {
|
|
|
1044
1215
|
if( !this.skipCodeInfo )
|
|
1045
1216
|
{
|
|
1046
1217
|
let panel = new LX.Panel({ className: "lexcodetabinfo", width: "calc(100%)", height: "auto" });
|
|
1047
|
-
panel.ln = 0;
|
|
1048
|
-
panel.col = 0;
|
|
1049
|
-
|
|
1050
|
-
this._refreshCodeInfo = ( ln = panel.ln, col = panel.col ) => {
|
|
1051
|
-
panel.ln = ln + 1;
|
|
1052
|
-
panel.col = col + 1;
|
|
1053
|
-
panel.clear();
|
|
1054
|
-
panel.sameLine();
|
|
1055
|
-
panel.addLabel( this.code.title, { float: 'right' });
|
|
1056
|
-
panel.addLabel( "Ln " + panel.ln, { width: "64px" });
|
|
1057
|
-
panel.addLabel( "Col " + panel.col, { width: "64px" });
|
|
1058
|
-
panel.addButton( "<b>{ }</b>", this.highlight, ( value, event ) => {
|
|
1059
|
-
LX.addContextMenu( "Language", event, m => {
|
|
1060
|
-
for( const lang of Object.keys(this.languages) )
|
|
1061
|
-
m.add( lang, this._changeLanguage.bind(this) );
|
|
1062
|
-
});
|
|
1063
|
-
}, { width: "25%", nameWidth: "15%" });
|
|
1064
|
-
panel.endLine();
|
|
1065
|
-
};
|
|
1066
1218
|
|
|
1067
|
-
|
|
1219
|
+
panel.sameLine();
|
|
1220
|
+
panel.addLabel( this.code.title, { float: 'right', signal: "@tab-name" });
|
|
1221
|
+
panel.addLabel( "Ln " + 1, { width: "64px", signal: "@cursor-line" });
|
|
1222
|
+
panel.addLabel( "Col " + 1, { width: "64px", signal: "@cursor-pos" });
|
|
1223
|
+
panel.addButton( "<b>{ }</b>", this.highlight, ( value, event ) => {
|
|
1224
|
+
LX.addContextMenu( "Language", event, m => {
|
|
1225
|
+
for( const lang of Object.keys(this.languages) )
|
|
1226
|
+
m.add( lang, this._changeLanguage.bind(this) );
|
|
1227
|
+
});
|
|
1228
|
+
}, { width: "25%", nameWidth: "15%", signal: "@highlight" });
|
|
1229
|
+
panel.endLine();
|
|
1068
1230
|
|
|
1069
1231
|
return panel;
|
|
1070
1232
|
}
|
|
1071
1233
|
else
|
|
1072
1234
|
{
|
|
1073
|
-
this._refreshCodeInfo = () => {};
|
|
1074
|
-
|
|
1075
1235
|
doAsync( () => {
|
|
1076
1236
|
|
|
1077
1237
|
// Change css a little bit...
|
|
@@ -1083,24 +1243,72 @@ class CodeEditor {
|
|
|
1083
1243
|
}
|
|
1084
1244
|
}
|
|
1085
1245
|
|
|
1246
|
+
_getFileIcon( name, extension ) {
|
|
1247
|
+
|
|
1248
|
+
const isNewTabButton = name ? ( name === '+' ) : false;
|
|
1249
|
+
const ext = extension ?? LX.getExtension( name );
|
|
1250
|
+
return ext == 'html' ? "fa-solid fa-code orange" :
|
|
1251
|
+
ext == 'css' ? "fa-solid fa-hashtag dodgerblue" :
|
|
1252
|
+
ext == 'xml' ? "fa-solid fa-rss orange" :
|
|
1253
|
+
ext == 'bat' ? "fa-brands fa-windows lightblue" :
|
|
1254
|
+
[ 'js', 'py', 'json', 'cpp', 'rs' ].indexOf( ext ) > -1 ? "images/" + ext + ".png" :
|
|
1255
|
+
!isNewTabButton ? "fa-solid fa-align-left gray" : undefined;
|
|
1256
|
+
}
|
|
1257
|
+
|
|
1086
1258
|
_onNewTab( e ) {
|
|
1087
1259
|
|
|
1088
1260
|
this.processFocus(false);
|
|
1089
1261
|
|
|
1090
1262
|
LX.addContextMenu( null, e, m => {
|
|
1091
1263
|
m.add( "Create", this.addTab.bind( this, "unnamed.js", true ) );
|
|
1092
|
-
m.add( "Load", this.
|
|
1264
|
+
m.add( "Load", this.loadTabFromFile.bind( this, "unnamed.js", true ) );
|
|
1093
1265
|
});
|
|
1094
1266
|
}
|
|
1095
1267
|
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
if(
|
|
1268
|
+
_onSelectTab( isNewTabButton, event, name, ) {
|
|
1269
|
+
|
|
1270
|
+
if( isNewTabButton )
|
|
1099
1271
|
{
|
|
1100
|
-
this.
|
|
1101
|
-
return
|
|
1272
|
+
this._onNewTab( event );
|
|
1273
|
+
return;
|
|
1102
1274
|
}
|
|
1103
1275
|
|
|
1276
|
+
var cursor = cursor ?? this.cursors.children[ 0 ];
|
|
1277
|
+
this.saveCursor( cursor, this.code.cursorState );
|
|
1278
|
+
|
|
1279
|
+
this.code = this.loadedTabs[ name ];
|
|
1280
|
+
this.restoreCursor( cursor, this.code.cursorState );
|
|
1281
|
+
|
|
1282
|
+
this.endSelection();
|
|
1283
|
+
this._changeLanguageFromExtension( LX.getExtension( name ) );
|
|
1284
|
+
this._updateDataInfoPanel( "@tab-name", name );
|
|
1285
|
+
}
|
|
1286
|
+
|
|
1287
|
+
_onContextMenuTab( isNewTabButton, event, name, ) {
|
|
1288
|
+
|
|
1289
|
+
if( isNewTabButton )
|
|
1290
|
+
return;
|
|
1291
|
+
|
|
1292
|
+
LX.addContextMenu( null, event, m => {
|
|
1293
|
+
m.add( "Close", () => { this.tabs.delete( name ) } );
|
|
1294
|
+
m.add( "" );
|
|
1295
|
+
m.add( "Rename", () => { console.warn( "TODO" )} );
|
|
1296
|
+
});
|
|
1297
|
+
}
|
|
1298
|
+
|
|
1299
|
+
addTab( name, selected, title ) {
|
|
1300
|
+
|
|
1301
|
+
// If already loaded, set new name...
|
|
1302
|
+
const repeats = Object.keys( editor.loadedTabs ).slice( 1 ).reduce( ( v, key ) => {
|
|
1303
|
+
const noRepeatName = key.replace( /[_\d+]/g, '');
|
|
1304
|
+
return v + ( noRepeatName == name );
|
|
1305
|
+
}, 0 );
|
|
1306
|
+
|
|
1307
|
+
if( repeats > 0 )
|
|
1308
|
+
name = name.split( '.' ).join( '_' + repeats + '.' );
|
|
1309
|
+
|
|
1310
|
+
const isNewTabButton = ( name === '+' );
|
|
1311
|
+
|
|
1104
1312
|
// Create code content
|
|
1105
1313
|
let code = document.createElement( 'div' );
|
|
1106
1314
|
code.className = 'code';
|
|
@@ -1129,34 +1337,25 @@ class CodeEditor {
|
|
|
1129
1337
|
this.loadFile( e.dataTransfer.files[ i ] );
|
|
1130
1338
|
});
|
|
1131
1339
|
|
|
1340
|
+
this.loadedTabs[ name ] = code;
|
|
1132
1341
|
this.openedTabs[ name ] = code;
|
|
1342
|
+
|
|
1343
|
+
const tabIcon = this._getFileIcon( name );
|
|
1133
1344
|
|
|
1134
|
-
|
|
1345
|
+
if( this.explorer && !isNewTabButton )
|
|
1346
|
+
{
|
|
1347
|
+
this.addExplorerItem( { 'id': name, 'skipVisibility': true, 'icon': tabIcon } );
|
|
1348
|
+
this.explorer.frefresh( name );
|
|
1349
|
+
}
|
|
1135
1350
|
|
|
1136
|
-
this.tabs.add(name, code, {
|
|
1351
|
+
this.tabs.add( name, code, {
|
|
1137
1352
|
selected: selected,
|
|
1138
|
-
fixed:
|
|
1353
|
+
fixed: isNewTabButton,
|
|
1139
1354
|
title: code.title,
|
|
1140
|
-
icon:
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
if(tabname == '+')
|
|
1146
|
-
{
|
|
1147
|
-
this._onNewTab( e );
|
|
1148
|
-
return;
|
|
1149
|
-
}
|
|
1150
|
-
|
|
1151
|
-
var cursor = cursor ?? this.cursors.children[ 0 ];
|
|
1152
|
-
this.saveCursor( cursor, this.code.cursorState );
|
|
1153
|
-
this.code = this.openedTabs[ tabname ];
|
|
1154
|
-
this.restoreCursor( cursor, this.code.cursorState );
|
|
1155
|
-
this.endSelection();
|
|
1156
|
-
this._changeLanguageFromExtension( LX.getExtension( tabname ) );
|
|
1157
|
-
this._refreshCodeInfo( cursor.line, cursor.position );
|
|
1158
|
-
}
|
|
1159
|
-
});
|
|
1355
|
+
icon: tabIcon,
|
|
1356
|
+
onSelect: this._onSelectTab.bind( this, isNewTabButton ),
|
|
1357
|
+
onContextMenu: this._onContextMenuTab.bind( this, isNewTabButton )
|
|
1358
|
+
} );
|
|
1160
1359
|
|
|
1161
1360
|
// Move into the sizer..
|
|
1162
1361
|
this.codeSizer.appendChild( code );
|
|
@@ -1168,11 +1367,66 @@ class CodeEditor {
|
|
|
1168
1367
|
this.code = code;
|
|
1169
1368
|
this.resetCursorPos( CodeEditor.CURSOR_LEFT | CodeEditor.CURSOR_TOP );
|
|
1170
1369
|
this.processLines();
|
|
1171
|
-
doAsync( () => this._refreshCodeInfo( 0, 0 ), 50 );
|
|
1172
1370
|
}
|
|
1371
|
+
|
|
1372
|
+
this._updateDataInfoPanel( "@tab-name", name );
|
|
1373
|
+
|
|
1374
|
+
// Bc it could be overrided..
|
|
1375
|
+
return name;
|
|
1173
1376
|
}
|
|
1174
1377
|
|
|
1175
|
-
loadTab() {
|
|
1378
|
+
loadTab( name ) {
|
|
1379
|
+
|
|
1380
|
+
// Already open...
|
|
1381
|
+
if( this.openedTabs[ name ] )
|
|
1382
|
+
{
|
|
1383
|
+
this.tabs.select( name );
|
|
1384
|
+
return;
|
|
1385
|
+
}
|
|
1386
|
+
|
|
1387
|
+
let code = this.loadedTabs[ name ]
|
|
1388
|
+
|
|
1389
|
+
if( !code )
|
|
1390
|
+
{
|
|
1391
|
+
this.addTab( name, true );
|
|
1392
|
+
// Unload lines from file...
|
|
1393
|
+
if( this._storedLines[ name ] )
|
|
1394
|
+
{
|
|
1395
|
+
this.code.lines = this._storedLines[ name ];
|
|
1396
|
+
delete this._storedLines[ name ];
|
|
1397
|
+
}
|
|
1398
|
+
this._changeLanguageFromExtension( LX.getExtension( name ) );
|
|
1399
|
+
return;
|
|
1400
|
+
}
|
|
1401
|
+
|
|
1402
|
+
this.openedTabs[ name ] = code;
|
|
1403
|
+
|
|
1404
|
+
const isNewTabButton = ( name === '+' );
|
|
1405
|
+
const tabIcon = this._getFileIcon( name );
|
|
1406
|
+
|
|
1407
|
+
this.tabs.add(name, code, {
|
|
1408
|
+
selected: true,
|
|
1409
|
+
fixed: isNewTabButton,
|
|
1410
|
+
title: code.title,
|
|
1411
|
+
icon: tabIcon,
|
|
1412
|
+
onSelect: this._onSelectTab.bind( this, isNewTabButton ),
|
|
1413
|
+
onContextMenu: this._onContextMenuTab.bind( this, isNewTabButton )
|
|
1414
|
+
});
|
|
1415
|
+
|
|
1416
|
+
// Move into the sizer..
|
|
1417
|
+
this.codeSizer.appendChild( code );
|
|
1418
|
+
|
|
1419
|
+
this.endSelection();
|
|
1420
|
+
|
|
1421
|
+
// Select as current...
|
|
1422
|
+
this.code = code;
|
|
1423
|
+
this.resetCursorPos( CodeEditor.CURSOR_LEFT | CodeEditor.CURSOR_TOP );
|
|
1424
|
+
this.processLines();
|
|
1425
|
+
this._changeLanguageFromExtension( LX.getExtension( name ) );
|
|
1426
|
+
this._updateDataInfoPanel( "@tab-name", tabname );
|
|
1427
|
+
}
|
|
1428
|
+
|
|
1429
|
+
loadTabFromFile() {
|
|
1176
1430
|
const input = document.createElement( 'input' );
|
|
1177
1431
|
input.type = 'file';
|
|
1178
1432
|
document.body.appendChild( input );
|
|
@@ -1191,7 +1445,7 @@ class CodeEditor {
|
|
|
1191
1445
|
this.restartBlink();
|
|
1192
1446
|
else {
|
|
1193
1447
|
clearInterval( this.blinker );
|
|
1194
|
-
this.cursors.classList.remove('show');
|
|
1448
|
+
this.cursors.classList.remove( 'show' );
|
|
1195
1449
|
}
|
|
1196
1450
|
}
|
|
1197
1451
|
|
|
@@ -1216,7 +1470,7 @@ class CodeEditor {
|
|
|
1216
1470
|
// Left click only...
|
|
1217
1471
|
if( e.button === 2 )
|
|
1218
1472
|
{
|
|
1219
|
-
this.processClick(e);
|
|
1473
|
+
this.processClick( e );
|
|
1220
1474
|
|
|
1221
1475
|
this.canOpenContextMenu = !this.selection;
|
|
1222
1476
|
|
|
@@ -1236,21 +1490,13 @@ class CodeEditor {
|
|
|
1236
1490
|
|
|
1237
1491
|
else if( e.type == 'mouseup' )
|
|
1238
1492
|
{
|
|
1239
|
-
|
|
1240
|
-
this.state.selectingText = false;
|
|
1241
|
-
this.processClick(e);
|
|
1242
|
-
this.endSelection();
|
|
1243
|
-
}
|
|
1244
|
-
|
|
1245
|
-
if(this.selection) this.selection.invertIfNecessary();
|
|
1246
|
-
|
|
1247
|
-
this.state.selectingText = false;
|
|
1493
|
+
this._onMouseUp( e );
|
|
1248
1494
|
}
|
|
1249
1495
|
|
|
1250
1496
|
else if( e.type == 'mousemove' )
|
|
1251
1497
|
{
|
|
1252
1498
|
if( this.state.selectingText )
|
|
1253
|
-
this.processSelection(e);
|
|
1499
|
+
this.processSelection( e );
|
|
1254
1500
|
}
|
|
1255
1501
|
|
|
1256
1502
|
else if ( e.type == 'click' ) // trip
|
|
@@ -1270,6 +1516,7 @@ class CodeEditor {
|
|
|
1270
1516
|
this.resetCursorPos( CodeEditor.CURSOR_LEFT );
|
|
1271
1517
|
e._shiftKey = true;
|
|
1272
1518
|
this.actions['End'].callback(cursor.line, cursor, e);
|
|
1519
|
+
this._tripleClickSelection = true;
|
|
1273
1520
|
break;
|
|
1274
1521
|
}
|
|
1275
1522
|
}
|
|
@@ -1300,7 +1547,24 @@ class CodeEditor {
|
|
|
1300
1547
|
}
|
|
1301
1548
|
}
|
|
1302
1549
|
|
|
1303
|
-
|
|
1550
|
+
_onMouseUp( e ) {
|
|
1551
|
+
|
|
1552
|
+
if( (LX.getTime() - this.lastMouseDown) < 300 ) {
|
|
1553
|
+
this.state.selectingText = false;
|
|
1554
|
+
this.processClick( e );
|
|
1555
|
+
this.endSelection();
|
|
1556
|
+
}
|
|
1557
|
+
|
|
1558
|
+
if( this.selection )
|
|
1559
|
+
{
|
|
1560
|
+
this.selection.invertIfNecessary();
|
|
1561
|
+
}
|
|
1562
|
+
|
|
1563
|
+
this.state.selectingText = false;
|
|
1564
|
+
delete this._lastSelectionKeyDir;
|
|
1565
|
+
}
|
|
1566
|
+
|
|
1567
|
+
processClick( e ) {
|
|
1304
1568
|
|
|
1305
1569
|
var cursor = this.cursors.children[ 0 ];
|
|
1306
1570
|
var code_rect = this.codeScroller.getBoundingClientRect();
|
|
@@ -1317,24 +1581,51 @@ class CodeEditor {
|
|
|
1317
1581
|
this.cursorToPosition( cursor, string.length );
|
|
1318
1582
|
|
|
1319
1583
|
this.hideAutoCompleteBox();
|
|
1320
|
-
|
|
1321
|
-
if( !skip_refresh )
|
|
1322
|
-
this._refreshCodeInfo( ln, cursor.position );
|
|
1323
1584
|
}
|
|
1324
1585
|
|
|
1325
|
-
processSelection( e, keep_range ) {
|
|
1586
|
+
processSelection( e, keep_range, flags = CodeEditor.SELECTION_X_Y ) {
|
|
1326
1587
|
|
|
1327
1588
|
var cursor = this.cursors.children[ 0 ];
|
|
1589
|
+
const isMouseEvent = e && ( e.constructor == MouseEvent );
|
|
1328
1590
|
|
|
1329
|
-
if(
|
|
1591
|
+
if( isMouseEvent ) this.processClick( e );
|
|
1330
1592
|
if( !this.selection )
|
|
1331
1593
|
this.startSelection( cursor );
|
|
1332
1594
|
|
|
1595
|
+
// Hide active line background
|
|
1596
|
+
this.code.childNodes.forEach( e => e.classList.remove( 'active-line' ) );
|
|
1597
|
+
|
|
1333
1598
|
// Update selection
|
|
1334
|
-
if(!keep_range)
|
|
1599
|
+
if( !keep_range )
|
|
1600
|
+
{
|
|
1601
|
+
let ccw = true;
|
|
1602
|
+
|
|
1603
|
+
// Check if we must change ccw or not ... (not with mouse)
|
|
1604
|
+
if( !isMouseEvent && this.line >= this.selection.fromY &&
|
|
1605
|
+
(this.line == this.selection.fromY ? this.position >= this.selection.fromX : true) )
|
|
1606
|
+
{
|
|
1607
|
+
ccw = ( e && this._lastSelectionKeyDir && ( e.key == 'ArrowRight' || e.key == 'ArrowDown' || e.key == 'End' ) );
|
|
1608
|
+
}
|
|
1609
|
+
|
|
1610
|
+
if( ccw )
|
|
1611
|
+
{
|
|
1612
|
+
if( flags & CodeEditor.SELECTION_X ) this.selection.fromX = cursor.position;
|
|
1613
|
+
if( flags & CodeEditor.SELECTION_Y ) this.selection.fromY = cursor.line;
|
|
1614
|
+
}
|
|
1615
|
+
else
|
|
1616
|
+
{
|
|
1617
|
+
if( flags & CodeEditor.SELECTION_X ) this.selection.toX = cursor.position;
|
|
1618
|
+
if( flags & CodeEditor.SELECTION_Y ) this.selection.toY = cursor.line;
|
|
1619
|
+
}
|
|
1620
|
+
|
|
1621
|
+
this._lastSelectionKeyDir = ccw;
|
|
1622
|
+
}
|
|
1623
|
+
|
|
1624
|
+
// Only leave if not a mouse selection...
|
|
1625
|
+
if( !isMouseEvent && this.selection.isEmpty() )
|
|
1335
1626
|
{
|
|
1336
|
-
this.
|
|
1337
|
-
|
|
1627
|
+
this.endSelection();
|
|
1628
|
+
return;
|
|
1338
1629
|
}
|
|
1339
1630
|
|
|
1340
1631
|
this.selection.chars = 0;
|
|
@@ -1477,9 +1768,10 @@ class CodeEditor {
|
|
|
1477
1768
|
const nlines = this.code.lines.length - 1;
|
|
1478
1769
|
this.selection.toX = this.code.lines[ nlines ].length;
|
|
1479
1770
|
this.selection.toY = nlines;
|
|
1480
|
-
this.processSelection( null, true );
|
|
1481
1771
|
this.cursorToPosition( cursor, this.selection.toX );
|
|
1482
1772
|
this.cursorToLine( cursor, this.selection.toY );
|
|
1773
|
+
this.processSelection( null, true );
|
|
1774
|
+
this.hideAutoCompleteBox();
|
|
1483
1775
|
break;
|
|
1484
1776
|
case 'c': // copy
|
|
1485
1777
|
this._copyContent();
|
|
@@ -1489,6 +1781,7 @@ class CodeEditor {
|
|
|
1489
1781
|
this.code.lines.splice( lidx, 0, this.code.lines[ lidx ] );
|
|
1490
1782
|
this.lineDown( cursor );
|
|
1491
1783
|
this.processLines();
|
|
1784
|
+
this.hideAutoCompleteBox();
|
|
1492
1785
|
return;
|
|
1493
1786
|
case 's': // save
|
|
1494
1787
|
e.preventDefault();
|
|
@@ -1499,14 +1792,15 @@ class CodeEditor {
|
|
|
1499
1792
|
return;
|
|
1500
1793
|
case 'x': // cut line
|
|
1501
1794
|
this._cutContent();
|
|
1795
|
+
this.hideAutoCompleteBox();
|
|
1502
1796
|
return;
|
|
1503
1797
|
case 'z': // undo
|
|
1504
1798
|
if(!this.code.undoSteps.length)
|
|
1505
1799
|
return;
|
|
1506
1800
|
const step = this.code.undoSteps.pop();
|
|
1507
1801
|
this.code.lines = step.lines;
|
|
1508
|
-
this.restoreCursor( cursor, step.cursor );
|
|
1509
1802
|
this.processLines();
|
|
1803
|
+
this.restoreCursor( cursor, step.cursor );
|
|
1510
1804
|
return;
|
|
1511
1805
|
}
|
|
1512
1806
|
}
|
|
@@ -1521,6 +1815,7 @@ class CodeEditor {
|
|
|
1521
1815
|
this.lineUp();
|
|
1522
1816
|
this.processLine( lidx - 1 );
|
|
1523
1817
|
this.processLine( lidx );
|
|
1818
|
+
this.hideAutoCompleteBox();
|
|
1524
1819
|
return;
|
|
1525
1820
|
case 'ArrowDown':
|
|
1526
1821
|
if(this.code.lines[ lidx + 1 ] == undefined)
|
|
@@ -1529,6 +1824,7 @@ class CodeEditor {
|
|
|
1529
1824
|
this.lineDown();
|
|
1530
1825
|
this.processLine( lidx );
|
|
1531
1826
|
this.processLine( lidx + 1 );
|
|
1827
|
+
this.hideAutoCompleteBox();
|
|
1532
1828
|
return;
|
|
1533
1829
|
}
|
|
1534
1830
|
}
|
|
@@ -1561,7 +1857,7 @@ class CodeEditor {
|
|
|
1561
1857
|
const enclosableKeys = ["\"", "'", "(", "{"];
|
|
1562
1858
|
if( enclosableKeys.indexOf( key ) > -1 )
|
|
1563
1859
|
{
|
|
1564
|
-
if( this._encloseSelectedWordWithKey(key, lidx, cursor) )
|
|
1860
|
+
if( this._encloseSelectedWordWithKey( key, lidx, cursor ) )
|
|
1565
1861
|
return;
|
|
1566
1862
|
}
|
|
1567
1863
|
|
|
@@ -1570,8 +1866,8 @@ class CodeEditor {
|
|
|
1570
1866
|
|
|
1571
1867
|
if( this.selection )
|
|
1572
1868
|
{
|
|
1573
|
-
this.actions['Backspace'].callback(lidx, cursor, e);
|
|
1574
|
-
lidx = cursor.line;
|
|
1869
|
+
this.actions['Backspace'].callback( lidx, cursor, e );
|
|
1870
|
+
lidx = cursor.line;
|
|
1575
1871
|
}
|
|
1576
1872
|
|
|
1577
1873
|
// Append key
|
|
@@ -1668,11 +1964,15 @@ class CodeEditor {
|
|
|
1668
1964
|
let lidx = cursor.line;
|
|
1669
1965
|
let text_to_cut = "";
|
|
1670
1966
|
|
|
1967
|
+
this._addUndoStep( cursor );
|
|
1968
|
+
|
|
1671
1969
|
if( !this.selection ) {
|
|
1672
1970
|
text_to_cut = "\n" + this.code.lines[ cursor.line ];
|
|
1673
1971
|
this.code.lines.splice( lidx, 1 );
|
|
1674
1972
|
this.processLines();
|
|
1675
1973
|
this.resetCursorPos( CodeEditor.CURSOR_LEFT );
|
|
1974
|
+
if( this.code.lines[ lidx ] == undefined )
|
|
1975
|
+
this.lineUp();
|
|
1676
1976
|
}
|
|
1677
1977
|
else {
|
|
1678
1978
|
|
|
@@ -1735,7 +2035,6 @@ class CodeEditor {
|
|
|
1735
2035
|
|
|
1736
2036
|
const start = performance.now();
|
|
1737
2037
|
|
|
1738
|
-
var gutter_html = "";
|
|
1739
2038
|
var code_html = "";
|
|
1740
2039
|
|
|
1741
2040
|
// Reset all lines content
|
|
@@ -1761,16 +2060,11 @@ class CodeEditor {
|
|
|
1761
2060
|
// Process visible lines
|
|
1762
2061
|
for( let i = this.visibleLinesViewport.x; i < this.visibleLinesViewport.y; ++i )
|
|
1763
2062
|
{
|
|
1764
|
-
gutter_html += "<span>" + (i + 1) + "</span>";
|
|
1765
2063
|
code_html += this.processLine( i, true );
|
|
1766
2064
|
}
|
|
1767
2065
|
|
|
1768
2066
|
this.code.innerHTML = code_html;
|
|
1769
2067
|
|
|
1770
|
-
// console.log("RANGE:", this.visibleLinesViewport);
|
|
1771
|
-
// console.log( "Num lines processed:", (this.visibleLinesViewport.y - this.visibleLinesViewport.x), performance.now() - start );
|
|
1772
|
-
// console.log("--------------------------------------------");
|
|
1773
|
-
|
|
1774
2068
|
// Update scroll data
|
|
1775
2069
|
this.codeScroller.scrollTop = lastScrollTop;
|
|
1776
2070
|
this.code.style.top = ( this.visibleLinesViewport.x * this.lineHeight ) + "px";
|
|
@@ -1779,10 +2073,8 @@ class CodeEditor {
|
|
|
1779
2073
|
if( this.selection )
|
|
1780
2074
|
this.processSelection( null, true );
|
|
1781
2075
|
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
delete this._pendingString;
|
|
1785
|
-
|
|
2076
|
+
this._clearTmpVariables();
|
|
2077
|
+
this._setActiveLine();
|
|
1786
2078
|
this.resize();
|
|
1787
2079
|
}
|
|
1788
2080
|
|
|
@@ -1793,7 +2085,10 @@ class CodeEditor {
|
|
|
1793
2085
|
|
|
1794
2086
|
const UPDATE_LINE = ( html ) => {
|
|
1795
2087
|
if( !force ) // Single line update
|
|
2088
|
+
{
|
|
1796
2089
|
this.code.childNodes[ local_line_num ].innerHTML = gutter_line + html;
|
|
2090
|
+
this._clearTmpVariables();
|
|
2091
|
+
}
|
|
1797
2092
|
else // Update all lines at once
|
|
1798
2093
|
return "<pre>" + ( gutter_line + html ) + "</pre>";
|
|
1799
2094
|
}
|
|
@@ -1847,8 +2142,6 @@ class CodeEditor {
|
|
|
1847
2142
|
{
|
|
1848
2143
|
if( token.substr( 0, 2 ) == '/*' )
|
|
1849
2144
|
this._buildingBlockComment = true;
|
|
1850
|
-
if( token.substr( token.length - 2 ) == '*/' )
|
|
1851
|
-
delete this._buildingBlockComment;
|
|
1852
2145
|
}
|
|
1853
2146
|
|
|
1854
2147
|
line_inner_html += this._evaluateToken( token, prev, next, (i == tokensToEvaluate.length - 1) );
|
|
@@ -1859,7 +2152,7 @@ class CodeEditor {
|
|
|
1859
2152
|
|
|
1860
2153
|
_processTokens( tokens, offset = 0 ) {
|
|
1861
2154
|
|
|
1862
|
-
if( this.highlight == 'C++' )
|
|
2155
|
+
if( this.highlight == 'C++' || this.highlight == 'CSS' )
|
|
1863
2156
|
{
|
|
1864
2157
|
var idx = tokens.slice( offset ).findIndex( ( value, index ) => this.isNumber( value ) );
|
|
1865
2158
|
if( idx > -1 )
|
|
@@ -1915,8 +2208,6 @@ class CodeEditor {
|
|
|
1915
2208
|
linestring = ogLine.substring( 0, hasCommentIdx );
|
|
1916
2209
|
}
|
|
1917
2210
|
|
|
1918
|
-
// const usesBlockComments = this.languages[ this.highlight ].blockComments ?? true;
|
|
1919
|
-
|
|
1920
2211
|
let tokensToEvaluate = []; // store in a temp array so we know prev and next tokens...
|
|
1921
2212
|
|
|
1922
2213
|
const pushToken = function( t ) {
|
|
@@ -1925,7 +2216,7 @@ class CodeEditor {
|
|
|
1925
2216
|
tokensToEvaluate.push( t );
|
|
1926
2217
|
};
|
|
1927
2218
|
|
|
1928
|
-
let iter = linestring.matchAll(/(
|
|
2219
|
+
let iter = linestring.matchAll(/(\*\/|\/\*|::|[\[\](){}<>.,;:*"'%@!/= ])/g);
|
|
1929
2220
|
let subtokens = iter.next();
|
|
1930
2221
|
if( subtokens.value )
|
|
1931
2222
|
{
|
|
@@ -1945,26 +2236,6 @@ class CodeEditor {
|
|
|
1945
2236
|
}
|
|
1946
2237
|
else tokensToEvaluate.push( linestring );
|
|
1947
2238
|
|
|
1948
|
-
// if( usesBlockComments )
|
|
1949
|
-
// {
|
|
1950
|
-
// var block = false;
|
|
1951
|
-
|
|
1952
|
-
// if( t.includes('/*') )
|
|
1953
|
-
// {
|
|
1954
|
-
// const idx = t.indexOf( '/*' );
|
|
1955
|
-
// tokensToEvaluate.push( t.substring( 0, idx ), '/*', t.substring( idx + 2 ) );
|
|
1956
|
-
// block |= true;
|
|
1957
|
-
// }
|
|
1958
|
-
// else if( t.includes('*/') )
|
|
1959
|
-
// {
|
|
1960
|
-
// const idx = t.indexOf( '*/' );
|
|
1961
|
-
// tokensToEvaluate.push( t.substring( 0, idx ), '*/', t.substring( idx + 2 ) );
|
|
1962
|
-
// block |= true;
|
|
1963
|
-
// }
|
|
1964
|
-
|
|
1965
|
-
// if( block ) continue;
|
|
1966
|
-
// }
|
|
1967
|
-
|
|
1968
2239
|
if( hasCommentIdx != undefined )
|
|
1969
2240
|
{
|
|
1970
2241
|
pushToken( ogLine.substring( hasCommentIdx ) );
|
|
@@ -2001,6 +2272,8 @@ class CodeEditor {
|
|
|
2001
2272
|
this._buildingString = token;
|
|
2002
2273
|
}
|
|
2003
2274
|
|
|
2275
|
+
const usesBlockComments = this.languages[ this.highlight ].blockComments ?? true;
|
|
2276
|
+
|
|
2004
2277
|
if(token == ' ')
|
|
2005
2278
|
{
|
|
2006
2279
|
if( this._buildingString != undefined )
|
|
@@ -2013,7 +2286,6 @@ class CodeEditor {
|
|
|
2013
2286
|
else
|
|
2014
2287
|
{
|
|
2015
2288
|
const singleLineCommentToken = this.languages[ this.highlight ].singleLineCommentToken ?? this.defaultSingleLineCommentToken;
|
|
2016
|
-
const usesBlockComments = this.languages[ this.highlight ].blockComments ?? true;
|
|
2017
2289
|
|
|
2018
2290
|
let token_classname = "";
|
|
2019
2291
|
let discardToken = false;
|
|
@@ -2039,12 +2311,6 @@ class CodeEditor {
|
|
|
2039
2311
|
else if( token.substr( 0, singleLineCommentToken.length ) == singleLineCommentToken )
|
|
2040
2312
|
token_classname = "cm-com";
|
|
2041
2313
|
|
|
2042
|
-
else if( usesBlockComments && token.substr( 0, 2 ) == '/*' )
|
|
2043
|
-
token_classname = "cm-com";
|
|
2044
|
-
|
|
2045
|
-
else if( usesBlockComments && token.substr( token.length - 2 ) == '*/' )
|
|
2046
|
-
token_classname = "cm-com";
|
|
2047
|
-
|
|
2048
2314
|
else if( this.isNumber( token ) || this.isNumber( token.replace(/[px]|[em]|%/g,'') ) )
|
|
2049
2315
|
token_classname = "cm-dec";
|
|
2050
2316
|
|
|
@@ -2076,6 +2342,11 @@ class CodeEditor {
|
|
|
2076
2342
|
token_classname = "cm-mtd";
|
|
2077
2343
|
|
|
2078
2344
|
|
|
2345
|
+
if( usesBlockComments && this._buildingBlockComment && token.substr( 0, 2 ) == '*/' )
|
|
2346
|
+
{
|
|
2347
|
+
delete this._buildingBlockComment;
|
|
2348
|
+
}
|
|
2349
|
+
|
|
2079
2350
|
// We finished constructing a string
|
|
2080
2351
|
if( this._buildingString && ( this._stringEnded || isLastToken ) )
|
|
2081
2352
|
{
|
|
@@ -2131,6 +2402,12 @@ class CodeEditor {
|
|
|
2131
2402
|
else if( token.lastChar == 'u' )
|
|
2132
2403
|
return !(token.includes('.')) && this.isNumber( token.substring(0, token.length - 1) );
|
|
2133
2404
|
}
|
|
2405
|
+
|
|
2406
|
+
else if(this.highlight == 'CSS')
|
|
2407
|
+
{
|
|
2408
|
+
if( token.lastChar == '%' )
|
|
2409
|
+
return this.isNumber( token.substring(0, token.length - 1) )
|
|
2410
|
+
}
|
|
2134
2411
|
|
|
2135
2412
|
return token.length && token != ' ' && !Number.isNaN(+token);
|
|
2136
2413
|
}
|
|
@@ -2208,31 +2485,43 @@ class CodeEditor {
|
|
|
2208
2485
|
lineUp( cursor, resetLeft ) {
|
|
2209
2486
|
|
|
2210
2487
|
cursor = cursor ?? this.cursors.children[ 0 ];
|
|
2488
|
+
|
|
2489
|
+
if( this.code.lines[ cursor.line - 1 ] == undefined )
|
|
2490
|
+
return false;
|
|
2491
|
+
|
|
2211
2492
|
cursor.line--;
|
|
2212
2493
|
cursor.line = Math.max( 0, cursor.line );
|
|
2213
2494
|
this.cursorToTop( cursor, resetLeft );
|
|
2495
|
+
|
|
2496
|
+
return true;
|
|
2214
2497
|
}
|
|
2215
2498
|
|
|
2216
2499
|
lineDown( cursor, resetLeft ) {
|
|
2217
2500
|
|
|
2218
2501
|
cursor = cursor ?? this.cursors.children[ 0 ];
|
|
2502
|
+
|
|
2503
|
+
if( this.code.lines[ cursor.line + 1 ] == undefined )
|
|
2504
|
+
return false;
|
|
2505
|
+
|
|
2219
2506
|
cursor.line++;
|
|
2220
2507
|
this.cursorToBottom( cursor, resetLeft );
|
|
2508
|
+
|
|
2509
|
+
return true;
|
|
2221
2510
|
}
|
|
2222
2511
|
|
|
2223
2512
|
restartBlink() {
|
|
2224
2513
|
|
|
2225
2514
|
if( !this.code ) return;
|
|
2226
2515
|
|
|
2227
|
-
clearInterval(this.blinker);
|
|
2228
|
-
this.cursors.classList.add('show');
|
|
2516
|
+
clearInterval( this.blinker );
|
|
2517
|
+
this.cursors.classList.add( 'show' );
|
|
2229
2518
|
|
|
2230
|
-
if
|
|
2519
|
+
if( this.cursorBlinkRate > 0 )
|
|
2231
2520
|
this.blinker = setInterval(() => {
|
|
2232
|
-
this.cursors.classList.toggle('show');
|
|
2521
|
+
this.cursors.classList.toggle( 'show' );
|
|
2233
2522
|
}, this.cursorBlinkRate);
|
|
2234
|
-
else if
|
|
2235
|
-
this.cursors.classList.remove('show');
|
|
2523
|
+
else if( this.cursorBlinkRate < 0 )
|
|
2524
|
+
this.cursors.classList.remove( 'show' );
|
|
2236
2525
|
}
|
|
2237
2526
|
|
|
2238
2527
|
startSelection( cursor ) {
|
|
@@ -2241,10 +2530,10 @@ class CodeEditor {
|
|
|
2241
2530
|
this.selections.innerHTML = "";
|
|
2242
2531
|
|
|
2243
2532
|
// Show elements
|
|
2244
|
-
this.selections.classList.add('show');
|
|
2533
|
+
this.selections.classList.add( 'show' );
|
|
2245
2534
|
|
|
2246
2535
|
// Create new selection instance
|
|
2247
|
-
this.selection = new CodeSelection(this, cursor.position, cursor.line);
|
|
2536
|
+
this.selection = new CodeSelection( this, cursor.position, cursor.line );
|
|
2248
2537
|
}
|
|
2249
2538
|
|
|
2250
2539
|
deleteSelection( cursor ) {
|
|
@@ -2261,7 +2550,7 @@ class CodeEditor {
|
|
|
2261
2550
|
|
|
2262
2551
|
// Get linear start index
|
|
2263
2552
|
let index = 0;
|
|
2264
|
-
for(let i = 0; i <= this.selection.fromY; i++)
|
|
2553
|
+
for( let i = 0; i <= this.selection.fromY; i++ )
|
|
2265
2554
|
index += (i == this.selection.fromY ? this.selection.fromX : this.code.lines[ i ].length);
|
|
2266
2555
|
|
|
2267
2556
|
index += this.selection.fromY * separator.length;
|
|
@@ -2274,18 +2563,17 @@ class CodeEditor {
|
|
|
2274
2563
|
|
|
2275
2564
|
this.cursorToLine( cursor, this.selection.fromY, true );
|
|
2276
2565
|
this.cursorToPosition( cursor, this.selection.fromX );
|
|
2277
|
-
|
|
2278
2566
|
this.endSelection();
|
|
2279
|
-
|
|
2280
2567
|
this.processLines();
|
|
2281
|
-
this._refreshCodeInfo( cursor.line, cursor.position );
|
|
2282
2568
|
}
|
|
2283
2569
|
|
|
2284
2570
|
endSelection() {
|
|
2285
2571
|
|
|
2286
|
-
this.selections.classList.remove('show');
|
|
2572
|
+
this.selections.classList.remove( 'show' );
|
|
2287
2573
|
this.selections.innerHTML = "";
|
|
2288
2574
|
delete this.selection;
|
|
2575
|
+
delete this._tripleClickSelection;
|
|
2576
|
+
delete this._lastSelectionKeyDir;
|
|
2289
2577
|
}
|
|
2290
2578
|
|
|
2291
2579
|
cursorToRight( key, cursor ) {
|
|
@@ -2297,7 +2585,6 @@ class CodeEditor {
|
|
|
2297
2585
|
cursor.position++;
|
|
2298
2586
|
|
|
2299
2587
|
this.restartBlink();
|
|
2300
|
-
this._refreshCodeInfo( cursor.line, cursor.position );
|
|
2301
2588
|
|
|
2302
2589
|
// Add horizontal scroll
|
|
2303
2590
|
|
|
@@ -2310,7 +2597,7 @@ class CodeEditor {
|
|
|
2310
2597
|
|
|
2311
2598
|
cursorToLeft( key, cursor ) {
|
|
2312
2599
|
|
|
2313
|
-
if(!key) return;
|
|
2600
|
+
if( !key ) return;
|
|
2314
2601
|
cursor = cursor ?? this.cursors.children[ 0 ];
|
|
2315
2602
|
cursor._left -= this.charWidth;
|
|
2316
2603
|
cursor._left = Math.max( cursor._left, 0 );
|
|
@@ -2318,7 +2605,6 @@ class CodeEditor {
|
|
|
2318
2605
|
cursor.position--;
|
|
2319
2606
|
cursor.position = Math.max( cursor.position, 0 );
|
|
2320
2607
|
this.restartBlink();
|
|
2321
|
-
this._refreshCodeInfo( cursor.line, cursor.position );
|
|
2322
2608
|
|
|
2323
2609
|
// Add horizontal scroll
|
|
2324
2610
|
|
|
@@ -2340,8 +2626,6 @@ class CodeEditor {
|
|
|
2340
2626
|
if(resetLeft)
|
|
2341
2627
|
this.resetCursorPos( CodeEditor.CURSOR_LEFT, cursor );
|
|
2342
2628
|
|
|
2343
|
-
this._refreshCodeInfo( cursor.line, cursor.position );
|
|
2344
|
-
|
|
2345
2629
|
doAsync(() => {
|
|
2346
2630
|
var first_line = ( this.getScrollTop() / this.lineHeight )|0;
|
|
2347
2631
|
if( (cursor.line - 1) < first_line )
|
|
@@ -2359,8 +2643,6 @@ class CodeEditor {
|
|
|
2359
2643
|
if(resetLeft)
|
|
2360
2644
|
this.resetCursorPos( CodeEditor.CURSOR_LEFT, cursor );
|
|
2361
2645
|
|
|
2362
|
-
this._refreshCodeInfo( cursor.line, cursor.position );
|
|
2363
|
-
|
|
2364
2646
|
doAsync(() => {
|
|
2365
2647
|
var last_line = ( ( this.codeScroller.offsetHeight + this.getScrollTop() ) / this.lineHeight )|0;
|
|
2366
2648
|
if( cursor.line >= last_line )
|
|
@@ -2370,9 +2652,10 @@ class CodeEditor {
|
|
|
2370
2652
|
|
|
2371
2653
|
cursorToString( cursor, text, reverse ) {
|
|
2372
2654
|
|
|
2655
|
+
if( !text.length ) return;
|
|
2373
2656
|
cursor = cursor ?? this.cursors.children[ 0 ];
|
|
2374
2657
|
for( let char of text )
|
|
2375
|
-
reverse ? this.cursorToLeft(char) : this.cursorToRight(char);
|
|
2658
|
+
reverse ? this.cursorToLeft( char ) : this.cursorToRight( char );
|
|
2376
2659
|
}
|
|
2377
2660
|
|
|
2378
2661
|
cursorToPosition( cursor, position ) {
|
|
@@ -2387,7 +2670,7 @@ class CodeEditor {
|
|
|
2387
2670
|
cursor.line = line;
|
|
2388
2671
|
cursor._top = this.lineHeight * line;
|
|
2389
2672
|
cursor.style.top = cursor._top + "px";
|
|
2390
|
-
if(resetLeft) this.resetCursorPos( CodeEditor.CURSOR_LEFT, cursor );
|
|
2673
|
+
if( resetLeft ) this.resetCursorPos( CodeEditor.CURSOR_LEFT, cursor );
|
|
2391
2674
|
}
|
|
2392
2675
|
|
|
2393
2676
|
saveCursor( cursor, state = {} ) {
|
|
@@ -2396,7 +2679,7 @@ class CodeEditor {
|
|
|
2396
2679
|
state.top = cursor._top;
|
|
2397
2680
|
state.left = cursor._left;
|
|
2398
2681
|
state.line = cursor.line;
|
|
2399
|
-
state.
|
|
2682
|
+
state.position = cursor.position;
|
|
2400
2683
|
return state;
|
|
2401
2684
|
}
|
|
2402
2685
|
|
|
@@ -2407,9 +2690,9 @@ class CodeEditor {
|
|
|
2407
2690
|
cursor.position = state.position ?? 0;
|
|
2408
2691
|
|
|
2409
2692
|
cursor._left = state.left ?? 0;
|
|
2410
|
-
cursor.style.left = "calc(" + (cursor._left - this.getScrollLeft()) + "px + " + this.xPadding + ")";
|
|
2693
|
+
cursor.style.left = "calc(" + ( cursor._left - this.getScrollLeft() ) + "px + " + this.xPadding + ")";
|
|
2411
2694
|
cursor._top = state.top ?? 0;
|
|
2412
|
-
cursor.style.top = "calc(" + (cursor._top - this.getScrollTop()) + "px)";
|
|
2695
|
+
cursor.style.top = "calc(" + ( cursor._top - this.getScrollTop() ) + "px)";
|
|
2413
2696
|
}
|
|
2414
2697
|
|
|
2415
2698
|
resetCursorPos( flag, cursor ) {
|
|
@@ -2419,14 +2702,14 @@ class CodeEditor {
|
|
|
2419
2702
|
if( flag & CodeEditor.CURSOR_LEFT )
|
|
2420
2703
|
{
|
|
2421
2704
|
cursor._left = 0;
|
|
2422
|
-
cursor.style.left = "calc(" + (-this.getScrollLeft()) + "px + " + this.xPadding + ")";
|
|
2705
|
+
cursor.style.left = "calc(" + ( -this.getScrollLeft() ) + "px + " + this.xPadding + ")";
|
|
2423
2706
|
cursor.position = 0;
|
|
2424
2707
|
}
|
|
2425
2708
|
|
|
2426
2709
|
if( flag & CodeEditor.CURSOR_TOP )
|
|
2427
2710
|
{
|
|
2428
2711
|
cursor._top = 0;
|
|
2429
|
-
cursor.style.top = (
|
|
2712
|
+
cursor.style.top = ( -this.getScrollTop() ) + "px";
|
|
2430
2713
|
cursor.line = 0;
|
|
2431
2714
|
}
|
|
2432
2715
|
}
|
|
@@ -2434,14 +2717,14 @@ class CodeEditor {
|
|
|
2434
2717
|
addSpaceTabs(n) {
|
|
2435
2718
|
|
|
2436
2719
|
for( var i = 0; i < n; ++i ) {
|
|
2437
|
-
this.actions['Tab'].callback();
|
|
2720
|
+
this.actions[ 'Tab' ].callback();
|
|
2438
2721
|
}
|
|
2439
2722
|
}
|
|
2440
2723
|
|
|
2441
2724
|
addSpaces(n) {
|
|
2442
2725
|
|
|
2443
2726
|
for( var i = 0; i < n; ++i ) {
|
|
2444
|
-
this.root.dispatchEvent(new CustomEvent('keydown', {'detail': {
|
|
2727
|
+
this.root.dispatchEvent( new CustomEvent( 'keydown', { 'detail': {
|
|
2445
2728
|
skip_undo: true,
|
|
2446
2729
|
key: ' '
|
|
2447
2730
|
}}));
|
|
@@ -2450,26 +2733,26 @@ class CodeEditor {
|
|
|
2450
2733
|
|
|
2451
2734
|
getScrollLeft() {
|
|
2452
2735
|
|
|
2453
|
-
if(!this.codeScroller) return 0;
|
|
2736
|
+
if( !this.codeScroller ) return 0;
|
|
2454
2737
|
return this.codeScroller.scrollLeft;
|
|
2455
2738
|
}
|
|
2456
2739
|
|
|
2457
2740
|
getScrollTop() {
|
|
2458
2741
|
|
|
2459
|
-
if(!this.codeScroller) return 0;
|
|
2742
|
+
if( !this.codeScroller ) return 0;
|
|
2460
2743
|
return this.codeScroller.scrollTop;
|
|
2461
2744
|
}
|
|
2462
2745
|
|
|
2463
2746
|
setScrollLeft( value ) {
|
|
2464
2747
|
|
|
2465
|
-
if(!this.codeScroller) return;
|
|
2748
|
+
if( !this.codeScroller ) return;
|
|
2466
2749
|
this.codeScroller.scrollLeft = value;
|
|
2467
2750
|
this.setScrollBarValue( 'horizontal', 0 );
|
|
2468
2751
|
}
|
|
2469
2752
|
|
|
2470
2753
|
setScrollTop( value ) {
|
|
2471
2754
|
|
|
2472
|
-
if(!this.codeScroller) return;
|
|
2755
|
+
if( !this.codeScroller ) return;
|
|
2473
2756
|
this.codeScroller.scrollTop = value;
|
|
2474
2757
|
this.setScrollBarValue( 'vertical' );
|
|
2475
2758
|
}
|
|
@@ -2601,46 +2884,70 @@ class CodeEditor {
|
|
|
2601
2884
|
getCharAtPos( cursor, offset = 0 ) {
|
|
2602
2885
|
|
|
2603
2886
|
cursor = cursor ?? this.cursors.children[ 0 ];
|
|
2604
|
-
return this.code.lines[ cursor.line ][cursor.position + offset];
|
|
2887
|
+
return this.code.lines[ cursor.line ][ cursor.position + offset ];
|
|
2605
2888
|
}
|
|
2606
2889
|
|
|
2607
|
-
getWordAtPos( cursor,
|
|
2890
|
+
getWordAtPos( cursor, loffset = 0, roffset ) {
|
|
2608
2891
|
|
|
2892
|
+
roffset = roffset ?? loffset;
|
|
2609
2893
|
cursor = cursor ?? this.cursors.children[ 0 ];
|
|
2610
2894
|
const col = cursor.line;
|
|
2611
|
-
const words = this.code.lines[col];
|
|
2895
|
+
const words = this.code.lines[ col ];
|
|
2612
2896
|
|
|
2613
|
-
const is_char =
|
|
2614
|
-
const exceptions = ['_', '#', '!'];
|
|
2615
|
-
const code = char.charCodeAt(0);
|
|
2616
|
-
return (exceptions.indexOf(char) > - 1) || (code > 47 && code < 58) || (code > 64 && code < 91) || (code > 96 && code < 123);
|
|
2897
|
+
const is_char = char => {
|
|
2898
|
+
const exceptions = [ '_', '#', '!' ];
|
|
2899
|
+
const code = char.charCodeAt( 0 );
|
|
2900
|
+
return (exceptions.indexOf( char ) > - 1) || (code > 47 && code < 58) || (code > 64 && code < 91) || (code > 96 && code < 123);
|
|
2617
2901
|
}
|
|
2618
2902
|
|
|
2619
|
-
let
|
|
2903
|
+
let from = cursor.position + roffset;
|
|
2904
|
+
let to = cursor.position + loffset;
|
|
2905
|
+
|
|
2906
|
+
// Check left ...
|
|
2907
|
+
|
|
2908
|
+
while( words[ from ] && is_char( words[ from ] ) )
|
|
2909
|
+
from--;
|
|
2620
2910
|
|
|
2621
|
-
|
|
2622
|
-
it--;
|
|
2911
|
+
from++;
|
|
2623
2912
|
|
|
2624
|
-
|
|
2625
|
-
it = cursor.position + offset;
|
|
2913
|
+
// Check right ...
|
|
2626
2914
|
|
|
2627
|
-
while( words[
|
|
2628
|
-
|
|
2915
|
+
while( words[ to ] && is_char( words[ to ] ) )
|
|
2916
|
+
to++;
|
|
2629
2917
|
|
|
2630
|
-
|
|
2918
|
+
// Skip spaces ...
|
|
2631
2919
|
|
|
2632
|
-
|
|
2920
|
+
let word = words.substring( from, to );
|
|
2921
|
+
if( word == ' ' )
|
|
2922
|
+
{
|
|
2923
|
+
if( loffset < 0 )
|
|
2924
|
+
{
|
|
2925
|
+
while( words[ from - 1 ] != undefined && words[ from - 1 ] == ' ' )
|
|
2926
|
+
from--;
|
|
2927
|
+
to++;
|
|
2928
|
+
word = words.substring( from, to + 1 );
|
|
2929
|
+
}
|
|
2930
|
+
else
|
|
2931
|
+
{
|
|
2932
|
+
while( words[ to ] != undefined && words[ to ] == ' ' )
|
|
2933
|
+
to++;
|
|
2934
|
+
from--;
|
|
2935
|
+
word = words.substring( from, to );
|
|
2936
|
+
}
|
|
2937
|
+
}
|
|
2938
|
+
|
|
2939
|
+
return [ word, from, to ];
|
|
2633
2940
|
}
|
|
2634
2941
|
|
|
2635
|
-
|
|
2942
|
+
_measureChar( char = "a", get_bb = false ) {
|
|
2636
2943
|
|
|
2637
|
-
var test = document.createElement("pre");
|
|
2944
|
+
var test = document.createElement( "pre" );
|
|
2638
2945
|
test.className = "codechar";
|
|
2639
2946
|
test.innerHTML = char;
|
|
2640
|
-
document.body.appendChild(test);
|
|
2947
|
+
document.body.appendChild( test );
|
|
2641
2948
|
var rect = test.getBoundingClientRect();
|
|
2642
2949
|
deleteElement( test );
|
|
2643
|
-
const bb = [Math.floor(rect.width), Math.floor(rect.height)];
|
|
2950
|
+
const bb = [ Math.floor( rect.width ), Math.floor( rect.height ) ];
|
|
2644
2951
|
return get_bb ? bb : bb[ 0 ];
|
|
2645
2952
|
}
|
|
2646
2953
|
|
|
@@ -2651,44 +2958,46 @@ class CodeEditor {
|
|
|
2651
2958
|
|
|
2652
2959
|
runScript( code ) {
|
|
2653
2960
|
|
|
2654
|
-
var script = document.createElement('script');
|
|
2961
|
+
var script = document.createElement( 'script' );
|
|
2655
2962
|
script.type = 'module';
|
|
2656
2963
|
script.innerHTML = code;
|
|
2657
2964
|
// script.src = url[ i ] + ( version ? "?version=" + version : "" );
|
|
2658
2965
|
script.async = false;
|
|
2659
2966
|
// script.onload = function(e) { };
|
|
2660
|
-
document.getElementsByTagName('head')[ 0 ].appendChild(script);
|
|
2967
|
+
document.getElementsByTagName( 'head' )[ 0 ].appendChild( script );
|
|
2661
2968
|
}
|
|
2662
2969
|
|
|
2663
2970
|
toJSONFormat( text ) {
|
|
2664
2971
|
|
|
2665
|
-
let params = text.split(
|
|
2972
|
+
let params = text.split( ':' );
|
|
2666
2973
|
|
|
2667
2974
|
for(let i = 0; i < params.length; i++) {
|
|
2668
|
-
let key = params[ i ].split(',');
|
|
2669
|
-
if(key.length > 1)
|
|
2670
|
-
|
|
2975
|
+
let key = params[ i ].split( ',' );
|
|
2976
|
+
if( key.length > 1 )
|
|
2977
|
+
{
|
|
2978
|
+
if( key[ key.length - 1 ].includes( ']' ))
|
|
2671
2979
|
continue;
|
|
2672
|
-
key = key[key.length-1];
|
|
2980
|
+
key = key[ key.length - 1 ];
|
|
2673
2981
|
}
|
|
2674
|
-
else if(key[ 0 ].includes(
|
|
2982
|
+
else if( key[ 0 ].includes( '}' ) )
|
|
2675
2983
|
continue;
|
|
2676
2984
|
else
|
|
2677
2985
|
key = key[ 0 ];
|
|
2678
|
-
key = key.replaceAll(/[{}\n\r]/g,
|
|
2679
|
-
if(key[ 0 ] != '"' && key[key.length - 1] != '"')
|
|
2680
|
-
|
|
2986
|
+
key = key.replaceAll( /[{}\n\r]/g, '' ).replaceAll( ' ', '' )
|
|
2987
|
+
if( key[ 0 ] != '"' && key[ key.length - 1 ] != '"')
|
|
2988
|
+
{
|
|
2989
|
+
params[ i ] = params[ i ].replace( key, '"' + key + '"' );
|
|
2681
2990
|
}
|
|
2682
2991
|
}
|
|
2683
2992
|
|
|
2684
|
-
text = params.join(':');
|
|
2993
|
+
text = params.join( ':' );
|
|
2685
2994
|
|
|
2686
2995
|
try {
|
|
2687
|
-
let json = JSON.parse(text);
|
|
2688
|
-
return JSON.stringify(json, undefined, 4);
|
|
2996
|
+
let json = JSON.parse( text );
|
|
2997
|
+
return JSON.stringify( json, undefined, 4 );
|
|
2689
2998
|
}
|
|
2690
|
-
catch(e) {
|
|
2691
|
-
alert("Invalid JSON format");
|
|
2999
|
+
catch( e ) {
|
|
3000
|
+
alert( "Invalid JSON format" );
|
|
2692
3001
|
return;
|
|
2693
3002
|
}
|
|
2694
3003
|
}
|
|
@@ -2728,10 +3037,10 @@ class CodeEditor {
|
|
|
2728
3037
|
if( !s.toLowerCase().includes(word.toLowerCase()) )
|
|
2729
3038
|
continue;
|
|
2730
3039
|
|
|
2731
|
-
var pre = document.createElement('pre');
|
|
3040
|
+
var pre = document.createElement( 'pre' );
|
|
2732
3041
|
this.autocomplete.appendChild(pre);
|
|
2733
3042
|
|
|
2734
|
-
var icon = document.createElement('a');
|
|
3043
|
+
var icon = document.createElement( 'a' );
|
|
2735
3044
|
|
|
2736
3045
|
if( this._mustHightlightWord( s, this.utils ) )
|
|
2737
3046
|
icon.className = "fa fa-cube";
|
|
@@ -2784,7 +3093,7 @@ class CodeEditor {
|
|
|
2784
3093
|
hideAutoCompleteBox() {
|
|
2785
3094
|
|
|
2786
3095
|
this.isAutoCompleteActive = false;
|
|
2787
|
-
this.autocomplete.classList.remove('show');
|
|
3096
|
+
this.autocomplete.classList.remove( 'show' );
|
|
2788
3097
|
}
|
|
2789
3098
|
|
|
2790
3099
|
autoCompleteWord( cursor, suggestion ) {
|
|
@@ -2792,7 +3101,7 @@ class CodeEditor {
|
|
|
2792
3101
|
if( !this.isAutoCompleteActive )
|
|
2793
3102
|
return;
|
|
2794
3103
|
|
|
2795
|
-
let [suggestedWord, idx] = this.
|
|
3104
|
+
let [suggestedWord, idx] = this._getSelectedAutoComplete();
|
|
2796
3105
|
suggestedWord = suggestion ?? suggestedWord;
|
|
2797
3106
|
|
|
2798
3107
|
const [word, start, end] = this.getWordAtPos( cursor, -1 );
|
|
@@ -2807,7 +3116,7 @@ class CodeEditor {
|
|
|
2807
3116
|
this.hideAutoCompleteBox();
|
|
2808
3117
|
}
|
|
2809
3118
|
|
|
2810
|
-
|
|
3119
|
+
_getSelectedAutoComplete() {
|
|
2811
3120
|
|
|
2812
3121
|
if( !this.isAutoCompleteActive )
|
|
2813
3122
|
return;
|
|
@@ -2826,12 +3135,12 @@ class CodeEditor {
|
|
|
2826
3135
|
}
|
|
2827
3136
|
}
|
|
2828
3137
|
|
|
2829
|
-
|
|
3138
|
+
_moveArrowSelectedAutoComplete( dir ) {
|
|
2830
3139
|
|
|
2831
3140
|
if( !this.isAutoCompleteActive )
|
|
2832
3141
|
return;
|
|
2833
3142
|
|
|
2834
|
-
const [word, idx] = this.
|
|
3143
|
+
const [word, idx] = this._getSelectedAutoComplete();
|
|
2835
3144
|
const offset = dir == 'down' ? 1 : -1;
|
|
2836
3145
|
|
|
2837
3146
|
if( dir == 'down' ) {
|
|
@@ -2840,12 +3149,51 @@ class CodeEditor {
|
|
|
2840
3149
|
if( (idx + offset) < 0 ) return;
|
|
2841
3150
|
}
|
|
2842
3151
|
|
|
2843
|
-
this.autocomplete.scrollTop += offset *
|
|
3152
|
+
this.autocomplete.scrollTop += offset * 20;
|
|
2844
3153
|
|
|
2845
3154
|
// Remove selected from the current word and add it to the next one
|
|
2846
3155
|
this.autocomplete.childNodes[ idx ].classList.remove('selected');
|
|
2847
3156
|
this.autocomplete.childNodes[ idx + offset ].classList.add('selected');
|
|
2848
3157
|
}
|
|
3158
|
+
|
|
3159
|
+
_updateDataInfoPanel( signal, value ) {
|
|
3160
|
+
|
|
3161
|
+
if( !this.skipCodeInfo )
|
|
3162
|
+
{
|
|
3163
|
+
LX.emit( signal, value );
|
|
3164
|
+
}
|
|
3165
|
+
}
|
|
3166
|
+
|
|
3167
|
+
_setActiveLine( number ) {
|
|
3168
|
+
|
|
3169
|
+
number = number ?? this.state.activeLine;
|
|
3170
|
+
|
|
3171
|
+
this._updateDataInfoPanel( "@cursor-line", "Ln " + ( number + 1 ) );
|
|
3172
|
+
|
|
3173
|
+
const old_local = this.toLocalLine( this.state.activeLine );
|
|
3174
|
+
let line = this.code.childNodes[ old_local ];
|
|
3175
|
+
|
|
3176
|
+
if( !line )
|
|
3177
|
+
return;
|
|
3178
|
+
|
|
3179
|
+
line.classList.remove( 'active-line' );
|
|
3180
|
+
|
|
3181
|
+
// Set new active
|
|
3182
|
+
{
|
|
3183
|
+
this.state.activeLine = number;
|
|
3184
|
+
|
|
3185
|
+
const new_local = this.toLocalLine( number );
|
|
3186
|
+
line = this.code.childNodes[ new_local ];
|
|
3187
|
+
if( line ) line.classList.add( 'active-line' );
|
|
3188
|
+
}
|
|
3189
|
+
}
|
|
3190
|
+
|
|
3191
|
+
_clearTmpVariables() {
|
|
3192
|
+
|
|
3193
|
+
delete this._buildingString;
|
|
3194
|
+
delete this._pendingString;
|
|
3195
|
+
delete this._buildingBlockComment;
|
|
3196
|
+
}
|
|
2849
3197
|
}
|
|
2850
3198
|
|
|
2851
3199
|
LX.CodeEditor = CodeEditor;
|