lexgui 0.1.23 → 0.1.25
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 +574 -225
- package/build/lexgui.css +25 -13
- package/build/lexgui.js +63 -37
- package/build/lexgui.module.js +53 -27
- package/changelog.md +48 -20
- package/examples/code_editor.html +1 -1
- package/package.json +1 -1
|
@@ -26,7 +26,8 @@ function sliceChars( str, idx, n = 1 ) {
|
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
function firstNonspaceIndex( str ) {
|
|
29
|
-
|
|
29
|
+
const index = str.search(/\S|$/)
|
|
30
|
+
return index < str.length ? index : -1;
|
|
30
31
|
}
|
|
31
32
|
|
|
32
33
|
function indexOfFrom( str, reg, from, reverse ) {
|
|
@@ -118,7 +119,7 @@ class CodeSelection {
|
|
|
118
119
|
this.editor.selections.appendChild(domEl);
|
|
119
120
|
|
|
120
121
|
// Hide active line background
|
|
121
|
-
this.editor.
|
|
122
|
+
this.editor._hideActiveLine();
|
|
122
123
|
}
|
|
123
124
|
};
|
|
124
125
|
|
|
@@ -201,8 +202,8 @@ class CodeEditor {
|
|
|
201
202
|
static WORD_TYPE_METHOD = 0;
|
|
202
203
|
static WORD_TYPE_CLASS = 1;
|
|
203
204
|
|
|
204
|
-
static CODE_MAX_FONT_SIZE = 22;
|
|
205
205
|
static CODE_MIN_FONT_SIZE = 9;
|
|
206
|
+
static CODE_MAX_FONT_SIZE = 22;
|
|
206
207
|
|
|
207
208
|
/**
|
|
208
209
|
* @param {*} options
|
|
@@ -333,7 +334,7 @@ class CodeEditor {
|
|
|
333
334
|
|
|
334
335
|
// Add main cursor
|
|
335
336
|
{
|
|
336
|
-
this._addCursor( 0, 0, true );
|
|
337
|
+
this._addCursor( 0, 0, true, true );
|
|
337
338
|
|
|
338
339
|
Object.defineProperty( this, 'line', {
|
|
339
340
|
get: (v) => { return this._getCurrentCursor().line }
|
|
@@ -493,7 +494,8 @@ class CodeEditor {
|
|
|
493
494
|
this.state = {
|
|
494
495
|
focused: false,
|
|
495
496
|
selectingText: false,
|
|
496
|
-
activeLine: null
|
|
497
|
+
activeLine: null,
|
|
498
|
+
keyChain: null
|
|
497
499
|
}
|
|
498
500
|
|
|
499
501
|
// Code
|
|
@@ -550,84 +552,16 @@ class CodeEditor {
|
|
|
550
552
|
'End', 'Tab', 'Escape'
|
|
551
553
|
];
|
|
552
554
|
|
|
553
|
-
this.
|
|
554
|
-
'JavaScript': ['var', 'let', 'const', 'this', 'in', 'of', 'true', 'false', 'new', 'function', 'NaN', 'static', 'class', 'constructor', 'null', 'typeof', 'debugger', 'abstract',
|
|
555
|
-
'arguments', 'extends', 'instanceof'],
|
|
556
|
-
'C++': ['int', 'float', 'double', 'bool', 'char', 'wchar_t', 'const', 'static_cast', 'dynamic_cast', 'new', 'delete', 'void', 'true', 'false', 'auto', 'struct', 'typedef', 'nullptr',
|
|
557
|
-
'NULL', 'unsigned', 'namespace'],
|
|
558
|
-
'JSON': ['true', 'false'],
|
|
559
|
-
'GLSL': ['true', 'false', 'function', 'int', 'float', 'vec2', 'vec3', 'vec4', 'mat2x2', 'mat3x3', 'mat4x4', 'struct'],
|
|
560
|
-
'CSS': ['body', 'html', 'canvas', 'div', 'input', 'span', '.'],
|
|
561
|
-
'WGSL': ['var', 'let', 'true', 'false', 'fn', 'bool', 'u32', 'i32', 'f16', 'f32', 'vec2f', 'vec3f', 'vec4f', 'mat2x2f', 'mat3x3f', 'mat4x4f', 'array', 'atomic', 'struct',
|
|
562
|
-
'sampler', 'sampler_comparison', 'texture_depth_2d', 'texture_depth_2d_array', 'texture_depth_cube', 'texture_depth_cube_array', 'texture_depth_multisampled_2d',
|
|
563
|
-
'texture_external', 'texture_1d', 'texture_2d', 'texture_2d_array', 'texture_3d', 'texture_cube', 'texture_cube_array', 'texture_storage_1d', 'texture_storage_2d',
|
|
564
|
-
'texture_storage_2d_array', 'texture_storage_3d'],
|
|
565
|
-
'Rust': ['as', 'const', 'crate', 'enum', 'extern', 'false', 'fn', 'impl', 'in', 'let', 'mod', 'move', 'mut', 'pub', 'ref', 'self', 'Self', 'static', 'struct', 'super', 'trait', 'true',
|
|
566
|
-
'type', 'unsafe', 'use', 'where', 'abstract', 'become', 'box', 'final', 'macro', 'override', 'priv', 'typeof', 'unsized', 'virtual'],
|
|
567
|
-
'Python': ['False', 'def', 'None', 'True', 'in', 'is', 'and', 'lambda', 'nonlocal', 'not', 'or'],
|
|
568
|
-
'Batch': ['set', 'SET', 'echo', 'ECHO', 'off', 'OFF', 'del', 'DEL', 'defined', 'DEFINED', 'setlocal', 'SETLOCAL', 'enabledelayedexpansion', 'ENABLEDELAYEDEXPANSION', 'driverquery',
|
|
569
|
-
'DRIVERQUERY', 'print', 'PRINT'],
|
|
570
|
-
'HTML': ['html', 'meta', 'title', 'link', 'script', 'body', 'DOCTYPE', 'head', 'br', 'i', 'a', 'li', 'img', 'tr', 'td', 'h1', 'h2', 'h3', 'h4', 'h5'],
|
|
571
|
-
'Markdown': ['br', 'i', 'a', 'li', 'img', 'table', 'title', 'tr', 'td', 'h1', 'h2', 'h3', 'h4', 'h5'],
|
|
572
|
-
};
|
|
573
|
-
this.utils = { // These ones don't have hightlight, used as suggestions to autocomplete only...
|
|
574
|
-
'JavaScript': ['querySelector', 'body', 'addEventListener', 'removeEventListener', 'remove', 'sort', 'keys', 'filter', 'isNaN', 'parseFloat', 'parseInt', 'EPSILON', 'isFinite',
|
|
575
|
-
'bind', 'prototype', 'length', 'assign', 'entries', 'values', 'concat', 'substring', 'substr', 'splice', 'slice', 'buffer', 'appendChild', 'createElement', 'prompt',
|
|
576
|
-
'alert'],
|
|
577
|
-
'WGSL': ['textureSample'],
|
|
578
|
-
'Python': ['abs', 'all', 'any', 'ascii', 'bin', 'bool', 'bytearray', 'bytes', 'callable', 'chr', 'classmethod', 'compile', 'complex', 'delattr', 'dict', 'dir', 'divmod',
|
|
579
|
-
'enumerate', 'eval', 'exec', 'filter', 'float', 'format', 'frozenset', 'getattr', 'globals', 'hasattr', 'hash', 'help', 'hex', 'id', 'input', 'int', 'isinstance',
|
|
580
|
-
'issubclass', 'iter', 'len', 'list', 'locals', 'map', 'max', 'memoryview', 'min', 'next', 'object', 'oct', 'open', 'ord', 'pow', 'print', 'property', 'range', 'repr',
|
|
581
|
-
'reversed', 'round', 'set', 'setattr', 'slice', 'sorted', 'staticmethod', 'str', 'sum', 'super', 'tuple', 'type', 'vars', 'zip']
|
|
582
|
-
};
|
|
583
|
-
this.types = {
|
|
584
|
-
'JavaScript': ['Object', 'String', 'Function', 'Boolean', 'Symbol', 'Error', 'Number', 'TextEncoder', 'TextDecoder'],
|
|
585
|
-
'Rust': ['u128'],
|
|
586
|
-
'Python': ['int', 'type', 'float', 'map', 'list', 'ArithmeticError', 'AssertionError', 'AttributeError', 'Exception', 'EOFError', 'FloatingPointError', 'GeneratorExit',
|
|
587
|
-
'ImportError', 'IndentationError', 'IndexError', 'KeyError', 'KeyboardInterrupt', 'LookupError', 'MemoryError', 'NameError', 'NotImplementedError', 'OSError',
|
|
588
|
-
'OverflowError', 'ReferenceError', 'RuntimeError', 'StopIteration', 'SyntaxError', 'TabError', 'SystemError', 'SystemExit', 'TypeError', 'UnboundLocalError',
|
|
589
|
-
'UnicodeError', 'UnicodeEncodeError', 'UnicodeDecodeError', 'UnicodeTranslateError', 'ValueError', 'ZeroDivisionError'],
|
|
590
|
-
'C++': ['uint8_t', 'uint16_t', 'uint32_t']
|
|
591
|
-
};
|
|
592
|
-
this.builtin = {
|
|
593
|
-
'JavaScript': ['document', 'console', 'window', 'navigator', 'performance'],
|
|
594
|
-
'CSS': ['*', '!important'],
|
|
595
|
-
'C++': ['vector', 'list', 'map'],
|
|
596
|
-
'HTML': ['type', 'xmlns', 'PUBLIC', 'http-equiv', 'src', 'style', 'lang', 'href', 'rel', 'content', 'xml', 'alt'], // attributes
|
|
597
|
-
'Markdown': ['type', 'src', 'style', 'lang', 'href', 'rel', 'content', 'valign', 'alt'], // attributes
|
|
598
|
-
};
|
|
599
|
-
this.statementsAndDeclarations = {
|
|
600
|
-
'JavaScript': ['for', 'if', 'else', 'case', 'switch', 'return', 'while', 'continue', 'break', 'do', 'import', 'from', 'throw', 'async', 'try', 'catch', 'await'],
|
|
601
|
-
'CSS': ['@', 'import'],
|
|
602
|
-
'C++': ['std', 'for', 'if', 'else', 'return', 'continue', 'break', 'case', 'switch', 'while', 'using', 'glm', 'spdlog'],
|
|
603
|
-
'GLSL': ['for', 'if', 'else', 'return', 'continue', 'break'],
|
|
604
|
-
'WGSL': ['const','for', 'if', 'else', 'return', 'continue', 'break', 'storage', 'read', 'uniform'],
|
|
605
|
-
'Rust': ['break', 'else', 'continue', 'for', 'if', 'loop', 'match', 'return', 'while', 'do', 'yield'],
|
|
606
|
-
'Python': ['if', 'raise', 'del', 'import', 'return', 'elif', 'try', 'else', 'while', 'as', 'except', 'with', 'assert', 'finally', 'yield', 'break', 'for', 'class', 'continue',
|
|
607
|
-
'global', 'pass'],
|
|
608
|
-
'Batch': ['if', 'IF', 'for', 'FOR', 'in', 'IN', 'do', 'DO', 'call', 'CALL', 'goto', 'GOTO', 'exit', 'EXIT']
|
|
609
|
-
};
|
|
610
|
-
this.symbols = {
|
|
611
|
-
'JavaScript': ['<', '>', '[', ']', '{', '}', '(', ')', ';', '=', '|', '||', '&', '&&', '?', '??'],
|
|
612
|
-
'C++': ['<', '>', '[', ']', '{', '}', '(', ')', ';', '=', '|', '||', '&', '&&', '?', '::', '*', '-', '+'],
|
|
613
|
-
'JSON': ['[', ']', '{', '}', '(', ')'],
|
|
614
|
-
'GLSL': ['[', ']', '{', '}', '(', ')'],
|
|
615
|
-
'WGSL': ['[', ']', '{', '}', '(', ')', '->'],
|
|
616
|
-
'CSS': ['{', '}', '(', ')', '*'],
|
|
617
|
-
'Rust': ['<', '>', '[', ']', '(', ')', '='],
|
|
618
|
-
'Python': ['<', '>', '[', ']', '(', ')', '='],
|
|
619
|
-
'Batch': ['[', ']', '(', ')', '%'],
|
|
620
|
-
'HTML': ['<', '>', '/']
|
|
621
|
-
};
|
|
555
|
+
this._blockCommentCache = [];
|
|
622
556
|
|
|
623
557
|
// Convert reserved word arrays to maps so we can search tokens faster
|
|
624
558
|
|
|
625
|
-
for( let lang in
|
|
626
|
-
for( let lang in
|
|
627
|
-
for( let lang in
|
|
628
|
-
for( let lang in
|
|
629
|
-
for( let lang in
|
|
630
|
-
for( let lang in
|
|
559
|
+
for( let lang in CodeEditor.keywords ) CodeEditor.keywords[lang] = CodeEditor.keywords[lang].reduce((a, v) => ({ ...a, [v]: true}), {});
|
|
560
|
+
for( let lang in CodeEditor.utils ) CodeEditor.utils[lang] = CodeEditor.utils[lang].reduce((a, v) => ({ ...a, [v]: true}), {});
|
|
561
|
+
for( let lang in CodeEditor.types ) CodeEditor.types[lang] = CodeEditor.types[lang].reduce((a, v) => ({ ...a, [v]: true}), {});
|
|
562
|
+
for( let lang in CodeEditor.builtin ) CodeEditor.builtin[lang] = CodeEditor.builtin[lang].reduce((a, v) => ({ ...a, [v]: true}), {});
|
|
563
|
+
for( let lang in CodeEditor.statementsAndDeclarations ) CodeEditor.statementsAndDeclarations[lang] = CodeEditor.statementsAndDeclarations[lang].reduce((a, v) => ({ ...a, [v]: true}), {});
|
|
564
|
+
for( let lang in CodeEditor.symbols ) CodeEditor.symbols[lang] = CodeEditor.symbols[lang].reduce((a, v) => ({ ...a, [v]: true}), {});
|
|
631
565
|
|
|
632
566
|
// Action keys
|
|
633
567
|
|
|
@@ -739,14 +673,18 @@ class CodeEditor {
|
|
|
739
673
|
if(idx > 0) this.cursorToString( cursor, prestring );
|
|
740
674
|
this.setScrollLeft( 0 );
|
|
741
675
|
|
|
676
|
+
// Merge cursors
|
|
677
|
+
this.mergeCursors( ln );
|
|
678
|
+
|
|
742
679
|
if( e.shiftKey && !e.cancelShift )
|
|
743
680
|
{
|
|
744
681
|
// Get last selection range
|
|
745
682
|
if( this.selection )
|
|
746
|
-
|
|
683
|
+
lastX += this.selection.chars;
|
|
747
684
|
|
|
748
685
|
if( !this.selection )
|
|
749
686
|
this.startSelection( cursor );
|
|
687
|
+
|
|
750
688
|
var string = this.code.lines[ ln ].substring( idx, lastX );
|
|
751
689
|
if( this.selection.sameLine() )
|
|
752
690
|
this.selection.selectInline( idx, cursor.line, this.measureString( string ) );
|
|
@@ -781,6 +719,9 @@ class CodeEditor {
|
|
|
781
719
|
|
|
782
720
|
const last_char = ( this.code.clientWidth / this.charWidth )|0;
|
|
783
721
|
this.setScrollLeft( cursor.position >= last_char ? ( cursor.position - last_char ) * this.charWidth : 0 );
|
|
722
|
+
|
|
723
|
+
// Merge cursors
|
|
724
|
+
this.mergeCursors( ln );
|
|
784
725
|
});
|
|
785
726
|
|
|
786
727
|
this.action( 'Enter', true, ( ln, cursor, e ) => {
|
|
@@ -806,6 +747,7 @@ class CodeEditor {
|
|
|
806
747
|
this.code.lines.splice( cursor.line + 1, 0, "" );
|
|
807
748
|
this.code.lines[cursor.line + 1] = this.code.lines[ ln ].substr( cursor.position ); // new line (below)
|
|
808
749
|
this.code.lines[ ln ] = this.code.lines[ ln ].substr( 0, cursor.position ); // line above
|
|
750
|
+
|
|
809
751
|
this.lineDown( cursor, true );
|
|
810
752
|
|
|
811
753
|
// Check indentation
|
|
@@ -864,24 +806,20 @@ class CodeEditor {
|
|
|
864
806
|
if( e.shiftKey ) {
|
|
865
807
|
if( !this.selection )
|
|
866
808
|
this.startSelection( cursor );
|
|
809
|
+
} else {
|
|
810
|
+
this.endSelection();
|
|
811
|
+
}
|
|
867
812
|
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
813
|
+
const canGoDown = this.lineDown( cursor );
|
|
814
|
+
const letter = this.getCharAtPos( cursor );
|
|
815
|
+
|
|
816
|
+
// Go to end of line if out of range
|
|
817
|
+
if( !letter || !canGoDown ) {
|
|
818
|
+
this.cursorToPosition( cursor, Math.max(this.code.lines[ cursor.line ].length, 0) );
|
|
819
|
+
}
|
|
874
820
|
|
|
821
|
+
if( e.shiftKey ) {
|
|
875
822
|
this.processSelection( e );
|
|
876
|
-
} else {
|
|
877
|
-
|
|
878
|
-
if( this.code.lines[ ln + 1 ] == undefined )
|
|
879
|
-
return;
|
|
880
|
-
this.endSelection();
|
|
881
|
-
this.lineDown( cursor );
|
|
882
|
-
// Go to end of line if out of line
|
|
883
|
-
var letter = this.getCharAtPos( cursor );
|
|
884
|
-
if( !letter ) this.actions['End'].callback(cursor.line, cursor, e);
|
|
885
823
|
}
|
|
886
824
|
}
|
|
887
825
|
// Move down autocomplete selection
|
|
@@ -1212,25 +1150,36 @@ class CodeEditor {
|
|
|
1212
1150
|
}
|
|
1213
1151
|
}
|
|
1214
1152
|
|
|
1215
|
-
_addCursor( line = 0, position = 0, isMain = false ) {
|
|
1153
|
+
_addCursor( line = 0, position = 0, force, isMain = false ) {
|
|
1154
|
+
|
|
1155
|
+
// If cursor in that position exists, remove it instead..
|
|
1156
|
+
const exists = Array.from( this.cursors.children ).find( v => v.position == position && v.line == line );
|
|
1157
|
+
if( exists && !force )
|
|
1158
|
+
{
|
|
1159
|
+
if( !exists.isMain )
|
|
1160
|
+
exists.remove();
|
|
1216
1161
|
|
|
1162
|
+
return;
|
|
1163
|
+
}
|
|
1164
|
+
|
|
1217
1165
|
let cursor = document.createElement( 'div' );
|
|
1218
1166
|
cursor.className = "cursor";
|
|
1219
1167
|
cursor.innerHTML = " ";
|
|
1220
|
-
cursor.
|
|
1168
|
+
cursor.isMain = isMain;
|
|
1221
1169
|
cursor._left = position * this.charWidth;
|
|
1222
1170
|
cursor.style.left = "calc( " + cursor._left + "px + " + this.xPadding + " )";
|
|
1223
1171
|
cursor._top = line * this.lineHeight;
|
|
1224
1172
|
cursor.style.top = cursor._top + "px";
|
|
1225
1173
|
cursor._position = position;
|
|
1226
1174
|
cursor._line = line;
|
|
1227
|
-
cursor.print = (function() { console.log( this
|
|
1175
|
+
cursor.print = (function() { console.log( this._line, this._position ) }).bind( cursor );
|
|
1176
|
+
cursor.isLast = (function() { return this.cursors.lastChild == cursor; }).bind( this );
|
|
1228
1177
|
|
|
1229
1178
|
Object.defineProperty( cursor, 'line', {
|
|
1230
1179
|
get: (v) => { return cursor._line },
|
|
1231
1180
|
set: (v) => {
|
|
1232
1181
|
cursor._line = v;
|
|
1233
|
-
if( cursor.
|
|
1182
|
+
if( cursor.isMain ) this._setActiveLine( v );
|
|
1234
1183
|
}
|
|
1235
1184
|
} );
|
|
1236
1185
|
|
|
@@ -1238,7 +1187,7 @@ class CodeEditor {
|
|
|
1238
1187
|
get: (v) => { return cursor._position },
|
|
1239
1188
|
set: (v) => {
|
|
1240
1189
|
cursor._position = v;
|
|
1241
|
-
if( cursor.
|
|
1190
|
+
if( cursor.isMain ) this._updateDataInfoPanel( "@cursor-pos", "Col " + v );
|
|
1242
1191
|
}
|
|
1243
1192
|
} );
|
|
1244
1193
|
|
|
@@ -1273,6 +1222,10 @@ class CodeEditor {
|
|
|
1273
1222
|
|
|
1274
1223
|
_addUndoStep( cursor, force, deleteRedo = true ) {
|
|
1275
1224
|
|
|
1225
|
+
// Only the mainc cursor stores undo steps
|
|
1226
|
+
if( !cursor.isMain )
|
|
1227
|
+
return;
|
|
1228
|
+
|
|
1276
1229
|
const d = new Date();
|
|
1277
1230
|
const current = d.getTime();
|
|
1278
1231
|
|
|
@@ -1281,7 +1234,7 @@ class CodeEditor {
|
|
|
1281
1234
|
if( !this._lastTime ) {
|
|
1282
1235
|
this._lastTime = current;
|
|
1283
1236
|
} else {
|
|
1284
|
-
if( ( current - this._lastTime ) >
|
|
1237
|
+
if( ( current - this._lastTime ) > 2000 ){
|
|
1285
1238
|
this._lastTime = null;
|
|
1286
1239
|
} else {
|
|
1287
1240
|
// If time not enough, reset timer
|
|
@@ -1299,22 +1252,80 @@ class CodeEditor {
|
|
|
1299
1252
|
|
|
1300
1253
|
this.code.undoSteps.push( {
|
|
1301
1254
|
lines: LX.deepCopy( this.code.lines ),
|
|
1302
|
-
|
|
1303
|
-
line: cursor.line,
|
|
1304
|
-
position: cursor.position
|
|
1255
|
+
cursors: this.saveCursors()
|
|
1305
1256
|
} );
|
|
1306
1257
|
}
|
|
1307
1258
|
|
|
1259
|
+
_doUndo( cursor ) {
|
|
1260
|
+
|
|
1261
|
+
if( !this.code.undoSteps.length )
|
|
1262
|
+
return;
|
|
1263
|
+
|
|
1264
|
+
this._addRedoStep( cursor );
|
|
1265
|
+
|
|
1266
|
+
// Extract info from the last code state
|
|
1267
|
+
const step = this.code.undoSteps.pop();
|
|
1268
|
+
|
|
1269
|
+
// Set old state lines
|
|
1270
|
+
this.code.lines = step.lines;
|
|
1271
|
+
this.processLines();
|
|
1272
|
+
|
|
1273
|
+
this._removeSecondaryCursors();
|
|
1274
|
+
|
|
1275
|
+
for( let i = 0; i < step.cursors.length; ++i )
|
|
1276
|
+
{
|
|
1277
|
+
var currentCursor = this.cursors.children[ i ];
|
|
1278
|
+
|
|
1279
|
+
// Generate new if needed
|
|
1280
|
+
if( !currentCursor )
|
|
1281
|
+
currentCursor = this._addCursor();
|
|
1282
|
+
|
|
1283
|
+
this.restoreCursor( currentCursor, step.cursors[ i ] );
|
|
1284
|
+
}
|
|
1285
|
+
|
|
1286
|
+
this._hideActiveLine();
|
|
1287
|
+
}
|
|
1288
|
+
|
|
1308
1289
|
_addRedoStep( cursor ) {
|
|
1309
1290
|
|
|
1291
|
+
// Only the mainc cursor stores redo steps
|
|
1292
|
+
if( !cursor.isMain )
|
|
1293
|
+
return;
|
|
1294
|
+
|
|
1310
1295
|
this.code.redoSteps.push( {
|
|
1311
1296
|
lines: LX.deepCopy( this.code.lines ),
|
|
1312
|
-
|
|
1313
|
-
line: cursor.line,
|
|
1314
|
-
position: cursor.position
|
|
1297
|
+
cursors: this.saveCursors()
|
|
1315
1298
|
} );
|
|
1316
1299
|
}
|
|
1317
1300
|
|
|
1301
|
+
_doRedo( cursor ) {
|
|
1302
|
+
|
|
1303
|
+
if( !this.code.redoSteps.length )
|
|
1304
|
+
return;
|
|
1305
|
+
|
|
1306
|
+
this._addUndoStep( cursor, true, false);
|
|
1307
|
+
|
|
1308
|
+
// Extract info from the next saved code state
|
|
1309
|
+
const step = this.code.redoSteps.pop();
|
|
1310
|
+
|
|
1311
|
+
// Set old state lines
|
|
1312
|
+
this.code.lines = step.lines;
|
|
1313
|
+
this.processLines();
|
|
1314
|
+
|
|
1315
|
+
this._removeSecondaryCursors();
|
|
1316
|
+
|
|
1317
|
+
for( let i = 0; i < step.cursors.length; ++i )
|
|
1318
|
+
{
|
|
1319
|
+
var currentCursor = this.cursors.children[ i ];
|
|
1320
|
+
|
|
1321
|
+
// Generate new if needed
|
|
1322
|
+
if( !currentCursor )
|
|
1323
|
+
currentCursor = this._addCursor();
|
|
1324
|
+
|
|
1325
|
+
this.restoreCursor( currentCursor, step.cursors[ i ] );
|
|
1326
|
+
}
|
|
1327
|
+
}
|
|
1328
|
+
|
|
1318
1329
|
_changeLanguage( lang ) {
|
|
1319
1330
|
|
|
1320
1331
|
this.code.language = lang;
|
|
@@ -1610,7 +1621,7 @@ class CodeEditor {
|
|
|
1610
1621
|
|
|
1611
1622
|
processMouse( e ) {
|
|
1612
1623
|
|
|
1613
|
-
if( !e.target.classList.contains('code') ) return;
|
|
1624
|
+
if( !e.target.classList.contains('code') && !e.target.classList.contains('codetabsarea') ) return;
|
|
1614
1625
|
if( !this.code ) return;
|
|
1615
1626
|
|
|
1616
1627
|
var cursor = this._getCurrentCursor();
|
|
@@ -1618,11 +1629,8 @@ class CodeEditor {
|
|
|
1618
1629
|
var mouse_pos = [(e.clientX - code_rect.x), (e.clientY - code_rect.y)];
|
|
1619
1630
|
|
|
1620
1631
|
// Discard out of lines click...
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
var ln = (mouse_pos[1] / this.lineHeight)|0;
|
|
1624
|
-
if(this.code.lines[ ln ] == undefined) return;
|
|
1625
|
-
}
|
|
1632
|
+
var ln = ( mouse_pos[ 1 ] / this.lineHeight ) | 0;
|
|
1633
|
+
if( ln < 0 ) return;
|
|
1626
1634
|
|
|
1627
1635
|
if( e.type == 'mousedown' )
|
|
1628
1636
|
{
|
|
@@ -1730,11 +1738,12 @@ class CodeEditor {
|
|
|
1730
1738
|
var position = [( e.clientX - code_rect.x ) + this.getScrollLeft(), (e.clientY - code_rect.y) + this.getScrollTop()];
|
|
1731
1739
|
var ln = (position[ 1 ] / this.lineHeight)|0;
|
|
1732
1740
|
|
|
1733
|
-
|
|
1734
|
-
|
|
1741
|
+
// Check out of range line
|
|
1742
|
+
const outOfRange = ln > this.code.lines.length - 1;
|
|
1743
|
+
ln = Math.min( ln, this.code.lines.length - 1 );
|
|
1735
1744
|
|
|
1736
1745
|
var ch = ( ( position[ 0 ] - parseInt( this.xPadding ) + 3) / this.charWidth )|0;
|
|
1737
|
-
var string = this.code.lines[ ln ].slice( 0, ch );
|
|
1746
|
+
var string = outOfRange ? this.code.lines[ ln ] : this.code.lines[ ln ].slice( 0, ch );
|
|
1738
1747
|
|
|
1739
1748
|
// Move main cursor there...
|
|
1740
1749
|
if( !e.altKey )
|
|
@@ -1764,8 +1773,7 @@ class CodeEditor {
|
|
|
1764
1773
|
if( !this.selection )
|
|
1765
1774
|
this.startSelection( cursor );
|
|
1766
1775
|
|
|
1767
|
-
|
|
1768
|
-
this.code.childNodes.forEach( e => e.classList.remove( 'active-line' ) );
|
|
1776
|
+
this._hideActiveLine();
|
|
1769
1777
|
|
|
1770
1778
|
// Update selection
|
|
1771
1779
|
if( !keep_range )
|
|
@@ -1911,10 +1919,36 @@ class CodeEditor {
|
|
|
1911
1919
|
}
|
|
1912
1920
|
}
|
|
1913
1921
|
|
|
1914
|
-
async processKey(
|
|
1922
|
+
async processKey( e ) {
|
|
1915
1923
|
|
|
1916
1924
|
const numCursors = this.cursors.childElementCount;
|
|
1917
1925
|
|
|
1926
|
+
if( !this.code || e.srcElement.constructor != HTMLDivElement )
|
|
1927
|
+
return;
|
|
1928
|
+
|
|
1929
|
+
const key = e.key ?? e.detail.key;
|
|
1930
|
+
const target = e.detail.targetCursor;
|
|
1931
|
+
|
|
1932
|
+
// Global keys
|
|
1933
|
+
|
|
1934
|
+
if( this._processGlobalKeys( e, key ) ) {
|
|
1935
|
+
// Stop propagation..
|
|
1936
|
+
return;
|
|
1937
|
+
}
|
|
1938
|
+
|
|
1939
|
+
// By cursor keys
|
|
1940
|
+
|
|
1941
|
+
if( target !== undefined )
|
|
1942
|
+
{
|
|
1943
|
+
this.processKeyAtTargetCursor( e, key, target );
|
|
1944
|
+
return;
|
|
1945
|
+
}
|
|
1946
|
+
|
|
1947
|
+
this._lastProcessedCursorIndex = null;
|
|
1948
|
+
|
|
1949
|
+
var lastProcessedCursor = null;
|
|
1950
|
+
var cursorOffset = new LX.vec2( 0, 0 );
|
|
1951
|
+
|
|
1918
1952
|
for( var i = 0; i < numCursors; i++ )
|
|
1919
1953
|
{
|
|
1920
1954
|
let cursor = this.cursors.children[ i ];
|
|
@@ -1923,16 +1957,97 @@ class CodeEditor {
|
|
|
1923
1957
|
if( !cursor )
|
|
1924
1958
|
break;
|
|
1925
1959
|
|
|
1926
|
-
|
|
1960
|
+
// Arrows don't modify code lines.. And only add offset if in the same line
|
|
1961
|
+
if( lastProcessedCursor && lastProcessedCursor.line == cursor.line && !key.includes( 'Arrow' ) )
|
|
1962
|
+
{
|
|
1963
|
+
cursor.position += cursorOffset.x;
|
|
1964
|
+
cursor.line += cursorOffset.y;
|
|
1965
|
+
|
|
1966
|
+
this.relocateCursors();
|
|
1967
|
+
}
|
|
1968
|
+
|
|
1969
|
+
lastProcessedCursor = this.saveCursor( cursor );
|
|
1970
|
+
this._lastProcessedCursorIndex = i;
|
|
1971
|
+
|
|
1972
|
+
this._processKeyAtCursor( e, key, cursor );
|
|
1973
|
+
|
|
1974
|
+
cursorOffset.x += ( cursor.position - lastProcessedCursor.position );
|
|
1975
|
+
cursorOffset.y += ( cursor.line - lastProcessedCursor.line );
|
|
1927
1976
|
}
|
|
1977
|
+
|
|
1978
|
+
// Clear tmp
|
|
1979
|
+
|
|
1980
|
+
delete this._lastProcessedCursorIndex;
|
|
1928
1981
|
}
|
|
1929
1982
|
|
|
1930
|
-
async
|
|
1983
|
+
async processKeyAtTargetCursor( e, key, targetIdx ) {
|
|
1931
1984
|
|
|
1932
|
-
|
|
1985
|
+
let cursor = this.cursors.children[ targetIdx ];
|
|
1986
|
+
|
|
1987
|
+
// We could delete secondary cursor while iterating..
|
|
1988
|
+
if( !cursor )
|
|
1933
1989
|
return;
|
|
1934
1990
|
|
|
1935
|
-
|
|
1991
|
+
this._processKeyAtCursor( e, key, cursor );
|
|
1992
|
+
this._processGlobalKeys( e, key );
|
|
1993
|
+
}
|
|
1994
|
+
|
|
1995
|
+
_processGlobalKeys( e, key ) {
|
|
1996
|
+
|
|
1997
|
+
let cursor = this._getCurrentCursor();
|
|
1998
|
+
|
|
1999
|
+
if( e.ctrlKey || e.metaKey )
|
|
2000
|
+
{
|
|
2001
|
+
e.preventDefault();
|
|
2002
|
+
|
|
2003
|
+
switch( key.toLowerCase() ) {
|
|
2004
|
+
case 'a': // select all
|
|
2005
|
+
this.selectAll();
|
|
2006
|
+
return true;
|
|
2007
|
+
case 'c': // k+c, comment line
|
|
2008
|
+
if( this.state.keyChain == 'k' ) {
|
|
2009
|
+
this._commentLines();
|
|
2010
|
+
return true;
|
|
2011
|
+
}
|
|
2012
|
+
return false;
|
|
2013
|
+
case 'f': // find/search
|
|
2014
|
+
this.showSearchBox();
|
|
2015
|
+
return true;
|
|
2016
|
+
case 'g': // find line
|
|
2017
|
+
this.showSearchLineBox();
|
|
2018
|
+
return true;
|
|
2019
|
+
case 'k': // shortcut chain
|
|
2020
|
+
this.state.keyChain = 'k';
|
|
2021
|
+
return true;
|
|
2022
|
+
case 's': // save
|
|
2023
|
+
this.onsave( this.getText() );
|
|
2024
|
+
return true;
|
|
2025
|
+
case 'u': // k+u, uncomment line
|
|
2026
|
+
if( this.state.keyChain == 'k' ) {
|
|
2027
|
+
this._uncommentLines();
|
|
2028
|
+
return true;
|
|
2029
|
+
}
|
|
2030
|
+
return false;
|
|
2031
|
+
case 'y': // redo
|
|
2032
|
+
this._doRedo( cursor );
|
|
2033
|
+
return true;
|
|
2034
|
+
case 'z': // undo
|
|
2035
|
+
this._doUndo( cursor );
|
|
2036
|
+
return true;
|
|
2037
|
+
case '+': // increase size
|
|
2038
|
+
this._increaseFontSize();
|
|
2039
|
+
return true;
|
|
2040
|
+
case '-': // decrease size
|
|
2041
|
+
this._decreaseFontSize();
|
|
2042
|
+
return true;
|
|
2043
|
+
}
|
|
2044
|
+
}
|
|
2045
|
+
|
|
2046
|
+
this.state.keyChain = null;
|
|
2047
|
+
return false;
|
|
2048
|
+
}
|
|
2049
|
+
|
|
2050
|
+
async _processKeyAtCursor( e, key, cursor ) {
|
|
1936
2051
|
|
|
1937
2052
|
const skip_undo = e.detail.skip_undo ?? false;
|
|
1938
2053
|
|
|
@@ -1945,32 +2060,20 @@ class CodeEditor {
|
|
|
1945
2060
|
|
|
1946
2061
|
// Check combinations
|
|
1947
2062
|
|
|
2063
|
+
const isLastCursor = cursor.isLast();
|
|
2064
|
+
|
|
1948
2065
|
if( e.ctrlKey || e.metaKey )
|
|
1949
2066
|
{
|
|
1950
2067
|
switch( key.toLowerCase() ) {
|
|
1951
|
-
case 'a': // select all
|
|
1952
|
-
e.preventDefault();
|
|
1953
|
-
this.selectAll( cursor );
|
|
1954
|
-
break;
|
|
1955
2068
|
case 'c': // copy
|
|
2069
|
+
// TODO: COPY TEXT FROM EVERY CURSOR
|
|
1956
2070
|
this._copyContent( cursor );
|
|
1957
2071
|
return;
|
|
1958
2072
|
case 'd': // duplicate line
|
|
1959
2073
|
e.preventDefault();
|
|
2074
|
+
// TODO: UPDATE NEXT CURSOR ON MODIFY STATE
|
|
1960
2075
|
this._duplicateLine( lidx, cursor );
|
|
1961
2076
|
return;
|
|
1962
|
-
case 'f': // find/search
|
|
1963
|
-
e.preventDefault();
|
|
1964
|
-
this.showSearchBox();
|
|
1965
|
-
return;
|
|
1966
|
-
case 'g': // find line
|
|
1967
|
-
e.preventDefault();
|
|
1968
|
-
this.showSearchLineBox();
|
|
1969
|
-
return;
|
|
1970
|
-
case 's': // save
|
|
1971
|
-
e.preventDefault();
|
|
1972
|
-
this.onsave( this.getText() );
|
|
1973
|
-
return;
|
|
1974
2077
|
case 'v': // paste
|
|
1975
2078
|
this._pasteContent( cursor );
|
|
1976
2079
|
return;
|
|
@@ -1978,39 +2081,13 @@ class CodeEditor {
|
|
|
1978
2081
|
this._cutContent( cursor );
|
|
1979
2082
|
this.hideAutoCompleteBox();
|
|
1980
2083
|
return;
|
|
1981
|
-
case 'y': // redo
|
|
1982
|
-
if( !this.code.redoSteps.length )
|
|
1983
|
-
return;
|
|
1984
|
-
this._addUndoStep( cursor, true, false);
|
|
1985
|
-
const redo_step = this.code.redoSteps.pop();
|
|
1986
|
-
this.code.lines = redo_step.lines;
|
|
1987
|
-
this.processLines();
|
|
1988
|
-
this.restoreCursor( cursor, redo_step.cursor );
|
|
1989
|
-
return;
|
|
1990
|
-
case 'z': // undo
|
|
1991
|
-
if( !this.code.undoSteps.length )
|
|
1992
|
-
return;
|
|
1993
|
-
this._addRedoStep( cursor );
|
|
1994
|
-
const undo_step = this.code.undoSteps.pop();
|
|
1995
|
-
this.code.lines = undo_step.lines;
|
|
1996
|
-
this.processLines();
|
|
1997
|
-
this.restoreCursor( cursor, undo_step.cursor );
|
|
1998
|
-
return;
|
|
1999
|
-
case '+': // increase size
|
|
2000
|
-
e.preventDefault();
|
|
2001
|
-
this._increaseFontSize();
|
|
2002
|
-
return;
|
|
2003
|
-
case '-': // decrease size
|
|
2004
|
-
e.preventDefault();
|
|
2005
|
-
this._decreaseFontSize();
|
|
2006
|
-
return;
|
|
2007
2084
|
case 'arrowdown': // add cursor below only for the main cursor..
|
|
2008
|
-
if(
|
|
2085
|
+
if( isLastCursor && this.code.lines[ lidx + 1 ] != undefined )
|
|
2009
2086
|
{
|
|
2010
|
-
var new_cursor = this._addCursor( cursor.line, cursor.position );
|
|
2087
|
+
var new_cursor = this._addCursor( cursor.line, cursor.position, true );
|
|
2011
2088
|
this.lineDown( new_cursor );
|
|
2012
|
-
return;
|
|
2013
2089
|
}
|
|
2090
|
+
return;
|
|
2014
2091
|
}
|
|
2015
2092
|
}
|
|
2016
2093
|
|
|
@@ -2136,6 +2213,9 @@ class CodeEditor {
|
|
|
2136
2213
|
async _pasteContent( cursor ) {
|
|
2137
2214
|
|
|
2138
2215
|
let text = await navigator.clipboard.readText();
|
|
2216
|
+
|
|
2217
|
+
this._addUndoStep( cursor, true );
|
|
2218
|
+
|
|
2139
2219
|
this.appendText( text, cursor );
|
|
2140
2220
|
}
|
|
2141
2221
|
|
|
@@ -2152,18 +2232,18 @@ class CodeEditor {
|
|
|
2152
2232
|
if( this.selection ) this.selection.invertIfNecessary();
|
|
2153
2233
|
|
|
2154
2234
|
const separator = "_NEWLINE_";
|
|
2155
|
-
let code = this.code.lines.join(separator);
|
|
2235
|
+
let code = this.code.lines.join( separator );
|
|
2156
2236
|
|
|
2157
2237
|
// Get linear start index
|
|
2158
2238
|
let index = 0;
|
|
2159
2239
|
|
|
2160
|
-
for(let i = 0; i <= this.selection.fromY; i++)
|
|
2161
|
-
index += (i == this.selection.fromY ? this.selection.fromX : this.code.lines[ i ].length);
|
|
2240
|
+
for( let i = 0; i <= this.selection.fromY; i++ )
|
|
2241
|
+
index += ( i == this.selection.fromY ? this.selection.fromX : this.code.lines[ i ].length );
|
|
2162
2242
|
|
|
2163
2243
|
index += this.selection.fromY * separator.length;
|
|
2164
|
-
const num_chars = this.selection.chars + (this.selection.toY - this.selection.fromY) * separator.length;
|
|
2165
|
-
const text = code.substr(index, num_chars);
|
|
2166
|
-
const lines = text.split(separator);
|
|
2244
|
+
const num_chars = this.selection.chars + ( this.selection.toY - this.selection.fromY ) * separator.length;
|
|
2245
|
+
const text = code.substr( index, num_chars );
|
|
2246
|
+
const lines = text.split( separator );
|
|
2167
2247
|
text_to_copy = lines.join('\n');
|
|
2168
2248
|
}
|
|
2169
2249
|
|
|
@@ -2221,6 +2301,114 @@ class CodeEditor {
|
|
|
2221
2301
|
this.hideAutoCompleteBox();
|
|
2222
2302
|
}
|
|
2223
2303
|
|
|
2304
|
+
_commentLines() {
|
|
2305
|
+
|
|
2306
|
+
this.state.keyChain = null;
|
|
2307
|
+
|
|
2308
|
+
if( this.selection )
|
|
2309
|
+
{
|
|
2310
|
+
var cursor = this._getCurrentCursor();
|
|
2311
|
+
this._addUndoStep( cursor, true );
|
|
2312
|
+
|
|
2313
|
+
const selectedLines = this.code.lines.slice( this.selection.fromY, this.selection.toY );
|
|
2314
|
+
const minIdx = Math.min(...selectedLines.map( v => {
|
|
2315
|
+
var idx = firstNonspaceIndex( v );
|
|
2316
|
+
return idx < 0 ? 1e10 : idx;
|
|
2317
|
+
} ));
|
|
2318
|
+
|
|
2319
|
+
for( var i = this.selection.fromY; i <= this.selection.toY; ++i )
|
|
2320
|
+
{
|
|
2321
|
+
this._commentLine( cursor, i, minIdx );
|
|
2322
|
+
}
|
|
2323
|
+
}
|
|
2324
|
+
else
|
|
2325
|
+
{
|
|
2326
|
+
for( let cursor of this.cursors.children )
|
|
2327
|
+
{
|
|
2328
|
+
this._addUndoStep( cursor, true );
|
|
2329
|
+
this._commentLine( cursor, cursor.line );
|
|
2330
|
+
}
|
|
2331
|
+
}
|
|
2332
|
+
|
|
2333
|
+
this.processLines();
|
|
2334
|
+
this._hideActiveLine();
|
|
2335
|
+
}
|
|
2336
|
+
|
|
2337
|
+
_commentLine( cursor, line, minNonspaceIdx ) {
|
|
2338
|
+
|
|
2339
|
+
const lang = this.languages[ this.highlight ];
|
|
2340
|
+
|
|
2341
|
+
if( !( lang.singleLineComments ?? true ))
|
|
2342
|
+
return;
|
|
2343
|
+
|
|
2344
|
+
const token = ( lang.singleLineCommentToken ?? this.defaultSingleLineCommentToken ) + ' ';
|
|
2345
|
+
const string = this.code.lines[ line ];
|
|
2346
|
+
|
|
2347
|
+
let idx = firstNonspaceIndex( string );
|
|
2348
|
+
if( idx > -1 )
|
|
2349
|
+
{
|
|
2350
|
+
// Update idx using min of the selected lines (if necessary..)
|
|
2351
|
+
idx = minNonspaceIdx ?? idx;
|
|
2352
|
+
|
|
2353
|
+
this.code.lines[ line ] = [
|
|
2354
|
+
string.substring( 0, idx ),
|
|
2355
|
+
token,
|
|
2356
|
+
string.substring( idx )
|
|
2357
|
+
].join( '' );
|
|
2358
|
+
|
|
2359
|
+
this.cursorToString( cursor, token );
|
|
2360
|
+
}
|
|
2361
|
+
}
|
|
2362
|
+
|
|
2363
|
+
_uncommentLines() {
|
|
2364
|
+
|
|
2365
|
+
this.state.keyChain = null;
|
|
2366
|
+
|
|
2367
|
+
if( this.selection )
|
|
2368
|
+
{
|
|
2369
|
+
var cursor = this._getCurrentCursor();
|
|
2370
|
+
this._addUndoStep( cursor, true );
|
|
2371
|
+
|
|
2372
|
+
for( var i = this.selection.fromY; i <= this.selection.toY; ++i )
|
|
2373
|
+
{
|
|
2374
|
+
this._uncommentLine( cursor, i );
|
|
2375
|
+
}
|
|
2376
|
+
}
|
|
2377
|
+
else
|
|
2378
|
+
{
|
|
2379
|
+
for( let cursor of this.cursors.children )
|
|
2380
|
+
{
|
|
2381
|
+
this._addUndoStep( cursor, true );
|
|
2382
|
+
this._uncommentLine( cursor, cursor.line );
|
|
2383
|
+
}
|
|
2384
|
+
}
|
|
2385
|
+
|
|
2386
|
+
this.processLines();
|
|
2387
|
+
this._hideActiveLine();
|
|
2388
|
+
}
|
|
2389
|
+
|
|
2390
|
+
_uncommentLine( cursor, line ) {
|
|
2391
|
+
|
|
2392
|
+
const lang = this.languages[ this.highlight ];
|
|
2393
|
+
|
|
2394
|
+
if( !( lang.singleLineComments ?? true ))
|
|
2395
|
+
return;
|
|
2396
|
+
|
|
2397
|
+
const token = lang.singleLineCommentToken ?? this.defaultSingleLineCommentToken;
|
|
2398
|
+
const string = this.code.lines[ line ];
|
|
2399
|
+
|
|
2400
|
+
if( string.includes( token ) )
|
|
2401
|
+
{
|
|
2402
|
+
this.code.lines[ line ] = string.replace( token + ' ', '' );
|
|
2403
|
+
|
|
2404
|
+
// try deleting token + space, and then if not, delete only the token
|
|
2405
|
+
if( string.length == this.code.lines[ line ].length )
|
|
2406
|
+
this.code.lines[ line ] = string.replace( token, '' );
|
|
2407
|
+
|
|
2408
|
+
this.cursorToString( cursor, 'X'.repeat( Math.abs( string.length - this.code.lines[ line ].length ) ), true );
|
|
2409
|
+
}
|
|
2410
|
+
}
|
|
2411
|
+
|
|
2224
2412
|
action( key, deleteSelection, fn ) {
|
|
2225
2413
|
|
|
2226
2414
|
this.actions[ key ] = {
|
|
@@ -2254,9 +2442,8 @@ class CodeEditor {
|
|
|
2254
2442
|
|
|
2255
2443
|
processLines( mode ) {
|
|
2256
2444
|
|
|
2257
|
-
const start = performance.now();
|
|
2258
|
-
|
|
2259
2445
|
var code_html = "";
|
|
2446
|
+
this._blockCommentCache.length = 0;
|
|
2260
2447
|
|
|
2261
2448
|
// Reset all lines content
|
|
2262
2449
|
this.code.innerHTML = "";
|
|
@@ -2301,6 +2488,13 @@ class CodeEditor {
|
|
|
2301
2488
|
|
|
2302
2489
|
processLine( linenum, force ) {
|
|
2303
2490
|
|
|
2491
|
+
// Check if we are in block comment sections..
|
|
2492
|
+
if( !force && this._inBlockCommentSection( linenum ) )
|
|
2493
|
+
{
|
|
2494
|
+
this.processLines();
|
|
2495
|
+
return;
|
|
2496
|
+
}
|
|
2497
|
+
|
|
2304
2498
|
const lang = this.languages[ this.highlight ];
|
|
2305
2499
|
const local_line_num = this.toLocalLine( linenum );
|
|
2306
2500
|
const gutter_line = "<span class='line-gutter'>" + (linenum + 1) + "</span>";
|
|
@@ -2309,6 +2503,7 @@ class CodeEditor {
|
|
|
2309
2503
|
if( !force ) // Single line update
|
|
2310
2504
|
{
|
|
2311
2505
|
this.code.childNodes[ local_line_num ].innerHTML = gutter_line + html;
|
|
2506
|
+
this._setActiveLine( linenum );
|
|
2312
2507
|
this._clearTmpVariables();
|
|
2313
2508
|
}
|
|
2314
2509
|
else // Update all lines at once
|
|
@@ -2335,6 +2530,9 @@ class CodeEditor {
|
|
|
2335
2530
|
return UPDATE_LINE( linestring );
|
|
2336
2531
|
}
|
|
2337
2532
|
|
|
2533
|
+
this._currentLineNumber = linenum;
|
|
2534
|
+
this._currentLineString = linestring;
|
|
2535
|
+
|
|
2338
2536
|
const tokensToEvaluate = this._getTokensFromLine( linestring );
|
|
2339
2537
|
|
|
2340
2538
|
if( !tokensToEvaluate.length )
|
|
@@ -2365,7 +2563,7 @@ class CodeEditor {
|
|
|
2365
2563
|
{
|
|
2366
2564
|
const blockCommentsToken = ( lang.blockCommentsTokens ?? this.defaultBlockCommentTokens )[ 0 ];
|
|
2367
2565
|
if( token.substr( 0, blockCommentsToken.length ) == blockCommentsToken )
|
|
2368
|
-
this._buildingBlockComment =
|
|
2566
|
+
this._buildingBlockComment = linenum;
|
|
2369
2567
|
}
|
|
2370
2568
|
|
|
2371
2569
|
line_inner_html += this._evaluateToken( {
|
|
@@ -2403,19 +2601,12 @@ class CodeEditor {
|
|
|
2403
2601
|
var matches = (linestring.substring( 0, idx ).match( re ) || []);
|
|
2404
2602
|
return (matches.length % 2) !== 0;
|
|
2405
2603
|
} );
|
|
2406
|
-
err |= stringKeys.some( function(v) {
|
|
2407
|
-
var re = new RegExp( v, "g" );
|
|
2408
|
-
var matches = (linestring.substring( idx ).match( re ) || []);
|
|
2409
|
-
return (matches.length % 2) !== 0;
|
|
2410
|
-
} );
|
|
2411
2604
|
return err ? undefined : idx;
|
|
2412
2605
|
}
|
|
2413
2606
|
}
|
|
2414
2607
|
|
|
2415
2608
|
_getTokensFromLine( linestring, skipNonWords ) {
|
|
2416
2609
|
|
|
2417
|
-
this._currentLineString = linestring;
|
|
2418
|
-
|
|
2419
2610
|
// Check if line comment
|
|
2420
2611
|
const ogLine = linestring;
|
|
2421
2612
|
const hasCommentIdx = this._lineHasComment( linestring );
|
|
@@ -2472,12 +2663,12 @@ class CodeEditor {
|
|
|
2472
2663
|
|
|
2473
2664
|
if( this.highlight == 'C++' || this.highlight == 'CSS' )
|
|
2474
2665
|
{
|
|
2475
|
-
var idx = tokens.slice( offset ).findIndex( ( value, index ) => this.
|
|
2666
|
+
var idx = tokens.slice( offset ).findIndex( ( value, index ) => this._isNumber( value ) );
|
|
2476
2667
|
if( idx > -1 )
|
|
2477
2668
|
{
|
|
2478
2669
|
idx += offset; // Add offset to compute within the whole array of tokens
|
|
2479
2670
|
let data = tokens[ idx ] + tokens[ ++idx ];
|
|
2480
|
-
while( this.
|
|
2671
|
+
while( this._isNumber( data ) )
|
|
2481
2672
|
{
|
|
2482
2673
|
tokens[ idx - 1 ] += tokens[ idx ];
|
|
2483
2674
|
tokens.splice( idx, 1 );
|
|
@@ -2525,7 +2716,7 @@ class CodeEditor {
|
|
|
2525
2716
|
// Manage strings
|
|
2526
2717
|
this._stringEnded = false;
|
|
2527
2718
|
|
|
2528
|
-
if( usePreviousTokenToCheckString || (
|
|
2719
|
+
if( usePreviousTokenToCheckString || ( this._buildingBlockComment === undefined && ( lang.tags ?? false ? ( this._enclosedByTokens( token, tokenIndex, '<', '>' ) ) : true ) ) )
|
|
2529
2720
|
{
|
|
2530
2721
|
const checkIfStringEnded = t => {
|
|
2531
2722
|
const idx = Object.values( customStringKeys ).indexOf( t );
|
|
@@ -2574,22 +2765,22 @@ class CodeEditor {
|
|
|
2574
2765
|
else if( this._buildingString != undefined )
|
|
2575
2766
|
discardToken = this._appendStringToken( token );
|
|
2576
2767
|
|
|
2577
|
-
else if( this._mustHightlightWord( token,
|
|
2768
|
+
else if( this._mustHightlightWord( token, CodeEditor.keywords ) && ( lang.tags ?? false ? ( this._enclosedByTokens( token, tokenIndex, '<', '>' ) ) : true ) )
|
|
2578
2769
|
token_classname = "cm-kwd";
|
|
2579
2770
|
|
|
2580
|
-
else if( this._mustHightlightWord( token,
|
|
2771
|
+
else if( this._mustHightlightWord( token, CodeEditor.builtin ) && ( lang.tags ?? false ? ( this._enclosedByTokens( token, tokenIndex, '<', '>' ) ) : true ) )
|
|
2581
2772
|
token_classname = "cm-bln";
|
|
2582
2773
|
|
|
2583
|
-
else if( this._mustHightlightWord( token,
|
|
2774
|
+
else if( this._mustHightlightWord( token, CodeEditor.statementsAndDeclarations ) )
|
|
2584
2775
|
token_classname = "cm-std";
|
|
2585
2776
|
|
|
2586
|
-
else if( this._mustHightlightWord( token,
|
|
2777
|
+
else if( this._mustHightlightWord( token, CodeEditor.symbols ) )
|
|
2587
2778
|
token_classname = "cm-sym";
|
|
2588
2779
|
|
|
2589
2780
|
else if( token.substr( 0, singleLineCommentToken.length ) == singleLineCommentToken )
|
|
2590
2781
|
token_classname = "cm-com";
|
|
2591
2782
|
|
|
2592
|
-
else if( this.
|
|
2783
|
+
else if( this._isNumber( token ) || this._isNumber( token.replace(/[px]|[em]|%/g,'') ) )
|
|
2593
2784
|
token_classname = "cm-dec";
|
|
2594
2785
|
|
|
2595
2786
|
else if( this._isCSSClass( token, prev, next ) )
|
|
@@ -2601,7 +2792,7 @@ class CodeEditor {
|
|
|
2601
2792
|
else if ( highlight == 'batch' && ( token == '@' || prev == ':' || prev == '@' ) )
|
|
2602
2793
|
token_classname = "cm-kwd";
|
|
2603
2794
|
|
|
2604
|
-
else if (
|
|
2795
|
+
else if ( [ 'cpp', 'wgsl', 'glsl' ].indexOf( highlight ) > -1 && token.includes( '#' ) ) // C++ preprocessor
|
|
2605
2796
|
token_classname = "cm-ppc";
|
|
2606
2797
|
|
|
2607
2798
|
else if ( highlight == 'cpp' && prev == '<' && (next == '>' || next == '*') ) // Defining template type in C++
|
|
@@ -2626,9 +2817,10 @@ class CodeEditor {
|
|
|
2626
2817
|
token_classname = "cm-mtd";
|
|
2627
2818
|
|
|
2628
2819
|
|
|
2629
|
-
if( usesBlockComments && this._buildingBlockComment
|
|
2820
|
+
if( usesBlockComments && this._buildingBlockComment != undefined
|
|
2630
2821
|
&& token.substr( 0, blockCommentsTokens[ 1 ].length ) == blockCommentsTokens[ 1 ] )
|
|
2631
2822
|
{
|
|
2823
|
+
this._blockCommentCache.push( new LX.vec2( this._buildingBlockComment, this._currentLineNumber ) );
|
|
2632
2824
|
delete this._buildingBlockComment;
|
|
2633
2825
|
}
|
|
2634
2826
|
|
|
@@ -2677,16 +2869,27 @@ class CodeEditor {
|
|
|
2677
2869
|
_enclosedByTokens( token, tokenIndex, tagStart, tagEnd ) {
|
|
2678
2870
|
|
|
2679
2871
|
const tokenStartIndex = this._currentTokenPositions[ tokenIndex ];
|
|
2680
|
-
const tagStartIndex = indexOfFrom(this._currentLineString, tagStart, tokenStartIndex, true );
|
|
2872
|
+
const tagStartIndex = indexOfFrom( this._currentLineString, tagStart, tokenStartIndex, true );
|
|
2681
2873
|
if( tagStartIndex < 0 ) // Not found..
|
|
2682
2874
|
return;
|
|
2683
|
-
const tagEndIndex = indexOfFrom(this._currentLineString, tagEnd, tokenStartIndex );
|
|
2875
|
+
const tagEndIndex = indexOfFrom( this._currentLineString, tagEnd, tokenStartIndex );
|
|
2684
2876
|
if( tagEndIndex < 0 ) // Not found..
|
|
2685
2877
|
return;
|
|
2686
2878
|
|
|
2687
2879
|
return ( tagStartIndex < tokenStartIndex ) && ( tagEndIndex >= ( tokenStartIndex + token.length ) );
|
|
2688
2880
|
}
|
|
2689
2881
|
|
|
2882
|
+
_inBlockCommentSection( line ) {
|
|
2883
|
+
|
|
2884
|
+
for( var section of this._blockCommentCache )
|
|
2885
|
+
{
|
|
2886
|
+
if( line >= section.x && line <= section.y )
|
|
2887
|
+
return true;
|
|
2888
|
+
}
|
|
2889
|
+
|
|
2890
|
+
return false;
|
|
2891
|
+
}
|
|
2892
|
+
|
|
2690
2893
|
_isCSSClass( token, prev, next ) {
|
|
2691
2894
|
|
|
2692
2895
|
if( this.highlight != 'CSS' )
|
|
@@ -2697,20 +2900,26 @@ class CodeEditor {
|
|
|
2697
2900
|
|| ( token[ 0 ] == '#' && prev != ':' ) );
|
|
2698
2901
|
}
|
|
2699
2902
|
|
|
2700
|
-
|
|
2903
|
+
_isNumber( token ) {
|
|
2701
2904
|
|
|
2702
2905
|
if(this.highlight == 'C++')
|
|
2703
2906
|
{
|
|
2704
2907
|
if( token.lastChar == 'f' )
|
|
2705
|
-
return this.
|
|
2908
|
+
return this._isNumber( token.substring(0, token.length - 1) )
|
|
2706
2909
|
else if( token.lastChar == 'u' )
|
|
2707
|
-
return !(token.includes('.')) && this.
|
|
2910
|
+
return !(token.includes('.')) && this._isNumber( token.substring(0, token.length - 1) );
|
|
2911
|
+
}
|
|
2912
|
+
|
|
2913
|
+
else if(this.highlight == 'WGSL')
|
|
2914
|
+
{
|
|
2915
|
+
if( token.lastChar == 'u' )
|
|
2916
|
+
return !(token.includes('.')) && this._isNumber( token.substring(0, token.length - 1) );
|
|
2708
2917
|
}
|
|
2709
2918
|
|
|
2710
2919
|
else if(this.highlight == 'CSS')
|
|
2711
2920
|
{
|
|
2712
2921
|
if( token.lastChar == '%' )
|
|
2713
|
-
return this.
|
|
2922
|
+
return this._isNumber( token.substring(0, token.length - 1) )
|
|
2714
2923
|
}
|
|
2715
2924
|
|
|
2716
2925
|
return token.length && token != ' ' && !Number.isNaN(+token);
|
|
@@ -2719,7 +2928,7 @@ class CodeEditor {
|
|
|
2719
2928
|
_isType( token, prev, next ) {
|
|
2720
2929
|
|
|
2721
2930
|
// Common case
|
|
2722
|
-
if( this._mustHightlightWord( token,
|
|
2931
|
+
if( this._mustHightlightWord( token, CodeEditor.types ) )
|
|
2723
2932
|
return true;
|
|
2724
2933
|
|
|
2725
2934
|
if( this.highlight == 'JavaScript' )
|
|
@@ -2732,11 +2941,12 @@ class CodeEditor {
|
|
|
2732
2941
|
}
|
|
2733
2942
|
else if ( this.highlight == 'WGSL' )
|
|
2734
2943
|
{
|
|
2735
|
-
const
|
|
2736
|
-
return
|
|
2737
|
-
|
|
2944
|
+
const not_kwd = !this._mustHightlightWord( token, CodeEditor.keywords );
|
|
2945
|
+
return (prev == 'struct' && next == '{') ||
|
|
2946
|
+
(not_kwd && prev == ':' && next == ';') ||
|
|
2947
|
+
( not_kwd &&
|
|
2738
2948
|
( prev == ':' && next == ')' || prev == ':' && next == ',' || prev == '>' && next == '{'
|
|
2739
|
-
|| prev == '<' && next == ',' || prev == '<' && next == '>' || prev == '>' && !next ));
|
|
2949
|
+
|| prev == '<' && next == ',' || prev == '<' && next == '>' || prev == '>' && token != ';' && !next ));
|
|
2740
2950
|
}
|
|
2741
2951
|
}
|
|
2742
2952
|
|
|
@@ -2804,6 +3014,7 @@ class CodeEditor {
|
|
|
2804
3014
|
return false;
|
|
2805
3015
|
|
|
2806
3016
|
cursor.line++;
|
|
3017
|
+
|
|
2807
3018
|
this.cursorToBottom( cursor, resetLeft );
|
|
2808
3019
|
|
|
2809
3020
|
return true;
|
|
@@ -2876,16 +3087,25 @@ class CodeEditor {
|
|
|
2876
3087
|
delete this._lastSelectionKeyDir;
|
|
2877
3088
|
}
|
|
2878
3089
|
|
|
2879
|
-
selectAll(
|
|
3090
|
+
selectAll() {
|
|
3091
|
+
|
|
3092
|
+
// Use main cursor
|
|
3093
|
+
this._removeSecondaryCursors();
|
|
2880
3094
|
|
|
3095
|
+
var cursor = this._getCurrentCursor();
|
|
2881
3096
|
this.resetCursorPos( CodeEditor.CURSOR_LEFT | CodeEditor.CURSOR_TOP, cursor );
|
|
3097
|
+
|
|
2882
3098
|
this.startSelection( cursor );
|
|
3099
|
+
|
|
2883
3100
|
const nlines = this.code.lines.length - 1;
|
|
2884
3101
|
this.selection.toX = this.code.lines[ nlines ].length;
|
|
2885
3102
|
this.selection.toY = nlines;
|
|
3103
|
+
|
|
2886
3104
|
this.cursorToPosition( cursor, this.selection.toX );
|
|
2887
3105
|
this.cursorToLine( cursor, this.selection.toY );
|
|
3106
|
+
|
|
2888
3107
|
this.processSelection( null, true );
|
|
3108
|
+
|
|
2889
3109
|
this.hideAutoCompleteBox();
|
|
2890
3110
|
}
|
|
2891
3111
|
|
|
@@ -2988,22 +3208,51 @@ class CodeEditor {
|
|
|
2988
3208
|
|
|
2989
3209
|
saveCursor( cursor, state = {} ) {
|
|
2990
3210
|
|
|
2991
|
-
state.top = cursor._top;
|
|
2992
|
-
state.left = cursor._left;
|
|
2993
|
-
state.line = cursor.line;
|
|
2994
3211
|
state.position = cursor.position;
|
|
2995
|
-
|
|
3212
|
+
state.line = cursor.line;
|
|
2996
3213
|
return state;
|
|
2997
3214
|
}
|
|
2998
3215
|
|
|
3216
|
+
saveCursors() {
|
|
3217
|
+
|
|
3218
|
+
var cursors = [];
|
|
3219
|
+
|
|
3220
|
+
for( let cursor of this.cursors.children )
|
|
3221
|
+
{
|
|
3222
|
+
cursors.push( this.saveCursor( cursor ) );
|
|
3223
|
+
}
|
|
3224
|
+
|
|
3225
|
+
return cursors;
|
|
3226
|
+
}
|
|
3227
|
+
|
|
3228
|
+
relocateCursors() {
|
|
3229
|
+
|
|
3230
|
+
for( let cursor of this.cursors.children )
|
|
3231
|
+
{
|
|
3232
|
+
cursor._left = cursor.position * this.charWidth;
|
|
3233
|
+
cursor.style.left = "calc(" + cursor._left + "px + " + this.xPadding + ")";
|
|
3234
|
+
cursor._top = cursor.line * this.lineHeight;
|
|
3235
|
+
cursor.style.top = "calc(" + cursor._top + "px)";
|
|
3236
|
+
}
|
|
3237
|
+
}
|
|
3238
|
+
|
|
3239
|
+
mergeCursors( line ) {
|
|
3240
|
+
|
|
3241
|
+
console.assert( line >= 0 );
|
|
3242
|
+
const cursorsInLine = Array.from( this.cursors.children ).filter( v => v.line == line );
|
|
3243
|
+
|
|
3244
|
+
while( cursorsInLine.length > 1 )
|
|
3245
|
+
cursorsInLine.pop().remove();
|
|
3246
|
+
}
|
|
3247
|
+
|
|
2999
3248
|
restoreCursor( cursor, state ) {
|
|
3000
3249
|
|
|
3001
|
-
cursor.line = state.line ?? 0;
|
|
3002
3250
|
cursor.position = state.position ?? 0;
|
|
3251
|
+
cursor.line = state.line ?? 0;
|
|
3003
3252
|
|
|
3004
|
-
cursor._left =
|
|
3253
|
+
cursor._left = cursor.position * this.charWidth;
|
|
3005
3254
|
cursor.style.left = "calc(" + cursor._left + "px + " + this.xPadding + ")";
|
|
3006
|
-
cursor._top =
|
|
3255
|
+
cursor._top = cursor.line * this.lineHeight;
|
|
3007
3256
|
cursor.style.top = "calc(" + cursor._top + "px)";
|
|
3008
3257
|
}
|
|
3009
3258
|
|
|
@@ -3038,7 +3287,8 @@ class CodeEditor {
|
|
|
3038
3287
|
for( var i = 0; i < n; ++i ) {
|
|
3039
3288
|
this.root.dispatchEvent( new CustomEvent( 'keydown', { 'detail': {
|
|
3040
3289
|
skip_undo: true,
|
|
3041
|
-
key: ' '
|
|
3290
|
+
key: ' ',
|
|
3291
|
+
targetCursor: this._lastProcessedCursorIndex
|
|
3042
3292
|
}}));
|
|
3043
3293
|
}
|
|
3044
3294
|
}
|
|
@@ -3324,11 +3574,11 @@ class CodeEditor {
|
|
|
3324
3574
|
|
|
3325
3575
|
// Add language special keys...
|
|
3326
3576
|
suggestions = suggestions.concat(
|
|
3327
|
-
Object.keys(
|
|
3328
|
-
Object.keys(
|
|
3329
|
-
Object.keys(
|
|
3330
|
-
Object.keys(
|
|
3331
|
-
Object.keys(
|
|
3577
|
+
Object.keys( CodeEditor.builtin[ this.highlight ] ?? {} ),
|
|
3578
|
+
Object.keys( CodeEditor.keywords[ this.highlight ] ?? {} ),
|
|
3579
|
+
Object.keys( CodeEditor.statementsAndDeclarations[ this.highlight ] ?? {} ),
|
|
3580
|
+
Object.keys( CodeEditor.types[ this.highlight ] ?? {} ),
|
|
3581
|
+
Object.keys( CodeEditor.utils[ this.highlight ] ?? {} )
|
|
3332
3582
|
);
|
|
3333
3583
|
|
|
3334
3584
|
// Add words in current tab plus remove current word
|
|
@@ -3350,9 +3600,9 @@ class CodeEditor {
|
|
|
3350
3600
|
|
|
3351
3601
|
var icon = document.createElement( 'a' );
|
|
3352
3602
|
|
|
3353
|
-
if( this._mustHightlightWord( s,
|
|
3603
|
+
if( this._mustHightlightWord( s, CodeEditor.utils ) )
|
|
3354
3604
|
icon.className = "fa fa-cube";
|
|
3355
|
-
else if( this._mustHightlightWord( s,
|
|
3605
|
+
else if( this._mustHightlightWord( s, CodeEditor.types ) )
|
|
3356
3606
|
icon.className = "fa fa-code";
|
|
3357
3607
|
else
|
|
3358
3608
|
icon.className = "fa fa-font";
|
|
@@ -3600,7 +3850,7 @@ class CodeEditor {
|
|
|
3600
3850
|
|
|
3601
3851
|
goToLine( line ) {
|
|
3602
3852
|
|
|
3603
|
-
if( !this.
|
|
3853
|
+
if( !this._isNumber( line ) )
|
|
3604
3854
|
return;
|
|
3605
3855
|
|
|
3606
3856
|
this.codeScroller.scrollTo( 0, Math.max( line - 15 ) * this.lineHeight );
|
|
@@ -3647,6 +3897,11 @@ class CodeEditor {
|
|
|
3647
3897
|
}
|
|
3648
3898
|
}
|
|
3649
3899
|
|
|
3900
|
+
_hideActiveLine() {
|
|
3901
|
+
|
|
3902
|
+
this.code.querySelectorAll( '.active-line' ).forEach( e => e.classList.remove( 'active-line' ) );
|
|
3903
|
+
}
|
|
3904
|
+
|
|
3650
3905
|
_increaseFontSize() {
|
|
3651
3906
|
|
|
3652
3907
|
// Change font size
|
|
@@ -3664,7 +3919,13 @@ class CodeEditor {
|
|
|
3664
3919
|
r.style.setProperty( "--code-editor-row-height", row_pixels + "px" );
|
|
3665
3920
|
this.lineHeight = row_pixels;
|
|
3666
3921
|
|
|
3667
|
-
|
|
3922
|
+
// Relocate cursors
|
|
3923
|
+
|
|
3924
|
+
this.relocateCursors();
|
|
3925
|
+
|
|
3926
|
+
// Resize the code area
|
|
3927
|
+
|
|
3928
|
+
this.processLines();
|
|
3668
3929
|
}
|
|
3669
3930
|
|
|
3670
3931
|
_decreaseFontSize() {
|
|
@@ -3684,12 +3945,19 @@ class CodeEditor {
|
|
|
3684
3945
|
r.style.setProperty( "--code-editor-row-height", row_pixels + "px" );
|
|
3685
3946
|
this.lineHeight = row_pixels;
|
|
3686
3947
|
|
|
3687
|
-
|
|
3948
|
+
// Relocate cursors
|
|
3949
|
+
|
|
3950
|
+
this.relocateCursors();
|
|
3951
|
+
|
|
3952
|
+
// Resize the code area
|
|
3953
|
+
|
|
3954
|
+
this.processLines();
|
|
3688
3955
|
}
|
|
3689
3956
|
|
|
3690
3957
|
_clearTmpVariables() {
|
|
3691
3958
|
|
|
3692
3959
|
delete this._currentLineString;
|
|
3960
|
+
delete this._currentLineNumber;
|
|
3693
3961
|
delete this._buildingString;
|
|
3694
3962
|
delete this._pendingString;
|
|
3695
3963
|
delete this._buildingBlockComment;
|
|
@@ -3697,6 +3965,87 @@ class CodeEditor {
|
|
|
3697
3965
|
}
|
|
3698
3966
|
}
|
|
3699
3967
|
|
|
3968
|
+
CodeEditor.keywords = {
|
|
3969
|
+
|
|
3970
|
+
'JavaScript': ['var', 'let', 'const', 'this', 'in', 'of', 'true', 'false', 'new', 'function', 'NaN', 'static', 'class', 'constructor', 'null', 'typeof', 'debugger', 'abstract',
|
|
3971
|
+
'arguments', 'extends', 'instanceof'],
|
|
3972
|
+
'C++': ['int', 'float', 'double', 'bool', 'char', 'wchar_t', 'const', 'static_cast', 'dynamic_cast', 'new', 'delete', 'void', 'true', 'false', 'auto', 'struct', 'typedef', 'nullptr',
|
|
3973
|
+
'NULL', 'unsigned', 'namespace'],
|
|
3974
|
+
'JSON': ['true', 'false'],
|
|
3975
|
+
'GLSL': ['true', 'false', 'function', 'int', 'float', 'vec2', 'vec3', 'vec4', 'mat2x2', 'mat3x3', 'mat4x4', 'struct'],
|
|
3976
|
+
'CSS': ['body', 'html', 'canvas', 'div', 'input', 'span', '.'],
|
|
3977
|
+
'WGSL': ['var', 'let', 'true', 'false', 'fn', 'bool', 'u32', 'i32', 'f16', 'f32', 'vec2f', 'vec3f', 'vec4f', 'mat2x2f', 'mat3x3f', 'mat4x4f', 'array', 'atomic', 'struct',
|
|
3978
|
+
'sampler', 'sampler_comparison', 'texture_depth_2d', 'texture_depth_2d_array', 'texture_depth_cube', 'texture_depth_cube_array', 'texture_depth_multisampled_2d',
|
|
3979
|
+
'texture_external', 'texture_1d', 'texture_2d', 'texture_2d_array', 'texture_3d', 'texture_cube', 'texture_cube_array', 'texture_storage_1d', 'texture_storage_2d',
|
|
3980
|
+
'texture_storage_2d_array', 'texture_storage_3d', 'vec2u', 'vec3u', 'vec4u'],
|
|
3981
|
+
'Rust': ['as', 'const', 'crate', 'enum', 'extern', 'false', 'fn', 'impl', 'in', 'let', 'mod', 'move', 'mut', 'pub', 'ref', 'self', 'Self', 'static', 'struct', 'super', 'trait', 'true',
|
|
3982
|
+
'type', 'unsafe', 'use', 'where', 'abstract', 'become', 'box', 'final', 'macro', 'override', 'priv', 'typeof', 'unsized', 'virtual'],
|
|
3983
|
+
'Python': ['False', 'def', 'None', 'True', 'in', 'is', 'and', 'lambda', 'nonlocal', 'not', 'or'],
|
|
3984
|
+
'Batch': ['set', 'SET', 'echo', 'ECHO', 'off', 'OFF', 'del', 'DEL', 'defined', 'DEFINED', 'setlocal', 'SETLOCAL', 'enabledelayedexpansion', 'ENABLEDELAYEDEXPANSION', 'driverquery',
|
|
3985
|
+
'DRIVERQUERY', 'print', 'PRINT'],
|
|
3986
|
+
'HTML': ['html', 'meta', 'title', 'link', 'script', 'body', 'DOCTYPE', 'head', 'br', 'i', 'a', 'li', 'img', 'tr', 'td', 'h1', 'h2', 'h3', 'h4', 'h5'],
|
|
3987
|
+
'Markdown': ['br', 'i', 'a', 'li', 'img', 'table', 'title', 'tr', 'td', 'h1', 'h2', 'h3', 'h4', 'h5'],
|
|
3988
|
+
};
|
|
3989
|
+
|
|
3990
|
+
CodeEditor.utils = { // These ones don't have hightlight, used as suggestions to autocomplete only...
|
|
3991
|
+
|
|
3992
|
+
'JavaScript': ['querySelector', 'body', 'addEventListener', 'removeEventListener', 'remove', 'sort', 'keys', 'filter', 'isNaN', 'parseFloat', 'parseInt', 'EPSILON', 'isFinite',
|
|
3993
|
+
'bind', 'prototype', 'length', 'assign', 'entries', 'values', 'concat', 'substring', 'substr', 'splice', 'slice', 'buffer', 'appendChild', 'createElement', 'prompt',
|
|
3994
|
+
'alert'],
|
|
3995
|
+
'WGSL': ['textureSample'],
|
|
3996
|
+
'Python': ['abs', 'all', 'any', 'ascii', 'bin', 'bool', 'bytearray', 'bytes', 'callable', 'chr', 'classmethod', 'compile', 'complex', 'delattr', 'dict', 'dir', 'divmod',
|
|
3997
|
+
'enumerate', 'eval', 'exec', 'filter', 'float', 'format', 'frozenset', 'getattr', 'globals', 'hasattr', 'hash', 'help', 'hex', 'id', 'input', 'int', 'isinstance',
|
|
3998
|
+
'issubclass', 'iter', 'len', 'list', 'locals', 'map', 'max', 'memoryview', 'min', 'next', 'object', 'oct', 'open', 'ord', 'pow', 'print', 'property', 'range', 'repr',
|
|
3999
|
+
'reversed', 'round', 'set', 'setattr', 'slice', 'sorted', 'staticmethod', 'str', 'sum', 'super', 'tuple', 'type', 'vars', 'zip']
|
|
4000
|
+
};
|
|
4001
|
+
|
|
4002
|
+
CodeEditor.types = {
|
|
4003
|
+
|
|
4004
|
+
'JavaScript': ['Object', 'String', 'Function', 'Boolean', 'Symbol', 'Error', 'Number', 'TextEncoder', 'TextDecoder'],
|
|
4005
|
+
'Rust': ['u128'],
|
|
4006
|
+
'Python': ['int', 'type', 'float', 'map', 'list', 'ArithmeticError', 'AssertionError', 'AttributeError', 'Exception', 'EOFError', 'FloatingPointError', 'GeneratorExit',
|
|
4007
|
+
'ImportError', 'IndentationError', 'IndexError', 'KeyError', 'KeyboardInterrupt', 'LookupError', 'MemoryError', 'NameError', 'NotImplementedError', 'OSError',
|
|
4008
|
+
'OverflowError', 'ReferenceError', 'RuntimeError', 'StopIteration', 'SyntaxError', 'TabError', 'SystemError', 'SystemExit', 'TypeError', 'UnboundLocalError',
|
|
4009
|
+
'UnicodeError', 'UnicodeEncodeError', 'UnicodeDecodeError', 'UnicodeTranslateError', 'ValueError', 'ZeroDivisionError'],
|
|
4010
|
+
'C++': ['uint8_t', 'uint16_t', 'uint32_t']
|
|
4011
|
+
};
|
|
4012
|
+
|
|
4013
|
+
CodeEditor.builtin = {
|
|
4014
|
+
|
|
4015
|
+
'JavaScript': ['document', 'console', 'window', 'navigator', 'performance'],
|
|
4016
|
+
'CSS': ['*', '!important'],
|
|
4017
|
+
'C++': ['vector', 'list', 'map'],
|
|
4018
|
+
'HTML': ['type', 'xmlns', 'PUBLIC', 'http-equiv', 'src', 'style', 'lang', 'href', 'rel', 'content', 'xml', 'alt'], // attributes
|
|
4019
|
+
'Markdown': ['type', 'src', 'style', 'lang', 'href', 'rel', 'content', 'valign', 'alt'], // attributes
|
|
4020
|
+
};
|
|
4021
|
+
|
|
4022
|
+
CodeEditor.statementsAndDeclarations = {
|
|
4023
|
+
|
|
4024
|
+
'JavaScript': ['for', 'if', 'else', 'case', 'switch', 'return', 'while', 'continue', 'break', 'do', 'import', 'from', 'throw', 'async', 'try', 'catch', 'await'],
|
|
4025
|
+
'CSS': ['@', 'import'],
|
|
4026
|
+
'C++': ['std', 'for', 'if', 'else', 'return', 'continue', 'break', 'case', 'switch', 'while', 'using', 'glm', 'spdlog'],
|
|
4027
|
+
'GLSL': ['for', 'if', 'else', 'return', 'continue', 'break'],
|
|
4028
|
+
'WGSL': ['const','for', 'if', 'else', 'return', 'continue', 'break', 'storage', 'read', 'read_write', 'uniform', 'function', 'workgroup'],
|
|
4029
|
+
'Rust': ['break', 'else', 'continue', 'for', 'if', 'loop', 'match', 'return', 'while', 'do', 'yield'],
|
|
4030
|
+
'Python': ['if', 'raise', 'del', 'import', 'return', 'elif', 'try', 'else', 'while', 'as', 'except', 'with', 'assert', 'finally', 'yield', 'break', 'for', 'class', 'continue',
|
|
4031
|
+
'global', 'pass'],
|
|
4032
|
+
'Batch': ['if', 'IF', 'for', 'FOR', 'in', 'IN', 'do', 'DO', 'call', 'CALL', 'goto', 'GOTO', 'exit', 'EXIT']
|
|
4033
|
+
};
|
|
4034
|
+
|
|
4035
|
+
CodeEditor.symbols = {
|
|
4036
|
+
|
|
4037
|
+
'JavaScript': ['<', '>', '[', ']', '{', '}', '(', ')', ';', '=', '|', '||', '&', '&&', '?', '??'],
|
|
4038
|
+
'C++': ['<', '>', '[', ']', '{', '}', '(', ')', ';', '=', '|', '||', '&', '&&', '?', '::', '*', '-', '+'],
|
|
4039
|
+
'JSON': ['[', ']', '{', '}', '(', ')'],
|
|
4040
|
+
'GLSL': ['[', ']', '{', '}', '(', ')'],
|
|
4041
|
+
'WGSL': ['[', ']', '{', '}', '(', ')', '->'],
|
|
4042
|
+
'CSS': ['{', '}', '(', ')', '*'],
|
|
4043
|
+
'Rust': ['<', '>', '[', ']', '(', ')', '='],
|
|
4044
|
+
'Python': ['<', '>', '[', ']', '(', ')', '='],
|
|
4045
|
+
'Batch': ['[', ']', '(', ')', '%'],
|
|
4046
|
+
'HTML': ['<', '>', '/']
|
|
4047
|
+
};
|
|
4048
|
+
|
|
3700
4049
|
LX.CodeEditor = CodeEditor;
|
|
3701
4050
|
|
|
3702
4051
|
export { CodeEditor };
|