lexgui 0.1.13 → 0.1.15
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 +353 -207
- package/build/components/timeline.js +104 -68
- package/build/lexgui.css +46 -14
- package/build/lexgui.js +29 -19
- package/build/lexgui.module.js +30 -19
- package/examples/code_editor.html +7 -2
- package/package.json +1 -1
|
@@ -29,6 +29,10 @@ function firstNonspaceIndex(str) {
|
|
|
29
29
|
return str.search(/\S|$/);
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
+
function deleteElement(el) {
|
|
33
|
+
if(el) el.remove();
|
|
34
|
+
}
|
|
35
|
+
|
|
32
36
|
let ASYNC_ENABLED = true;
|
|
33
37
|
|
|
34
38
|
function doAsync( fn, ms ) {
|
|
@@ -106,9 +110,6 @@ class CodeEditor {
|
|
|
106
110
|
|
|
107
111
|
CodeEditor.__instances.push( this );
|
|
108
112
|
|
|
109
|
-
this.disable_edition = options.disable_edition ?? false;
|
|
110
|
-
|
|
111
|
-
this.skip_info = options.skip_info;
|
|
112
113
|
this.base_area = area;
|
|
113
114
|
this.area = new LX.Area( { className: "lexcodeeditor", height: "auto", no_append: true } );
|
|
114
115
|
|
|
@@ -129,14 +130,21 @@ class CodeEditor {
|
|
|
129
130
|
this.root.tabIndex = -1;
|
|
130
131
|
area.attach( this.root );
|
|
131
132
|
|
|
132
|
-
this.
|
|
133
|
+
this.skipCodeInfo = options.skip_info ?? false;
|
|
134
|
+
this.disableEdition = options.disable_edition ?? false;
|
|
135
|
+
|
|
136
|
+
if( !this.disableEdition )
|
|
137
|
+
{
|
|
138
|
+
this.root.addEventListener( 'keydown', this.processKey.bind(this), true);
|
|
139
|
+
this.root.addEventListener( 'focus', this.processFocus.bind(this, true) );
|
|
140
|
+
this.root.addEventListener( 'focusout', this.processFocus.bind(this, false) );
|
|
141
|
+
}
|
|
142
|
+
|
|
133
143
|
this.root.addEventListener( 'mousedown', this.processMouse.bind(this) );
|
|
134
144
|
this.root.addEventListener( 'mouseup', this.processMouse.bind(this) );
|
|
135
145
|
this.root.addEventListener( 'mousemove', this.processMouse.bind(this) );
|
|
136
146
|
this.root.addEventListener( 'click', this.processMouse.bind(this) );
|
|
137
147
|
this.root.addEventListener( 'contextmenu', this.processMouse.bind(this) );
|
|
138
|
-
this.root.addEventListener( 'focus', this.processFocus.bind(this, true) );
|
|
139
|
-
this.root.addEventListener( 'focusout', this.processFocus.bind(this, false) );
|
|
140
148
|
|
|
141
149
|
// Cursors and selection
|
|
142
150
|
|
|
@@ -195,50 +203,100 @@ class CodeEditor {
|
|
|
195
203
|
this.tabSpaces = 4;
|
|
196
204
|
this.maxUndoSteps = 16;
|
|
197
205
|
this.lineHeight = 20;
|
|
206
|
+
this.defaultSingleLineCommentToken = "//";
|
|
198
207
|
this.charWidth = 8; //this.measureChar();
|
|
199
208
|
this._lastTime = null;
|
|
200
209
|
|
|
201
|
-
this.
|
|
202
|
-
|
|
203
|
-
|
|
210
|
+
this.pairKeys = {
|
|
211
|
+
"\"": "\"",
|
|
212
|
+
"'": "'",
|
|
213
|
+
"(": ")",
|
|
214
|
+
"{": "}",
|
|
215
|
+
"[": "]"
|
|
216
|
+
};
|
|
217
|
+
|
|
218
|
+
this.stringKeys = { // adding @ because some words are always true in (e.g. constructor..)
|
|
219
|
+
"@\"": "\"",
|
|
220
|
+
"@'": "'"
|
|
221
|
+
};
|
|
222
|
+
|
|
223
|
+
// Scan tokens..
|
|
224
|
+
setInterval( this.scanWordSuggestions.bind(this), 2000 );
|
|
225
|
+
|
|
226
|
+
this.languages = {
|
|
227
|
+
'Plain Text': { },
|
|
228
|
+
'JavaScript': { },
|
|
229
|
+
'C++': { },
|
|
230
|
+
'CSS': { },
|
|
231
|
+
'GLSL': { },
|
|
232
|
+
'WGSL': { },
|
|
233
|
+
'JSON': { },
|
|
234
|
+
'XML': { },
|
|
235
|
+
'Python': { },
|
|
236
|
+
'Batch': { blockComments: false, singleLineCommentToken: '::' }
|
|
237
|
+
};
|
|
238
|
+
|
|
204
239
|
this.specialKeys = [
|
|
205
240
|
'Backspace', 'Enter', 'ArrowUp', 'ArrowDown',
|
|
206
241
|
'ArrowRight', 'ArrowLeft', 'Delete', 'Home',
|
|
207
242
|
'End', 'Tab', 'Escape'
|
|
208
243
|
];
|
|
209
244
|
this.keywords = {
|
|
210
|
-
'JavaScript': ['var', 'let', 'const', 'this', 'in', 'of', 'true', 'false', 'new', 'function', 'NaN', 'static', 'class', 'constructor', 'null', 'typeof', 'debugger'
|
|
245
|
+
'JavaScript': ['var', 'let', 'const', 'this', 'in', 'of', 'true', 'false', 'new', 'function', 'NaN', 'static', 'class', 'constructor', 'null', 'typeof', 'debugger', 'abstract',
|
|
246
|
+
'arguments', 'extends', 'instanceof'],
|
|
247
|
+
'C++': ['int', 'float', 'double', 'bool', 'char', 'wchar_t', 'const', 'static_cast', 'dynamic_cast', 'new', 'delete', 'void', 'true', 'false', 'auto', 'struct', 'typedef', 'nullptr',
|
|
248
|
+
'NULL', 'unsigned'],
|
|
211
249
|
'GLSL': ['true', 'false', 'function', 'int', 'float', 'vec2', 'vec3', 'vec4', 'mat2x2', 'mat3x3', 'mat4x4', 'struct'],
|
|
212
250
|
'CSS': ['body', 'html', 'canvas', 'div', 'input', 'span', '.'],
|
|
213
251
|
'WGSL': ['var', 'let', 'true', 'false', 'fn', 'bool', 'u32', 'i32', 'f16', 'f32', 'vec2f', 'vec3f', 'vec4f', 'mat2x2f', 'mat3x3f', 'mat4x4f', 'array', 'atomic', 'struct',
|
|
214
252
|
'sampler', 'sampler_comparison', 'texture_depth_2d', 'texture_depth_2d_array', 'texture_depth_cube', 'texture_depth_cube_array', 'texture_depth_multisampled_2d',
|
|
215
253
|
'texture_external', 'texture_1d', 'texture_2d', 'texture_2d_array', 'texture_3d', 'texture_cube', 'texture_cube_array', 'texture_storage_1d', 'texture_storage_2d',
|
|
216
|
-
'texture_storage_2d_array', 'texture_storage_3d']
|
|
254
|
+
'texture_storage_2d_array', 'texture_storage_3d'],
|
|
255
|
+
'Python': ['False', 'def', 'None', 'True', 'in', 'is', 'and', 'lambda', 'nonlocal', 'not', 'or'],
|
|
256
|
+
'Batch': ['set', 'SET', 'echo', 'ECHO', 'off', 'OFF', 'del', 'DEL', 'defined', 'DEFINED', 'setlocal', 'SETLOCAL', 'enabledelayedexpansion', 'ENABLEDELAYEDEXPANSION', 'driverquery',
|
|
257
|
+
'DRIVERQUERY', 'print', 'PRINT']
|
|
217
258
|
};
|
|
218
259
|
this.utils = { // These ones don't have hightlight, used as suggestions to autocomplete only...
|
|
219
260
|
'JavaScript': ['querySelector', 'body', 'addEventListener', 'removeEventListener', 'remove', 'sort', 'keys', 'filter', 'isNaN', 'parseFloat', 'parseInt', 'EPSILON', 'isFinite',
|
|
220
|
-
'bind', 'prototype', 'length', 'assign', 'entries', 'values', 'concat', 'substring', 'substr', 'splice', 'slice', 'buffer', 'appendChild', 'createElement'
|
|
221
|
-
|
|
261
|
+
'bind', 'prototype', 'length', 'assign', 'entries', 'values', 'concat', 'substring', 'substr', 'splice', 'slice', 'buffer', 'appendChild', 'createElement', 'prompt',
|
|
262
|
+
'alert'],
|
|
263
|
+
'WGSL': ['textureSample'],
|
|
264
|
+
'Python': ['abs', 'all', 'any', 'ascii', 'bin', 'bool', 'bytearray', 'bytes', 'callable', 'chr', 'classmethod', 'compile', 'complex', 'delattr', 'dict', 'dir', 'divmod',
|
|
265
|
+
'enumerate', 'eval', 'exec', 'filter', 'float', 'format', 'frozenset', 'getattr', 'globals', 'hasattr', 'hash', 'help', 'hex', 'id', 'input', 'int', 'isinstance',
|
|
266
|
+
'issubclass', 'iter', 'len', 'list', 'locals', 'map', 'max', 'memoryview', 'min', 'next', 'object', 'oct', 'open', 'ord', 'pow', 'print', 'property', 'range', 'repr',
|
|
267
|
+
'reversed', 'round', 'set', 'setattr', 'slice', 'sorted', 'staticmethod', 'str', 'sum', 'super', 'tuple', 'type', 'vars', 'zip']
|
|
222
268
|
};
|
|
223
269
|
this.types = {
|
|
224
|
-
'JavaScript': ['Object', 'String', 'Function', 'Boolean', 'Symbol', 'Error', 'Number']
|
|
270
|
+
'JavaScript': ['Object', 'String', 'Function', 'Boolean', 'Symbol', 'Error', 'Number', 'TextEncoder', 'TextDecoder'],
|
|
271
|
+
'Python': ['int', 'type', 'float', 'map', 'list', 'ArithmeticError', 'AssertionError', 'AttributeError', 'Exception', 'EOFError', 'FloatingPointError', 'GeneratorExit',
|
|
272
|
+
'ImportError', 'IndentationError', 'IndexError', 'KeyError', 'KeyboardInterrupt', 'LookupError', 'MemoryError', 'NameError', 'NotImplementedError', 'OSError',
|
|
273
|
+
'OverflowError', 'ReferenceError', 'RuntimeError', 'StopIteration', 'SyntaxError', 'TabError', 'SystemError', 'SystemExit', 'TypeError', 'UnboundLocalError',
|
|
274
|
+
'UnicodeError', 'UnicodeEncodeError', 'UnicodeDecodeError', 'UnicodeTranslateError', 'ValueError', 'ZeroDivisionError' ],
|
|
275
|
+
'C++': ['uint8_t', 'uint16_t', 'uint32_t']
|
|
225
276
|
};
|
|
226
277
|
this.builtin = {
|
|
227
|
-
'JavaScript': ['document', 'console', 'window', 'navigator'],
|
|
228
|
-
'CSS': ['*', '!important']
|
|
278
|
+
'JavaScript': ['document', 'console', 'window', 'navigator', 'performance'],
|
|
279
|
+
'CSS': ['*', '!important'],
|
|
280
|
+
'C++': ['vector', 'list', 'map']
|
|
229
281
|
};
|
|
230
282
|
this.statementsAndDeclarations = {
|
|
231
|
-
'JavaScript': ['for', 'if', 'else', 'case', 'switch', 'return', 'while', 'continue', 'break', 'do', 'import',
|
|
232
|
-
|
|
283
|
+
'JavaScript': ['for', 'if', 'else', 'case', 'switch', 'return', 'while', 'continue', 'break', 'do', 'import', 'from', 'throw', 'async', 'try', 'catch', 'await'],
|
|
284
|
+
'C++': ['std', 'for', 'if', 'else', 'return', 'continue', 'break', 'case', 'switch', 'while', 'glm'],
|
|
233
285
|
'GLSL': ['for', 'if', 'else', 'return', 'continue', 'break'],
|
|
234
|
-
'WGSL': ['const','for', 'if', 'else', 'return', 'continue', 'break', 'storage', 'read', 'uniform']
|
|
286
|
+
'WGSL': ['const','for', 'if', 'else', 'return', 'continue', 'break', 'storage', 'read', 'uniform'],
|
|
287
|
+
'Python': ['if', 'raise', 'del', 'import', 'return', 'elif', 'try', 'else', 'while', 'as', 'except', 'with', 'assert', 'finally', 'yield', 'break', 'for', 'class', 'continue',
|
|
288
|
+
'global', 'pass'],
|
|
289
|
+
'Batch': ['if', 'IF', 'for', 'FOR', 'in', 'IN', 'do', 'DO', 'call', 'CALL', 'goto', 'GOTO', 'exit', 'EXIT']
|
|
235
290
|
};
|
|
236
291
|
this.symbols = {
|
|
237
292
|
'JavaScript': ['<', '>', '[', ']', '{', '}', '(', ')', ';', '=', '|', '||', '&', '&&', '?', '??'],
|
|
293
|
+
'C++': ['<', '>', '[', ']', '{', '}', '(', ')', ';', '=', '|', '||', '&', '&&', '?', '::'],
|
|
238
294
|
'JSON': ['[', ']', '{', '}', '(', ')'],
|
|
239
295
|
'GLSL': ['[', ']', '{', '}', '(', ')'],
|
|
240
296
|
'WGSL': ['[', ']', '{', '}', '(', ')', '->'],
|
|
241
|
-
'CSS': ['{', '}', '(', ')', '*']
|
|
297
|
+
'CSS': ['{', '}', '(', ')', '*'],
|
|
298
|
+
'Python': ['<', '>', '[', ']', '(', ')', '='],
|
|
299
|
+
'Batch': ['[', ']', '(', ')', '%'],
|
|
242
300
|
};
|
|
243
301
|
|
|
244
302
|
// Action keys
|
|
@@ -323,7 +381,7 @@ class CodeEditor {
|
|
|
323
381
|
|
|
324
382
|
this.resetCursorPos( CodeEditor.CURSOR_LEFT );
|
|
325
383
|
if(idx > 0) this.cursorToString(cursor, prestring);
|
|
326
|
-
this._refreshCodeInfo(cursor.line
|
|
384
|
+
this._refreshCodeInfo(cursor.line, cursor.position);
|
|
327
385
|
this.code.scrollLeft = 0;
|
|
328
386
|
|
|
329
387
|
if( e.shiftKey && !e.cancelShift )
|
|
@@ -335,7 +393,7 @@ class CodeEditor {
|
|
|
335
393
|
this.startSelection(cursor);
|
|
336
394
|
var string = this.code.lines[ln].substring(idx, last_pos);
|
|
337
395
|
this.selection.selectInline(idx, cursor.line, this.measureString(string));
|
|
338
|
-
} else
|
|
396
|
+
} else if( !e.keepSelection )
|
|
339
397
|
this.endSelection();
|
|
340
398
|
});
|
|
341
399
|
|
|
@@ -411,7 +469,7 @@ class CodeEditor {
|
|
|
411
469
|
|
|
412
470
|
var letter = this.getCharAtPos( cursor );
|
|
413
471
|
if(!letter) {
|
|
414
|
-
this.selection.toX =
|
|
472
|
+
this.selection.toX = this.code.lines[cursor.line].length;
|
|
415
473
|
this.cursorToPosition(cursor, this.selection.toX);
|
|
416
474
|
}
|
|
417
475
|
|
|
@@ -517,13 +575,16 @@ class CodeEditor {
|
|
|
517
575
|
}
|
|
518
576
|
}
|
|
519
577
|
else if( cursor.line > 0 ) {
|
|
520
|
-
|
|
578
|
+
|
|
579
|
+
if( e.shiftKey ) {
|
|
580
|
+
if(!this.selection) this.startSelection(cursor);
|
|
581
|
+
}
|
|
582
|
+
|
|
521
583
|
this.lineUp( cursor );
|
|
522
584
|
this.resetCursorPos( CodeEditor.CURSOR_LEFT );
|
|
523
585
|
this.cursorToPosition( cursor, this.code.lines[cursor.line].length );
|
|
524
586
|
|
|
525
587
|
if( e.shiftKey ) {
|
|
526
|
-
if(!this.selection) this.startSelection(cursor);
|
|
527
588
|
this.selection.toX = cursor.position;
|
|
528
589
|
this.selection.toY--;
|
|
529
590
|
this.processSelection(null, true);
|
|
@@ -582,17 +643,22 @@ class CodeEditor {
|
|
|
582
643
|
}
|
|
583
644
|
else if( this.code.lines[ cursor.line + 1 ] !== undefined ) {
|
|
584
645
|
|
|
646
|
+
if( e.shiftKey ) {
|
|
647
|
+
if(!this.selection) this.startSelection(cursor);
|
|
648
|
+
e.cancelShift = true;
|
|
649
|
+
e.keepSelection = true;
|
|
650
|
+
}
|
|
651
|
+
|
|
585
652
|
this.lineDown( cursor );
|
|
586
|
-
e.cancelShift = true;
|
|
587
653
|
this.actions['Home'].callback(cursor.line, cursor, e);
|
|
588
|
-
|
|
589
|
-
|
|
654
|
+
|
|
590
655
|
if( e.shiftKey ) {
|
|
591
|
-
if(!this.selection) this.startSelection(cursor);
|
|
592
656
|
this.selection.toX = cursor.position;
|
|
593
657
|
this.selection.toY++;
|
|
594
658
|
this.processSelection(null, true);
|
|
595
659
|
}
|
|
660
|
+
|
|
661
|
+
this.hideAutoCompleteBox();
|
|
596
662
|
}
|
|
597
663
|
}
|
|
598
664
|
});
|
|
@@ -621,7 +687,7 @@ class CodeEditor {
|
|
|
621
687
|
}
|
|
622
688
|
|
|
623
689
|
// This can be used to empty all text...
|
|
624
|
-
setText( text = "" ) {
|
|
690
|
+
setText( text = "", lang ) {
|
|
625
691
|
|
|
626
692
|
let new_lines = text.split('\n');
|
|
627
693
|
this.code.lines = [].concat(new_lines);
|
|
@@ -632,6 +698,11 @@ class CodeEditor {
|
|
|
632
698
|
this.cursorToLine(cursor, new_lines.length); // Already substracted 1
|
|
633
699
|
this.cursorToPosition(cursor, lastLine.length);
|
|
634
700
|
this.processLines();
|
|
701
|
+
|
|
702
|
+
if( lang )
|
|
703
|
+
{
|
|
704
|
+
this._changeLanguage( lang );
|
|
705
|
+
}
|
|
635
706
|
}
|
|
636
707
|
|
|
637
708
|
appendText( text ) {
|
|
@@ -703,8 +774,9 @@ class CodeEditor {
|
|
|
703
774
|
this.addTab(name, true, title);
|
|
704
775
|
text = text.replaceAll('\r', '');
|
|
705
776
|
this.code.lines = text.split('\n');
|
|
706
|
-
this.processLines();
|
|
707
777
|
this._refreshCodeInfo();
|
|
778
|
+
this._changeLanguageFromExtension( LX.getExtension(name) );
|
|
779
|
+
this.processLines();
|
|
708
780
|
};
|
|
709
781
|
|
|
710
782
|
if(file.constructor == String)
|
|
@@ -713,7 +785,6 @@ class CodeEditor {
|
|
|
713
785
|
LX.request({ url: filename, success: text => {
|
|
714
786
|
|
|
715
787
|
const name = filename.substring(filename.lastIndexOf('/') + 1);
|
|
716
|
-
this._changeLanguageFromExtension( LX.getExtension(name) );
|
|
717
788
|
inner_add_tab( text, name, filename );
|
|
718
789
|
} });
|
|
719
790
|
}
|
|
@@ -722,7 +793,6 @@ class CodeEditor {
|
|
|
722
793
|
const fr = new FileReader();
|
|
723
794
|
fr.readAsText( file );
|
|
724
795
|
fr.onload = e => {
|
|
725
|
-
this._changeLanguageFromExtension( LX.getExtension(file.name) );
|
|
726
796
|
const text = e.currentTarget.result;
|
|
727
797
|
inner_add_tab( text, file.name );
|
|
728
798
|
};
|
|
@@ -742,6 +812,8 @@ class CodeEditor {
|
|
|
742
812
|
}
|
|
743
813
|
|
|
744
814
|
_changeLanguage( lang ) {
|
|
815
|
+
|
|
816
|
+
this.code.lang = lang;
|
|
745
817
|
this.highlight = lang;
|
|
746
818
|
this._refreshCodeInfo();
|
|
747
819
|
this.processLines();
|
|
@@ -749,14 +821,21 @@ class CodeEditor {
|
|
|
749
821
|
|
|
750
822
|
_changeLanguageFromExtension( ext ) {
|
|
751
823
|
|
|
824
|
+
if( !ext )
|
|
825
|
+
return this._changeLanguage( this.code.lang );
|
|
826
|
+
|
|
752
827
|
switch(ext.toLowerCase())
|
|
753
828
|
{
|
|
754
829
|
case 'js': return this._changeLanguage('JavaScript');
|
|
830
|
+
case 'cpp': return this._changeLanguage('C++');
|
|
831
|
+
case 'h': return this._changeLanguage('C++');
|
|
755
832
|
case 'glsl': return this._changeLanguage('GLSL');
|
|
756
833
|
case 'css': return this._changeLanguage('CSS');
|
|
757
834
|
case 'json': return this._changeLanguage('JSON');
|
|
758
835
|
case 'xml': return this._changeLanguage('XML');
|
|
759
836
|
case 'wgsl': return this._changeLanguage('WGSL');
|
|
837
|
+
case 'py': return this._changeLanguage('Python');
|
|
838
|
+
case 'bat': return this._changeLanguage('Batch');
|
|
760
839
|
case 'txt':
|
|
761
840
|
default:
|
|
762
841
|
this._changeLanguage('Plain Text');
|
|
@@ -765,23 +844,23 @@ class CodeEditor {
|
|
|
765
844
|
|
|
766
845
|
_createPanelInfo() {
|
|
767
846
|
|
|
768
|
-
if( !this.
|
|
847
|
+
if( !this.skipCodeInfo )
|
|
769
848
|
{
|
|
770
849
|
let panel = new LX.Panel({ className: "lexcodetabinfo", width: "calc(100%)", height: "auto" });
|
|
771
850
|
panel.ln = 0;
|
|
772
851
|
panel.col = 0;
|
|
773
852
|
|
|
774
853
|
this._refreshCodeInfo = (ln = panel.ln, col = panel.col) => {
|
|
775
|
-
panel.ln = ln;
|
|
776
|
-
panel.col = col;
|
|
854
|
+
panel.ln = ln + 1;
|
|
855
|
+
panel.col = col + 1;
|
|
777
856
|
panel.clear();
|
|
778
857
|
panel.sameLine();
|
|
779
858
|
panel.addLabel(this.code.title, { float: 'right' });
|
|
780
|
-
panel.addLabel("Ln " + ln, { width: "64px" });
|
|
781
|
-
panel.addLabel("Col " + col, { width: "64px" });
|
|
859
|
+
panel.addLabel("Ln " + panel.ln, { width: "64px" });
|
|
860
|
+
panel.addLabel("Col " + panel.col, { width: "64px" });
|
|
782
861
|
panel.addButton("<b>{ }</b>", this.highlight, (value, event) => {
|
|
783
862
|
LX.addContextMenu( "Language", event, m => {
|
|
784
|
-
for( const lang of this.languages )
|
|
863
|
+
for( const lang of Object.keys(this.languages) )
|
|
785
864
|
m.add( lang, this._changeLanguage.bind(this) );
|
|
786
865
|
});
|
|
787
866
|
}, { width: "25%", nameWidth: "15%" });
|
|
@@ -829,6 +908,7 @@ class CodeEditor {
|
|
|
829
908
|
let code = document.createElement('div');
|
|
830
909
|
code.className = 'code';
|
|
831
910
|
code.lines = [""];
|
|
911
|
+
code.lang = "Plain Text";
|
|
832
912
|
code.cursorState = {};
|
|
833
913
|
code.undoSteps = [];
|
|
834
914
|
code.tabName = name;
|
|
@@ -882,7 +962,7 @@ class CodeEditor {
|
|
|
882
962
|
this.restoreCursor(cursor, this.code.cursorState);
|
|
883
963
|
this.endSelection();
|
|
884
964
|
this._changeLanguageFromExtension( LX.getExtension(tabname) );
|
|
885
|
-
this._refreshCodeInfo(cursor.line
|
|
965
|
+
this._refreshCodeInfo(cursor.line, cursor.position);
|
|
886
966
|
|
|
887
967
|
// Restore scroll
|
|
888
968
|
this.gutter.scrollTop = this.code.scrollTop;
|
|
@@ -1012,15 +1092,18 @@ class CodeEditor {
|
|
|
1012
1092
|
return;
|
|
1013
1093
|
|
|
1014
1094
|
LX.addContextMenu( null, e, m => {
|
|
1015
|
-
m.add( "Format/JSON", () => {
|
|
1016
|
-
let json = this.toJSONFormat(this.getText());
|
|
1017
|
-
this.code.lines = json.split("\n");
|
|
1018
|
-
this.processLines();
|
|
1019
|
-
} );
|
|
1020
|
-
m.add( "" )
|
|
1021
|
-
m.add( "Cut", () => { this._cutContent(); } );
|
|
1022
1095
|
m.add( "Copy", () => { this._copyContent(); } );
|
|
1023
|
-
|
|
1096
|
+
if( !this.disableEdition )
|
|
1097
|
+
{
|
|
1098
|
+
m.add( "Cut", () => { this._cutContent(); } );
|
|
1099
|
+
m.add( "Paste", () => { this._pasteContent(); } );
|
|
1100
|
+
m.add( "" );
|
|
1101
|
+
m.add( "Format/JSON", () => {
|
|
1102
|
+
let json = this.toJSONFormat(this.getText());
|
|
1103
|
+
this.code.lines = json.split("\n");
|
|
1104
|
+
this.processLines();
|
|
1105
|
+
} );
|
|
1106
|
+
}
|
|
1024
1107
|
});
|
|
1025
1108
|
|
|
1026
1109
|
this.canOpenContextMenu = false;
|
|
@@ -1048,7 +1131,7 @@ class CodeEditor {
|
|
|
1048
1131
|
this.hideAutoCompleteBox();
|
|
1049
1132
|
|
|
1050
1133
|
if(!skip_refresh)
|
|
1051
|
-
this._refreshCodeInfo( ln
|
|
1134
|
+
this._refreshCodeInfo( ln, cursor.position );
|
|
1052
1135
|
}
|
|
1053
1136
|
|
|
1054
1137
|
processSelection( e, keep_range ) {
|
|
@@ -1078,7 +1161,7 @@ class CodeEditor {
|
|
|
1078
1161
|
if( deltaY >= 0 )
|
|
1079
1162
|
{
|
|
1080
1163
|
while( deltaY < (this.selections.childElementCount - 1) )
|
|
1081
|
-
this.selections.lastChild
|
|
1164
|
+
deleteElement( this.selections.lastChild );
|
|
1082
1165
|
|
|
1083
1166
|
for(let i = fromY; i <= toY; i++){
|
|
1084
1167
|
|
|
@@ -1121,7 +1204,7 @@ class CodeEditor {
|
|
|
1121
1204
|
else // Selection goes up...
|
|
1122
1205
|
{
|
|
1123
1206
|
while( Math.abs(deltaY) < (this.selections.childElementCount - 1) )
|
|
1124
|
-
this.selections.firstChild
|
|
1207
|
+
deleteElement( this.selections.firstChild );
|
|
1125
1208
|
|
|
1126
1209
|
for(let i = toY; i <= fromY; i++){
|
|
1127
1210
|
|
|
@@ -1303,36 +1386,33 @@ class CodeEditor {
|
|
|
1303
1386
|
lidx = cursor.line; // Update this, since it's from the old code
|
|
1304
1387
|
}
|
|
1305
1388
|
|
|
1306
|
-
// Append key
|
|
1389
|
+
// Append key
|
|
1307
1390
|
|
|
1308
|
-
this.
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1391
|
+
const isPairKey = (Object.values( this.pairKeys ).indexOf( key ) > -1) && !this.wasKeyPaired;
|
|
1392
|
+
const sameKeyNext = isPairKey && (this.code.lines[lidx][cursor.position] === key);
|
|
1393
|
+
|
|
1394
|
+
if( !sameKeyNext )
|
|
1395
|
+
{
|
|
1396
|
+
this.code.lines[lidx] = [
|
|
1397
|
+
this.code.lines[lidx].slice(0, cursor.position),
|
|
1398
|
+
key,
|
|
1399
|
+
this.code.lines[lidx].slice(cursor.position)
|
|
1400
|
+
].join('');
|
|
1401
|
+
}
|
|
1313
1402
|
|
|
1314
1403
|
this.cursorToRight( key );
|
|
1315
1404
|
|
|
1316
1405
|
// Some custom cases for auto key pair (), {}, "", '', ...
|
|
1317
|
-
|
|
1318
|
-
const
|
|
1319
|
-
if(
|
|
1406
|
+
|
|
1407
|
+
const keyMustPair = (this.pairKeys[ key ] !== undefined);
|
|
1408
|
+
if( keyMustPair && !this.wasKeyPaired )
|
|
1320
1409
|
{
|
|
1321
|
-
// Find pair key
|
|
1322
|
-
let pair = key;
|
|
1323
|
-
switch(key)
|
|
1324
|
-
{
|
|
1325
|
-
case "'":
|
|
1326
|
-
case "\"":
|
|
1327
|
-
break;
|
|
1328
|
-
case "(": pair = ")"; break;
|
|
1329
|
-
case "{": pair = "}"; break;
|
|
1330
|
-
}
|
|
1331
|
-
|
|
1332
1410
|
// Make sure to detect later that the key is paired automatically to avoid loops...
|
|
1333
1411
|
this.wasKeyPaired = true;
|
|
1334
1412
|
|
|
1335
|
-
|
|
1413
|
+
if(sameKeyNext) return;
|
|
1414
|
+
|
|
1415
|
+
this.root.dispatchEvent(new KeyboardEvent('keydown', { 'key': this.pairKeys[ key ] }));
|
|
1336
1416
|
this.cursorToLeft( key, cursor );
|
|
1337
1417
|
return;
|
|
1338
1418
|
}
|
|
@@ -1424,68 +1504,143 @@ class CodeEditor {
|
|
|
1424
1504
|
};
|
|
1425
1505
|
}
|
|
1426
1506
|
|
|
1427
|
-
|
|
1507
|
+
scanWordSuggestions() {
|
|
1428
1508
|
|
|
1429
|
-
|
|
1430
|
-
{
|
|
1431
|
-
this.gutter.innerHTML = "";
|
|
1432
|
-
this.code.innerHTML = "";
|
|
1433
|
-
this.code.tokens = {};
|
|
1434
|
-
}
|
|
1509
|
+
this.code.tokens = {};
|
|
1435
1510
|
|
|
1436
|
-
for( let i =
|
|
1511
|
+
for( let i = 0; i < this.code.lines.length; ++i )
|
|
1437
1512
|
{
|
|
1438
|
-
this.
|
|
1513
|
+
const linestring = this.code.lines[ i ];
|
|
1514
|
+
const tokens = this._getTokensFromString( linestring, true );
|
|
1515
|
+
tokens.forEach( t => this.code.tokens[ t ] = 1 );
|
|
1439
1516
|
}
|
|
1517
|
+
}
|
|
1440
1518
|
|
|
1441
|
-
|
|
1442
|
-
|
|
1519
|
+
processLines( from ) {
|
|
1520
|
+
|
|
1521
|
+
// const start = performance.now();
|
|
1522
|
+
|
|
1523
|
+
this.gutter.innerHTML = "";
|
|
1524
|
+
this.code.innerHTML = "";
|
|
1525
|
+
|
|
1526
|
+
for( let i = 0; i < this.code.lines.length; ++i )
|
|
1443
1527
|
{
|
|
1444
|
-
|
|
1445
|
-
this.gutter.lastChild.remove();
|
|
1446
|
-
while( this.code.lines.length != this.code.children.length )
|
|
1447
|
-
this.code.lastChild.remove();
|
|
1528
|
+
this.processLine( i, true );
|
|
1448
1529
|
}
|
|
1449
1530
|
|
|
1531
|
+
// console.log( performance.now() - start );
|
|
1450
1532
|
}
|
|
1451
1533
|
|
|
1452
|
-
processLine( linenum ) {
|
|
1534
|
+
processLine( linenum, force ) {
|
|
1453
1535
|
|
|
1454
|
-
delete this.
|
|
1536
|
+
delete this._buildingString; // multi-line strings not supported by now
|
|
1455
1537
|
|
|
1456
1538
|
// It's allowed to process only 1 line to optimize
|
|
1457
1539
|
let linestring = this.code.lines[ linenum ];
|
|
1458
|
-
|
|
1459
|
-
var pre =
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1540
|
+
|
|
1541
|
+
var pre = document.createElement('pre');
|
|
1542
|
+
pre.dataset['linenum'] = linenum;
|
|
1543
|
+
|
|
1544
|
+
// Line gutter
|
|
1545
|
+
var linenumspan = document.createElement('span');
|
|
1546
|
+
linenumspan.innerHTML = (linenum + 1);
|
|
1547
|
+
|
|
1548
|
+
if( force )
|
|
1466
1549
|
{
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
}
|
|
1471
|
-
else
|
|
1550
|
+
this.gutter.appendChild(linenumspan);
|
|
1551
|
+
this.code.appendChild( pre );
|
|
1552
|
+
} else
|
|
1472
1553
|
{
|
|
1473
|
-
|
|
1554
|
+
deleteElement( this.gutter.childNodes[ linenum ] );
|
|
1555
|
+
deleteElement( this.code.childNodes[ linenum ] );
|
|
1556
|
+
this.gutter.insertChildAtIndex( linenumspan, linenum );
|
|
1557
|
+
this.code.insertChildAtIndex( pre, linenum );
|
|
1474
1558
|
}
|
|
1475
1559
|
|
|
1476
1560
|
var linespan = document.createElement('span');
|
|
1477
1561
|
pre.appendChild(linespan);
|
|
1478
1562
|
|
|
1563
|
+
const tokensToEvaluate = this._getTokensFromString( linestring );
|
|
1564
|
+
|
|
1565
|
+
let line_inner_html = "";
|
|
1566
|
+
|
|
1567
|
+
// Process all tokens
|
|
1568
|
+
for( var i = 0; i < tokensToEvaluate.length; ++i )
|
|
1569
|
+
{
|
|
1570
|
+
let it = i - 1;
|
|
1571
|
+
let prev = tokensToEvaluate[it];
|
|
1572
|
+
while( prev == ' ' ) {
|
|
1573
|
+
it--;
|
|
1574
|
+
prev = tokensToEvaluate[it];
|
|
1575
|
+
}
|
|
1576
|
+
|
|
1577
|
+
it = i + 1;
|
|
1578
|
+
let next = tokensToEvaluate[it];
|
|
1579
|
+
while( next == ' ' || next == '"') {
|
|
1580
|
+
it++;
|
|
1581
|
+
next = tokensToEvaluate[it];
|
|
1582
|
+
}
|
|
1583
|
+
|
|
1584
|
+
let token = tokensToEvaluate[i];
|
|
1585
|
+
|
|
1586
|
+
if( this.languages[ this.highlight ].blockComments ?? true )
|
|
1587
|
+
{
|
|
1588
|
+
if( token.substr(0, 2) == '/*' )
|
|
1589
|
+
this._buildingBlockComment = true;
|
|
1590
|
+
if( token.substr(token.length - 2) == '*/' )
|
|
1591
|
+
delete this._buildingBlockComment;
|
|
1592
|
+
}
|
|
1593
|
+
|
|
1594
|
+
line_inner_html += this.evaluateToken(token, prev, next);
|
|
1595
|
+
}
|
|
1596
|
+
|
|
1597
|
+
linespan.innerHTML = line_inner_html;
|
|
1598
|
+
}
|
|
1599
|
+
|
|
1600
|
+
_processTokens( tokens, offset = 0 ) {
|
|
1601
|
+
|
|
1602
|
+
if( this.highlight == 'C++' )
|
|
1603
|
+
{
|
|
1604
|
+
var idx = tokens.slice(offset).findIndex( (value, index) => this.isNumber(value) );
|
|
1605
|
+
if( idx > -1 )
|
|
1606
|
+
{
|
|
1607
|
+
idx += offset; // Add offset to compute within the whole array of tokens
|
|
1608
|
+
let data = tokens[idx] + tokens[++idx];
|
|
1609
|
+
while( this.isNumber( data ) )
|
|
1610
|
+
{
|
|
1611
|
+
tokens[ idx - 1 ] += tokens[ idx ];
|
|
1612
|
+
tokens.splice( idx, 1 );
|
|
1613
|
+
data += tokens[idx];
|
|
1614
|
+
}
|
|
1615
|
+
// Scan for numbers again
|
|
1616
|
+
return this._processTokens( tokens, idx );
|
|
1617
|
+
}
|
|
1618
|
+
}
|
|
1619
|
+
|
|
1620
|
+
return tokens;
|
|
1621
|
+
}
|
|
1622
|
+
|
|
1623
|
+
_getTokensFromString( linestring, skipNonWords ) {
|
|
1624
|
+
|
|
1479
1625
|
// Check if line comment
|
|
1480
|
-
const
|
|
1626
|
+
const singleLineCommentToken = this.languages[ this.highlight ].singleLineCommentToken ?? this.defaultSingleLineCommentToken;
|
|
1627
|
+
const is_comment = linestring.split(singleLineCommentToken);
|
|
1481
1628
|
linestring = ( is_comment.length > 1 ) ? is_comment[0] : linestring;
|
|
1482
1629
|
|
|
1483
1630
|
const tokens = linestring.split(' ').join('¬ ¬').split('¬'); // trick to split without losing spaces
|
|
1484
|
-
|
|
1631
|
+
let tokensToEvaluate = []; // store in a temp array so we know prev and next tokens...
|
|
1485
1632
|
|
|
1486
1633
|
for( let t of tokens )
|
|
1487
1634
|
{
|
|
1488
|
-
|
|
1635
|
+
if( !t.length || (skipNonWords && ( t.includes('"') || t.length < 3 )) )
|
|
1636
|
+
continue;
|
|
1637
|
+
|
|
1638
|
+
if( t == ' ' ) {
|
|
1639
|
+
tokensToEvaluate.push( t );
|
|
1640
|
+
continue;
|
|
1641
|
+
}
|
|
1642
|
+
|
|
1643
|
+
let iter = t.matchAll(/(::|[\[\](){}<>.,;:"'])/g);
|
|
1489
1644
|
let subtokens = iter.next();
|
|
1490
1645
|
if( subtokens.value )
|
|
1491
1646
|
{
|
|
@@ -1493,56 +1648,23 @@ class CodeEditor {
|
|
|
1493
1648
|
while( subtokens.value != undefined )
|
|
1494
1649
|
{
|
|
1495
1650
|
const _pt = t.substring(idx, subtokens.value.index);
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
idx = subtokens.value.index +
|
|
1651
|
+
if( _pt.length ) tokensToEvaluate.push( _pt );
|
|
1652
|
+
tokensToEvaluate.push( subtokens.value[0] );
|
|
1653
|
+
idx = subtokens.value.index + subtokens.value[0].length;
|
|
1499
1654
|
subtokens = iter.next();
|
|
1500
1655
|
if(!subtokens.value) {
|
|
1501
1656
|
const _at = t.substring(idx);
|
|
1502
|
-
|
|
1657
|
+
if( _at.length ) tokensToEvaluate.push( _at );
|
|
1503
1658
|
}
|
|
1504
1659
|
}
|
|
1505
1660
|
}
|
|
1506
|
-
else
|
|
1507
|
-
to_process.push( t );
|
|
1661
|
+
else tokensToEvaluate.push( t );
|
|
1508
1662
|
}
|
|
1509
1663
|
|
|
1510
|
-
if( is_comment.length > 1 )
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
// Process all tokens
|
|
1514
|
-
for( var i = 0; i < to_process.length; ++i )
|
|
1515
|
-
{
|
|
1516
|
-
let it = i - 1;
|
|
1517
|
-
let prev = to_process[it];
|
|
1518
|
-
while( prev == '' || prev == ' ' ) {
|
|
1519
|
-
it--;
|
|
1520
|
-
prev = to_process[it];
|
|
1521
|
-
}
|
|
1664
|
+
if( is_comment.length > 1 && !skipNonWords )
|
|
1665
|
+
tokensToEvaluate.push( singleLineCommentToken + is_comment[1] );
|
|
1522
1666
|
|
|
1523
|
-
|
|
1524
|
-
let next = to_process[it];
|
|
1525
|
-
while( next == '' || next == ' ' || next == '"') {
|
|
1526
|
-
it++;
|
|
1527
|
-
next = to_process[it];
|
|
1528
|
-
}
|
|
1529
|
-
|
|
1530
|
-
let token = to_process[i];
|
|
1531
|
-
if( token.substr(0, 2) == '/*' )
|
|
1532
|
-
this._building_block_comment = true;
|
|
1533
|
-
if( token.substr(token.length - 2) == '*/' )
|
|
1534
|
-
delete this._building_block_comment;
|
|
1535
|
-
|
|
1536
|
-
this.processToken(token, linespan, prev, next);
|
|
1537
|
-
}
|
|
1538
|
-
|
|
1539
|
-
// add line gutter
|
|
1540
|
-
if(!single_update)
|
|
1541
|
-
{
|
|
1542
|
-
var linenumspan = document.createElement('span');
|
|
1543
|
-
linenumspan.innerHTML = (linenum + 1);
|
|
1544
|
-
this.gutter.appendChild(linenumspan);
|
|
1545
|
-
}
|
|
1667
|
+
return this._processTokens( tokensToEvaluate );
|
|
1546
1668
|
}
|
|
1547
1669
|
|
|
1548
1670
|
_mustHightlightWord( token, kindArray ) {
|
|
@@ -1550,88 +1672,97 @@ class CodeEditor {
|
|
|
1550
1672
|
return kindArray[this.highlight] && kindArray[this.highlight].indexOf(token) > -1;
|
|
1551
1673
|
}
|
|
1552
1674
|
|
|
1553
|
-
|
|
1675
|
+
evaluateToken( token, prev, next ) {
|
|
1554
1676
|
|
|
1555
|
-
let
|
|
1556
|
-
let highlight = this.highlight.replace(/\s/g, '').toLowerCase();
|
|
1677
|
+
let stringEnded = false;
|
|
1678
|
+
let highlight = this.highlight.replace(/\s/g, '').replaceAll("+", "p").toLowerCase();
|
|
1679
|
+
let inner_html = "", token_classname = "";
|
|
1680
|
+
|
|
1681
|
+
const singleLineCommentToken = this.languages[ this.highlight ].singleLineCommentToken ?? this.defaultSingleLineCommentToken;
|
|
1682
|
+
const usesBlockComments = this.languages[ this.highlight ].blockComments ?? true;
|
|
1683
|
+
const customStringKeys = Object.assign( {}, this.stringKeys );
|
|
1684
|
+
|
|
1685
|
+
if( highlight == 'cpp' && prev && prev.includes('#') ) // preprocessor code..
|
|
1686
|
+
{
|
|
1687
|
+
customStringKeys['@<'] = '>';
|
|
1688
|
+
}
|
|
1557
1689
|
|
|
1558
|
-
|
|
1690
|
+
// Manage strings
|
|
1691
|
+
if( this._buildingString != undefined )
|
|
1559
1692
|
{
|
|
1560
|
-
|
|
1561
|
-
|
|
1693
|
+
const idx = Object.values(customStringKeys).indexOf( token );
|
|
1694
|
+
stringEnded = (idx > -1) && (idx == Object.values(customStringKeys).indexOf( customStringKeys[ '@' + this._buildingString ] ));
|
|
1695
|
+
}
|
|
1696
|
+
else if( customStringKeys[ '@' + token ] )
|
|
1697
|
+
{
|
|
1698
|
+
// Start new string
|
|
1699
|
+
this._buildingString = token;
|
|
1562
1700
|
}
|
|
1563
1701
|
|
|
1564
1702
|
if(token == ' ')
|
|
1565
1703
|
{
|
|
1566
|
-
|
|
1704
|
+
inner_html += token;
|
|
1567
1705
|
}
|
|
1568
1706
|
else
|
|
1569
1707
|
{
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
if( this._building_block_comment )
|
|
1574
|
-
span.classList.add("cm-com");
|
|
1708
|
+
if( this._buildingBlockComment != undefined )
|
|
1709
|
+
token_classname += "cm-com";
|
|
1575
1710
|
|
|
1576
|
-
else if( this.
|
|
1577
|
-
|
|
1711
|
+
else if( this._buildingString != undefined )
|
|
1712
|
+
token_classname += "cm-str";
|
|
1578
1713
|
|
|
1579
1714
|
else if( this._mustHightlightWord( token, this.keywords ) )
|
|
1580
|
-
|
|
1715
|
+
token_classname += "cm-kwd";
|
|
1581
1716
|
|
|
1582
1717
|
else if( this._mustHightlightWord( token, this.builtin ) )
|
|
1583
|
-
|
|
1718
|
+
token_classname += "cm-bln";
|
|
1584
1719
|
|
|
1585
1720
|
else if( this._mustHightlightWord( token, this.statementsAndDeclarations ) )
|
|
1586
|
-
|
|
1721
|
+
token_classname += "cm-std";
|
|
1587
1722
|
|
|
1588
|
-
|
|
1589
|
-
|
|
1723
|
+
else if( this._mustHightlightWord( token, this.symbols ) )
|
|
1724
|
+
token_classname += "cm-sym";
|
|
1590
1725
|
|
|
1591
|
-
else if( token.substr(0, 2) ==
|
|
1592
|
-
|
|
1726
|
+
else if( token.substr(0, 2) == singleLineCommentToken )
|
|
1727
|
+
token_classname += "cm-com";
|
|
1593
1728
|
|
|
1594
|
-
else if( token.substr(0, 2) == '/*' )
|
|
1595
|
-
|
|
1729
|
+
else if( usesBlockComments && token.substr(0, 2) == '/*' )
|
|
1730
|
+
token_classname += "cm-com";
|
|
1596
1731
|
|
|
1597
|
-
else if( token.substr(token.length - 2) == '*/' )
|
|
1598
|
-
|
|
1732
|
+
else if( usesBlockComments && token.substr(token.length - 2) == '*/' )
|
|
1733
|
+
token_classname += "cm-com";
|
|
1599
1734
|
|
|
1600
1735
|
else if( this.isNumber(token) || this.isNumber( token.replace(/[px]|[em]|%/g,'') ) )
|
|
1601
|
-
|
|
1736
|
+
token_classname += "cm-dec";
|
|
1602
1737
|
|
|
1603
1738
|
else if( this.isCSSClass(token, prev, next) )
|
|
1604
|
-
|
|
1739
|
+
token_classname += "cm-kwd";
|
|
1605
1740
|
|
|
1606
|
-
else if ( this.isType(token, prev, next) )
|
|
1607
|
-
|
|
1608
|
-
this.code.tokens[ token ] = CodeEditor.WORD_TYPE_CLASS;
|
|
1609
|
-
}
|
|
1741
|
+
else if ( this.isType(token, prev, next) )
|
|
1742
|
+
token_classname += "cm-typ";
|
|
1610
1743
|
|
|
1611
|
-
else if ( token[0] != '@' && next == '(' )
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1744
|
+
else if ( token[0] != '@' && next == '(' )
|
|
1745
|
+
token_classname += "cm-mtd";
|
|
1746
|
+
|
|
1747
|
+
else if ( highlight == 'cpp' && token.includes('#') ) // C++ preprocessor
|
|
1748
|
+
token_classname += "cm-ppc";
|
|
1749
|
+
|
|
1750
|
+
else if ( highlight == 'cpp' && prev != 'WDWD:' && next == '::' ) // C++ Class
|
|
1751
|
+
token_classname += "cm-typ";
|
|
1615
1752
|
|
|
1616
1753
|
else if ( highlight == 'css' && prev == ':' && (next == ';' || next == '!important') ) // CSS value
|
|
1617
|
-
|
|
1754
|
+
token_classname += "cm-str";
|
|
1618
1755
|
|
|
1619
1756
|
else if ( highlight == 'css' && prev == undefined && next == ':' ) // CSS attribute
|
|
1620
|
-
|
|
1621
|
-
else {
|
|
1622
|
-
|
|
1623
|
-
if( token.length > 1 )
|
|
1624
|
-
{
|
|
1625
|
-
// Store in token map to show later as autocomplete suggestions
|
|
1626
|
-
this.code.tokens[ token ] = -1;
|
|
1627
|
-
}
|
|
1628
|
-
}
|
|
1757
|
+
token_classname += "cm-typ";
|
|
1629
1758
|
|
|
1630
|
-
|
|
1631
|
-
|
|
1759
|
+
token_classname += " " + highlight;
|
|
1760
|
+
inner_html += "<span class=' " + token_classname + "'>" + token + "</span>";
|
|
1632
1761
|
}
|
|
1633
1762
|
|
|
1634
|
-
if(
|
|
1763
|
+
if(stringEnded) delete this._buildingString;
|
|
1764
|
+
|
|
1765
|
+
return inner_html;
|
|
1635
1766
|
}
|
|
1636
1767
|
|
|
1637
1768
|
isCSSClass( token, prev, next ) {
|
|
@@ -1639,7 +1770,16 @@ class CodeEditor {
|
|
|
1639
1770
|
}
|
|
1640
1771
|
|
|
1641
1772
|
isNumber( token ) {
|
|
1642
|
-
|
|
1773
|
+
|
|
1774
|
+
if(this.highlight == 'C++')
|
|
1775
|
+
{
|
|
1776
|
+
if( token.lastChar == 'f' )
|
|
1777
|
+
return this.isNumber( token.substring(0, token.length - 1) )
|
|
1778
|
+
else if( token.lastChar == 'u' )
|
|
1779
|
+
return !(token.includes('.')) && this.isNumber( token.substring(0, token.length - 1) );
|
|
1780
|
+
}
|
|
1781
|
+
|
|
1782
|
+
return token.length && token != ' ' && !Number.isNaN(+token);
|
|
1643
1783
|
}
|
|
1644
1784
|
|
|
1645
1785
|
isType( token, prev, next ) {
|
|
@@ -1652,6 +1792,10 @@ class CodeEditor {
|
|
|
1652
1792
|
{
|
|
1653
1793
|
return (prev == 'class' && next == '{') || (prev == 'new' && next == '(');
|
|
1654
1794
|
}
|
|
1795
|
+
else if( this.highlight == 'C++' )
|
|
1796
|
+
{
|
|
1797
|
+
return (prev == 'class' && next == '{') || (prev == 'struct' && next == '{');
|
|
1798
|
+
}
|
|
1655
1799
|
else if ( this.highlight == 'WGSL' )
|
|
1656
1800
|
{
|
|
1657
1801
|
const is_kwd = (this.keywords[this.highlight] && this.keywords[this.highlight].indexOf(token) == -1);
|
|
@@ -1667,7 +1811,7 @@ class CodeEditor {
|
|
|
1667
1811
|
if( !this.selection || (this.selection.fromY != this.selection.toY) )
|
|
1668
1812
|
return false;
|
|
1669
1813
|
|
|
1670
|
-
|
|
1814
|
+
this.selection.invertIfNecessary();
|
|
1671
1815
|
|
|
1672
1816
|
// Insert first..
|
|
1673
1817
|
this.code.lines[lidx] = [
|
|
@@ -1752,8 +1896,10 @@ class CodeEditor {
|
|
|
1752
1896
|
|
|
1753
1897
|
deleteSelection( cursor ) {
|
|
1754
1898
|
|
|
1755
|
-
|
|
1899
|
+
// I think it's not necessary but...
|
|
1900
|
+
if(this.disableEdition)
|
|
1756
1901
|
return;
|
|
1902
|
+
|
|
1757
1903
|
// Some selections don't depend on mouse up..
|
|
1758
1904
|
if(this.selection) this.selection.invertIfNecessary();
|
|
1759
1905
|
|
|
@@ -1796,7 +1942,7 @@ class CodeEditor {
|
|
|
1796
1942
|
cursor.style.left = "calc(" + (cursor._left - this.getScrollLeft()) + "px + " + this.xPadding + ")";
|
|
1797
1943
|
cursor.position++;
|
|
1798
1944
|
this.restartBlink();
|
|
1799
|
-
this._refreshCodeInfo( cursor.line
|
|
1945
|
+
this._refreshCodeInfo( cursor.line, cursor.position );
|
|
1800
1946
|
|
|
1801
1947
|
// Add horizontal scroll
|
|
1802
1948
|
|
|
@@ -1817,7 +1963,7 @@ class CodeEditor {
|
|
|
1817
1963
|
cursor.position--;
|
|
1818
1964
|
cursor.position = Math.max(cursor.position, 0);
|
|
1819
1965
|
this.restartBlink();
|
|
1820
|
-
this._refreshCodeInfo( cursor.line
|
|
1966
|
+
this._refreshCodeInfo( cursor.line, cursor.position );
|
|
1821
1967
|
|
|
1822
1968
|
doAsync(() => {
|
|
1823
1969
|
var first_char = (this.code.scrollLeft / this.charWidth)|0;
|
|
@@ -1837,7 +1983,7 @@ class CodeEditor {
|
|
|
1837
1983
|
if(resetLeft)
|
|
1838
1984
|
this.resetCursorPos( CodeEditor.CURSOR_LEFT, cursor );
|
|
1839
1985
|
|
|
1840
|
-
this._refreshCodeInfo( cursor.line
|
|
1986
|
+
this._refreshCodeInfo( cursor.line, cursor.position );
|
|
1841
1987
|
|
|
1842
1988
|
doAsync(() => {
|
|
1843
1989
|
var first_line = (this.code.scrollTop / this.lineHeight)|0;
|
|
@@ -1856,7 +2002,7 @@ class CodeEditor {
|
|
|
1856
2002
|
if(resetLeft)
|
|
1857
2003
|
this.resetCursorPos( CodeEditor.CURSOR_LEFT, cursor );
|
|
1858
2004
|
|
|
1859
|
-
this._refreshCodeInfo( cursor.line
|
|
2005
|
+
this._refreshCodeInfo( cursor.line, cursor.position );
|
|
1860
2006
|
|
|
1861
2007
|
doAsync(() => {
|
|
1862
2008
|
var last_line = ((this.code.scrollTop + this.code.offsetHeight) / this.lineHeight)|0;
|
|
@@ -1970,7 +2116,7 @@ class CodeEditor {
|
|
|
1970
2116
|
const words = this.code.lines[col];
|
|
1971
2117
|
|
|
1972
2118
|
const is_char = (char) => {
|
|
1973
|
-
const exceptions = ['_'];
|
|
2119
|
+
const exceptions = ['_', '#', '!'];
|
|
1974
2120
|
const code = char.charCodeAt(0);
|
|
1975
2121
|
return (exceptions.indexOf(char) > - 1) || (code > 47 && code < 58) || (code > 64 && code < 91) || (code > 96 && code < 123);
|
|
1976
2122
|
}
|
|
@@ -1998,7 +2144,7 @@ class CodeEditor {
|
|
|
1998
2144
|
test.innerHTML = char;
|
|
1999
2145
|
document.body.appendChild(test);
|
|
2000
2146
|
var rect = test.getBoundingClientRect();
|
|
2001
|
-
test
|
|
2147
|
+
deleteElement( test );
|
|
2002
2148
|
const bb = [Math.floor(rect.width), Math.floor(rect.height)];
|
|
2003
2149
|
return get_bb ? bb : bb[0];
|
|
2004
2150
|
}
|
|
@@ -2073,10 +2219,10 @@ class CodeEditor {
|
|
|
2073
2219
|
);
|
|
2074
2220
|
|
|
2075
2221
|
// Add words in current tab plus remove current word
|
|
2076
|
-
|
|
2222
|
+
suggestions = suggestions.concat( Object.keys(this.code.tokens).filter( a => a != word ) );
|
|
2077
2223
|
|
|
2078
|
-
// Remove
|
|
2079
|
-
suggestions = suggestions.filter( (value, index) => value.length >
|
|
2224
|
+
// Remove 1/2 char words and duplicates...
|
|
2225
|
+
suggestions = suggestions.filter( (value, index) => value.length > 2 && suggestions.indexOf(value) === index );
|
|
2080
2226
|
|
|
2081
2227
|
// Order...
|
|
2082
2228
|
suggestions = suggestions.sort( (a, b) => a.localeCompare(b) );
|