lexgui 0.1.41 → 0.1.43
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 +451 -271
- package/build/components/timeline.js +165 -109
- package/build/lexgui.css +142 -71
- package/build/lexgui.js +1162 -835
- package/build/lexgui.module.js +979 -647
- package/changelog.md +35 -3
- package/demo.js +16 -12
- package/examples/asset_view.html +3 -2
- package/examples/code_editor.html +11 -6
- package/examples/previews/side_bar.png +0 -0
- package/examples/previews/timeline.png +0 -0
- package/examples/side_bar.html +2 -2
- package/package.json +1 -1
|
@@ -88,7 +88,7 @@ class CodeSelection {
|
|
|
88
88
|
{
|
|
89
89
|
swapElements( this, 'fromX', 'toX' );
|
|
90
90
|
swapElements( this, 'fromY', 'toY' );
|
|
91
|
-
}
|
|
91
|
+
}
|
|
92
92
|
else if( this.sameLine() && this.fromX > this.toX )
|
|
93
93
|
{
|
|
94
94
|
swapElements( this, 'fromX', 'toX' );
|
|
@@ -96,7 +96,7 @@ class CodeSelection {
|
|
|
96
96
|
}
|
|
97
97
|
|
|
98
98
|
selectInline( cursor, x, y, width, isSearchResult ) {
|
|
99
|
-
|
|
99
|
+
|
|
100
100
|
this.chars = width / this.editor.charWidth;
|
|
101
101
|
this.fromX = x;
|
|
102
102
|
this.toX = x + this.chars;
|
|
@@ -104,7 +104,7 @@ class CodeSelection {
|
|
|
104
104
|
|
|
105
105
|
var domEl = document.createElement( 'div' );
|
|
106
106
|
domEl.className = this.className;
|
|
107
|
-
|
|
107
|
+
|
|
108
108
|
domEl._top = y * this.editor.lineHeight;
|
|
109
109
|
domEl.style.top = domEl._top + "px";
|
|
110
110
|
domEl._left = x * this.editor.charWidth;
|
|
@@ -164,9 +164,9 @@ class ScrollBar {
|
|
|
164
164
|
this.root = document.createElement( 'div' );
|
|
165
165
|
this.root.className = "lexcodescrollbar";
|
|
166
166
|
|
|
167
|
-
if( type & ScrollBar.SCROLLBAR_VERTICAL )
|
|
167
|
+
if( type & ScrollBar.SCROLLBAR_VERTICAL )
|
|
168
168
|
this.root.classList.add( 'vertical' );
|
|
169
|
-
else if( type & ScrollBar.SCROLLBAR_HORIZONTAL )
|
|
169
|
+
else if( type & ScrollBar.SCROLLBAR_HORIZONTAL )
|
|
170
170
|
this.root.classList.add( 'horizontal' );
|
|
171
171
|
|
|
172
172
|
this.thumb = document.createElement( 'div' );
|
|
@@ -176,11 +176,11 @@ class ScrollBar {
|
|
|
176
176
|
this.root.appendChild( this.thumb );
|
|
177
177
|
|
|
178
178
|
this.thumb.addEventListener( "mousedown", inner_mousedown );
|
|
179
|
-
|
|
179
|
+
|
|
180
180
|
this.lastPosition = new LX.vec2( 0, 0 );
|
|
181
181
|
|
|
182
182
|
let that = this;
|
|
183
|
-
|
|
183
|
+
|
|
184
184
|
function inner_mousedown( e )
|
|
185
185
|
{
|
|
186
186
|
var doc = editor.root.ownerDocument;
|
|
@@ -194,7 +194,7 @@ class ScrollBar {
|
|
|
194
194
|
function inner_mousemove( e )
|
|
195
195
|
{
|
|
196
196
|
var dt = that.lastPosition.sub( new LX.vec2( e.x, e.y ) );
|
|
197
|
-
if( that.type & ScrollBar.SCROLLBAR_VERTICAL )
|
|
197
|
+
if( that.type & ScrollBar.SCROLLBAR_VERTICAL )
|
|
198
198
|
editor.updateVerticalScrollFromScrollBar( dt.y )
|
|
199
199
|
else
|
|
200
200
|
editor.updateHorizontalScrollFromScrollBar( dt.x )
|
|
@@ -239,7 +239,10 @@ class CodeEditor {
|
|
|
239
239
|
|
|
240
240
|
/**
|
|
241
241
|
* @param {*} options
|
|
242
|
-
*
|
|
242
|
+
* name:
|
|
243
|
+
* skipInfo:
|
|
244
|
+
* fileExplorer:
|
|
245
|
+
* allowAddScripts:
|
|
243
246
|
*/
|
|
244
247
|
|
|
245
248
|
constructor( area, options = {} ) {
|
|
@@ -247,11 +250,11 @@ class CodeEditor {
|
|
|
247
250
|
window.editor = this;
|
|
248
251
|
|
|
249
252
|
CodeEditor.__instances.push( this );
|
|
250
|
-
|
|
253
|
+
|
|
251
254
|
// File explorer
|
|
252
|
-
if( options.
|
|
255
|
+
if( options.fileExplorer ?? false )
|
|
253
256
|
{
|
|
254
|
-
var [explorerArea, codeArea] = area.split({ sizes:["15%","85%"] });
|
|
257
|
+
var [ explorerArea, codeArea ] = area.split({ sizes:[ "15%","85%" ] });
|
|
255
258
|
explorerArea.setLimitBox( 180, 20, 512 );
|
|
256
259
|
this.explorerArea = explorerArea;
|
|
257
260
|
|
|
@@ -259,40 +262,42 @@ class CodeEditor {
|
|
|
259
262
|
|
|
260
263
|
panel.addTitle( "EXPLORER" );
|
|
261
264
|
|
|
265
|
+
this._tabStorage = {};
|
|
266
|
+
|
|
262
267
|
let sceneData = {
|
|
263
268
|
'id': 'WORKSPACE',
|
|
264
269
|
'skipVisibility': true,
|
|
265
270
|
'children': []
|
|
266
271
|
};
|
|
267
|
-
|
|
268
|
-
this.explorer = panel.addTree( null, sceneData, {
|
|
272
|
+
|
|
273
|
+
this.explorer = panel.addTree( null, sceneData, {
|
|
269
274
|
filter: false,
|
|
270
275
|
rename: false,
|
|
271
276
|
skip_default_icon: true,
|
|
272
|
-
onevent: (event) => {
|
|
277
|
+
onevent: (event) => {
|
|
273
278
|
switch(event.type) {
|
|
274
279
|
// case LX.TreeEvent.NODE_SELECTED:
|
|
275
280
|
// if( !this.tabs.tabDOMs[ event.node.id ] ) break;
|
|
276
281
|
case LX.TreeEvent.NODE_DBLCLICKED:
|
|
277
282
|
this.loadTab( event.node.id );
|
|
278
283
|
break;
|
|
279
|
-
case LX.TreeEvent.NODE_DELETED:
|
|
284
|
+
case LX.TreeEvent.NODE_DELETED:
|
|
280
285
|
this.tabs.delete( event.node.id );
|
|
281
286
|
delete this.loadedTabs[ event.node.id ];
|
|
282
287
|
break;
|
|
283
|
-
// case LX.TreeEvent.NODE_CONTEXTMENU:
|
|
288
|
+
// case LX.TreeEvent.NODE_CONTEXTMENU:
|
|
284
289
|
// LX.addContextMenu( event.multiple ? "Selected Nodes" : event.node.id, event.value, m => {
|
|
285
|
-
//
|
|
290
|
+
//
|
|
286
291
|
// });
|
|
287
292
|
// break;
|
|
288
|
-
// case LX.TreeEvent.NODE_DRAGGED:
|
|
289
|
-
// console.log(event.node.id + " is now child of " + event.value.id);
|
|
293
|
+
// case LX.TreeEvent.NODE_DRAGGED:
|
|
294
|
+
// console.log(event.node.id + " is now child of " + event.value.id);
|
|
290
295
|
// break;
|
|
291
296
|
}
|
|
292
297
|
}
|
|
293
|
-
});
|
|
298
|
+
});
|
|
294
299
|
|
|
295
|
-
this.addExplorerItem = function( item )
|
|
300
|
+
this.addExplorerItem = function( item )
|
|
296
301
|
{
|
|
297
302
|
if( !this.explorer.data.children.find( (value, index) => value.id === item.id ) )
|
|
298
303
|
this.explorer.data.children.push( item );
|
|
@@ -305,7 +310,7 @@ class CodeEditor {
|
|
|
305
310
|
}
|
|
306
311
|
|
|
307
312
|
this.base_area = area;
|
|
308
|
-
this.area = new LX.Area( { className: "lexcodeeditor", height: "100%",
|
|
313
|
+
this.area = new LX.Area( { className: "lexcodeeditor", height: "100%", skipAppend: true } );
|
|
309
314
|
|
|
310
315
|
this.tabs = this.area.addTabs( { onclose: (name) => {
|
|
311
316
|
delete this.openedTabs[ name ];
|
|
@@ -315,8 +320,9 @@ class CodeEditor {
|
|
|
315
320
|
this.cursors.classList.remove( 'show' );
|
|
316
321
|
}
|
|
317
322
|
} } );
|
|
323
|
+
|
|
318
324
|
this.tabs.root.addEventListener( 'dblclick', (e) => {
|
|
319
|
-
if( options.
|
|
325
|
+
if( options.allowAddScripts ?? true ) {
|
|
320
326
|
e.preventDefault();
|
|
321
327
|
this.addTab("unnamed.js", true);
|
|
322
328
|
}
|
|
@@ -332,8 +338,8 @@ class CodeEditor {
|
|
|
332
338
|
this.root.tabIndex = -1;
|
|
333
339
|
area.attach( this.root );
|
|
334
340
|
|
|
335
|
-
this.skipCodeInfo = options.
|
|
336
|
-
this.disableEdition = options.
|
|
341
|
+
this.skipCodeInfo = options.skipInfo ?? false;
|
|
342
|
+
this.disableEdition = options.disableEdition ?? false;
|
|
337
343
|
|
|
338
344
|
if( !this.disableEdition )
|
|
339
345
|
{
|
|
@@ -341,7 +347,7 @@ class CodeEditor {
|
|
|
341
347
|
this.root.addEventListener( 'focus', this.processFocus.bind( this, true ) );
|
|
342
348
|
this.root.addEventListener( 'focusout', this.processFocus.bind( this, false ) );
|
|
343
349
|
}
|
|
344
|
-
|
|
350
|
+
|
|
345
351
|
this.root.addEventListener( 'mousedown', this.processMouse.bind(this) );
|
|
346
352
|
this.root.addEventListener( 'mouseup', this.processMouse.bind(this) );
|
|
347
353
|
this.root.addEventListener( 'mousemove', this.processMouse.bind(this) );
|
|
@@ -397,8 +403,8 @@ class CodeEditor {
|
|
|
397
403
|
if( this.visibleLinesViewport.y < (this.code.lines.length - 1) )
|
|
398
404
|
{
|
|
399
405
|
const totalLinesInViewport = ((this.codeScroller.offsetHeight - 36) / this.lineHeight)|0;
|
|
400
|
-
const scrollDownBoundary =
|
|
401
|
-
( Math.max( this.visibleLinesViewport.y - totalLinesInViewport, 0 ) - 1 ) * this.lineHeight;
|
|
406
|
+
const scrollDownBoundary =
|
|
407
|
+
( Math.max( this.visibleLinesViewport.y - totalLinesInViewport, 0 ) - 1 ) * this.lineHeight;
|
|
402
408
|
|
|
403
409
|
if( scrollTop >= scrollDownBoundary )
|
|
404
410
|
this.processLines( CodeEditor.UPDATE_VISIBLE_LINES );
|
|
@@ -462,7 +468,7 @@ class CodeEditor {
|
|
|
462
468
|
{
|
|
463
469
|
var box = document.createElement( 'div' );
|
|
464
470
|
box.className = "searchbox";
|
|
465
|
-
|
|
471
|
+
|
|
466
472
|
var searchPanel = new LX.Panel();
|
|
467
473
|
box.appendChild( searchPanel.root );
|
|
468
474
|
|
|
@@ -485,7 +491,7 @@ class CodeEditor {
|
|
|
485
491
|
{
|
|
486
492
|
var box = document.createElement( 'div' );
|
|
487
493
|
box.className = "searchbox gotoline";
|
|
488
|
-
|
|
494
|
+
|
|
489
495
|
var searchPanel = new LX.Panel();
|
|
490
496
|
box.appendChild( searchPanel.root );
|
|
491
497
|
|
|
@@ -507,7 +513,7 @@ class CodeEditor {
|
|
|
507
513
|
{
|
|
508
514
|
this.codeSizer = document.createElement( 'div' );
|
|
509
515
|
this.codeSizer.className = "code-sizer";
|
|
510
|
-
|
|
516
|
+
|
|
511
517
|
// Append all childs
|
|
512
518
|
while( this.codeScroller.firstChild )
|
|
513
519
|
this.codeSizer.appendChild( this.codeScroller.firstChild );
|
|
@@ -549,7 +555,7 @@ class CodeEditor {
|
|
|
549
555
|
};
|
|
550
556
|
|
|
551
557
|
this.stringKeys = { // adding @ because some words are always true in (e.g. constructor..)
|
|
552
|
-
"@\"": "\"",
|
|
558
|
+
"@\"": "\"",
|
|
553
559
|
"@'": "'"
|
|
554
560
|
};
|
|
555
561
|
|
|
@@ -559,8 +565,10 @@ class CodeEditor {
|
|
|
559
565
|
this.languages = {
|
|
560
566
|
'Plain Text': { ext: 'txt', blockComments: false, singleLineComments: false },
|
|
561
567
|
'JavaScript': { ext: 'js' },
|
|
562
|
-
'C
|
|
568
|
+
'C': { ext: [ 'c', 'h' ] },
|
|
569
|
+
'C++': { ext: [ 'cpp', 'hpp' ] },
|
|
563
570
|
'CSS': { ext: 'css' },
|
|
571
|
+
'CMake': { ext: 'cmake', singleLineCommentToken: '#', blockComments: false, ignoreCase: true },
|
|
564
572
|
'GLSL': { ext: 'glsl' },
|
|
565
573
|
'WGSL': { ext: 'wgsl' },
|
|
566
574
|
'JSON': { ext: 'json', blockComments: false, singleLineComments: false },
|
|
@@ -573,7 +581,7 @@ class CodeEditor {
|
|
|
573
581
|
};
|
|
574
582
|
|
|
575
583
|
this.specialKeys = [
|
|
576
|
-
'Backspace', 'Enter', 'ArrowUp', 'ArrowDown',
|
|
584
|
+
'Backspace', 'Enter', 'ArrowUp', 'ArrowDown',
|
|
577
585
|
'ArrowRight', 'ArrowLeft', 'Delete', 'Home',
|
|
578
586
|
'End', 'Tab', 'Escape'
|
|
579
587
|
];
|
|
@@ -587,10 +595,10 @@ class CodeEditor {
|
|
|
587
595
|
for( let lang in CodeEditor.keywords ) CodeEditor.keywords[lang] = CodeEditor.keywords[lang].reduce((a, v) => ({ ...a, [v]: true}), {});
|
|
588
596
|
for( let lang in CodeEditor.utils ) CodeEditor.utils[lang] = CodeEditor.utils[lang].reduce((a, v) => ({ ...a, [v]: true}), {});
|
|
589
597
|
for( let lang in CodeEditor.types ) CodeEditor.types[lang] = CodeEditor.types[lang].reduce((a, v) => ({ ...a, [v]: true}), {});
|
|
590
|
-
for( let lang in CodeEditor.
|
|
598
|
+
for( let lang in CodeEditor.builtIn ) CodeEditor.builtIn[lang] = CodeEditor.builtIn[lang].reduce((a, v) => ({ ...a, [v]: true}), {});
|
|
591
599
|
for( let lang in CodeEditor.statementsAndDeclarations ) CodeEditor.statementsAndDeclarations[lang] = CodeEditor.statementsAndDeclarations[lang].reduce((a, v) => ({ ...a, [v]: true}), {});
|
|
592
600
|
for( let lang in CodeEditor.symbols ) CodeEditor.symbols[lang] = CodeEditor.symbols[lang].reduce((a, v) => ({ ...a, [v]: true}), {});
|
|
593
|
-
|
|
601
|
+
|
|
594
602
|
CodeEditor._staticReady = true;
|
|
595
603
|
}
|
|
596
604
|
|
|
@@ -613,7 +621,7 @@ class CodeEditor {
|
|
|
613
621
|
if( cursor.selection ) {
|
|
614
622
|
this.deleteSelection( cursor );
|
|
615
623
|
// Remove entire line when selecting with triple click
|
|
616
|
-
if( this._tripleClickSelection )
|
|
624
|
+
if( this._tripleClickSelection )
|
|
617
625
|
{
|
|
618
626
|
this.actions['Backspace'].callback( ln, cursor, e );
|
|
619
627
|
this.lineDown( cursor, true );
|
|
@@ -626,7 +634,7 @@ class CodeEditor {
|
|
|
626
634
|
|
|
627
635
|
var deleteFromPosition = cursor.position - 1;
|
|
628
636
|
var numCharsDeleted = 1;
|
|
629
|
-
|
|
637
|
+
|
|
630
638
|
// Delete full word
|
|
631
639
|
if( e.shiftKey )
|
|
632
640
|
{
|
|
@@ -646,7 +654,7 @@ class CodeEditor {
|
|
|
646
654
|
|
|
647
655
|
if( this.useAutoComplete )
|
|
648
656
|
this.showAutoCompleteBox( 'foo', cursor );
|
|
649
|
-
}
|
|
657
|
+
}
|
|
650
658
|
else if( this.code.lines[ ln - 1 ] != undefined ) {
|
|
651
659
|
|
|
652
660
|
this.lineUp( cursor );
|
|
@@ -663,7 +671,7 @@ class CodeEditor {
|
|
|
663
671
|
this.action( 'Delete', false, ( ln, cursor, e ) => {
|
|
664
672
|
|
|
665
673
|
this._addUndoStep( cursor );
|
|
666
|
-
|
|
674
|
+
|
|
667
675
|
if( cursor.selection ) {
|
|
668
676
|
// Use 'Backspace' as it's the same callback...
|
|
669
677
|
this.actions['Backspace'].callback( ln, cursor, e );
|
|
@@ -674,7 +682,7 @@ class CodeEditor {
|
|
|
674
682
|
if( letter ) {
|
|
675
683
|
this.code.lines[ ln ] = sliceChars( this.code.lines[ ln ], cursor.position );
|
|
676
684
|
this.processLine( ln );
|
|
677
|
-
}
|
|
685
|
+
}
|
|
678
686
|
else if( this.code.lines[ ln + 1 ] != undefined ) {
|
|
679
687
|
this.code.lines[ ln ] += this.code.lines[ ln + 1 ];
|
|
680
688
|
this.code.lines.splice( ln + 1, 1 );
|
|
@@ -684,7 +692,7 @@ class CodeEditor {
|
|
|
684
692
|
});
|
|
685
693
|
|
|
686
694
|
this.action( 'Tab', true, ( ln, cursor, e ) => {
|
|
687
|
-
|
|
695
|
+
|
|
688
696
|
if( this._skipTabs )
|
|
689
697
|
{
|
|
690
698
|
this._skipTabs--;
|
|
@@ -712,7 +720,7 @@ class CodeEditor {
|
|
|
712
720
|
}, "shiftKey");
|
|
713
721
|
|
|
714
722
|
this.action( 'Home', false, ( ln, cursor, e ) => {
|
|
715
|
-
|
|
723
|
+
|
|
716
724
|
let idx = firstNonspaceIndex( this.code.lines[ ln ] );
|
|
717
725
|
|
|
718
726
|
// We already are in the first non space index...
|
|
@@ -732,7 +740,7 @@ class CodeEditor {
|
|
|
732
740
|
if( e.shiftKey && !e.cancelShift )
|
|
733
741
|
{
|
|
734
742
|
// Get last selection range
|
|
735
|
-
if( cursor.selection )
|
|
743
|
+
if( cursor.selection )
|
|
736
744
|
lastX += cursor.selection.chars;
|
|
737
745
|
|
|
738
746
|
if( !cursor.selection )
|
|
@@ -750,9 +758,9 @@ class CodeEditor {
|
|
|
750
758
|
});
|
|
751
759
|
|
|
752
760
|
this.action( 'End', false, ( ln, cursor, e ) => {
|
|
753
|
-
|
|
761
|
+
|
|
754
762
|
if( ( e.shiftKey || e._shiftKey ) && !e.cancelShift ) {
|
|
755
|
-
|
|
763
|
+
|
|
756
764
|
var string = this.code.lines[ ln ].substring( cursor.position );
|
|
757
765
|
if( !cursor.selection )
|
|
758
766
|
this.startSelection( cursor );
|
|
@@ -761,7 +769,7 @@ class CodeEditor {
|
|
|
761
769
|
else
|
|
762
770
|
{
|
|
763
771
|
this.resetCursorPos( CodeEditor.CURSOR_LEFT, cursor );
|
|
764
|
-
this.cursorToString( cursor, this.code.lines[ ln ] );
|
|
772
|
+
this.cursorToString( cursor, this.code.lines[ ln ] );
|
|
765
773
|
this._processSelection( cursor, e );
|
|
766
774
|
}
|
|
767
775
|
} else if( !e.keepSelection )
|
|
@@ -833,7 +841,7 @@ class CodeEditor {
|
|
|
833
841
|
if( !letter ) {
|
|
834
842
|
this.cursorToPosition( cursor, this.code.lines[ cursor.line ].length );
|
|
835
843
|
}
|
|
836
|
-
|
|
844
|
+
|
|
837
845
|
this._processSelection( cursor, e, false );
|
|
838
846
|
|
|
839
847
|
} else {
|
|
@@ -843,7 +851,7 @@ class CodeEditor {
|
|
|
843
851
|
var letter = this.getCharAtPos( cursor );
|
|
844
852
|
if( !letter ) this.actions['End'].callback( cursor.line, cursor, e );
|
|
845
853
|
}
|
|
846
|
-
}
|
|
854
|
+
}
|
|
847
855
|
// Move up autocomplete selection
|
|
848
856
|
else
|
|
849
857
|
{
|
|
@@ -874,7 +882,7 @@ class CodeEditor {
|
|
|
874
882
|
if( e.shiftKey ) {
|
|
875
883
|
this._processSelection( cursor, e );
|
|
876
884
|
}
|
|
877
|
-
}
|
|
885
|
+
}
|
|
878
886
|
// Move down autocomplete selection
|
|
879
887
|
else
|
|
880
888
|
{
|
|
@@ -910,7 +918,7 @@ class CodeEditor {
|
|
|
910
918
|
// Selections...
|
|
911
919
|
if( e.shiftKey ) {
|
|
912
920
|
if( !cursor.selection )
|
|
913
|
-
this.startSelection( cursor );
|
|
921
|
+
this.startSelection( cursor );
|
|
914
922
|
}
|
|
915
923
|
else
|
|
916
924
|
this.endSelection();
|
|
@@ -944,9 +952,9 @@ class CodeEditor {
|
|
|
944
952
|
}
|
|
945
953
|
}
|
|
946
954
|
else if( cursor.line > 0 ) {
|
|
947
|
-
|
|
955
|
+
|
|
948
956
|
if( e.shiftKey && !cursor.selection ) this.startSelection( cursor );
|
|
949
|
-
|
|
957
|
+
|
|
950
958
|
this.lineUp( cursor );
|
|
951
959
|
|
|
952
960
|
e.cancelShift = e.keepSelection = true;
|
|
@@ -961,7 +969,7 @@ class CodeEditor {
|
|
|
961
969
|
this.action( 'ArrowRight', false, ( ln, cursor, e ) => {
|
|
962
970
|
|
|
963
971
|
// Nothing to do..
|
|
964
|
-
if( cursor.line == this.code.lines.length - 1 &&
|
|
972
|
+
if( cursor.line == this.code.lines.length - 1 &&
|
|
965
973
|
cursor.position == this.code.lines[ cursor.line ].length )
|
|
966
974
|
return;
|
|
967
975
|
|
|
@@ -1025,14 +1033,14 @@ class CodeEditor {
|
|
|
1025
1033
|
}
|
|
1026
1034
|
}
|
|
1027
1035
|
else if( this.code.lines[ cursor.line + 1 ] !== undefined ) {
|
|
1028
|
-
|
|
1036
|
+
|
|
1029
1037
|
if( e.shiftKey ) {
|
|
1030
1038
|
if( !cursor.selection ) this.startSelection( cursor );
|
|
1031
1039
|
}
|
|
1032
1040
|
else this.endSelection();
|
|
1033
1041
|
|
|
1034
1042
|
this.lineDown( cursor, true );
|
|
1035
|
-
|
|
1043
|
+
|
|
1036
1044
|
if( e.shiftKey ) this._processSelection( cursor, e, false );
|
|
1037
1045
|
|
|
1038
1046
|
this.hideAutoCompleteBox();
|
|
@@ -1041,14 +1049,16 @@ class CodeEditor {
|
|
|
1041
1049
|
});
|
|
1042
1050
|
|
|
1043
1051
|
// Default code tab
|
|
1044
|
-
|
|
1052
|
+
|
|
1045
1053
|
this.loadedTabs = { };
|
|
1046
1054
|
this.openedTabs = { };
|
|
1047
|
-
|
|
1048
|
-
if( options.
|
|
1055
|
+
|
|
1056
|
+
if( options.allowAddScripts ?? true )
|
|
1057
|
+
{
|
|
1049
1058
|
this.addTab("+", false, "New File");
|
|
1059
|
+
}
|
|
1050
1060
|
|
|
1051
|
-
this.addTab( options.name || "untitled", true, options.title );
|
|
1061
|
+
this.addTab( options.name || "untitled", true, options.title, { language: "CSS" } );
|
|
1052
1062
|
|
|
1053
1063
|
// Create inspector panel
|
|
1054
1064
|
let panel = this._createPanelInfo();
|
|
@@ -1064,7 +1074,7 @@ class CodeEditor {
|
|
|
1064
1074
|
display: "swap"
|
|
1065
1075
|
}
|
|
1066
1076
|
);
|
|
1067
|
-
|
|
1077
|
+
|
|
1068
1078
|
// Add to the document.fonts (FontFaceSet)
|
|
1069
1079
|
document.fonts.add( commitMono );
|
|
1070
1080
|
|
|
@@ -1085,7 +1095,7 @@ class CodeEditor {
|
|
|
1085
1095
|
|
|
1086
1096
|
// This received key inputs from the entire document...
|
|
1087
1097
|
onKeyPressed( e ) {
|
|
1088
|
-
|
|
1098
|
+
|
|
1089
1099
|
// Toggle visibility of the file explorer
|
|
1090
1100
|
if( e.key == 'b' && e.ctrlKey && this.explorer )
|
|
1091
1101
|
{
|
|
@@ -1154,7 +1164,7 @@ class CodeEditor {
|
|
|
1154
1164
|
|
|
1155
1165
|
// Add first line
|
|
1156
1166
|
this.code.lines[ lidx ] = [
|
|
1157
|
-
this.code.lines[ lidx ].slice( 0, cursor.position ),
|
|
1167
|
+
this.code.lines[ lidx ].slice( 0, cursor.position ),
|
|
1158
1168
|
first_line
|
|
1159
1169
|
].join('');
|
|
1160
1170
|
|
|
@@ -1181,8 +1191,8 @@ class CodeEditor {
|
|
|
1181
1191
|
else
|
|
1182
1192
|
{
|
|
1183
1193
|
this.code.lines[ lidx ] = [
|
|
1184
|
-
this.code.lines[ lidx ].slice( 0, cursor.position ),
|
|
1185
|
-
new_lines[ 0 ],
|
|
1194
|
+
this.code.lines[ lidx ].slice( 0, cursor.position ),
|
|
1195
|
+
new_lines[ 0 ],
|
|
1186
1196
|
this.code.lines[ lidx ].slice( cursor.position )
|
|
1187
1197
|
].join('');
|
|
1188
1198
|
|
|
@@ -1191,7 +1201,7 @@ class CodeEditor {
|
|
|
1191
1201
|
}
|
|
1192
1202
|
}
|
|
1193
1203
|
|
|
1194
|
-
loadFile( file ) {
|
|
1204
|
+
loadFile( file, options = {} ) {
|
|
1195
1205
|
|
|
1196
1206
|
const inner_add_tab = ( text, name, title ) => {
|
|
1197
1207
|
|
|
@@ -1207,16 +1217,25 @@ class CodeEditor {
|
|
|
1207
1217
|
|
|
1208
1218
|
if( this.explorer )
|
|
1209
1219
|
{
|
|
1210
|
-
this.
|
|
1211
|
-
|
|
1212
|
-
|
|
1220
|
+
this._tabStorage[ name ] = {
|
|
1221
|
+
lines: lines,
|
|
1222
|
+
options: options
|
|
1223
|
+
};
|
|
1224
|
+
|
|
1225
|
+
const ext = this.languages[ options.language ] ?. ext;
|
|
1226
|
+
this.addExplorerItem( { 'id': name, 'skipVisibility': true, 'icon': this._getFileIcon( name, ext ) } );
|
|
1213
1227
|
this.explorer.frefresh( name );
|
|
1214
1228
|
}
|
|
1215
1229
|
else
|
|
1216
1230
|
{
|
|
1217
|
-
this.addTab(name, true, title);
|
|
1231
|
+
this.addTab( name, true, title, options );
|
|
1218
1232
|
this.code.lines = lines;
|
|
1219
|
-
|
|
1233
|
+
|
|
1234
|
+
// Default inferred language if not specified
|
|
1235
|
+
if( !options.language )
|
|
1236
|
+
{
|
|
1237
|
+
this._changeLanguageFromExtension( LX.getExtension( name ) );
|
|
1238
|
+
}
|
|
1220
1239
|
}
|
|
1221
1240
|
};
|
|
1222
1241
|
|
|
@@ -1224,7 +1243,6 @@ class CodeEditor {
|
|
|
1224
1243
|
{
|
|
1225
1244
|
let filename = file;
|
|
1226
1245
|
LX.request({ url: filename, success: text => {
|
|
1227
|
-
|
|
1228
1246
|
const name = filename.substring(filename.lastIndexOf( '/' ) + 1);
|
|
1229
1247
|
inner_add_tab( text, name, filename );
|
|
1230
1248
|
} });
|
|
@@ -1233,7 +1251,7 @@ class CodeEditor {
|
|
|
1233
1251
|
{
|
|
1234
1252
|
const fr = new FileReader();
|
|
1235
1253
|
fr.readAsText( file );
|
|
1236
|
-
fr.onload = e => {
|
|
1254
|
+
fr.onload = e => {
|
|
1237
1255
|
const text = e.currentTarget.result;
|
|
1238
1256
|
inner_add_tab( text, file.name );
|
|
1239
1257
|
};
|
|
@@ -1251,7 +1269,7 @@ class CodeEditor {
|
|
|
1251
1269
|
|
|
1252
1270
|
return;
|
|
1253
1271
|
}
|
|
1254
|
-
|
|
1272
|
+
|
|
1255
1273
|
let cursor = document.createElement( 'div' );
|
|
1256
1274
|
cursor.name = "cursor" + this.cursors.childElementCount;
|
|
1257
1275
|
cursor.className = "cursor";
|
|
@@ -1268,7 +1286,7 @@ class CodeEditor {
|
|
|
1268
1286
|
|
|
1269
1287
|
Object.defineProperty( cursor, 'line', {
|
|
1270
1288
|
get: (v) => { return cursor._line },
|
|
1271
|
-
set: (v) => {
|
|
1289
|
+
set: (v) => {
|
|
1272
1290
|
cursor._line = v;
|
|
1273
1291
|
if( cursor.isMain ) this._setActiveLine( v );
|
|
1274
1292
|
}
|
|
@@ -1276,7 +1294,7 @@ class CodeEditor {
|
|
|
1276
1294
|
|
|
1277
1295
|
Object.defineProperty( cursor, 'position', {
|
|
1278
1296
|
get: (v) => { return cursor._position },
|
|
1279
|
-
set: (v) => {
|
|
1297
|
+
set: (v) => {
|
|
1280
1298
|
cursor._position = v;
|
|
1281
1299
|
if( cursor.isMain ) this._updateDataInfoPanel( "@cursor-pos", "Col " + ( v + 1 ) );
|
|
1282
1300
|
}
|
|
@@ -1335,7 +1353,7 @@ class CodeEditor {
|
|
|
1335
1353
|
}
|
|
1336
1354
|
}
|
|
1337
1355
|
|
|
1338
|
-
if( deleteRedo )
|
|
1356
|
+
if( deleteRedo )
|
|
1339
1357
|
{
|
|
1340
1358
|
// Remove all redo steps
|
|
1341
1359
|
this.code.redoSteps.length = 0;
|
|
@@ -1417,10 +1435,16 @@ class CodeEditor {
|
|
|
1417
1435
|
}
|
|
1418
1436
|
}
|
|
1419
1437
|
|
|
1420
|
-
_changeLanguage( lang ) {
|
|
1438
|
+
_changeLanguage( lang, override = false ) {
|
|
1421
1439
|
|
|
1422
1440
|
this.code.language = lang;
|
|
1423
1441
|
this.highlight = lang;
|
|
1442
|
+
|
|
1443
|
+
if( override )
|
|
1444
|
+
{
|
|
1445
|
+
this.code.languageOverride = lang;
|
|
1446
|
+
}
|
|
1447
|
+
|
|
1424
1448
|
this._updateDataInfoPanel( "@highlight", lang );
|
|
1425
1449
|
this.processLines();
|
|
1426
1450
|
|
|
@@ -1437,7 +1461,8 @@ class CodeEditor {
|
|
|
1437
1461
|
{
|
|
1438
1462
|
iconEl = document.createElement( 'i' );
|
|
1439
1463
|
iconEl.className = icon;
|
|
1440
|
-
} else
|
|
1464
|
+
} else
|
|
1465
|
+
{
|
|
1441
1466
|
iconEl = document.createElement( 'img' );
|
|
1442
1467
|
iconEl.src = "https://raw.githubusercontent.com/jxarco/lexgui.js/master/" + icon;
|
|
1443
1468
|
}
|
|
@@ -1455,21 +1480,38 @@ class CodeEditor {
|
|
|
1455
1480
|
}
|
|
1456
1481
|
|
|
1457
1482
|
_changeLanguageFromExtension( ext ) {
|
|
1458
|
-
|
|
1483
|
+
|
|
1459
1484
|
if( !ext )
|
|
1460
|
-
|
|
1485
|
+
{
|
|
1486
|
+
return this._changeLanguage( this.code.language );
|
|
1487
|
+
}
|
|
1461
1488
|
|
|
1462
1489
|
for( let l in this.languages )
|
|
1463
1490
|
{
|
|
1464
|
-
|
|
1465
|
-
|
|
1491
|
+
const langExtension = this.languages[ l ].ext;
|
|
1492
|
+
|
|
1493
|
+
if( langExtension.constructor == Array )
|
|
1494
|
+
{
|
|
1495
|
+
if( langExtension.indexOf( ext ) > -1 )
|
|
1496
|
+
{
|
|
1497
|
+
return this._changeLanguage( l );
|
|
1498
|
+
}
|
|
1499
|
+
}
|
|
1500
|
+
else
|
|
1501
|
+
{
|
|
1502
|
+
if( langExtension == ext )
|
|
1503
|
+
{
|
|
1504
|
+
return this._changeLanguage( l );
|
|
1505
|
+
}
|
|
1506
|
+
}
|
|
1507
|
+
|
|
1466
1508
|
}
|
|
1467
1509
|
|
|
1468
1510
|
this._changeLanguage( 'Plain Text' );
|
|
1469
1511
|
}
|
|
1470
1512
|
|
|
1471
1513
|
_createPanelInfo() {
|
|
1472
|
-
|
|
1514
|
+
|
|
1473
1515
|
if( !this.skipCodeInfo )
|
|
1474
1516
|
{
|
|
1475
1517
|
let panel = new LX.Panel({ className: "lexcodetabinfo", width: "calc(100%)", height: "auto" });
|
|
@@ -1491,8 +1533,12 @@ class CodeEditor {
|
|
|
1491
1533
|
}, { width: "10%", nameWidth: "15%", signal: "@tab-spaces" });
|
|
1492
1534
|
panel.addButton( "<b>{ }</b>", this.highlight, ( value, event ) => {
|
|
1493
1535
|
LX.addContextMenu( "Language", event, m => {
|
|
1494
|
-
for( const lang of Object.keys(this.languages) )
|
|
1495
|
-
|
|
1536
|
+
for( const lang of Object.keys( this.languages ) )
|
|
1537
|
+
{
|
|
1538
|
+
m.add( lang, v => {
|
|
1539
|
+
this._changeLanguage( v, true )
|
|
1540
|
+
} );
|
|
1541
|
+
}
|
|
1496
1542
|
});
|
|
1497
1543
|
}, { width: "17.5%", nameWidth: "15%", signal: "@highlight" });
|
|
1498
1544
|
panel.endLine();
|
|
@@ -1517,12 +1563,36 @@ class CodeEditor {
|
|
|
1517
1563
|
_getFileIcon( name, extension ) {
|
|
1518
1564
|
|
|
1519
1565
|
const isNewTabButton = name ? ( name === '+' ) : false;
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1566
|
+
|
|
1567
|
+
if( !extension )
|
|
1568
|
+
{
|
|
1569
|
+
extension = LX.getExtension( name );
|
|
1570
|
+
}
|
|
1571
|
+
else
|
|
1572
|
+
{
|
|
1573
|
+
const possibleExtensions = [].concat( extension );
|
|
1574
|
+
|
|
1575
|
+
if( name )
|
|
1576
|
+
{
|
|
1577
|
+
const fileExtension = LX.getExtension( name );
|
|
1578
|
+
const idx = possibleExtensions.indexOf( fileExtension );
|
|
1579
|
+
|
|
1580
|
+
if( idx > -1)
|
|
1581
|
+
{
|
|
1582
|
+
extension = possibleExtensions[ idx ];
|
|
1583
|
+
}
|
|
1584
|
+
}
|
|
1585
|
+
else
|
|
1586
|
+
{
|
|
1587
|
+
extension = possibleExtensions[ 0 ];
|
|
1588
|
+
}
|
|
1589
|
+
}
|
|
1590
|
+
|
|
1591
|
+
return extension == "html" ? "fa-solid fa-code orange" :
|
|
1592
|
+
extension == "css" ? "fa-solid fa-hashtag dodgerblue" :
|
|
1593
|
+
extension == "xml" ? "fa-solid fa-rss orange" :
|
|
1594
|
+
extension == "bat" ? "fa-brands fa-windows lightblue" :
|
|
1595
|
+
[ 'js', 'py', 'json', 'cpp', 'hpp', 'rs', 'md' ].indexOf( extension ) > -1 ? "images/" + extension + ".png" :
|
|
1526
1596
|
!isNewTabButton ? "fa-solid fa-align-left gray" : undefined;
|
|
1527
1597
|
}
|
|
1528
1598
|
|
|
@@ -1547,18 +1617,26 @@ class CodeEditor {
|
|
|
1547
1617
|
this._removeSecondaryCursors();
|
|
1548
1618
|
var cursor = this._getCurrentCursor( true );
|
|
1549
1619
|
|
|
1550
|
-
this.saveCursor( cursor, this.code.cursorState );
|
|
1620
|
+
this.saveCursor( cursor, this.code.cursorState );
|
|
1551
1621
|
|
|
1552
1622
|
this.code = this.loadedTabs[ name ];
|
|
1553
|
-
this.restoreCursor( cursor, this.code.cursorState );
|
|
1623
|
+
this.restoreCursor( cursor, this.code.cursorState );
|
|
1554
1624
|
|
|
1555
1625
|
this.endSelection();
|
|
1556
|
-
this._changeLanguageFromExtension( LX.getExtension( name ) );
|
|
1557
1626
|
this._updateDataInfoPanel( "@tab-name", name );
|
|
1627
|
+
|
|
1628
|
+
if( this.code.languageOverride )
|
|
1629
|
+
{
|
|
1630
|
+
this._changeLanguage( this.code.languageOverride );
|
|
1631
|
+
}
|
|
1632
|
+
else
|
|
1633
|
+
{
|
|
1634
|
+
this._changeLanguageFromExtension( LX.getExtension( name ) );
|
|
1635
|
+
}
|
|
1558
1636
|
}
|
|
1559
1637
|
|
|
1560
1638
|
_onContextMenuTab( isNewTabButton, event, name, ) {
|
|
1561
|
-
|
|
1639
|
+
|
|
1562
1640
|
if( isNewTabButton )
|
|
1563
1641
|
return;
|
|
1564
1642
|
|
|
@@ -1569,8 +1647,8 @@ class CodeEditor {
|
|
|
1569
1647
|
});
|
|
1570
1648
|
}
|
|
1571
1649
|
|
|
1572
|
-
addTab( name, selected, title ) {
|
|
1573
|
-
|
|
1650
|
+
addTab( name, selected, title, options = {} ) {
|
|
1651
|
+
|
|
1574
1652
|
// If already loaded, set new name...
|
|
1575
1653
|
const repeats = Object.keys( editor.loadedTabs ).slice( 1 ).reduce( ( v, key ) => {
|
|
1576
1654
|
const noRepeatName = key.replace( /[_\d+]/g, '');
|
|
@@ -1586,7 +1664,7 @@ class CodeEditor {
|
|
|
1586
1664
|
let code = document.createElement( 'div' );
|
|
1587
1665
|
code.className = 'code';
|
|
1588
1666
|
code.lines = [ "" ];
|
|
1589
|
-
code.language = "Plain Text";
|
|
1667
|
+
code.language = options.language ?? "Plain Text";
|
|
1590
1668
|
code.cursorState = {};
|
|
1591
1669
|
code.undoSteps = [];
|
|
1592
1670
|
code.redoSteps = [];
|
|
@@ -1613,7 +1691,7 @@ class CodeEditor {
|
|
|
1613
1691
|
|
|
1614
1692
|
this.loadedTabs[ name ] = code;
|
|
1615
1693
|
this.openedTabs[ name ] = code;
|
|
1616
|
-
|
|
1694
|
+
|
|
1617
1695
|
const tabIcon = this._getFileIcon( name );
|
|
1618
1696
|
|
|
1619
1697
|
if( this.explorer && !isNewTabButton )
|
|
@@ -1622,27 +1700,33 @@ class CodeEditor {
|
|
|
1622
1700
|
this.explorer.frefresh( name );
|
|
1623
1701
|
}
|
|
1624
1702
|
|
|
1625
|
-
this.tabs.add( name, code, {
|
|
1626
|
-
selected: selected,
|
|
1627
|
-
fixed: isNewTabButton,
|
|
1628
|
-
title: code.title,
|
|
1629
|
-
icon: tabIcon,
|
|
1703
|
+
this.tabs.add( name, code, {
|
|
1704
|
+
selected: selected,
|
|
1705
|
+
fixed: isNewTabButton,
|
|
1706
|
+
title: code.title,
|
|
1707
|
+
icon: tabIcon,
|
|
1630
1708
|
onSelect: this._onSelectTab.bind( this, isNewTabButton ),
|
|
1631
1709
|
onContextMenu: this._onContextMenuTab.bind( this, isNewTabButton )
|
|
1632
1710
|
} );
|
|
1633
1711
|
|
|
1634
1712
|
// Move into the sizer..
|
|
1635
1713
|
this.codeSizer.appendChild( code );
|
|
1636
|
-
|
|
1714
|
+
|
|
1637
1715
|
this.endSelection();
|
|
1638
1716
|
|
|
1639
1717
|
if( selected )
|
|
1640
1718
|
{
|
|
1641
|
-
this.code = code;
|
|
1719
|
+
this.code = code;
|
|
1642
1720
|
this.resetCursorPos( CodeEditor.CURSOR_LEFT | CodeEditor.CURSOR_TOP );
|
|
1643
1721
|
this.processLines();
|
|
1644
1722
|
}
|
|
1645
1723
|
|
|
1724
|
+
if( options.language )
|
|
1725
|
+
{
|
|
1726
|
+
code.languageOverride = options.language;
|
|
1727
|
+
this._changeLanguage( code.languageOverride );
|
|
1728
|
+
}
|
|
1729
|
+
|
|
1646
1730
|
this._updateDataInfoPanel( "@tab-name", name );
|
|
1647
1731
|
|
|
1648
1732
|
// Bc it could be overrided..
|
|
@@ -1663,41 +1747,53 @@ class CodeEditor {
|
|
|
1663
1747
|
if( !code )
|
|
1664
1748
|
{
|
|
1665
1749
|
this.addTab( name, true );
|
|
1666
|
-
|
|
1667
|
-
|
|
1750
|
+
|
|
1751
|
+
// Unload lines from storage...
|
|
1752
|
+
const tabData = this._tabStorage[ name ];
|
|
1753
|
+
if( tabData )
|
|
1668
1754
|
{
|
|
1669
|
-
this.code.lines =
|
|
1670
|
-
|
|
1755
|
+
this.code.lines = tabData.lines;
|
|
1756
|
+
|
|
1757
|
+
if( tabData.options.language )
|
|
1758
|
+
{
|
|
1759
|
+
this._changeLanguage( tabData.options.language, true );
|
|
1760
|
+
}
|
|
1761
|
+
else
|
|
1762
|
+
{
|
|
1763
|
+
this._changeLanguageFromExtension( LX.getExtension( name ) );
|
|
1764
|
+
}
|
|
1765
|
+
|
|
1766
|
+
delete this._tabStorage[ name ];
|
|
1671
1767
|
}
|
|
1672
|
-
|
|
1768
|
+
|
|
1673
1769
|
return;
|
|
1674
1770
|
}
|
|
1675
1771
|
|
|
1676
1772
|
this.openedTabs[ name ] = code;
|
|
1677
|
-
|
|
1773
|
+
|
|
1678
1774
|
const isNewTabButton = ( name === '+' );
|
|
1679
1775
|
const tabIcon = this._getFileIcon( name );
|
|
1680
1776
|
|
|
1681
|
-
this.tabs.add(name, code, {
|
|
1682
|
-
selected: true,
|
|
1683
|
-
fixed: isNewTabButton,
|
|
1684
|
-
title: code.title,
|
|
1685
|
-
icon: tabIcon,
|
|
1777
|
+
this.tabs.add(name, code, {
|
|
1778
|
+
selected: true,
|
|
1779
|
+
fixed: isNewTabButton,
|
|
1780
|
+
title: code.title,
|
|
1781
|
+
icon: tabIcon,
|
|
1686
1782
|
onSelect: this._onSelectTab.bind( this, isNewTabButton ),
|
|
1687
1783
|
onContextMenu: this._onContextMenuTab.bind( this, isNewTabButton )
|
|
1688
1784
|
});
|
|
1689
1785
|
|
|
1690
1786
|
// Move into the sizer..
|
|
1691
1787
|
this.codeSizer.appendChild( code );
|
|
1692
|
-
|
|
1788
|
+
|
|
1693
1789
|
this.endSelection();
|
|
1694
1790
|
|
|
1695
1791
|
// Select as current...
|
|
1696
|
-
this.code = code;
|
|
1792
|
+
this.code = code;
|
|
1697
1793
|
this.resetCursorPos( CodeEditor.CURSOR_LEFT | CodeEditor.CURSOR_TOP );
|
|
1698
1794
|
this.processLines();
|
|
1699
1795
|
this._changeLanguageFromExtension( LX.getExtension( name ) );
|
|
1700
|
-
this._updateDataInfoPanel( "@tab-name", tabname );
|
|
1796
|
+
this._updateDataInfoPanel( "@tab-name", code.tabname );
|
|
1701
1797
|
}
|
|
1702
1798
|
|
|
1703
1799
|
loadTabFromFile() {
|
|
@@ -1747,7 +1843,7 @@ class CodeEditor {
|
|
|
1747
1843
|
|
|
1748
1844
|
if( cursor.selection )
|
|
1749
1845
|
{
|
|
1750
|
-
this.canOpenContextMenu |= (cursor.line >= cursor.selection.fromY && cursor.line <= cursor.selection.toY
|
|
1846
|
+
this.canOpenContextMenu |= (cursor.line >= cursor.selection.fromY && cursor.line <= cursor.selection.toY
|
|
1751
1847
|
&& cursor.position >= cursor.selection.fromX && cursor.position <= cursor.selection.toX);
|
|
1752
1848
|
if( this.canOpenContextMenu )
|
|
1753
1849
|
return;
|
|
@@ -1759,7 +1855,7 @@ class CodeEditor {
|
|
|
1759
1855
|
this.endSelection();
|
|
1760
1856
|
this.processClick( e );
|
|
1761
1857
|
}
|
|
1762
|
-
|
|
1858
|
+
|
|
1763
1859
|
else if( e.type == 'mouseup' )
|
|
1764
1860
|
{
|
|
1765
1861
|
this._onMouseUp( e );
|
|
@@ -1807,11 +1903,11 @@ class CodeEditor {
|
|
|
1807
1903
|
m.add( "Cut", () => { this._cutContent( cursor ); } );
|
|
1808
1904
|
m.add( "Paste", () => { this._pasteContent( cursor ); } );
|
|
1809
1905
|
m.add( "" );
|
|
1810
|
-
m.add( "Format/JSON", () => {
|
|
1906
|
+
m.add( "Format/JSON", () => {
|
|
1811
1907
|
let json = this.toJSONFormat( this.getText() );
|
|
1812
1908
|
if( !json )
|
|
1813
1909
|
return;
|
|
1814
|
-
this.code.lines = json.split( "\n" );
|
|
1910
|
+
this.code.lines = json.split( "\n" );
|
|
1815
1911
|
this.processLines();
|
|
1816
1912
|
} );
|
|
1817
1913
|
}
|
|
@@ -1859,7 +1955,7 @@ class CodeEditor {
|
|
|
1859
1955
|
this.cursorToLine( cursor, ln, true );
|
|
1860
1956
|
this.cursorToPosition( cursor, string.length );
|
|
1861
1957
|
}
|
|
1862
|
-
|
|
1958
|
+
|
|
1863
1959
|
// Add new cursor
|
|
1864
1960
|
else
|
|
1865
1961
|
{
|
|
@@ -1905,7 +2001,7 @@ class CodeEditor {
|
|
|
1905
2001
|
let ccw = true;
|
|
1906
2002
|
|
|
1907
2003
|
// Check if we must change ccw or not ... (not with mouse)
|
|
1908
|
-
if( !isMouseEvent && cursor.line >= cursor.selection.fromY &&
|
|
2004
|
+
if( !isMouseEvent && cursor.line >= cursor.selection.fromY &&
|
|
1909
2005
|
(cursor.line == cursor.selection.fromY ? cursor.position >= cursor.selection.fromX : true) )
|
|
1910
2006
|
{
|
|
1911
2007
|
ccw = ( e && this._lastSelectionKeyDir && ( e.key == 'ArrowRight' || e.key == 'ArrowDown' || e.key == 'End' ) );
|
|
@@ -1968,7 +2064,7 @@ class CodeEditor {
|
|
|
1968
2064
|
|
|
1969
2065
|
// Compute new width and selection margins
|
|
1970
2066
|
let string;
|
|
1971
|
-
|
|
2067
|
+
|
|
1972
2068
|
if(sId == 0) // First line 2 cases (single line, multiline)
|
|
1973
2069
|
{
|
|
1974
2070
|
const reverse = fromX > toX;
|
|
@@ -1982,7 +2078,7 @@ class CodeEditor {
|
|
|
1982
2078
|
string = (i == toY) ? this.code.lines[ i ].substring( 0, toX ) : this.code.lines[ i ]; // Last line, any multiple line...
|
|
1983
2079
|
if( isVisible ) domEl.style.left = this.xPadding;
|
|
1984
2080
|
}
|
|
1985
|
-
|
|
2081
|
+
|
|
1986
2082
|
const stringWidth = this.measureString( string );
|
|
1987
2083
|
cursor.selection.chars += stringWidth / this.charWidth;
|
|
1988
2084
|
|
|
@@ -2019,7 +2115,7 @@ class CodeEditor {
|
|
|
2019
2115
|
|
|
2020
2116
|
// Compute new width and selection margins
|
|
2021
2117
|
let string;
|
|
2022
|
-
|
|
2118
|
+
|
|
2023
2119
|
if( sId == 0 )
|
|
2024
2120
|
{
|
|
2025
2121
|
string = this.code.lines[ i ].substr(toX);
|
|
@@ -2031,10 +2127,10 @@ class CodeEditor {
|
|
|
2031
2127
|
string = (i == fromY) ? this.code.lines[ i ].substring(0, fromX) : this.code.lines[ i ]; // Last line, any multiple line...
|
|
2032
2128
|
if( isVisible ) domEl.style.left = this.xPadding;
|
|
2033
2129
|
}
|
|
2034
|
-
|
|
2130
|
+
|
|
2035
2131
|
const stringWidth = this.measureString( string );
|
|
2036
2132
|
cursor.selection.chars += stringWidth / this.charWidth;
|
|
2037
|
-
|
|
2133
|
+
|
|
2038
2134
|
if( isVisible )
|
|
2039
2135
|
{
|
|
2040
2136
|
domEl.style.width = (stringWidth || 8) + "px";
|
|
@@ -2046,10 +2142,10 @@ class CodeEditor {
|
|
|
2046
2142
|
}
|
|
2047
2143
|
|
|
2048
2144
|
async processKey( e ) {
|
|
2049
|
-
|
|
2145
|
+
|
|
2050
2146
|
const numCursors = this.cursors.childElementCount;
|
|
2051
2147
|
|
|
2052
|
-
if( !this.code || e.srcElement.constructor != HTMLDivElement )
|
|
2148
|
+
if( !this.code || e.srcElement.constructor != HTMLDivElement )
|
|
2053
2149
|
return;
|
|
2054
2150
|
|
|
2055
2151
|
const key = e.key ?? e.detail.key;
|
|
@@ -2254,7 +2350,7 @@ class CodeEditor {
|
|
|
2254
2350
|
return;
|
|
2255
2351
|
}
|
|
2256
2352
|
}
|
|
2257
|
-
|
|
2353
|
+
|
|
2258
2354
|
// Apply binded actions...
|
|
2259
2355
|
|
|
2260
2356
|
for( const actKey in this.actions ) {
|
|
@@ -2286,11 +2382,11 @@ class CodeEditor {
|
|
|
2286
2382
|
const enclosableKeys = [ "\"", "'", "(", "{" ];
|
|
2287
2383
|
if( enclosableKeys.indexOf( key ) > -1 )
|
|
2288
2384
|
{
|
|
2289
|
-
if( this._encloseSelectedWordWithKey( key, lidx, cursor ) )
|
|
2385
|
+
if( this._encloseSelectedWordWithKey( key, lidx, cursor ) )
|
|
2290
2386
|
return;
|
|
2291
2387
|
}
|
|
2292
2388
|
|
|
2293
|
-
// Until this point, if there was a selection, we need
|
|
2389
|
+
// Until this point, if there was a selection, we need
|
|
2294
2390
|
// to delete the content..
|
|
2295
2391
|
|
|
2296
2392
|
if( cursor.selection )
|
|
@@ -2307,8 +2403,8 @@ class CodeEditor {
|
|
|
2307
2403
|
if( !sameKeyNext )
|
|
2308
2404
|
{
|
|
2309
2405
|
this.code.lines[ lidx ] = [
|
|
2310
|
-
this.code.lines[ lidx ].slice( 0, cursor.position ),
|
|
2311
|
-
key,
|
|
2406
|
+
this.code.lines[ lidx ].slice( 0, cursor.position ),
|
|
2407
|
+
key,
|
|
2312
2408
|
this.code.lines[ lidx ].slice( cursor.position )
|
|
2313
2409
|
].join('');
|
|
2314
2410
|
}
|
|
@@ -2316,7 +2412,7 @@ class CodeEditor {
|
|
|
2316
2412
|
this.cursorToRight( key, cursor );
|
|
2317
2413
|
|
|
2318
2414
|
// Some custom cases for auto key pair (), {}, "", '', ...
|
|
2319
|
-
|
|
2415
|
+
|
|
2320
2416
|
const keyMustPair = (this.pairKeys[ key ] !== undefined);
|
|
2321
2417
|
if( keyMustPair && !this.wasKeyPaired )
|
|
2322
2418
|
{
|
|
@@ -2377,7 +2473,7 @@ class CodeEditor {
|
|
|
2377
2473
|
text_to_copy = "\n" + this.code.lines[ cursor.line ];
|
|
2378
2474
|
}
|
|
2379
2475
|
else {
|
|
2380
|
-
|
|
2476
|
+
|
|
2381
2477
|
// Some selections don't depend on mouse up..
|
|
2382
2478
|
if( cursor.selection ) cursor.selection.invertIfNecessary();
|
|
2383
2479
|
|
|
@@ -2386,11 +2482,11 @@ class CodeEditor {
|
|
|
2386
2482
|
|
|
2387
2483
|
// Get linear start index
|
|
2388
2484
|
let index = 0;
|
|
2389
|
-
|
|
2485
|
+
|
|
2390
2486
|
for( let i = 0; i <= cursor.selection.fromY; i++ )
|
|
2391
2487
|
index += ( i == cursor.selection.fromY ? cursor.selection.fromX : this.code.lines[ i ].length );
|
|
2392
2488
|
|
|
2393
|
-
index += cursor.selection.fromY * separator.length;
|
|
2489
|
+
index += cursor.selection.fromY * separator.length;
|
|
2394
2490
|
const num_chars = cursor.selection.chars + ( cursor.selection.toY - cursor.selection.fromY ) * separator.length;
|
|
2395
2491
|
const text = code.substr( index, num_chars );
|
|
2396
2492
|
const lines = text.split( separator );
|
|
@@ -2416,7 +2512,7 @@ class CodeEditor {
|
|
|
2416
2512
|
this.lineUp( cursor );
|
|
2417
2513
|
}
|
|
2418
2514
|
else {
|
|
2419
|
-
|
|
2515
|
+
|
|
2420
2516
|
// Some selections don't depend on mouse up..
|
|
2421
2517
|
if( cursor.selection ) cursor.selection.invertIfNecessary();
|
|
2422
2518
|
|
|
@@ -2425,11 +2521,11 @@ class CodeEditor {
|
|
|
2425
2521
|
|
|
2426
2522
|
// Get linear start index
|
|
2427
2523
|
let index = 0;
|
|
2428
|
-
|
|
2524
|
+
|
|
2429
2525
|
for(let i = 0; i <= cursor.selection.fromY; i++)
|
|
2430
2526
|
index += (i == cursor.selection.fromY ? cursor.selection.fromX : this.code.lines[ i ].length);
|
|
2431
2527
|
|
|
2432
|
-
index += cursor.selection.fromY * separator.length;
|
|
2528
|
+
index += cursor.selection.fromY * separator.length;
|
|
2433
2529
|
const num_chars = cursor.selection.chars + (cursor.selection.toY - cursor.selection.fromY) * separator.length;
|
|
2434
2530
|
const text = code.substr(index, num_chars);
|
|
2435
2531
|
const lines = text.split(separator);
|
|
@@ -2442,7 +2538,7 @@ class CodeEditor {
|
|
|
2442
2538
|
}
|
|
2443
2539
|
|
|
2444
2540
|
_duplicateLine( lidx, cursor ) {
|
|
2445
|
-
|
|
2541
|
+
|
|
2446
2542
|
this.endSelection();
|
|
2447
2543
|
this._addUndoStep( cursor, true );
|
|
2448
2544
|
this.code.lines.splice( lidx, 0, this.code.lines[ lidx ] );
|
|
@@ -2599,20 +2695,20 @@ class CodeEditor {
|
|
|
2599
2695
|
}
|
|
2600
2696
|
|
|
2601
2697
|
processLines( mode ) {
|
|
2602
|
-
|
|
2698
|
+
|
|
2603
2699
|
var code_html = "";
|
|
2604
2700
|
this._blockCommentCache.length = 0;
|
|
2605
|
-
|
|
2701
|
+
|
|
2606
2702
|
// Reset all lines content
|
|
2607
2703
|
this.code.innerHTML = "";
|
|
2608
|
-
|
|
2704
|
+
|
|
2609
2705
|
// Get info about lines in viewport
|
|
2610
2706
|
const lastScrollTop = this.getScrollTop();
|
|
2611
|
-
this.firstLineInViewport = ( mode ?? CodeEditor.KEEP_VISIBLE_LINES ) & CodeEditor.UPDATE_VISIBLE_LINES ?
|
|
2707
|
+
this.firstLineInViewport = ( mode ?? CodeEditor.KEEP_VISIBLE_LINES ) & CodeEditor.UPDATE_VISIBLE_LINES ?
|
|
2612
2708
|
( (lastScrollTop / this.lineHeight)|0 ) : this.firstLineInViewport;
|
|
2613
2709
|
const totalLinesInViewport = ((this.codeScroller.offsetHeight - 36) / this.lineHeight)|0;
|
|
2614
|
-
this.visibleLinesViewport = new LX.vec2(
|
|
2615
|
-
Math.max( this.firstLineInViewport - this.lineScrollMargin.x, 0 ),
|
|
2710
|
+
this.visibleLinesViewport = new LX.vec2(
|
|
2711
|
+
Math.max( this.firstLineInViewport - this.lineScrollMargin.x, 0 ),
|
|
2616
2712
|
Math.min( this.firstLineInViewport + totalLinesInViewport + this.lineScrollMargin.y, this.code.lines.length )
|
|
2617
2713
|
);
|
|
2618
2714
|
|
|
@@ -2622,15 +2718,15 @@ class CodeEditor {
|
|
|
2622
2718
|
if( diff <= this.lineScrollMargin.y )
|
|
2623
2719
|
this.visibleLinesViewport.y += diff;
|
|
2624
2720
|
}
|
|
2625
|
-
|
|
2721
|
+
|
|
2626
2722
|
// Process visible lines
|
|
2627
2723
|
for( let i = this.visibleLinesViewport.x; i < this.visibleLinesViewport.y; ++i )
|
|
2628
2724
|
{
|
|
2629
2725
|
code_html += this.processLine( i, true );
|
|
2630
2726
|
}
|
|
2631
|
-
|
|
2727
|
+
|
|
2632
2728
|
this.code.innerHTML = code_html;
|
|
2633
|
-
|
|
2729
|
+
|
|
2634
2730
|
// Update scroll data
|
|
2635
2731
|
this.codeScroller.scrollTop = lastScrollTop;
|
|
2636
2732
|
this.code.style.top = ( this.visibleLinesViewport.x * this.lineHeight ) + "px";
|
|
@@ -2668,10 +2764,10 @@ class CodeEditor {
|
|
|
2668
2764
|
}
|
|
2669
2765
|
|
|
2670
2766
|
// multi-line strings not supported by now
|
|
2671
|
-
delete this._buildingString;
|
|
2767
|
+
delete this._buildingString;
|
|
2672
2768
|
delete this._pendingString;
|
|
2673
2769
|
delete this._markdownHeader;
|
|
2674
|
-
|
|
2770
|
+
|
|
2675
2771
|
let linestring = this.code.lines[ linenum ];
|
|
2676
2772
|
|
|
2677
2773
|
// Single line
|
|
@@ -2706,14 +2802,14 @@ class CodeEditor {
|
|
|
2706
2802
|
it--;
|
|
2707
2803
|
prev = tokensToEvaluate[ it ];
|
|
2708
2804
|
}
|
|
2709
|
-
|
|
2805
|
+
|
|
2710
2806
|
it = i + 1;
|
|
2711
2807
|
let next = tokensToEvaluate[ it ];
|
|
2712
2808
|
while( next == ' ' || next == '"' ) {
|
|
2713
2809
|
it++;
|
|
2714
2810
|
next = tokensToEvaluate[ it ];
|
|
2715
2811
|
}
|
|
2716
|
-
|
|
2812
|
+
|
|
2717
2813
|
const token = tokensToEvaluate[ i ];
|
|
2718
2814
|
|
|
2719
2815
|
if( lang.blockComments ?? true )
|
|
@@ -2731,7 +2827,8 @@ class CodeEditor {
|
|
|
2731
2827
|
nextWithSpaces: tokensToEvaluate[ i + 1 ],
|
|
2732
2828
|
tokenIndex: i,
|
|
2733
2829
|
isFirstToken: (i == 0),
|
|
2734
|
-
isLastToken: (i == tokensToEvaluate.length - 1)
|
|
2830
|
+
isLastToken: (i == tokensToEvaluate.length - 1),
|
|
2831
|
+
tokens: tokensToEvaluate
|
|
2735
2832
|
} );
|
|
2736
2833
|
}
|
|
2737
2834
|
|
|
@@ -2753,10 +2850,10 @@ class CodeEditor {
|
|
|
2753
2850
|
const stringKeys = Object.values( this.stringKeys );
|
|
2754
2851
|
// Count times we started a string BEFORE the comment
|
|
2755
2852
|
var err = false;
|
|
2756
|
-
err |= stringKeys.some( function(v) {
|
|
2757
|
-
var re = new RegExp( v, "g" );
|
|
2853
|
+
err |= stringKeys.some( function(v) {
|
|
2854
|
+
var re = new RegExp( v, "g" );
|
|
2758
2855
|
var matches = (linestring.substring( 0, idx ).match( re ) || []);
|
|
2759
|
-
return (matches.length % 2) !== 0;
|
|
2856
|
+
return (matches.length % 2) !== 0;
|
|
2760
2857
|
} );
|
|
2761
2858
|
return err ? undefined : idx;
|
|
2762
2859
|
}
|
|
@@ -2839,9 +2936,21 @@ class CodeEditor {
|
|
|
2839
2936
|
return tokens;
|
|
2840
2937
|
}
|
|
2841
2938
|
|
|
2842
|
-
_mustHightlightWord( token, kindArray ) {
|
|
2939
|
+
_mustHightlightWord( token, kindArray, lang ) {
|
|
2940
|
+
|
|
2941
|
+
if( !lang )
|
|
2942
|
+
{
|
|
2943
|
+
lang = this.languages[ this.highlight ];
|
|
2944
|
+
}
|
|
2945
|
+
|
|
2946
|
+
let t = token;
|
|
2947
|
+
|
|
2948
|
+
if( lang.ignoreCase )
|
|
2949
|
+
{
|
|
2950
|
+
t = t.toLowerCase();
|
|
2951
|
+
}
|
|
2843
2952
|
|
|
2844
|
-
return kindArray[this.highlight] && kindArray[this.highlight][
|
|
2953
|
+
return kindArray[ this.highlight ] && kindArray[ this.highlight ][ t ] != undefined;
|
|
2845
2954
|
}
|
|
2846
2955
|
|
|
2847
2956
|
_evaluateToken( ctxData ) {
|
|
@@ -2859,10 +2968,10 @@ class CodeEditor {
|
|
|
2859
2968
|
|
|
2860
2969
|
var usePreviousTokenToCheckString = false;
|
|
2861
2970
|
|
|
2862
|
-
if(
|
|
2971
|
+
if( [ 'cpp', 'c' ].indexOf( highlight ) > -1 && prev && prev.includes( '#' ) ) // preprocessor code..
|
|
2863
2972
|
{
|
|
2864
2973
|
customStringKeys['@<'] = '>';
|
|
2865
|
-
}
|
|
2974
|
+
}
|
|
2866
2975
|
else if( highlight == 'markdown' && ( ctxData.prevWithSpaces == '[' || ctxData.nextWithSpaces == ']' ) )
|
|
2867
2976
|
{
|
|
2868
2977
|
// console.warn(prev, token, next)
|
|
@@ -2883,43 +2992,43 @@ class CodeEditor {
|
|
|
2883
2992
|
if( this._buildingString != undefined )
|
|
2884
2993
|
{
|
|
2885
2994
|
checkIfStringEnded( usePreviousTokenToCheckString ? ctxData.nextWithSpaces : token );
|
|
2886
|
-
}
|
|
2995
|
+
}
|
|
2887
2996
|
else if( customStringKeys[ '@' + ( usePreviousTokenToCheckString ? ctxData.prevWithSpaces : token ) ] )
|
|
2888
|
-
{
|
|
2997
|
+
{
|
|
2889
2998
|
// Start new string
|
|
2890
2999
|
this._buildingString = ( usePreviousTokenToCheckString ? ctxData.prevWithSpaces : token );
|
|
2891
3000
|
|
|
2892
3001
|
// Check if string ended in same token using next...
|
|
2893
|
-
if( usePreviousTokenToCheckString )
|
|
3002
|
+
if( usePreviousTokenToCheckString )
|
|
2894
3003
|
{
|
|
2895
3004
|
checkIfStringEnded( ctxData.nextWithSpaces );
|
|
2896
3005
|
}
|
|
2897
3006
|
}
|
|
2898
3007
|
}
|
|
2899
|
-
|
|
3008
|
+
|
|
2900
3009
|
const usesBlockComments = lang.blockComments ?? true;
|
|
2901
3010
|
const blockCommentsTokens = lang.blockCommentsTokens ?? this.defaultBlockCommentTokens;
|
|
2902
3011
|
const singleLineCommentToken = lang.singleLineCommentToken ?? this.defaultSingleLineCommentToken;
|
|
2903
|
-
|
|
3012
|
+
|
|
2904
3013
|
let token_classname = "";
|
|
2905
3014
|
let discardToken = false;
|
|
2906
3015
|
|
|
2907
3016
|
if( this._buildingBlockComment != undefined )
|
|
2908
3017
|
token_classname = "cm-com";
|
|
2909
|
-
|
|
3018
|
+
|
|
2910
3019
|
else if( this._buildingString != undefined )
|
|
2911
3020
|
discardToken = this._appendStringToken( token );
|
|
2912
|
-
|
|
2913
|
-
else if( this.
|
|
3021
|
+
|
|
3022
|
+
else if( this._isKeyword( ctxData, lang ) )
|
|
2914
3023
|
token_classname = "cm-kwd";
|
|
2915
3024
|
|
|
2916
|
-
else if( this._mustHightlightWord( token, CodeEditor.
|
|
3025
|
+
else if( this._mustHightlightWord( token, CodeEditor.builtIn, lang ) && ( lang.tags ?? false ? ( this._enclosedByTokens( token, tokenIndex, '<', '>' ) ) : true ) )
|
|
2917
3026
|
token_classname = "cm-bln";
|
|
2918
3027
|
|
|
2919
|
-
else if( this._mustHightlightWord( token, CodeEditor.statementsAndDeclarations ) )
|
|
3028
|
+
else if( this._mustHightlightWord( token, CodeEditor.statementsAndDeclarations, lang ) )
|
|
2920
3029
|
token_classname = "cm-std";
|
|
2921
3030
|
|
|
2922
|
-
else if( this._mustHightlightWord( token, CodeEditor.symbols ) )
|
|
3031
|
+
else if( this._mustHightlightWord( token, CodeEditor.symbols, lang ) )
|
|
2923
3032
|
token_classname = "cm-sym";
|
|
2924
3033
|
|
|
2925
3034
|
else if( token.substr( 0, singleLineCommentToken.length ) == singleLineCommentToken )
|
|
@@ -2928,16 +3037,16 @@ class CodeEditor {
|
|
|
2928
3037
|
else if( this._isNumber( token ) || this._isNumber( token.replace(/[px]|[em]|%/g,'') ) )
|
|
2929
3038
|
token_classname = "cm-dec";
|
|
2930
3039
|
|
|
2931
|
-
else if( this._isCSSClass(
|
|
3040
|
+
else if( this._isCSSClass( ctxData ) )
|
|
2932
3041
|
token_classname = "cm-kwd";
|
|
2933
3042
|
|
|
2934
|
-
else if ( this._isType(
|
|
3043
|
+
else if ( this._isType( ctxData, lang ) )
|
|
2935
3044
|
token_classname = "cm-typ";
|
|
2936
3045
|
|
|
2937
3046
|
else if ( highlight == 'batch' && ( token == '@' || prev == ':' || prev == '@' ) )
|
|
2938
3047
|
token_classname = "cm-kwd";
|
|
2939
3048
|
|
|
2940
|
-
else if ( [ 'cpp', 'wgsl', 'glsl' ].indexOf( highlight ) > -1 && token.includes( '#' ) ) // C++ preprocessor
|
|
3049
|
+
else if ( [ 'cpp', 'c', 'wgsl', 'glsl' ].indexOf( highlight ) > -1 && token.includes( '#' ) ) // C++ preprocessor
|
|
2941
3050
|
token_classname = "cm-ppc";
|
|
2942
3051
|
|
|
2943
3052
|
else if ( highlight == 'cpp' && prev == '<' && (next == '>' || next == '*') ) // Defining template type in C++
|
|
@@ -2951,7 +3060,7 @@ class CodeEditor {
|
|
|
2951
3060
|
|
|
2952
3061
|
else if ( highlight == 'css' && prev == undefined && next == ':' ) // CSS attribute
|
|
2953
3062
|
token_classname = "cm-typ";
|
|
2954
|
-
|
|
3063
|
+
|
|
2955
3064
|
else if ( this._markdownHeader || ( highlight == 'markdown' && isFirstToken && token.replaceAll('#', '').length != token.length ) ) // Header
|
|
2956
3065
|
{
|
|
2957
3066
|
token_classname = "cm-kwd";
|
|
@@ -2962,7 +3071,7 @@ class CodeEditor {
|
|
|
2962
3071
|
token_classname = "cm-mtd";
|
|
2963
3072
|
|
|
2964
3073
|
|
|
2965
|
-
if( usesBlockComments && this._buildingBlockComment != undefined
|
|
3074
|
+
if( usesBlockComments && this._buildingBlockComment != undefined
|
|
2966
3075
|
&& token.substr( 0, blockCommentsTokens[ 1 ].length ) == blockCommentsTokens[ 1 ] )
|
|
2967
3076
|
{
|
|
2968
3077
|
this._blockCommentCache.push( new LX.vec2( this._buildingBlockComment, this._currentLineNumber ) );
|
|
@@ -2981,14 +3090,18 @@ class CodeEditor {
|
|
|
2981
3090
|
this._buildingString = this._stringEnded ? undefined : this._buildingString;
|
|
2982
3091
|
|
|
2983
3092
|
if( discardToken )
|
|
3093
|
+
{
|
|
2984
3094
|
return "";
|
|
3095
|
+
}
|
|
2985
3096
|
|
|
2986
3097
|
token = token.replace( "<", "<" );
|
|
2987
3098
|
token = token.replace( ">", ">" );
|
|
2988
3099
|
|
|
2989
3100
|
// No highlighting, no need to put it inside another span..
|
|
2990
3101
|
if( !token_classname.length )
|
|
3102
|
+
{
|
|
2991
3103
|
return token;
|
|
3104
|
+
}
|
|
2992
3105
|
|
|
2993
3106
|
return "<span class='" + highlight + " " + token_classname + "'>" + token + "</span>";
|
|
2994
3107
|
}
|
|
@@ -3016,11 +3129,17 @@ class CodeEditor {
|
|
|
3016
3129
|
const tagStartIndex = indexOfFrom( this._currentLineString, tagStart, tokenStartIndex, true );
|
|
3017
3130
|
if( tagStartIndex < 0 ) // Not found..
|
|
3018
3131
|
return;
|
|
3132
|
+
const tagStartIndexOpposite = indexOfFrom( this._currentLineString, tagEnd, tokenStartIndex, true );
|
|
3133
|
+
if( tagStartIndexOpposite >= 0 && tagStartIndexOpposite > tagStartIndex ) // Found the opposite first while reversing..
|
|
3134
|
+
return;
|
|
3019
3135
|
const tagEndIndex = indexOfFrom( this._currentLineString, tagEnd, tokenStartIndex );
|
|
3020
3136
|
if( tagEndIndex < 0 ) // Not found..
|
|
3021
3137
|
return;
|
|
3022
3138
|
|
|
3023
|
-
|
|
3139
|
+
if( ( tagStartIndex < tokenStartIndex ) && ( tagEndIndex >= ( tokenStartIndex + token.length ) ) && !this._mustHightlightWord( token, CodeEditor.symbols ) )
|
|
3140
|
+
{
|
|
3141
|
+
return [ tagStartIndex, tagEndIndex ];
|
|
3142
|
+
}
|
|
3024
3143
|
}
|
|
3025
3144
|
|
|
3026
3145
|
_inBlockCommentSection( line ) {
|
|
@@ -3028,52 +3147,104 @@ class CodeEditor {
|
|
|
3028
3147
|
for( var section of this._blockCommentCache )
|
|
3029
3148
|
{
|
|
3030
3149
|
if( line >= section.x && line <= section.y )
|
|
3150
|
+
{
|
|
3031
3151
|
return true;
|
|
3152
|
+
}
|
|
3032
3153
|
}
|
|
3033
3154
|
|
|
3034
3155
|
return false;
|
|
3035
3156
|
}
|
|
3036
3157
|
|
|
3037
|
-
|
|
3158
|
+
_isKeyword( ctxData, lang ) {
|
|
3159
|
+
|
|
3160
|
+
const token = ctxData.token;
|
|
3161
|
+
const tokenIndex = ctxData.tokenIndex;
|
|
3162
|
+
const tokens = ctxData.tokens;
|
|
3163
|
+
|
|
3164
|
+
let isKwd = this._mustHightlightWord( token, CodeEditor.keywords ) || this.highlight == 'XML';
|
|
3165
|
+
|
|
3166
|
+
if( this.highlight == 'CMake' )
|
|
3167
|
+
{
|
|
3168
|
+
// Highlight $ symbol
|
|
3169
|
+
if( token == '$' && this._enclosedByTokens( tokens[ tokenIndex + 2 ], tokenIndex + 2, '{', '}' ) )
|
|
3170
|
+
{
|
|
3171
|
+
isKwd = true;
|
|
3172
|
+
}
|
|
3173
|
+
// Highlight what is between the { }
|
|
3174
|
+
else if( this._enclosedByTokens( token, tokenIndex, '{', '}' ) )
|
|
3175
|
+
{
|
|
3176
|
+
isKwd |= ( ctxData.tokens[ tokenIndex - 2 ] == '$' );
|
|
3177
|
+
}
|
|
3178
|
+
}
|
|
3179
|
+
else if( lang.tags )
|
|
3180
|
+
{
|
|
3181
|
+
isKwd &= ( this._enclosedByTokens( token, tokenIndex, '<', '>' ) != undefined );
|
|
3182
|
+
}
|
|
3183
|
+
|
|
3184
|
+
|
|
3185
|
+
return isKwd;
|
|
3186
|
+
}
|
|
3187
|
+
|
|
3188
|
+
_isCSSClass( ctxData ) {
|
|
3189
|
+
|
|
3190
|
+
const token = ctxData.token;
|
|
3191
|
+
const prev = ctxData.prev;
|
|
3192
|
+
const next = ctxData.next;
|
|
3038
3193
|
|
|
3039
3194
|
if( this.highlight != 'CSS' )
|
|
3195
|
+
{
|
|
3040
3196
|
return false;
|
|
3197
|
+
}
|
|
3041
3198
|
|
|
3042
|
-
return ( prev == '.' || prev == '::'
|
|
3043
|
-
|| ( prev == ':' && next == '{' )
|
|
3199
|
+
return ( prev == '.' || prev == '::'
|
|
3200
|
+
|| ( prev == ':' && next == '{' )
|
|
3044
3201
|
|| ( token[ 0 ] == '#' && prev != ':' ) );
|
|
3045
3202
|
}
|
|
3046
3203
|
|
|
3047
3204
|
_isNumber( token ) {
|
|
3048
3205
|
|
|
3049
|
-
|
|
3206
|
+
const subToken = token.substring( 0, token.length - 1 );
|
|
3207
|
+
|
|
3208
|
+
if( this.highlight == 'C++' )
|
|
3050
3209
|
{
|
|
3051
3210
|
if( token.lastChar == 'f' )
|
|
3052
|
-
|
|
3211
|
+
{
|
|
3212
|
+
return this._isNumber( subToken )
|
|
3213
|
+
}
|
|
3053
3214
|
else if( token.lastChar == 'u' )
|
|
3054
|
-
|
|
3215
|
+
{
|
|
3216
|
+
return !(token.includes('.')) && this._isNumber( subToken );
|
|
3217
|
+
}
|
|
3055
3218
|
}
|
|
3056
|
-
|
|
3057
|
-
else if(this.highlight == 'WGSL')
|
|
3219
|
+
else if( this.highlight == 'WGSL' )
|
|
3058
3220
|
{
|
|
3059
3221
|
if( token.lastChar == 'u' )
|
|
3060
|
-
|
|
3222
|
+
{
|
|
3223
|
+
return !(token.includes('.')) && this._isNumber( subToken );
|
|
3224
|
+
}
|
|
3061
3225
|
}
|
|
3062
|
-
|
|
3063
|
-
else if(this.highlight == 'CSS')
|
|
3226
|
+
else if( this.highlight == 'CSS' )
|
|
3064
3227
|
{
|
|
3065
3228
|
if( token.lastChar == '%' )
|
|
3066
|
-
|
|
3229
|
+
{
|
|
3230
|
+
return this._isNumber( subToken )
|
|
3231
|
+
}
|
|
3067
3232
|
}
|
|
3068
|
-
|
|
3069
|
-
return token.length && token != ' ' && !Number.isNaN(+token);
|
|
3233
|
+
|
|
3234
|
+
return token.length && token != ' ' && !Number.isNaN( +token );
|
|
3070
3235
|
}
|
|
3071
3236
|
|
|
3072
|
-
_isType(
|
|
3073
|
-
|
|
3237
|
+
_isType( ctxData, lang ) {
|
|
3238
|
+
|
|
3239
|
+
const token = ctxData.token;
|
|
3240
|
+
const prev = ctxData.prev;
|
|
3241
|
+
const next = ctxData.next;
|
|
3242
|
+
|
|
3074
3243
|
// Common case
|
|
3075
|
-
if( this._mustHightlightWord( token, CodeEditor.types ) )
|
|
3244
|
+
if( this._mustHightlightWord( token, CodeEditor.types, lang ) )
|
|
3245
|
+
{
|
|
3076
3246
|
return true;
|
|
3247
|
+
}
|
|
3077
3248
|
|
|
3078
3249
|
if( this.highlight == 'JavaScript' )
|
|
3079
3250
|
{
|
|
@@ -3085,11 +3256,11 @@ class CodeEditor {
|
|
|
3085
3256
|
}
|
|
3086
3257
|
else if ( this.highlight == 'WGSL' )
|
|
3087
3258
|
{
|
|
3088
|
-
const not_kwd = !this._mustHightlightWord( token, CodeEditor.keywords );
|
|
3089
|
-
return (prev == 'struct' && next == '{') ||
|
|
3090
|
-
(not_kwd && prev == ':' && next == ';') ||
|
|
3091
|
-
( not_kwd &&
|
|
3092
|
-
( prev == ':' && next == ')' || prev == ':' && next == ',' || prev == '>' && next == '{'
|
|
3259
|
+
const not_kwd = !this._mustHightlightWord( token, CodeEditor.keywords, lang );
|
|
3260
|
+
return (prev == 'struct' && next == '{') ||
|
|
3261
|
+
(not_kwd && prev == ':' && next == ';') ||
|
|
3262
|
+
( not_kwd &&
|
|
3263
|
+
( prev == ':' && next == ')' || prev == ':' && next == ',' || prev == '>' && next == '{'
|
|
3093
3264
|
|| prev == '<' && next == ',' || prev == '<' && next == '>' || prev == '>' && token != ';' && !next ));
|
|
3094
3265
|
}
|
|
3095
3266
|
}
|
|
@@ -3098,13 +3269,13 @@ class CodeEditor {
|
|
|
3098
3269
|
|
|
3099
3270
|
if( !cursor.selection || (cursor.selection.fromY != cursor.selection.toY) )
|
|
3100
3271
|
return false;
|
|
3101
|
-
|
|
3272
|
+
|
|
3102
3273
|
cursor.selection.invertIfNecessary();
|
|
3103
3274
|
|
|
3104
3275
|
// Insert first..
|
|
3105
3276
|
this.code.lines[ lidx ] = [
|
|
3106
|
-
this.code.lines[ lidx ].slice(0, cursor.selection.fromX),
|
|
3107
|
-
key,
|
|
3277
|
+
this.code.lines[ lidx ].slice(0, cursor.selection.fromX),
|
|
3278
|
+
key,
|
|
3108
3279
|
this.code.lines[ lidx ].slice(cursor.selection.fromX)
|
|
3109
3280
|
].join('');
|
|
3110
3281
|
|
|
@@ -3123,14 +3294,14 @@ class CodeEditor {
|
|
|
3123
3294
|
|
|
3124
3295
|
// Insert the other
|
|
3125
3296
|
this.code.lines[ lidx ] = [
|
|
3126
|
-
this.code.lines[ lidx ].slice(0, cursor.position),
|
|
3127
|
-
key,
|
|
3297
|
+
this.code.lines[ lidx ].slice(0, cursor.position),
|
|
3298
|
+
key,
|
|
3128
3299
|
this.code.lines[ lidx ].slice(cursor.position)
|
|
3129
3300
|
].join('');
|
|
3130
3301
|
|
|
3131
3302
|
// Recompute and reposition current selection
|
|
3132
|
-
|
|
3133
|
-
cursor.selection.fromX++;
|
|
3303
|
+
|
|
3304
|
+
cursor.selection.fromX++;
|
|
3134
3305
|
cursor.selection.toX++;
|
|
3135
3306
|
|
|
3136
3307
|
this._processSelection( cursor );
|
|
@@ -3142,7 +3313,7 @@ class CodeEditor {
|
|
|
3142
3313
|
|
|
3143
3314
|
lineUp( cursor, resetLeft ) {
|
|
3144
3315
|
|
|
3145
|
-
if( this.code.lines[ cursor.line - 1 ] == undefined )
|
|
3316
|
+
if( this.code.lines[ cursor.line - 1 ] == undefined )
|
|
3146
3317
|
return false;
|
|
3147
3318
|
|
|
3148
3319
|
cursor.line--;
|
|
@@ -3153,10 +3324,10 @@ class CodeEditor {
|
|
|
3153
3324
|
}
|
|
3154
3325
|
|
|
3155
3326
|
lineDown( cursor, resetLeft ) {
|
|
3156
|
-
|
|
3157
|
-
if( this.code.lines[ cursor.line + 1 ] == undefined )
|
|
3327
|
+
|
|
3328
|
+
if( this.code.lines[ cursor.line + 1 ] == undefined )
|
|
3158
3329
|
return false;
|
|
3159
|
-
|
|
3330
|
+
|
|
3160
3331
|
cursor.line++;
|
|
3161
3332
|
|
|
3162
3333
|
this.cursorToBottom( cursor, resetLeft );
|
|
@@ -3195,8 +3366,8 @@ class CodeEditor {
|
|
|
3195
3366
|
|
|
3196
3367
|
deleteSelection( cursor ) {
|
|
3197
3368
|
|
|
3198
|
-
// I think it's not necessary but...
|
|
3199
|
-
if( this.disableEdition )
|
|
3369
|
+
// I think it's not necessary but...
|
|
3370
|
+
if( this.disableEdition )
|
|
3200
3371
|
return;
|
|
3201
3372
|
|
|
3202
3373
|
// Some selections don't depend on mouse up..
|
|
@@ -3210,14 +3381,14 @@ class CodeEditor {
|
|
|
3210
3381
|
for( let i = 0; i <= cursor.selection.fromY; i++ )
|
|
3211
3382
|
index += (i == cursor.selection.fromY ? cursor.selection.fromX : this.code.lines[ i ].length);
|
|
3212
3383
|
|
|
3213
|
-
index += cursor.selection.fromY * separator.length;
|
|
3384
|
+
index += cursor.selection.fromY * separator.length;
|
|
3214
3385
|
|
|
3215
3386
|
const num_chars = cursor.selection.chars + (cursor.selection.toY - cursor.selection.fromY) * separator.length;
|
|
3216
3387
|
const pre = code.slice( 0, index );
|
|
3217
3388
|
const post = code.slice( index + num_chars );
|
|
3218
3389
|
|
|
3219
3390
|
this.code.lines = ( pre + post ).split( separator );
|
|
3220
|
-
|
|
3391
|
+
|
|
3221
3392
|
this.cursorToLine( cursor, cursor.selection.fromY, true );
|
|
3222
3393
|
this.cursorToPosition( cursor, cursor.selection.fromX );
|
|
3223
3394
|
this.endSelection( cursor );
|
|
@@ -3315,7 +3486,7 @@ class CodeEditor {
|
|
|
3315
3486
|
cursor._top = Math.max(cursor._top, 0);
|
|
3316
3487
|
cursor.style.top = "calc(" + cursor._top + "px)";
|
|
3317
3488
|
this.restartBlink();
|
|
3318
|
-
|
|
3489
|
+
|
|
3319
3490
|
if( resetLeft )
|
|
3320
3491
|
this.resetCursorPos( CodeEditor.CURSOR_LEFT, cursor );
|
|
3321
3492
|
|
|
@@ -3345,10 +3516,10 @@ class CodeEditor {
|
|
|
3345
3516
|
|
|
3346
3517
|
cursorToString( cursor, text, reverse ) {
|
|
3347
3518
|
|
|
3348
|
-
if( !text.length )
|
|
3519
|
+
if( !text.length )
|
|
3349
3520
|
return;
|
|
3350
3521
|
|
|
3351
|
-
for( let char of text )
|
|
3522
|
+
for( let char of text )
|
|
3352
3523
|
reverse ? this.cursorToLeft( char, cursor ) : this.cursorToRight( char, cursor );
|
|
3353
3524
|
}
|
|
3354
3525
|
|
|
@@ -3436,7 +3607,7 @@ class CodeEditor {
|
|
|
3436
3607
|
}
|
|
3437
3608
|
|
|
3438
3609
|
resetCursorPos( flag, cursor ) {
|
|
3439
|
-
|
|
3610
|
+
|
|
3440
3611
|
cursor = cursor ?? this._getCurrentCursor();
|
|
3441
3612
|
|
|
3442
3613
|
if( flag & CodeEditor.CURSOR_LEFT )
|
|
@@ -3455,14 +3626,14 @@ class CodeEditor {
|
|
|
3455
3626
|
}
|
|
3456
3627
|
|
|
3457
3628
|
_addSpaceTabs( cursor, n ) {
|
|
3458
|
-
|
|
3629
|
+
|
|
3459
3630
|
for( var i = 0; i < n; ++i ) {
|
|
3460
3631
|
this.actions[ 'Tab' ].callback( cursor.line, cursor, null );
|
|
3461
3632
|
}
|
|
3462
3633
|
}
|
|
3463
3634
|
|
|
3464
3635
|
_addSpaces( n ) {
|
|
3465
|
-
|
|
3636
|
+
|
|
3466
3637
|
for( var i = 0; i < n; ++i ) {
|
|
3467
3638
|
this.root.dispatchEvent( new CustomEvent( 'keydown', { 'detail': {
|
|
3468
3639
|
skip_undo: true,
|
|
@@ -3509,33 +3680,33 @@ class CodeEditor {
|
|
|
3509
3680
|
}
|
|
3510
3681
|
|
|
3511
3682
|
getScrollLeft() {
|
|
3512
|
-
|
|
3683
|
+
|
|
3513
3684
|
if( !this.codeScroller ) return 0;
|
|
3514
3685
|
return this.codeScroller.scrollLeft;
|
|
3515
3686
|
}
|
|
3516
3687
|
|
|
3517
3688
|
getScrollTop() {
|
|
3518
|
-
|
|
3689
|
+
|
|
3519
3690
|
if( !this.codeScroller ) return 0;
|
|
3520
3691
|
return this.codeScroller.scrollTop;
|
|
3521
3692
|
}
|
|
3522
3693
|
|
|
3523
3694
|
setScrollLeft( value ) {
|
|
3524
|
-
|
|
3695
|
+
|
|
3525
3696
|
if( !this.codeScroller ) return;
|
|
3526
3697
|
this.codeScroller.scrollLeft = value;
|
|
3527
3698
|
this.setScrollBarValue( 'horizontal', 0 );
|
|
3528
3699
|
}
|
|
3529
3700
|
|
|
3530
3701
|
setScrollTop( value ) {
|
|
3531
|
-
|
|
3702
|
+
|
|
3532
3703
|
if( !this.codeScroller ) return;
|
|
3533
3704
|
this.codeScroller.scrollTop = value;
|
|
3534
3705
|
this.setScrollBarValue( 'vertical' );
|
|
3535
3706
|
}
|
|
3536
3707
|
|
|
3537
3708
|
resize( pMaxLength ) {
|
|
3538
|
-
|
|
3709
|
+
|
|
3539
3710
|
setTimeout( () => {
|
|
3540
3711
|
|
|
3541
3712
|
// Update max viewport
|
|
@@ -3593,7 +3764,7 @@ class CodeEditor {
|
|
|
3593
3764
|
{
|
|
3594
3765
|
const scrollBarHeight = this.vScrollbar.thumb.parentElement.offsetHeight;
|
|
3595
3766
|
const scrollThumbHeight = this.vScrollbar.thumb.offsetHeight;
|
|
3596
|
-
|
|
3767
|
+
|
|
3597
3768
|
const scrollHeight = this.codeScroller.scrollHeight - this.codeScroller.clientHeight;
|
|
3598
3769
|
const currentScroll = this.codeScroller.scrollTop;
|
|
3599
3770
|
|
|
@@ -3632,13 +3803,13 @@ class CodeEditor {
|
|
|
3632
3803
|
const scrollWidth = this.codeScroller.scrollWidth - this.codeScroller.clientWidth;
|
|
3633
3804
|
const currentScroll = (this.hScrollbar.thumb._left * scrollWidth) / ( scrollBarWidth - scrollThumbWidth );
|
|
3634
3805
|
this.codeScroller.scrollLeft = currentScroll;
|
|
3635
|
-
|
|
3806
|
+
|
|
3636
3807
|
|
|
3637
3808
|
this._discardScroll = true;
|
|
3638
3809
|
}
|
|
3639
3810
|
|
|
3640
3811
|
updateVerticalScrollFromScrollBar( value ) {
|
|
3641
|
-
|
|
3812
|
+
|
|
3642
3813
|
value = this.vScrollbar.thumb._top - value;
|
|
3643
3814
|
|
|
3644
3815
|
// Move scrollbar thumb
|
|
@@ -3657,12 +3828,12 @@ class CodeEditor {
|
|
|
3657
3828
|
}
|
|
3658
3829
|
|
|
3659
3830
|
getCharAtPos( cursor, offset = 0 ) {
|
|
3660
|
-
|
|
3831
|
+
|
|
3661
3832
|
return this.code.lines[ cursor.line ][ cursor.position + offset ];
|
|
3662
3833
|
}
|
|
3663
3834
|
|
|
3664
3835
|
getWordAtPos( cursor, offset = 0 ) {
|
|
3665
|
-
|
|
3836
|
+
|
|
3666
3837
|
const col = cursor.line;
|
|
3667
3838
|
const words = this.code.lines[ col ];
|
|
3668
3839
|
|
|
@@ -3706,13 +3877,13 @@ class CodeEditor {
|
|
|
3706
3877
|
from--;
|
|
3707
3878
|
word = words.substring( from, to );
|
|
3708
3879
|
}
|
|
3709
|
-
}
|
|
3710
|
-
|
|
3880
|
+
}
|
|
3881
|
+
|
|
3711
3882
|
return [ word, from, to ];
|
|
3712
3883
|
}
|
|
3713
3884
|
|
|
3714
3885
|
_measureChar( char = "a", use_floating = false, get_bb = false ) {
|
|
3715
|
-
|
|
3886
|
+
|
|
3716
3887
|
var line = document.createElement( "pre" );
|
|
3717
3888
|
var text = document.createElement( "span" );
|
|
3718
3889
|
line.appendChild( text );
|
|
@@ -3776,7 +3947,7 @@ class CodeEditor {
|
|
|
3776
3947
|
}
|
|
3777
3948
|
|
|
3778
3949
|
showAutoCompleteBox( key, cursor ) {
|
|
3779
|
-
|
|
3950
|
+
|
|
3780
3951
|
if( !cursor.isMain )
|
|
3781
3952
|
return;
|
|
3782
3953
|
|
|
@@ -3791,8 +3962,8 @@ class CodeEditor {
|
|
|
3791
3962
|
let suggestions = [];
|
|
3792
3963
|
|
|
3793
3964
|
// Add language special keys...
|
|
3794
|
-
suggestions = suggestions.concat(
|
|
3795
|
-
Object.keys( CodeEditor.
|
|
3965
|
+
suggestions = suggestions.concat(
|
|
3966
|
+
Object.keys( CodeEditor.builtIn[ this.highlight ] ?? {} ),
|
|
3796
3967
|
Object.keys( CodeEditor.keywords[ this.highlight ] ?? {} ),
|
|
3797
3968
|
Object.keys( CodeEditor.statementsAndDeclarations[ this.highlight ] ?? {} ),
|
|
3798
3969
|
Object.keys( CodeEditor.types[ this.highlight ] ?? {} ),
|
|
@@ -3802,7 +3973,7 @@ class CodeEditor {
|
|
|
3802
3973
|
// Add words in current tab plus remove current word
|
|
3803
3974
|
// suggestions = suggestions.concat( Object.keys(this.code.tokens).filter( a => a != word ) );
|
|
3804
3975
|
|
|
3805
|
-
// Remove 1/2 char words and duplicates...
|
|
3976
|
+
// Remove 1/2 char words and duplicates...
|
|
3806
3977
|
suggestions = suggestions.filter( (value, index) => value.length > 2 && suggestions.indexOf(value) === index );
|
|
3807
3978
|
|
|
3808
3979
|
// Order...
|
|
@@ -3817,7 +3988,7 @@ class CodeEditor {
|
|
|
3817
3988
|
this.autocomplete.appendChild( pre );
|
|
3818
3989
|
|
|
3819
3990
|
var icon = document.createElement( 'a' );
|
|
3820
|
-
|
|
3991
|
+
|
|
3821
3992
|
if( this._mustHightlightWord( s, CodeEditor.utils ) )
|
|
3822
3993
|
icon.className = "fa fa-cube";
|
|
3823
3994
|
else if( this._mustHightlightWord( s, CodeEditor.types ) )
|
|
@@ -3829,7 +4000,7 @@ class CodeEditor {
|
|
|
3829
4000
|
|
|
3830
4001
|
pre.addEventListener( 'click', () => {
|
|
3831
4002
|
this.autoCompleteWord( s );
|
|
3832
|
-
} );
|
|
4003
|
+
} );
|
|
3833
4004
|
|
|
3834
4005
|
// Highlight the written part
|
|
3835
4006
|
const index = s.toLowerCase().indexOf( word.toLowerCase() );
|
|
@@ -3875,7 +4046,7 @@ class CodeEditor {
|
|
|
3875
4046
|
}
|
|
3876
4047
|
|
|
3877
4048
|
autoCompleteWord( suggestion ) {
|
|
3878
|
-
|
|
4049
|
+
|
|
3879
4050
|
if( !this.isAutoCompleteActive )
|
|
3880
4051
|
return;
|
|
3881
4052
|
|
|
@@ -3902,7 +4073,7 @@ class CodeEditor {
|
|
|
3902
4073
|
}
|
|
3903
4074
|
|
|
3904
4075
|
_getSelectedAutoComplete() {
|
|
3905
|
-
|
|
4076
|
+
|
|
3906
4077
|
if( !this.isAutoCompleteActive )
|
|
3907
4078
|
return;
|
|
3908
4079
|
|
|
@@ -3942,7 +4113,7 @@ class CodeEditor {
|
|
|
3942
4113
|
}
|
|
3943
4114
|
|
|
3944
4115
|
showSearchBox( clear ) {
|
|
3945
|
-
|
|
4116
|
+
|
|
3946
4117
|
this.hideSearchLineBox();
|
|
3947
4118
|
|
|
3948
4119
|
this.searchbox.classList.add( 'opened' );
|
|
@@ -4011,7 +4182,7 @@ class CodeEditor {
|
|
|
4011
4182
|
}
|
|
4012
4183
|
|
|
4013
4184
|
const getIndex = l => {
|
|
4014
|
-
|
|
4185
|
+
|
|
4015
4186
|
var string = this.code.lines[ l ];
|
|
4016
4187
|
|
|
4017
4188
|
if( reverse )
|
|
@@ -4065,10 +4236,10 @@ class CodeEditor {
|
|
|
4065
4236
|
};
|
|
4066
4237
|
return;
|
|
4067
4238
|
}
|
|
4068
|
-
|
|
4239
|
+
|
|
4069
4240
|
/*
|
|
4070
4241
|
Position idx is computed from last pos, which could be in same line,
|
|
4071
|
-
so we search in the substring (first_ocurrence, end). That's why we
|
|
4242
|
+
so we search in the substring (first_ocurrence, end). That's why we
|
|
4072
4243
|
have to add the length of the substring (0, first_ocurrence)
|
|
4073
4244
|
*/
|
|
4074
4245
|
|
|
@@ -4081,9 +4252,9 @@ class CodeEditor {
|
|
|
4081
4252
|
|
|
4082
4253
|
this._lastTextFound = text;
|
|
4083
4254
|
|
|
4084
|
-
this.codeScroller.scrollTo(
|
|
4085
|
-
Math.max( char * this.charWidth - this.codeScroller.clientWidth, 0 ),
|
|
4086
|
-
Math.max( line - 10, 0 ) * this.lineHeight
|
|
4255
|
+
this.codeScroller.scrollTo(
|
|
4256
|
+
Math.max( char * this.charWidth - this.codeScroller.clientWidth, 0 ),
|
|
4257
|
+
Math.max( line - 10, 0 ) * this.lineHeight
|
|
4087
4258
|
);
|
|
4088
4259
|
|
|
4089
4260
|
if( callback )
|
|
@@ -4107,7 +4278,7 @@ class CodeEditor {
|
|
|
4107
4278
|
}
|
|
4108
4279
|
|
|
4109
4280
|
showSearchLineBox() {
|
|
4110
|
-
|
|
4281
|
+
|
|
4111
4282
|
this.hideSearchBox();
|
|
4112
4283
|
|
|
4113
4284
|
this.searchlinebox.classList.add( 'opened' );
|
|
@@ -4271,7 +4442,7 @@ class CodeEditor {
|
|
|
4271
4442
|
|
|
4272
4443
|
delete this._currentLineString;
|
|
4273
4444
|
delete this._currentLineNumber;
|
|
4274
|
-
delete this._buildingString;
|
|
4445
|
+
delete this._buildingString;
|
|
4275
4446
|
delete this._pendingString;
|
|
4276
4447
|
delete this._buildingBlockComment;
|
|
4277
4448
|
delete this._markdownHeader;
|
|
@@ -4283,8 +4454,13 @@ CodeEditor.keywords = {
|
|
|
4283
4454
|
|
|
4284
4455
|
'JavaScript': ['var', 'let', 'const', 'this', 'in', 'of', 'true', 'false', 'new', 'function', 'NaN', 'static', 'class', 'constructor', 'null', 'typeof', 'debugger', 'abstract',
|
|
4285
4456
|
'arguments', 'extends', 'instanceof', 'Infinity'],
|
|
4286
|
-
'C
|
|
4287
|
-
|
|
4457
|
+
'C': ['int', 'float', 'double', 'long', 'short', 'char', 'const', 'void', 'true', 'false', 'auto', 'struct', 'typedef', 'signed', 'volatile', 'unsigned', 'static', 'extern', 'enum', 'register',
|
|
4458
|
+
'union'],
|
|
4459
|
+
'C++': ['int', 'float', 'double', 'bool', 'long', 'short', 'char', 'wchar_t', 'const', 'static_cast', 'dynamic_cast', 'new', 'delete', 'void', 'true', 'false', 'auto', 'struct', 'typedef', 'nullptr',
|
|
4460
|
+
'NULL', 'signed', 'unsigned', 'namespace', 'enum', 'extern', 'union', 'sizeof', 'static'],
|
|
4461
|
+
'CMake': ['cmake_minimum_required', 'set', 'not', 'if', 'endif', 'exists', 'string', 'strequal', 'add_definitions', 'macro', 'endmacro', 'file', 'list', 'source_group', 'add_executable',
|
|
4462
|
+
'target_include_directories', 'set_target_properties', 'set_property', 'add_compile_options', 'add_link_options', 'include_directories', 'add_library', 'target_link_libraries',
|
|
4463
|
+
'target_link_options', 'add_subdirectory', 'add_compile_definitions', 'project', 'cache'],
|
|
4288
4464
|
'JSON': ['true', 'false'],
|
|
4289
4465
|
'GLSL': ['true', 'false', 'function', 'int', 'float', 'vec2', 'vec3', 'vec4', 'mat2x2', 'mat3x3', 'mat4x4', 'struct'],
|
|
4290
4466
|
'CSS': ['body', 'html', 'canvas', 'div', 'input', 'span', '.'],
|
|
@@ -4292,10 +4468,10 @@ CodeEditor.keywords = {
|
|
|
4292
4468
|
'sampler', 'sampler_comparison', 'texture_depth_2d', 'texture_depth_2d_array', 'texture_depth_cube', 'texture_depth_cube_array', 'texture_depth_multisampled_2d',
|
|
4293
4469
|
'texture_external', 'texture_1d', 'texture_2d', 'texture_2d_array', 'texture_3d', 'texture_cube', 'texture_cube_array', 'texture_storage_1d', 'texture_storage_2d',
|
|
4294
4470
|
'texture_storage_2d_array', 'texture_storage_3d', 'vec2u', 'vec3u', 'vec4u'],
|
|
4295
|
-
'Rust': ['as', 'const', 'crate', 'enum', 'extern', 'false', 'fn', 'impl', 'in', 'let', 'mod', 'move', 'mut', 'pub', 'ref', 'self', 'Self', 'static', 'struct', 'super', 'trait', 'true',
|
|
4471
|
+
'Rust': ['as', 'const', 'crate', 'enum', 'extern', 'false', 'fn', 'impl', 'in', 'let', 'mod', 'move', 'mut', 'pub', 'ref', 'self', 'Self', 'static', 'struct', 'super', 'trait', 'true',
|
|
4296
4472
|
'type', 'unsafe', 'use', 'where', 'abstract', 'become', 'box', 'final', 'macro', 'override', 'priv', 'typeof', 'unsized', 'virtual'],
|
|
4297
4473
|
'Python': ['False', 'def', 'None', 'True', 'in', 'is', 'and', 'lambda', 'nonlocal', 'not', 'or'],
|
|
4298
|
-
'Batch': ['set', 'SET', 'echo', 'ECHO', 'off', 'OFF', 'del', 'DEL', 'defined', 'DEFINED', 'setlocal', 'SETLOCAL', 'enabledelayedexpansion', 'ENABLEDELAYEDEXPANSION', 'driverquery',
|
|
4474
|
+
'Batch': ['set', 'SET', 'echo', 'ECHO', 'off', 'OFF', 'del', 'DEL', 'defined', 'DEFINED', 'setlocal', 'SETLOCAL', 'enabledelayedexpansion', 'ENABLEDELAYEDEXPANSION', 'driverquery',
|
|
4299
4475
|
'DRIVERQUERY', 'print', 'PRINT'],
|
|
4300
4476
|
'HTML': ['html', 'meta', 'title', 'link', 'script', 'body', 'DOCTYPE', 'head', 'br', 'i', 'a', 'li', 'img', 'tr', 'td', 'h1', 'h2', 'h3', 'h4', 'h5'],
|
|
4301
4477
|
'Markdown': ['br', 'i', 'a', 'li', 'img', 'table', 'title', 'tr', 'td', 'h1', 'h2', 'h3', 'h4', 'h5'],
|
|
@@ -4307,9 +4483,9 @@ CodeEditor.utils = { // These ones don't have hightlight, used as suggestions to
|
|
|
4307
4483
|
'bind', 'prototype', 'length', 'assign', 'entries', 'values', 'concat', 'substring', 'substr', 'splice', 'slice', 'buffer', 'appendChild', 'createElement', 'prompt',
|
|
4308
4484
|
'alert'],
|
|
4309
4485
|
'WGSL': ['textureSample'],
|
|
4310
|
-
'Python': ['abs', 'all', 'any', 'ascii', 'bin', 'bool', 'bytearray', 'bytes', 'callable', 'chr', 'classmethod', 'compile', 'complex', 'delattr', 'dict', 'dir', 'divmod',
|
|
4486
|
+
'Python': ['abs', 'all', 'any', 'ascii', 'bin', 'bool', 'bytearray', 'bytes', 'callable', 'chr', 'classmethod', 'compile', 'complex', 'delattr', 'dict', 'dir', 'divmod',
|
|
4311
4487
|
'enumerate', 'eval', 'exec', 'filter', 'float', 'format', 'frozenset', 'getattr', 'globals', 'hasattr', 'hash', 'help', 'hex', 'id', 'input', 'int', 'isinstance',
|
|
4312
|
-
'issubclass', 'iter', 'len', 'list', 'locals', 'map', 'max', 'memoryview', 'min', 'next', 'object', 'oct', 'open', 'ord', 'pow', 'print', 'property', 'range', 'repr',
|
|
4488
|
+
'issubclass', 'iter', 'len', 'list', 'locals', 'map', 'max', 'memoryview', 'min', 'next', 'object', 'oct', 'open', 'ord', 'pow', 'print', 'property', 'range', 'repr',
|
|
4313
4489
|
'reversed', 'round', 'set', 'setattr', 'slice', 'sorted', 'staticmethod', 'str', 'sum', 'super', 'tuple', 'type', 'vars', 'zip']
|
|
4314
4490
|
};
|
|
4315
4491
|
|
|
@@ -4318,14 +4494,14 @@ CodeEditor.types = {
|
|
|
4318
4494
|
'JavaScript': ['Object', 'String', 'Function', 'Boolean', 'Symbol', 'Error', 'Number', 'TextEncoder', 'TextDecoder', 'Array', 'ArrayBuffer', 'InputEvent', 'MouseEvent',
|
|
4319
4495
|
'Int8Array', 'Int16Array', 'Int32Array', 'Float32Array', 'Float64Array', 'Element'],
|
|
4320
4496
|
'Rust': ['u128'],
|
|
4321
|
-
'Python': ['int', 'type', 'float', 'map', 'list', 'ArithmeticError', 'AssertionError', 'AttributeError', 'Exception', 'EOFError', 'FloatingPointError', 'GeneratorExit',
|
|
4497
|
+
'Python': ['int', 'type', 'float', 'map', 'list', 'ArithmeticError', 'AssertionError', 'AttributeError', 'Exception', 'EOFError', 'FloatingPointError', 'GeneratorExit',
|
|
4322
4498
|
'ImportError', 'IndentationError', 'IndexError', 'KeyError', 'KeyboardInterrupt', 'LookupError', 'MemoryError', 'NameError', 'NotImplementedError', 'OSError',
|
|
4323
|
-
'OverflowError', 'ReferenceError', 'RuntimeError', 'StopIteration', 'SyntaxError', 'TabError', 'SystemError', 'SystemExit', 'TypeError', 'UnboundLocalError',
|
|
4499
|
+
'OverflowError', 'ReferenceError', 'RuntimeError', 'StopIteration', 'SyntaxError', 'TabError', 'SystemError', 'SystemExit', 'TypeError', 'UnboundLocalError',
|
|
4324
4500
|
'UnicodeError', 'UnicodeEncodeError', 'UnicodeDecodeError', 'UnicodeTranslateError', 'ValueError', 'ZeroDivisionError'],
|
|
4325
4501
|
'C++': ['uint8_t', 'uint16_t', 'uint32_t']
|
|
4326
4502
|
};
|
|
4327
4503
|
|
|
4328
|
-
CodeEditor.
|
|
4504
|
+
CodeEditor.builtIn = {
|
|
4329
4505
|
|
|
4330
4506
|
'JavaScript': ['document', 'console', 'window', 'navigator', 'performance'],
|
|
4331
4507
|
'CSS': ['*', '!important'],
|
|
@@ -4338,11 +4514,12 @@ CodeEditor.statementsAndDeclarations = {
|
|
|
4338
4514
|
|
|
4339
4515
|
'JavaScript': ['for', 'if', 'else', 'case', 'switch', 'return', 'while', 'continue', 'break', 'do', 'import', 'from', 'throw', 'async', 'try', 'catch', 'await'],
|
|
4340
4516
|
'CSS': ['@', 'import'],
|
|
4341
|
-
'C
|
|
4517
|
+
'C': ['for', 'if', 'else', 'return', 'continue', 'break', 'case', 'switch', 'while', 'using', 'default', 'goto', 'do'],
|
|
4518
|
+
'C++': ['std', 'for', 'if', 'else', 'return', 'continue', 'break', 'case', 'switch', 'while', 'using', 'glm', 'spdlog', 'default'],
|
|
4342
4519
|
'GLSL': ['for', 'if', 'else', 'return', 'continue', 'break'],
|
|
4343
4520
|
'WGSL': ['const','for', 'if', 'else', 'return', 'continue', 'break', 'storage', 'read', 'read_write', 'uniform', 'function', 'workgroup'],
|
|
4344
4521
|
'Rust': ['break', 'else', 'continue', 'for', 'if', 'loop', 'match', 'return', 'while', 'do', 'yield'],
|
|
4345
|
-
'Python': ['if', 'raise', 'del', 'import', 'return', 'elif', 'try', 'else', 'while', 'as', 'except', 'with', 'assert', 'finally', 'yield', 'break', 'for', 'class', 'continue',
|
|
4522
|
+
'Python': ['if', 'raise', 'del', 'import', 'return', 'elif', 'try', 'else', 'while', 'as', 'except', 'with', 'assert', 'finally', 'yield', 'break', 'for', 'class', 'continue',
|
|
4346
4523
|
'global', 'pass', 'from'],
|
|
4347
4524
|
'Batch': ['if', 'IF', 'for', 'FOR', 'in', 'IN', 'do', 'DO', 'call', 'CALL', 'goto', 'GOTO', 'exit', 'EXIT']
|
|
4348
4525
|
};
|
|
@@ -4350,7 +4527,9 @@ CodeEditor.statementsAndDeclarations = {
|
|
|
4350
4527
|
CodeEditor.symbols = {
|
|
4351
4528
|
|
|
4352
4529
|
'JavaScript': ['<', '>', '[', ']', '{', '}', '(', ')', ';', '=', '|', '||', '&', '&&', '?', '??'],
|
|
4530
|
+
'C': ['<', '>', '[', ']', '{', '}', '(', ')', ';', '=', '|', '||', '&', '&&', '?', '*', '-', '+'],
|
|
4353
4531
|
'C++': ['<', '>', '[', ']', '{', '}', '(', ')', ';', '=', '|', '||', '&', '&&', '?', '::', '*', '-', '+'],
|
|
4532
|
+
'CMake': ['{', '}'],
|
|
4354
4533
|
'JSON': ['[', ']', '{', '}', '(', ')'],
|
|
4355
4534
|
'GLSL': ['[', ']', '{', '}', '(', ')'],
|
|
4356
4535
|
'WGSL': ['[', ']', '{', '}', '(', ')', '->'],
|
|
@@ -4358,7 +4537,8 @@ CodeEditor.symbols = {
|
|
|
4358
4537
|
'Rust': ['<', '>', '[', ']', '(', ')', '='],
|
|
4359
4538
|
'Python': ['<', '>', '[', ']', '(', ')', '='],
|
|
4360
4539
|
'Batch': ['[', ']', '(', ')', '%'],
|
|
4361
|
-
'HTML': ['<', '>', '/']
|
|
4540
|
+
'HTML': ['<', '>', '/'],
|
|
4541
|
+
'XML': ['<', '>', '/']
|
|
4362
4542
|
};
|
|
4363
4543
|
|
|
4364
4544
|
LX.CodeEditor = CodeEditor;
|