lexgui 0.1.20 → 0.1.22
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 +519 -110
- package/build/lexgui.css +102 -106
- package/build/lexgui.js +5 -5
- package/build/lexgui.module.js +5 -5
- package/changelog.md +14 -0
- package/examples/code_editor.html +7 -7
- package/package.json +1 -1
|
@@ -21,14 +21,33 @@ function swapArrayElements( array, id0, id1 ) {
|
|
|
21
21
|
[array[id0], array[id1]] = [array[id1], array[id0]];
|
|
22
22
|
};
|
|
23
23
|
|
|
24
|
-
function
|
|
25
|
-
return str.substr(0, idx) + str.substr(idx +
|
|
24
|
+
function sliceChars( str, idx, n = 1 ) {
|
|
25
|
+
return str.substr(0, idx) + str.substr(idx + n);
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
function firstNonspaceIndex( str ) {
|
|
29
29
|
return str.search(/\S|$/);
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
+
function indexOfFrom( str, reg, from, reverse ) {
|
|
33
|
+
|
|
34
|
+
from = from ?? 0;
|
|
35
|
+
|
|
36
|
+
if( reverse )
|
|
37
|
+
{
|
|
38
|
+
str = str.substr( 0, from );
|
|
39
|
+
var k = from - 1;
|
|
40
|
+
while( str[ k ] && str[ k ] != reg )
|
|
41
|
+
k--;
|
|
42
|
+
return str[ k ] ? k : -1;
|
|
43
|
+
}
|
|
44
|
+
else
|
|
45
|
+
{
|
|
46
|
+
str = str.substr( from );
|
|
47
|
+
return from + str.indexOf( reg );
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
32
51
|
function deleteElement( el ) {
|
|
33
52
|
if( el ) el.remove();
|
|
34
53
|
}
|
|
@@ -44,10 +63,11 @@ function doAsync( fn, ms ) {
|
|
|
44
63
|
|
|
45
64
|
class CodeSelection {
|
|
46
65
|
|
|
47
|
-
constructor( editor, ix, iy ) {
|
|
66
|
+
constructor( editor, ix, iy, className = "lexcodeselection" ) {
|
|
48
67
|
|
|
49
68
|
this.editor = editor;
|
|
50
69
|
this.chars = 0;
|
|
70
|
+
this.className = className;
|
|
51
71
|
|
|
52
72
|
this.fromX = ix;
|
|
53
73
|
this.toX = ix;
|
|
@@ -88,7 +108,7 @@ class CodeSelection {
|
|
|
88
108
|
this.fromY = this.toY = y;
|
|
89
109
|
|
|
90
110
|
var domEl = document.createElement( 'div' );
|
|
91
|
-
domEl.className =
|
|
111
|
+
domEl.className = this.className;
|
|
92
112
|
|
|
93
113
|
domEl._top = y * this.editor.lineHeight;
|
|
94
114
|
domEl.style.top = domEl._top + "px";
|
|
@@ -181,6 +201,9 @@ class CodeEditor {
|
|
|
181
201
|
static WORD_TYPE_METHOD = 0;
|
|
182
202
|
static WORD_TYPE_CLASS = 1;
|
|
183
203
|
|
|
204
|
+
static CODE_MAX_FONT_SIZE = 20;
|
|
205
|
+
static CODE_MIN_FONT_SIZE = 11;
|
|
206
|
+
|
|
184
207
|
/**
|
|
185
208
|
* @param {*} options
|
|
186
209
|
* skip_info, allow_add_scripts, name
|
|
@@ -281,7 +304,7 @@ class CodeEditor {
|
|
|
281
304
|
|
|
282
305
|
if( !this.disableEdition )
|
|
283
306
|
{
|
|
284
|
-
this.root.addEventListener( 'keydown', this.processKey.bind( this)
|
|
307
|
+
this.root.addEventListener( 'keydown', this.processKey.bind( this) );
|
|
285
308
|
this.root.addEventListener( 'focus', this.processFocus.bind( this, true ) );
|
|
286
309
|
this.root.addEventListener( 'focusout', this.processFocus.bind( this, false ) );
|
|
287
310
|
}
|
|
@@ -393,8 +416,16 @@ class CodeEditor {
|
|
|
393
416
|
});
|
|
394
417
|
|
|
395
418
|
this.codeScroller.addEventListener( 'wheel', e => {
|
|
396
|
-
|
|
397
|
-
|
|
419
|
+
if( e.ctrlKey )
|
|
420
|
+
{
|
|
421
|
+
e.preventDefault();
|
|
422
|
+
( e.deltaY > 0.0 ? this._decreaseFontSize() : this._increaseFontSize() );
|
|
423
|
+
}
|
|
424
|
+
else
|
|
425
|
+
{
|
|
426
|
+
const dX = ( e.deltaY > 0.0 ? 10.0 : -10.0 ) * ( e.shiftKey ? 1.0 : 0.0 );
|
|
427
|
+
if( dX != 0.0 ) this.setScrollBarValue( 'horizontal', dX );
|
|
428
|
+
}
|
|
398
429
|
});
|
|
399
430
|
}
|
|
400
431
|
|
|
@@ -427,6 +458,51 @@ class CodeEditor {
|
|
|
427
458
|
this.isAutoCompleteActive = false;
|
|
428
459
|
}
|
|
429
460
|
|
|
461
|
+
// Add search box
|
|
462
|
+
{
|
|
463
|
+
var box = document.createElement( 'div' );
|
|
464
|
+
box.className = "searchbox";
|
|
465
|
+
|
|
466
|
+
var searchPanel = new LX.Panel();
|
|
467
|
+
box.appendChild( searchPanel.root );
|
|
468
|
+
|
|
469
|
+
searchPanel.sameLine( 4 );
|
|
470
|
+
searchPanel.addText( null, "", null, { placeholder: "Find" } );
|
|
471
|
+
searchPanel.addButton( null, "up", () => this.search( null, true ), { className: 'micro', icon: "fa fa-arrow-up" } );
|
|
472
|
+
searchPanel.addButton( null, "down", () => this.search(), { className: 'micro', icon: "fa fa-arrow-down" } );
|
|
473
|
+
searchPanel.addButton( null, "x", this.hideSearchBox.bind( this ), { className: 'micro', icon: "fa fa-xmark" } );
|
|
474
|
+
|
|
475
|
+
box.querySelector( 'input' ).addEventListener( 'keyup', e => {
|
|
476
|
+
if( e.key == 'Escape' ) this.hideSearchBox();
|
|
477
|
+
else if( e.key == 'Enter' ) this.search( e.target.value, !!e.shiftKey );
|
|
478
|
+
} );
|
|
479
|
+
|
|
480
|
+
this.searchbox = box;
|
|
481
|
+
this.tabs.area.attach( box );
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
// Add search LINE box
|
|
485
|
+
{
|
|
486
|
+
var box = document.createElement( 'div' );
|
|
487
|
+
box.className = "searchbox gotoline";
|
|
488
|
+
|
|
489
|
+
var searchPanel = new LX.Panel();
|
|
490
|
+
box.appendChild( searchPanel.root );
|
|
491
|
+
|
|
492
|
+
searchPanel.addText( null, "", ( value, event ) => {
|
|
493
|
+
input.value = ":" + value.replaceAll( ':', '' );
|
|
494
|
+
this.goToLine( input.value.slice( 1 ) );
|
|
495
|
+
}, { placeholder: "Go to line", trigger: "input" } );
|
|
496
|
+
|
|
497
|
+
let input = box.querySelector( 'input' );
|
|
498
|
+
input.addEventListener( 'keyup', e => {
|
|
499
|
+
if( e.key == 'Escape' ) this.hideSearchLineBox();
|
|
500
|
+
} );
|
|
501
|
+
|
|
502
|
+
this.searchlinebox = box;
|
|
503
|
+
this.tabs.area.attach( box );
|
|
504
|
+
}
|
|
505
|
+
|
|
430
506
|
// Add code-sizer
|
|
431
507
|
{
|
|
432
508
|
this.codeSizer = document.createElement( 'div' );
|
|
@@ -458,8 +534,8 @@ class CodeEditor {
|
|
|
458
534
|
this.tabSpaces = 4;
|
|
459
535
|
this.maxUndoSteps = 16;
|
|
460
536
|
this.lineHeight = 20;
|
|
461
|
-
this.defaultSingleLineCommentToken =
|
|
462
|
-
this.
|
|
537
|
+
this.defaultSingleLineCommentToken = '//';
|
|
538
|
+
this.defaultBlockCommentTokens = [ '/*', '*/' ];
|
|
463
539
|
this._lastTime = null;
|
|
464
540
|
|
|
465
541
|
this.pairKeys = {
|
|
@@ -479,18 +555,19 @@ class CodeEditor {
|
|
|
479
555
|
// setInterval( this.scanWordSuggestions.bind( this ), 2000 );
|
|
480
556
|
|
|
481
557
|
this.languages = {
|
|
482
|
-
'Plain Text': { ext: 'txt' },
|
|
558
|
+
'Plain Text': { ext: 'txt', blockComments: false, singleLineComments: false },
|
|
483
559
|
'JavaScript': { ext: 'js' },
|
|
484
560
|
'C++': { ext: 'cpp' },
|
|
485
561
|
'CSS': { ext: 'css' },
|
|
486
562
|
'GLSL': { ext: 'glsl' },
|
|
487
563
|
'WGSL': { ext: 'wgsl' },
|
|
488
|
-
'JSON': { ext: 'json' },
|
|
489
|
-
'XML': { ext: 'xml' },
|
|
564
|
+
'JSON': { ext: 'json', blockComments: false, singleLineComments: false },
|
|
565
|
+
'XML': { ext: 'xml', tags: true },
|
|
490
566
|
'Rust': { ext: 'rs' },
|
|
491
567
|
'Python': { ext: 'py', singleLineCommentToken: '#' },
|
|
492
|
-
'HTML': { ext: 'html' },
|
|
493
|
-
'Batch': { ext: 'bat', blockComments: false, singleLineCommentToken: '::' }
|
|
568
|
+
'HTML': { ext: 'html', tags: true, singleLineComments: false, blockCommentsTokens: [ '<!--', '-->' ] },
|
|
569
|
+
'Batch': { ext: 'bat', blockComments: false, singleLineCommentToken: '::' },
|
|
570
|
+
'Markdown': { ext: 'md', blockComments: false, singleLineCommentToken: '::', tags: true }
|
|
494
571
|
};
|
|
495
572
|
|
|
496
573
|
this.specialKeys = [
|
|
@@ -516,7 +593,8 @@ class CodeEditor {
|
|
|
516
593
|
'Python': ['False', 'def', 'None', 'True', 'in', 'is', 'and', 'lambda', 'nonlocal', 'not', 'or'],
|
|
517
594
|
'Batch': ['set', 'SET', 'echo', 'ECHO', 'off', 'OFF', 'del', 'DEL', 'defined', 'DEFINED', 'setlocal', 'SETLOCAL', 'enabledelayedexpansion', 'ENABLEDELAYEDEXPANSION', 'driverquery',
|
|
518
595
|
'DRIVERQUERY', 'print', 'PRINT'],
|
|
519
|
-
'HTML': ['html', 'meta', 'title', 'link', 'script', 'body', 'DOCTYPE', 'head'],
|
|
596
|
+
'HTML': ['html', 'meta', 'title', 'link', 'script', 'body', 'DOCTYPE', 'head', 'br', 'i', 'a', 'li', 'img', 'tr', 'td', 'h1', 'h2', 'h3', 'h4', 'h5'],
|
|
597
|
+
'Markdown': ['br', 'i', 'a', 'li', 'img', 'table', 'title', 'tr', 'td', 'h1', 'h2', 'h3', 'h4', 'h5'],
|
|
520
598
|
};
|
|
521
599
|
this.utils = { // These ones don't have hightlight, used as suggestions to autocomplete only...
|
|
522
600
|
'JavaScript': ['querySelector', 'body', 'addEventListener', 'removeEventListener', 'remove', 'sort', 'keys', 'filter', 'isNaN', 'parseFloat', 'parseInt', 'EPSILON', 'isFinite',
|
|
@@ -541,7 +619,8 @@ class CodeEditor {
|
|
|
541
619
|
'JavaScript': ['document', 'console', 'window', 'navigator', 'performance'],
|
|
542
620
|
'CSS': ['*', '!important'],
|
|
543
621
|
'C++': ['vector', 'list', 'map'],
|
|
544
|
-
'HTML': ['type', 'xmlns', 'PUBLIC', 'http-equiv', 'src', 'lang', 'href', 'rel', 'content', 'xml'], // attributes
|
|
622
|
+
'HTML': ['type', 'xmlns', 'PUBLIC', 'http-equiv', 'src', 'style', 'lang', 'href', 'rel', 'content', 'xml', 'alt'], // attributes
|
|
623
|
+
'Markdown': ['type', 'src', 'style', 'lang', 'href', 'rel', 'content', 'valign', 'alt'], // attributes
|
|
545
624
|
};
|
|
546
625
|
this.statementsAndDeclarations = {
|
|
547
626
|
'JavaScript': ['for', 'if', 'else', 'case', 'switch', 'return', 'while', 'continue', 'break', 'do', 'import', 'from', 'throw', 'async', 'try', 'catch', 'await'],
|
|
@@ -579,6 +658,7 @@ class CodeEditor {
|
|
|
579
658
|
|
|
580
659
|
this.action( 'Escape', false, ( ln, cursor, e ) => {
|
|
581
660
|
this.hideAutoCompleteBox();
|
|
661
|
+
this.hideSearchBox();
|
|
582
662
|
});
|
|
583
663
|
|
|
584
664
|
this.action( 'Backspace', false, ( ln, cursor, e ) => {
|
|
@@ -595,16 +675,37 @@ class CodeEditor {
|
|
|
595
675
|
}
|
|
596
676
|
}
|
|
597
677
|
else {
|
|
678
|
+
|
|
598
679
|
var letter = this.getCharAtPos( cursor, -1 );
|
|
599
680
|
if( letter ) {
|
|
600
|
-
|
|
601
|
-
|
|
681
|
+
|
|
682
|
+
var deleteFromPosition = cursor.position - 1;
|
|
683
|
+
var numCharsDeleted = 1;
|
|
684
|
+
|
|
685
|
+
// Delete full word
|
|
686
|
+
if( e.shiftKey )
|
|
687
|
+
{
|
|
688
|
+
const [word, from, to] = this.getWordAtPos( cursor, -1 );
|
|
689
|
+
|
|
690
|
+
if( word.length > 1 )
|
|
691
|
+
{
|
|
692
|
+
deleteFromPosition = from;
|
|
693
|
+
numCharsDeleted = word.length;
|
|
694
|
+
}
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
this.code.lines[ ln ] = sliceChars( this.code.lines[ ln ], deleteFromPosition, numCharsDeleted );
|
|
602
698
|
this.processLine( ln );
|
|
699
|
+
|
|
700
|
+
this.cursorToPosition( cursor, deleteFromPosition );
|
|
701
|
+
|
|
603
702
|
if( this.useAutoComplete )
|
|
604
703
|
this.showAutoCompleteBox( 'foo', cursor );
|
|
605
704
|
}
|
|
606
705
|
else if( this.code.lines[ ln - 1 ] != undefined ) {
|
|
706
|
+
|
|
607
707
|
this.lineUp();
|
|
708
|
+
e.cancelShift = true;
|
|
608
709
|
this.actions[ 'End' ].callback( cursor.line, cursor, e );
|
|
609
710
|
// Move line on top
|
|
610
711
|
this.code.lines[ ln - 1 ] += this.code.lines[ ln ];
|
|
@@ -626,7 +727,7 @@ class CodeEditor {
|
|
|
626
727
|
{
|
|
627
728
|
var letter = this.getCharAtPos( cursor );
|
|
628
729
|
if( letter ) {
|
|
629
|
-
this.code.lines[ ln ] =
|
|
730
|
+
this.code.lines[ ln ] = sliceChars( this.code.lines[ ln ], cursor.position );
|
|
630
731
|
this.processLine( ln );
|
|
631
732
|
}
|
|
632
733
|
else if(this.code.lines[ ln + 1 ] != undefined) {
|
|
@@ -721,7 +822,7 @@ class CodeEditor {
|
|
|
721
822
|
return;
|
|
722
823
|
}
|
|
723
824
|
|
|
724
|
-
this._addUndoStep( cursor );
|
|
825
|
+
this._addUndoStep( cursor, true );
|
|
725
826
|
|
|
726
827
|
var _c0 = this.getCharAtPos( cursor, -1 );
|
|
727
828
|
var _c1 = this.getCharAtPos( cursor );
|
|
@@ -949,7 +1050,7 @@ class CodeEditor {
|
|
|
949
1050
|
if( options.allow_add_scripts ?? true )
|
|
950
1051
|
this.addTab("+", false, "New File");
|
|
951
1052
|
|
|
952
|
-
this.addTab(options.name || "untitled", true, options.title);
|
|
1053
|
+
this.addTab( options.name || "untitled", true, options.title );
|
|
953
1054
|
|
|
954
1055
|
// Create inspector panel
|
|
955
1056
|
let panel = this._createPanelInfo();
|
|
@@ -967,14 +1068,15 @@ class CodeEditor {
|
|
|
967
1068
|
);
|
|
968
1069
|
|
|
969
1070
|
// Add to the document.fonts (FontFaceSet)
|
|
970
|
-
document.fonts.add(commitMono);
|
|
1071
|
+
document.fonts.add( commitMono );
|
|
971
1072
|
|
|
972
1073
|
// Load the font
|
|
973
1074
|
commitMono.load();
|
|
974
1075
|
|
|
975
1076
|
// Wait until the fonts are all loaded
|
|
976
1077
|
document.fonts.ready.then(() => {
|
|
977
|
-
console.log("commitMono loaded")
|
|
1078
|
+
// console.log("commitMono loaded")
|
|
1079
|
+
this.charWidth = this._measureChar( "a", true );
|
|
978
1080
|
});
|
|
979
1081
|
}
|
|
980
1082
|
|
|
@@ -1132,23 +1234,32 @@ class CodeEditor {
|
|
|
1132
1234
|
}
|
|
1133
1235
|
}
|
|
1134
1236
|
|
|
1135
|
-
_addUndoStep( cursor ) {
|
|
1237
|
+
_addUndoStep( cursor, force, deleteRedo = true ) {
|
|
1136
1238
|
|
|
1137
1239
|
const d = new Date();
|
|
1138
1240
|
const current = d.getTime();
|
|
1139
1241
|
|
|
1140
|
-
if( !
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
if( ( current - this._lastTime ) > 3000 ){
|
|
1144
|
-
this._lastTime = null;
|
|
1145
|
-
} else {
|
|
1146
|
-
// If time not enough, reset timer
|
|
1242
|
+
if( !force )
|
|
1243
|
+
{
|
|
1244
|
+
if( !this._lastTime ) {
|
|
1147
1245
|
this._lastTime = current;
|
|
1148
|
-
|
|
1246
|
+
} else {
|
|
1247
|
+
if( ( current - this._lastTime ) > 3000 ){
|
|
1248
|
+
this._lastTime = null;
|
|
1249
|
+
} else {
|
|
1250
|
+
// If time not enough, reset timer
|
|
1251
|
+
this._lastTime = current;
|
|
1252
|
+
return;
|
|
1253
|
+
}
|
|
1149
1254
|
}
|
|
1150
1255
|
}
|
|
1151
1256
|
|
|
1257
|
+
if( deleteRedo )
|
|
1258
|
+
{
|
|
1259
|
+
// Remove all redo steps
|
|
1260
|
+
this.code.redoSteps.length = 0;
|
|
1261
|
+
}
|
|
1262
|
+
|
|
1152
1263
|
var cursor = cursor ?? this.cursors.children[ 0 ];
|
|
1153
1264
|
|
|
1154
1265
|
this.code.undoSteps.push( {
|
|
@@ -1159,6 +1270,18 @@ class CodeEditor {
|
|
|
1159
1270
|
} );
|
|
1160
1271
|
}
|
|
1161
1272
|
|
|
1273
|
+
_addRedoStep( cursor ) {
|
|
1274
|
+
|
|
1275
|
+
var cursor = cursor ?? this.cursors.children[ 0 ];
|
|
1276
|
+
|
|
1277
|
+
this.code.redoSteps.push( {
|
|
1278
|
+
lines: LX.deepCopy( this.code.lines ),
|
|
1279
|
+
cursor: this.saveCursor( cursor ),
|
|
1280
|
+
line: cursor.line,
|
|
1281
|
+
position: cursor.position
|
|
1282
|
+
} );
|
|
1283
|
+
}
|
|
1284
|
+
|
|
1162
1285
|
_changeLanguage( lang ) {
|
|
1163
1286
|
|
|
1164
1287
|
this.code.language = lang;
|
|
@@ -1316,6 +1439,7 @@ class CodeEditor {
|
|
|
1316
1439
|
code.language = "Plain Text";
|
|
1317
1440
|
code.cursorState = {};
|
|
1318
1441
|
code.undoSteps = [];
|
|
1442
|
+
code.redoSteps = [];
|
|
1319
1443
|
code.tabName = name;
|
|
1320
1444
|
code.title = title ?? name;
|
|
1321
1445
|
code.tokens = {};
|
|
@@ -1486,6 +1610,7 @@ class CodeEditor {
|
|
|
1486
1610
|
this.lastMouseDown = LX.getTime();
|
|
1487
1611
|
this.state.selectingText = true;
|
|
1488
1612
|
this.endSelection();
|
|
1613
|
+
this.processClick( e );
|
|
1489
1614
|
}
|
|
1490
1615
|
|
|
1491
1616
|
else if( e.type == 'mouseup' )
|
|
@@ -1549,9 +1674,8 @@ class CodeEditor {
|
|
|
1549
1674
|
|
|
1550
1675
|
_onMouseUp( e ) {
|
|
1551
1676
|
|
|
1552
|
-
if( (LX.getTime() - this.lastMouseDown) <
|
|
1677
|
+
if( (LX.getTime() - this.lastMouseDown) < 120 ) {
|
|
1553
1678
|
this.state.selectingText = false;
|
|
1554
|
-
this.processClick( e );
|
|
1555
1679
|
this.endSelection();
|
|
1556
1680
|
}
|
|
1557
1681
|
|
|
@@ -1741,7 +1865,7 @@ class CodeEditor {
|
|
|
1741
1865
|
|
|
1742
1866
|
async processKey( e ) {
|
|
1743
1867
|
|
|
1744
|
-
if( !this.code )
|
|
1868
|
+
if( !this.code || e.srcElement.constructor != HTMLDivElement )
|
|
1745
1869
|
return;
|
|
1746
1870
|
|
|
1747
1871
|
var key = e.key ?? e.detail.key;
|
|
@@ -1778,11 +1902,20 @@ class CodeEditor {
|
|
|
1778
1902
|
return;
|
|
1779
1903
|
case 'd': // duplicate line
|
|
1780
1904
|
e.preventDefault();
|
|
1905
|
+
this.endSelection();
|
|
1781
1906
|
this.code.lines.splice( lidx, 0, this.code.lines[ lidx ] );
|
|
1782
1907
|
this.lineDown( cursor );
|
|
1783
1908
|
this.processLines();
|
|
1784
1909
|
this.hideAutoCompleteBox();
|
|
1785
1910
|
return;
|
|
1911
|
+
case 'f': // find/search
|
|
1912
|
+
e.preventDefault();
|
|
1913
|
+
this.showSearchBox();
|
|
1914
|
+
return;
|
|
1915
|
+
case 'g': // find line
|
|
1916
|
+
e.preventDefault();
|
|
1917
|
+
this.showSearchLineBox();
|
|
1918
|
+
return;
|
|
1786
1919
|
case 's': // save
|
|
1787
1920
|
e.preventDefault();
|
|
1788
1921
|
this.onsave( this.getText() );
|
|
@@ -1794,13 +1927,31 @@ class CodeEditor {
|
|
|
1794
1927
|
this._cutContent();
|
|
1795
1928
|
this.hideAutoCompleteBox();
|
|
1796
1929
|
return;
|
|
1930
|
+
case 'y': // redo
|
|
1931
|
+
if(!this.code.redoSteps.length)
|
|
1932
|
+
return;
|
|
1933
|
+
this._addUndoStep( cursor, true, false);
|
|
1934
|
+
const redo_step = this.code.redoSteps.pop();
|
|
1935
|
+
this.code.lines = redo_step.lines;
|
|
1936
|
+
this.processLines();
|
|
1937
|
+
this.restoreCursor( cursor, redo_step.cursor );
|
|
1938
|
+
return;
|
|
1797
1939
|
case 'z': // undo
|
|
1798
1940
|
if(!this.code.undoSteps.length)
|
|
1799
1941
|
return;
|
|
1800
|
-
|
|
1801
|
-
this.code.
|
|
1942
|
+
this._addRedoStep( cursor );
|
|
1943
|
+
const undo_step = this.code.undoSteps.pop();
|
|
1944
|
+
this.code.lines = undo_step.lines;
|
|
1802
1945
|
this.processLines();
|
|
1803
|
-
this.restoreCursor( cursor,
|
|
1946
|
+
this.restoreCursor( cursor, undo_step.cursor );
|
|
1947
|
+
return;
|
|
1948
|
+
case '+': // increase size
|
|
1949
|
+
e.preventDefault();
|
|
1950
|
+
this._increaseFontSize();
|
|
1951
|
+
return;
|
|
1952
|
+
case '-': // decrease size
|
|
1953
|
+
e.preventDefault();
|
|
1954
|
+
this._decreaseFontSize();
|
|
1804
1955
|
return;
|
|
1805
1956
|
}
|
|
1806
1957
|
}
|
|
@@ -1964,7 +2115,7 @@ class CodeEditor {
|
|
|
1964
2115
|
let lidx = cursor.line;
|
|
1965
2116
|
let text_to_cut = "";
|
|
1966
2117
|
|
|
1967
|
-
this._addUndoStep( cursor );
|
|
2118
|
+
this._addUndoStep( cursor, true );
|
|
1968
2119
|
|
|
1969
2120
|
if( !this.selection ) {
|
|
1970
2121
|
text_to_cut = "\n" + this.code.lines[ cursor.line ];
|
|
@@ -2080,6 +2231,7 @@ class CodeEditor {
|
|
|
2080
2231
|
|
|
2081
2232
|
processLine( linenum, force ) {
|
|
2082
2233
|
|
|
2234
|
+
const lang = this.languages[ this.highlight ];
|
|
2083
2235
|
const local_line_num = this.toLocalLine( linenum );
|
|
2084
2236
|
const gutter_line = "<span class='line-gutter'>" + (linenum + 1) + "</span>";
|
|
2085
2237
|
|
|
@@ -2096,6 +2248,7 @@ class CodeEditor {
|
|
|
2096
2248
|
// multi-line strings not supported by now
|
|
2097
2249
|
delete this._buildingString;
|
|
2098
2250
|
delete this._pendingString;
|
|
2251
|
+
delete this._markdownHeader;
|
|
2099
2252
|
|
|
2100
2253
|
let linestring = this.code.lines[ linenum ];
|
|
2101
2254
|
|
|
@@ -2138,44 +2291,36 @@ class CodeEditor {
|
|
|
2138
2291
|
|
|
2139
2292
|
const token = tokensToEvaluate[ i ];
|
|
2140
2293
|
|
|
2141
|
-
if(
|
|
2294
|
+
if( lang.blockComments ?? true )
|
|
2142
2295
|
{
|
|
2143
|
-
|
|
2296
|
+
const blockCommentsToken = ( lang.blockCommentsTokens ?? this.defaultBlockCommentTokens )[ 0 ];
|
|
2297
|
+
if( token.substr( 0, blockCommentsToken.length ) == blockCommentsToken )
|
|
2144
2298
|
this._buildingBlockComment = true;
|
|
2145
2299
|
}
|
|
2146
2300
|
|
|
2147
|
-
line_inner_html += this._evaluateToken(
|
|
2301
|
+
line_inner_html += this._evaluateToken( {
|
|
2302
|
+
token: token,
|
|
2303
|
+
prev: prev,
|
|
2304
|
+
prevWithSpaces: tokensToEvaluate[ i - 1 ],
|
|
2305
|
+
next: next,
|
|
2306
|
+
nextWithSpaces: tokensToEvaluate[ i + 1 ],
|
|
2307
|
+
tokenIndex: i,
|
|
2308
|
+
isFirstToken: (i == 0),
|
|
2309
|
+
isLastToken: (i == tokensToEvaluate.length - 1)
|
|
2310
|
+
} );
|
|
2148
2311
|
}
|
|
2149
2312
|
|
|
2150
2313
|
return UPDATE_LINE( line_inner_html );
|
|
2151
2314
|
}
|
|
2152
2315
|
|
|
2153
|
-
|
|
2154
|
-
|
|
2155
|
-
if( this.highlight == 'C++' || this.highlight == 'CSS' )
|
|
2156
|
-
{
|
|
2157
|
-
var idx = tokens.slice( offset ).findIndex( ( value, index ) => this.isNumber( value ) );
|
|
2158
|
-
if( idx > -1 )
|
|
2159
|
-
{
|
|
2160
|
-
idx += offset; // Add offset to compute within the whole array of tokens
|
|
2161
|
-
let data = tokens[ idx ] + tokens[ ++idx ];
|
|
2162
|
-
while( this.isNumber( data ) )
|
|
2163
|
-
{
|
|
2164
|
-
tokens[ idx - 1 ] += tokens[ idx ];
|
|
2165
|
-
tokens.splice( idx, 1 );
|
|
2166
|
-
data += tokens[ idx ];
|
|
2167
|
-
}
|
|
2168
|
-
// Scan for numbers again
|
|
2169
|
-
return this._processTokens( tokens, idx );
|
|
2170
|
-
}
|
|
2171
|
-
}
|
|
2316
|
+
_lineHasComment( linestring ) {
|
|
2172
2317
|
|
|
2173
|
-
|
|
2174
|
-
}
|
|
2318
|
+
const lang = this.languages[ this.highlight ];
|
|
2175
2319
|
|
|
2176
|
-
|
|
2320
|
+
if( !(lang.singleLineComments ?? true) )
|
|
2321
|
+
return;
|
|
2177
2322
|
|
|
2178
|
-
const singleLineCommentToken =
|
|
2323
|
+
const singleLineCommentToken = lang.singleLineCommentToken ?? this.defaultSingleLineCommentToken;
|
|
2179
2324
|
const idx = linestring.indexOf( singleLineCommentToken );
|
|
2180
2325
|
|
|
2181
2326
|
if( idx > -1 )
|
|
@@ -2199,6 +2344,8 @@ class CodeEditor {
|
|
|
2199
2344
|
|
|
2200
2345
|
_getTokensFromLine( linestring, skipNonWords ) {
|
|
2201
2346
|
|
|
2347
|
+
this._currentLineString = linestring;
|
|
2348
|
+
|
|
2202
2349
|
// Check if line comment
|
|
2203
2350
|
const ogLine = linestring;
|
|
2204
2351
|
const hasCommentIdx = this._lineHasComment( linestring );
|
|
@@ -2209,14 +2356,19 @@ class CodeEditor {
|
|
|
2209
2356
|
}
|
|
2210
2357
|
|
|
2211
2358
|
let tokensToEvaluate = []; // store in a temp array so we know prev and next tokens...
|
|
2359
|
+
let charCounterList = [];
|
|
2360
|
+
let charCounter = 0;
|
|
2212
2361
|
|
|
2213
2362
|
const pushToken = function( t ) {
|
|
2214
2363
|
if( (skipNonWords && ( t.includes('"') || t.length < 3 )) )
|
|
2215
2364
|
return;
|
|
2216
2365
|
tokensToEvaluate.push( t );
|
|
2366
|
+
charCounterList.push( charCounter );
|
|
2367
|
+
// Update positions
|
|
2368
|
+
charCounter += t.length;
|
|
2217
2369
|
};
|
|
2218
2370
|
|
|
2219
|
-
let iter = linestring.matchAll(/(
|
|
2371
|
+
let iter = linestring.matchAll(/(<!--|-->|\*\/|\/\*|::|[\[\](){}<>.,;:*"'%@!/= ])/g);
|
|
2220
2372
|
let subtokens = iter.next();
|
|
2221
2373
|
if( subtokens.value )
|
|
2222
2374
|
{
|
|
@@ -2234,47 +2386,103 @@ class CodeEditor {
|
|
|
2234
2386
|
}
|
|
2235
2387
|
}
|
|
2236
2388
|
}
|
|
2237
|
-
else
|
|
2389
|
+
else pushToken( linestring );
|
|
2238
2390
|
|
|
2239
2391
|
if( hasCommentIdx != undefined )
|
|
2240
2392
|
{
|
|
2241
2393
|
pushToken( ogLine.substring( hasCommentIdx ) );
|
|
2242
2394
|
}
|
|
2243
2395
|
|
|
2396
|
+
this._currentTokenPositions = charCounterList;
|
|
2397
|
+
|
|
2244
2398
|
return this._processTokens( tokensToEvaluate );
|
|
2245
2399
|
}
|
|
2246
2400
|
|
|
2401
|
+
_processTokens( tokens, offset = 0 ) {
|
|
2402
|
+
|
|
2403
|
+
if( this.highlight == 'C++' || this.highlight == 'CSS' )
|
|
2404
|
+
{
|
|
2405
|
+
var idx = tokens.slice( offset ).findIndex( ( value, index ) => this.isNumber( value ) );
|
|
2406
|
+
if( idx > -1 )
|
|
2407
|
+
{
|
|
2408
|
+
idx += offset; // Add offset to compute within the whole array of tokens
|
|
2409
|
+
let data = tokens[ idx ] + tokens[ ++idx ];
|
|
2410
|
+
while( this.isNumber( data ) )
|
|
2411
|
+
{
|
|
2412
|
+
tokens[ idx - 1 ] += tokens[ idx ];
|
|
2413
|
+
tokens.splice( idx, 1 );
|
|
2414
|
+
data += tokens[ idx ];
|
|
2415
|
+
}
|
|
2416
|
+
// Scan for numbers again
|
|
2417
|
+
return this._processTokens( tokens, idx );
|
|
2418
|
+
}
|
|
2419
|
+
}
|
|
2420
|
+
|
|
2421
|
+
return tokens;
|
|
2422
|
+
}
|
|
2423
|
+
|
|
2247
2424
|
_mustHightlightWord( token, kindArray ) {
|
|
2248
2425
|
|
|
2249
2426
|
return kindArray[this.highlight] && kindArray[this.highlight][token] != undefined;
|
|
2250
2427
|
}
|
|
2251
2428
|
|
|
2252
|
-
_evaluateToken(
|
|
2429
|
+
_evaluateToken( ctxData ) {
|
|
2430
|
+
|
|
2431
|
+
let token = ctxData.token,
|
|
2432
|
+
prev = ctxData.prev,
|
|
2433
|
+
next = ctxData.next,
|
|
2434
|
+
tokenIndex = ctxData.tokenIndex,
|
|
2435
|
+
isFirstToken = ctxData.isFirstToken,
|
|
2436
|
+
isLastToken = ctxData.isLastToken;
|
|
2253
2437
|
|
|
2254
|
-
const
|
|
2255
|
-
|
|
2438
|
+
const lang = this.languages[ this.highlight ],
|
|
2439
|
+
highlight = this.highlight.replace( /\s/g, '' ).replaceAll( "+", "p" ).toLowerCase(),
|
|
2440
|
+
customStringKeys = Object.assign( {}, this.stringKeys );
|
|
2256
2441
|
|
|
2257
|
-
|
|
2442
|
+
var usePreviousTokenToCheckString = false;
|
|
2443
|
+
|
|
2444
|
+
if( highlight == 'cpp' && prev && prev.includes( '#' ) ) // preprocessor code..
|
|
2258
2445
|
{
|
|
2259
2446
|
customStringKeys['@<'] = '>';
|
|
2447
|
+
}
|
|
2448
|
+
else if( highlight == 'markdown' && ( ctxData.prevWithSpaces == '[' || ctxData.nextWithSpaces == ']' ) )
|
|
2449
|
+
{
|
|
2450
|
+
// console.warn(prev, token, next)
|
|
2451
|
+
usePreviousTokenToCheckString = true;
|
|
2452
|
+
customStringKeys['@['] = ']';
|
|
2260
2453
|
}
|
|
2261
2454
|
|
|
2262
2455
|
// Manage strings
|
|
2263
2456
|
this._stringEnded = false;
|
|
2264
|
-
|
|
2457
|
+
|
|
2458
|
+
if( usePreviousTokenToCheckString || ( !this._buildingBlockComment && ( lang.tags ?? false ? ( this._enclosedByTokens( token, tokenIndex, '<', '>' ) ) : true ) ) )
|
|
2265
2459
|
{
|
|
2266
|
-
const
|
|
2267
|
-
|
|
2268
|
-
|
|
2269
|
-
|
|
2270
|
-
|
|
2271
|
-
|
|
2272
|
-
|
|
2273
|
-
|
|
2460
|
+
const checkIfStringEnded = t => {
|
|
2461
|
+
const idx = Object.values( customStringKeys ).indexOf( t );
|
|
2462
|
+
this._stringEnded = (idx > -1) && (idx == Object.values(customStringKeys).indexOf( customStringKeys[ '@' + this._buildingString ] ));
|
|
2463
|
+
};
|
|
2464
|
+
|
|
2465
|
+
if( this._buildingString != undefined )
|
|
2466
|
+
{
|
|
2467
|
+
checkIfStringEnded( usePreviousTokenToCheckString ? ctxData.nextWithSpaces : token );
|
|
2468
|
+
}
|
|
2469
|
+
else if( customStringKeys[ '@' + ( usePreviousTokenToCheckString ? ctxData.prevWithSpaces : token ) ] )
|
|
2470
|
+
{
|
|
2471
|
+
// Start new string
|
|
2472
|
+
this._buildingString = ( usePreviousTokenToCheckString ? ctxData.prevWithSpaces : token );
|
|
2274
2473
|
|
|
2275
|
-
|
|
2474
|
+
// Check if string ended in same token using next...
|
|
2475
|
+
if( usePreviousTokenToCheckString )
|
|
2476
|
+
{
|
|
2477
|
+
checkIfStringEnded( ctxData.nextWithSpaces );
|
|
2478
|
+
}
|
|
2479
|
+
}
|
|
2480
|
+
}
|
|
2481
|
+
|
|
2482
|
+
const usesBlockComments = lang.blockComments ?? true;
|
|
2483
|
+
const blockCommentsTokens = lang.blockCommentsTokens ?? this.defaultBlockCommentTokens;
|
|
2276
2484
|
|
|
2277
|
-
if(token == ' ')
|
|
2485
|
+
if( !usePreviousTokenToCheckString && token == ' ' )
|
|
2278
2486
|
{
|
|
2279
2487
|
if( this._buildingString != undefined )
|
|
2280
2488
|
{
|
|
@@ -2285,7 +2493,7 @@ class CodeEditor {
|
|
|
2285
2493
|
}
|
|
2286
2494
|
else
|
|
2287
2495
|
{
|
|
2288
|
-
const singleLineCommentToken =
|
|
2496
|
+
const singleLineCommentToken = lang.singleLineCommentToken ?? this.defaultSingleLineCommentToken;
|
|
2289
2497
|
|
|
2290
2498
|
let token_classname = "";
|
|
2291
2499
|
let discardToken = false;
|
|
@@ -2296,10 +2504,10 @@ class CodeEditor {
|
|
|
2296
2504
|
else if( this._buildingString != undefined )
|
|
2297
2505
|
discardToken = this._appendStringToken( token );
|
|
2298
2506
|
|
|
2299
|
-
else if( this._mustHightlightWord( token, this.keywords ) )
|
|
2507
|
+
else if( this._mustHightlightWord( token, this.keywords ) && ( lang.tags ?? false ? ( this._enclosedByTokens( token, tokenIndex, '<', '>' ) ) : true ) )
|
|
2300
2508
|
token_classname = "cm-kwd";
|
|
2301
2509
|
|
|
2302
|
-
else if( this._mustHightlightWord( token, this.builtin ) )
|
|
2510
|
+
else if( this._mustHightlightWord( token, this.builtin ) && ( lang.tags ?? false ? ( this._enclosedByTokens( token, tokenIndex, '<', '>' ) ) : true ) )
|
|
2303
2511
|
token_classname = "cm-bln";
|
|
2304
2512
|
|
|
2305
2513
|
else if( this._mustHightlightWord( token, this.statementsAndDeclarations ) )
|
|
@@ -2337,12 +2545,19 @@ class CodeEditor {
|
|
|
2337
2545
|
|
|
2338
2546
|
else if ( highlight == 'css' && prev == undefined && next == ':' ) // CSS attribute
|
|
2339
2547
|
token_classname = "cm-typ";
|
|
2548
|
+
|
|
2549
|
+
else if ( this._markdownHeader || ( highlight == 'markdown' && isFirstToken && token.replaceAll('#', '').length != token.length ) ) // Header
|
|
2550
|
+
{
|
|
2551
|
+
token_classname = "cm-kwd";
|
|
2552
|
+
this._markdownHeader = true;
|
|
2553
|
+
}
|
|
2340
2554
|
|
|
2341
2555
|
else if ( token[ 0 ] != '@' && token[ 0 ] != ',' && next == '(' )
|
|
2342
2556
|
token_classname = "cm-mtd";
|
|
2343
2557
|
|
|
2344
2558
|
|
|
2345
|
-
if( usesBlockComments && this._buildingBlockComment
|
|
2559
|
+
if( usesBlockComments && this._buildingBlockComment
|
|
2560
|
+
&& token.substr( 0, blockCommentsTokens[ 1 ].length ) == blockCommentsTokens[ 1 ] )
|
|
2346
2561
|
{
|
|
2347
2562
|
delete this._buildingBlockComment;
|
|
2348
2563
|
}
|
|
@@ -2389,6 +2604,19 @@ class CodeEditor {
|
|
|
2389
2604
|
return chars;
|
|
2390
2605
|
}
|
|
2391
2606
|
|
|
2607
|
+
_enclosedByTokens( token, tokenIndex, tagStart, tagEnd ) {
|
|
2608
|
+
|
|
2609
|
+
const tokenStartIndex = this._currentTokenPositions[ tokenIndex ];
|
|
2610
|
+
const tagStartIndex = indexOfFrom(this._currentLineString, tagStart, tokenStartIndex, true );
|
|
2611
|
+
if( tagStartIndex < 0 ) // Not found..
|
|
2612
|
+
return;
|
|
2613
|
+
const tagEndIndex = indexOfFrom(this._currentLineString, tagEnd, tokenStartIndex );
|
|
2614
|
+
if( tagEndIndex < 0 ) // Not found..
|
|
2615
|
+
return;
|
|
2616
|
+
|
|
2617
|
+
return ( tagStartIndex < tokenStartIndex ) && ( tagEndIndex >= ( tokenStartIndex + token.length ) );
|
|
2618
|
+
}
|
|
2619
|
+
|
|
2392
2620
|
_isCSSClass( token, prev, next ) {
|
|
2393
2621
|
return this.highlight == 'CSS' && prev == '.';
|
|
2394
2622
|
}
|
|
@@ -2690,9 +2918,9 @@ class CodeEditor {
|
|
|
2690
2918
|
cursor.position = state.position ?? 0;
|
|
2691
2919
|
|
|
2692
2920
|
cursor._left = state.left ?? 0;
|
|
2693
|
-
cursor.style.left = "calc(" +
|
|
2921
|
+
cursor.style.left = "calc(" + cursor._left + "px + " + this.xPadding + ")";
|
|
2694
2922
|
cursor._top = state.top ?? 0;
|
|
2695
|
-
cursor.style.top = "calc(" +
|
|
2923
|
+
cursor.style.top = "calc(" + cursor._top + "px)";
|
|
2696
2924
|
}
|
|
2697
2925
|
|
|
2698
2926
|
resetCursorPos( flag, cursor ) {
|
|
@@ -2773,8 +3001,6 @@ class CodeEditor {
|
|
|
2773
3001
|
|
|
2774
3002
|
this.resizeScrollBars();
|
|
2775
3003
|
|
|
2776
|
-
// console.warn("Resize editor viewport");
|
|
2777
|
-
|
|
2778
3004
|
}, 10 );
|
|
2779
3005
|
}
|
|
2780
3006
|
|
|
@@ -2939,15 +3165,16 @@ class CodeEditor {
|
|
|
2939
3165
|
return [ word, from, to ];
|
|
2940
3166
|
}
|
|
2941
3167
|
|
|
2942
|
-
_measureChar( char = "a", get_bb = false ) {
|
|
3168
|
+
_measureChar( char = "a", use_floating = false, get_bb = false ) {
|
|
2943
3169
|
|
|
2944
|
-
var
|
|
2945
|
-
|
|
2946
|
-
|
|
2947
|
-
|
|
2948
|
-
|
|
2949
|
-
|
|
2950
|
-
|
|
3170
|
+
var line = document.createElement( "pre" );
|
|
3171
|
+
var text = document.createElement( "span" );
|
|
3172
|
+
line.appendChild( text );
|
|
3173
|
+
text.innerText = char;
|
|
3174
|
+
this.code.appendChild( line );
|
|
3175
|
+
var rect = text.getBoundingClientRect();
|
|
3176
|
+
deleteElement( line );
|
|
3177
|
+
const bb = [ use_floating ? rect.width : Math.floor( rect.width ), use_floating ? rect.height : Math.floor( rect.height ) ];
|
|
2951
3178
|
return get_bb ? bb : bb[ 0 ];
|
|
2952
3179
|
}
|
|
2953
3180
|
|
|
@@ -3030,15 +3257,15 @@ class CodeEditor {
|
|
|
3030
3257
|
suggestions = suggestions.filter( (value, index) => value.length > 2 && suggestions.indexOf(value) === index );
|
|
3031
3258
|
|
|
3032
3259
|
// Order...
|
|
3033
|
-
suggestions = suggestions.sort( (a, b) => a.localeCompare(b) );
|
|
3260
|
+
suggestions = suggestions.sort( ( a, b ) => a.localeCompare( b ) );
|
|
3034
3261
|
|
|
3035
3262
|
for( let s of suggestions )
|
|
3036
3263
|
{
|
|
3037
|
-
if( !s.toLowerCase().includes(word.toLowerCase()) )
|
|
3264
|
+
if( !s.toLowerCase().includes( word.toLowerCase() ) )
|
|
3038
3265
|
continue;
|
|
3039
3266
|
|
|
3040
3267
|
var pre = document.createElement( 'pre' );
|
|
3041
|
-
this.autocomplete.appendChild(pre);
|
|
3268
|
+
this.autocomplete.appendChild( pre );
|
|
3042
3269
|
|
|
3043
3270
|
var icon = document.createElement( 'a' );
|
|
3044
3271
|
|
|
@@ -3049,27 +3276,27 @@ class CodeEditor {
|
|
|
3049
3276
|
else
|
|
3050
3277
|
icon.className = "fa fa-font";
|
|
3051
3278
|
|
|
3052
|
-
pre.appendChild(icon);
|
|
3279
|
+
pre.appendChild( icon );
|
|
3053
3280
|
|
|
3054
3281
|
pre.addEventListener( 'click', () => {
|
|
3055
3282
|
this.autoCompleteWord( cursor, s );
|
|
3056
3283
|
} );
|
|
3057
3284
|
|
|
3058
3285
|
// Highlight the written part
|
|
3059
|
-
const index = s.toLowerCase().indexOf(word.toLowerCase());
|
|
3286
|
+
const index = s.toLowerCase().indexOf( word.toLowerCase() );
|
|
3060
3287
|
|
|
3061
|
-
var preWord = document.createElement('span');
|
|
3062
|
-
preWord.innerHTML = s.substring(0, index);
|
|
3063
|
-
pre.appendChild(preWord);
|
|
3288
|
+
var preWord = document.createElement( 'span' );
|
|
3289
|
+
preWord.innerHTML = s.substring( 0, index );
|
|
3290
|
+
pre.appendChild( preWord );
|
|
3064
3291
|
|
|
3065
3292
|
var actualWord = document.createElement('span');
|
|
3066
|
-
actualWord.innerHTML = s.substr(index, word.length);
|
|
3293
|
+
actualWord.innerHTML = s.substr( index, word.length );
|
|
3067
3294
|
actualWord.classList.add( 'word-highlight' );
|
|
3068
|
-
pre.appendChild(actualWord);
|
|
3295
|
+
pre.appendChild( actualWord );
|
|
3069
3296
|
|
|
3070
3297
|
var postWord = document.createElement('span');
|
|
3071
|
-
postWord.innerHTML = s.substring(index + word.length);
|
|
3072
|
-
pre.appendChild(postWord);
|
|
3298
|
+
postWord.innerHTML = s.substring( index + word.length );
|
|
3299
|
+
pre.appendChild( postWord );
|
|
3073
3300
|
}
|
|
3074
3301
|
|
|
3075
3302
|
if( !this.autocomplete.childElementCount )
|
|
@@ -3156,6 +3383,146 @@ class CodeEditor {
|
|
|
3156
3383
|
this.autocomplete.childNodes[ idx + offset ].classList.add('selected');
|
|
3157
3384
|
}
|
|
3158
3385
|
|
|
3386
|
+
showSearchBox( clear ) {
|
|
3387
|
+
|
|
3388
|
+
this.searchbox.classList.add( 'opened' );
|
|
3389
|
+
this.searchboxActive = true;
|
|
3390
|
+
|
|
3391
|
+
const input = this.searchbox.querySelector( 'input' );
|
|
3392
|
+
|
|
3393
|
+
if( clear )
|
|
3394
|
+
{
|
|
3395
|
+
input.value = "";
|
|
3396
|
+
}
|
|
3397
|
+
|
|
3398
|
+
input.focus();
|
|
3399
|
+
}
|
|
3400
|
+
|
|
3401
|
+
hideSearchBox() {
|
|
3402
|
+
|
|
3403
|
+
if( this.searchboxActive )
|
|
3404
|
+
{
|
|
3405
|
+
this.searchbox.classList.remove( 'opened' );
|
|
3406
|
+
this.searchboxActive = false;
|
|
3407
|
+
}
|
|
3408
|
+
|
|
3409
|
+
else if( this._lastResult )
|
|
3410
|
+
{
|
|
3411
|
+
this._lastResult.dom.remove();
|
|
3412
|
+
delete this._lastResult;
|
|
3413
|
+
}
|
|
3414
|
+
}
|
|
3415
|
+
|
|
3416
|
+
search( text, reverse ) {
|
|
3417
|
+
|
|
3418
|
+
text = text ?? this._lastTextFound;
|
|
3419
|
+
|
|
3420
|
+
if( !text )
|
|
3421
|
+
return;
|
|
3422
|
+
|
|
3423
|
+
let cursorData = new LX.vec2( this.position, this.line );
|
|
3424
|
+
let line = null;
|
|
3425
|
+
let char = -1;
|
|
3426
|
+
|
|
3427
|
+
if( this._lastResult )
|
|
3428
|
+
{
|
|
3429
|
+
this._lastResult.dom.remove();
|
|
3430
|
+
cursorData = this._lastResult.pos;
|
|
3431
|
+
delete this._lastResult;
|
|
3432
|
+
}
|
|
3433
|
+
|
|
3434
|
+
const getIndex = l => {
|
|
3435
|
+
return this.code.lines[ l ].substr( l == cursorData.y ? cursorData.x : 0 ).indexOf( text );
|
|
3436
|
+
};
|
|
3437
|
+
|
|
3438
|
+
if( reverse )
|
|
3439
|
+
{
|
|
3440
|
+
for( var j = cursorData.y; j >= 0; --j )
|
|
3441
|
+
{
|
|
3442
|
+
char = getIndex( j );
|
|
3443
|
+
if( char > -1 )
|
|
3444
|
+
{
|
|
3445
|
+
line = j;
|
|
3446
|
+
break;
|
|
3447
|
+
}
|
|
3448
|
+
}
|
|
3449
|
+
}
|
|
3450
|
+
else
|
|
3451
|
+
{
|
|
3452
|
+
for( var j = cursorData.y; j < this.code.lines.length; ++j )
|
|
3453
|
+
{
|
|
3454
|
+
char = getIndex( j );
|
|
3455
|
+
if( char > -1 )
|
|
3456
|
+
{
|
|
3457
|
+
line = j;
|
|
3458
|
+
break;
|
|
3459
|
+
}
|
|
3460
|
+
}
|
|
3461
|
+
}
|
|
3462
|
+
|
|
3463
|
+
if( line == null)
|
|
3464
|
+
{
|
|
3465
|
+
alert("No results!")
|
|
3466
|
+
return;
|
|
3467
|
+
}
|
|
3468
|
+
|
|
3469
|
+
/*
|
|
3470
|
+
Position idx is computed from last pos, which could be in same line,
|
|
3471
|
+
so we search in the substring (first_ocurrence, end). That's why we
|
|
3472
|
+
have to add the length of the substring (0, first_ocurrence)
|
|
3473
|
+
*/
|
|
3474
|
+
|
|
3475
|
+
char += ( line == cursorData.y ? cursorData.x : 0 );
|
|
3476
|
+
|
|
3477
|
+
// Text found..
|
|
3478
|
+
|
|
3479
|
+
this._lastTextFound = text;
|
|
3480
|
+
|
|
3481
|
+
this.codeScroller.scrollTo(
|
|
3482
|
+
Math.max( char * this.charWidth - this.codeScroller.clientWidth ),
|
|
3483
|
+
Math.max( line - 10 ) * this.lineHeight
|
|
3484
|
+
);
|
|
3485
|
+
|
|
3486
|
+
// Show elements
|
|
3487
|
+
this.selections.classList.add( 'show' );
|
|
3488
|
+
|
|
3489
|
+
// Create new selection instance
|
|
3490
|
+
this.selection = new CodeSelection( this, 0, 0, "lexcodesearchresult" );
|
|
3491
|
+
this.selection.selectInline( char, line, this.measureString( text ) );
|
|
3492
|
+
this._lastResult = {
|
|
3493
|
+
'dom': this.selections.lastChild,
|
|
3494
|
+
'pos': new LX.vec2( char + text.length, line )
|
|
3495
|
+
};
|
|
3496
|
+
|
|
3497
|
+
}
|
|
3498
|
+
|
|
3499
|
+
showSearchLineBox() {
|
|
3500
|
+
|
|
3501
|
+
this.searchlinebox.classList.add( 'opened' );
|
|
3502
|
+
this.searchlineboxActive = true;
|
|
3503
|
+
|
|
3504
|
+
const input = this.searchlinebox.querySelector( 'input' );
|
|
3505
|
+
input.value = ":";
|
|
3506
|
+
input.focus();
|
|
3507
|
+
}
|
|
3508
|
+
|
|
3509
|
+
hideSearchLineBox() {
|
|
3510
|
+
|
|
3511
|
+
if( this.searchlineboxActive )
|
|
3512
|
+
{
|
|
3513
|
+
this.searchlinebox.classList.remove( 'opened' );
|
|
3514
|
+
this.searchlineboxActive = false;
|
|
3515
|
+
}
|
|
3516
|
+
}
|
|
3517
|
+
|
|
3518
|
+
goToLine( line ) {
|
|
3519
|
+
|
|
3520
|
+
if( !this.isNumber( line ) )
|
|
3521
|
+
return;
|
|
3522
|
+
|
|
3523
|
+
this.codeScroller.scrollTo( 0, Math.max( line - 15 ) * this.lineHeight );
|
|
3524
|
+
}
|
|
3525
|
+
|
|
3159
3526
|
_updateDataInfoPanel( signal, value ) {
|
|
3160
3527
|
|
|
3161
3528
|
if( !this.skipCodeInfo )
|
|
@@ -3188,11 +3555,53 @@ class CodeEditor {
|
|
|
3188
3555
|
}
|
|
3189
3556
|
}
|
|
3190
3557
|
|
|
3558
|
+
_increaseFontSize() {
|
|
3559
|
+
|
|
3560
|
+
// Change font size
|
|
3561
|
+
|
|
3562
|
+
var r = document.querySelector( ':root' );
|
|
3563
|
+
var s = getComputedStyle( r );
|
|
3564
|
+
var pixels = parseInt( s.getPropertyValue( "--code-editor-font-size" ) );
|
|
3565
|
+
pixels = LX.UTILS.clamp( pixels + 1, CodeEditor.CODE_MIN_FONT_SIZE, CodeEditor.CODE_MAX_FONT_SIZE );
|
|
3566
|
+
r.style.setProperty( "--code-editor-font-size", pixels + "px" );
|
|
3567
|
+
this.charWidth = this._measureChar( "a", true );
|
|
3568
|
+
|
|
3569
|
+
// Change row size
|
|
3570
|
+
|
|
3571
|
+
var row_pixels = pixels + 6;
|
|
3572
|
+
r.style.setProperty( "--code-editor-row-height", row_pixels + "px" );
|
|
3573
|
+
this.lineHeight = row_pixels;
|
|
3574
|
+
|
|
3575
|
+
this.processLines(); // ... it's necessary?
|
|
3576
|
+
}
|
|
3577
|
+
|
|
3578
|
+
_decreaseFontSize() {
|
|
3579
|
+
|
|
3580
|
+
// Change font size
|
|
3581
|
+
|
|
3582
|
+
var r = document.querySelector( ':root' );
|
|
3583
|
+
var s = getComputedStyle( r );
|
|
3584
|
+
var pixels = parseInt( s.getPropertyValue( "--code-editor-font-size" ) );
|
|
3585
|
+
pixels = LX.UTILS.clamp( pixels - 1, CodeEditor.CODE_MIN_FONT_SIZE, CodeEditor.CODE_MAX_FONT_SIZE );
|
|
3586
|
+
r.style.setProperty( "--code-editor-font-size", pixels + "px" );
|
|
3587
|
+
this.charWidth = this._measureChar( "a", true );
|
|
3588
|
+
|
|
3589
|
+
// Change row size
|
|
3590
|
+
|
|
3591
|
+
var row_pixels = pixels + 6;
|
|
3592
|
+
r.style.setProperty( "--code-editor-row-height", row_pixels + "px" );
|
|
3593
|
+
this.lineHeight = row_pixels;
|
|
3594
|
+
|
|
3595
|
+
this.processLines(); // ... it's necessary?
|
|
3596
|
+
}
|
|
3597
|
+
|
|
3191
3598
|
_clearTmpVariables() {
|
|
3192
3599
|
|
|
3600
|
+
delete this._currentLineString;
|
|
3193
3601
|
delete this._buildingString;
|
|
3194
3602
|
delete this._pendingString;
|
|
3195
3603
|
delete this._buildingBlockComment;
|
|
3604
|
+
delete this._markdownHeader;
|
|
3196
3605
|
}
|
|
3197
3606
|
}
|
|
3198
3607
|
|