lexgui 0.1.13 → 0.1.14

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.
@@ -106,9 +106,6 @@ class CodeEditor {
106
106
 
107
107
  CodeEditor.__instances.push( this );
108
108
 
109
- this.disable_edition = options.disable_edition ?? false;
110
-
111
- this.skip_info = options.skip_info;
112
109
  this.base_area = area;
113
110
  this.area = new LX.Area( { className: "lexcodeeditor", height: "auto", no_append: true } );
114
111
 
@@ -129,14 +126,21 @@ class CodeEditor {
129
126
  this.root.tabIndex = -1;
130
127
  area.attach( this.root );
131
128
 
132
- this.root.addEventListener( 'keydown', this.processKey.bind(this), true);
129
+ this.skipCodeInfo = options.skip_info ?? false;
130
+ this.disableEdition = options.disable_edition ?? false;
131
+
132
+ if( !this.disableEdition )
133
+ {
134
+ this.root.addEventListener( 'keydown', this.processKey.bind(this), true);
135
+ this.root.addEventListener( 'focus', this.processFocus.bind(this, true) );
136
+ this.root.addEventListener( 'focusout', this.processFocus.bind(this, false) );
137
+ }
138
+
133
139
  this.root.addEventListener( 'mousedown', this.processMouse.bind(this) );
134
140
  this.root.addEventListener( 'mouseup', this.processMouse.bind(this) );
135
141
  this.root.addEventListener( 'mousemove', this.processMouse.bind(this) );
136
142
  this.root.addEventListener( 'click', this.processMouse.bind(this) );
137
143
  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
144
 
141
145
  // Cursors and selection
142
146
 
@@ -198,8 +202,19 @@ class CodeEditor {
198
202
  this.charWidth = 8; //this.measureChar();
199
203
  this._lastTime = null;
200
204
 
205
+ this.pairKeys = {
206
+ "\"": "\"",
207
+ "'": "'",
208
+ "(": ")",
209
+ "{": "}",
210
+ "[": "]"
211
+ };
212
+
213
+ // Scan tokens..
214
+ setInterval( this.scanWordSuggestions.bind(this), 2000 );
215
+
201
216
  this.languages = [
202
- 'Plain Text', 'JavaScript', 'CSS', 'GLSL', 'WGSL', 'JSON', 'XML'
217
+ 'Plain Text', 'JavaScript', 'C++', 'CSS', 'GLSL', 'WGSL', 'JSON', 'XML', 'Python'
203
218
  ];
204
219
  this.specialKeys = [
205
220
  'Backspace', 'Enter', 'ArrowUp', 'ArrowDown',
@@ -207,38 +222,54 @@ class CodeEditor {
207
222
  'End', 'Tab', 'Escape'
208
223
  ];
209
224
  this.keywords = {
210
- 'JavaScript': ['var', 'let', 'const', 'this', 'in', 'of', 'true', 'false', 'new', 'function', 'NaN', 'static', 'class', 'constructor', 'null', 'typeof', 'debugger'],
225
+ 'JavaScript': ['var', 'let', 'const', 'this', 'in', 'of', 'true', 'false', 'new', 'function', 'NaN', 'static', 'class', 'constructor', 'null', 'typeof', 'debugger', 'abstract',
226
+ 'arguments', 'extends', 'instanceof'],
227
+ 'C++': ['int', 'float', 'bool', 'const', 'static_cast', 'dynamic_cast', 'new', 'delete', 'void', 'true', 'false', 'auto', 'struct', 'typedef'],
211
228
  'GLSL': ['true', 'false', 'function', 'int', 'float', 'vec2', 'vec3', 'vec4', 'mat2x2', 'mat3x3', 'mat4x4', 'struct'],
212
229
  'CSS': ['body', 'html', 'canvas', 'div', 'input', 'span', '.'],
213
230
  'WGSL': ['var', 'let', 'true', 'false', 'fn', 'bool', 'u32', 'i32', 'f16', 'f32', 'vec2f', 'vec3f', 'vec4f', 'mat2x2f', 'mat3x3f', 'mat4x4f', 'array', 'atomic', 'struct',
214
231
  'sampler', 'sampler_comparison', 'texture_depth_2d', 'texture_depth_2d_array', 'texture_depth_cube', 'texture_depth_cube_array', 'texture_depth_multisampled_2d',
215
232
  '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']
233
+ 'texture_storage_2d_array', 'texture_storage_3d'],
234
+ 'Python': ['False', 'def', 'None', 'True', 'in', 'is', 'and', 'lambda', 'nonlocal', 'not', 'or']
217
235
  };
218
236
  this.utils = { // These ones don't have hightlight, used as suggestions to autocomplete only...
219
237
  '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
- 'WGSL': ['textureSample']
238
+ 'bind', 'prototype', 'length', 'assign', 'entries', 'values', 'concat', 'substring', 'substr', 'splice', 'slice', 'buffer', 'appendChild', 'createElement', 'prompt',
239
+ 'alert'],
240
+ 'WGSL': ['textureSample'],
241
+ 'Python': ['abs', 'all', 'any', 'ascii', 'bin', 'bool', 'bytearray', 'bytes', 'callable', 'chr', 'classmethod', 'compile', 'complex', 'delattr', 'dict', 'dir', 'divmod',
242
+ 'enumerate', 'eval', 'exec', 'filter', 'float', 'format', 'frozenset', 'getattr', 'globals', 'hasattr', 'hash', 'help', 'hex', 'id', 'input', 'int', 'isinstance',
243
+ 'issubclass', 'iter', 'len', 'list', 'locals', 'map', 'max', 'memoryview', 'min', 'next', 'object', 'oct', 'open', 'ord', 'pow', 'print', 'property', 'range', 'repr',
244
+ 'reversed', 'round', 'set', 'setattr', 'slice', 'sorted', 'staticmethod', 'str', 'sum', 'super', 'tuple', 'type', 'vars', 'zip']
222
245
  };
223
246
  this.types = {
224
- 'JavaScript': ['Object', 'String', 'Function', 'Boolean', 'Symbol', 'Error', 'Number']
247
+ 'JavaScript': ['Object', 'String', 'Function', 'Boolean', 'Symbol', 'Error', 'Number', 'TextEncoder', 'TextDecoder'],
248
+ 'Python': ['int', 'type', 'float', 'map', 'list', 'ArithmeticError', 'AssertionError', 'AttributeError', 'Exception', 'EOFError', 'FloatingPointError', 'GeneratorExit',
249
+ 'ImportError', 'IndentationError', 'IndexError', 'KeyError', 'KeyboardInterrupt', 'LookupError', 'MemoryError', 'NameError', 'NotImplementedError', 'OSError',
250
+ 'OverflowError', 'ReferenceError', 'RuntimeError', 'StopIteration', 'SyntaxError', 'TabError', 'SystemError', 'SystemExit', 'TypeError', 'UnboundLocalError',
251
+ 'UnicodeError', 'UnicodeEncodeError', 'UnicodeDecodeError', 'UnicodeTranslateError', 'ValueError', 'ZeroDivisionError' ]
225
252
  };
226
253
  this.builtin = {
227
- 'JavaScript': ['document', 'console', 'window', 'navigator'],
228
- 'CSS': ['*', '!important']
254
+ 'JavaScript': ['document', 'console', 'window', 'navigator', 'performance'],
255
+ 'CSS': ['*', '!important'],
256
+ 'C++': ['vector', 'list', 'map']
229
257
  };
230
258
  this.statementsAndDeclarations = {
231
- 'JavaScript': ['for', 'if', 'else', 'case', 'switch', 'return', 'while', 'continue', 'break', 'do', 'import',
232
- 'from', 'throw', 'async', 'try', 'catch'],
259
+ 'JavaScript': ['for', 'if', 'else', 'case', 'switch', 'return', 'while', 'continue', 'break', 'do', 'import', 'from', 'throw', 'async', 'try', 'catch', 'await'],
260
+ 'C++': ['std', 'for', 'if', 'else', 'return', 'continue', 'break', 'case', 'switch', 'while', 'glm'],
233
261
  'GLSL': ['for', 'if', 'else', 'return', 'continue', 'break'],
234
- 'WGSL': ['const','for', 'if', 'else', 'return', 'continue', 'break', 'storage', 'read', 'uniform']
262
+ 'WGSL': ['const','for', 'if', 'else', 'return', 'continue', 'break', 'storage', 'read', 'uniform'],
263
+ 'Python': ['if', 'raise', 'del', 'import', 'return', 'elif', 'try', 'else', 'while', 'as', 'except', 'with', 'assert', 'finally', 'yield', 'break', 'for', 'class', 'continue', 'global', 'pass']
235
264
  };
236
265
  this.symbols = {
237
266
  'JavaScript': ['<', '>', '[', ']', '{', '}', '(', ')', ';', '=', '|', '||', '&', '&&', '?', '??'],
267
+ 'C++': ['<', '>', '[', ']', '{', '}', '(', ')', ';', '=', '|', '||', '&', '&&', '?', '::'],
238
268
  'JSON': ['[', ']', '{', '}', '(', ')'],
239
269
  'GLSL': ['[', ']', '{', '}', '(', ')'],
240
270
  'WGSL': ['[', ']', '{', '}', '(', ')', '->'],
241
- 'CSS': ['{', '}', '(', ')', '*']
271
+ 'CSS': ['{', '}', '(', ')', '*'],
272
+ 'Python': ['<', '>', '[', ']', '(', ')', '=']
242
273
  };
243
274
 
244
275
  // Action keys
@@ -323,7 +354,7 @@ class CodeEditor {
323
354
 
324
355
  this.resetCursorPos( CodeEditor.CURSOR_LEFT );
325
356
  if(idx > 0) this.cursorToString(cursor, prestring);
326
- this._refreshCodeInfo(cursor.line + 1, cursor.position);
357
+ this._refreshCodeInfo(cursor.line, cursor.position);
327
358
  this.code.scrollLeft = 0;
328
359
 
329
360
  if( e.shiftKey && !e.cancelShift )
@@ -752,11 +783,14 @@ class CodeEditor {
752
783
  switch(ext.toLowerCase())
753
784
  {
754
785
  case 'js': return this._changeLanguage('JavaScript');
786
+ case 'cpp': return this._changeLanguage('C++');
787
+ case 'h': return this._changeLanguage('C++');
755
788
  case 'glsl': return this._changeLanguage('GLSL');
756
789
  case 'css': return this._changeLanguage('CSS');
757
790
  case 'json': return this._changeLanguage('JSON');
758
791
  case 'xml': return this._changeLanguage('XML');
759
792
  case 'wgsl': return this._changeLanguage('WGSL');
793
+ case 'py': return this._changeLanguage('Python');
760
794
  case 'txt':
761
795
  default:
762
796
  this._changeLanguage('Plain Text');
@@ -765,20 +799,20 @@ class CodeEditor {
765
799
 
766
800
  _createPanelInfo() {
767
801
 
768
- if( !this.skip_info )
802
+ if( !this.skipCodeInfo )
769
803
  {
770
804
  let panel = new LX.Panel({ className: "lexcodetabinfo", width: "calc(100%)", height: "auto" });
771
805
  panel.ln = 0;
772
806
  panel.col = 0;
773
807
 
774
808
  this._refreshCodeInfo = (ln = panel.ln, col = panel.col) => {
775
- panel.ln = ln;
776
- panel.col = col;
809
+ panel.ln = ln + 1;
810
+ panel.col = col + 1;
777
811
  panel.clear();
778
812
  panel.sameLine();
779
813
  panel.addLabel(this.code.title, { float: 'right' });
780
- panel.addLabel("Ln " + ln, { width: "64px" });
781
- panel.addLabel("Col " + col, { width: "64px" });
814
+ panel.addLabel("Ln " + panel.ln, { width: "64px" });
815
+ panel.addLabel("Col " + panel.col, { width: "64px" });
782
816
  panel.addButton("<b>{ }</b>", this.highlight, (value, event) => {
783
817
  LX.addContextMenu( "Language", event, m => {
784
818
  for( const lang of this.languages )
@@ -882,7 +916,7 @@ class CodeEditor {
882
916
  this.restoreCursor(cursor, this.code.cursorState);
883
917
  this.endSelection();
884
918
  this._changeLanguageFromExtension( LX.getExtension(tabname) );
885
- this._refreshCodeInfo(cursor.line + 1, cursor.position);
919
+ this._refreshCodeInfo(cursor.line, cursor.position);
886
920
 
887
921
  // Restore scroll
888
922
  this.gutter.scrollTop = this.code.scrollTop;
@@ -1012,15 +1046,18 @@ class CodeEditor {
1012
1046
  return;
1013
1047
 
1014
1048
  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
1049
  m.add( "Copy", () => { this._copyContent(); } );
1023
- m.add( "Paste", () => { this._pasteContent(); } );
1050
+ if( !this.disableEdition )
1051
+ {
1052
+ m.add( "Cut", () => { this._cutContent(); } );
1053
+ m.add( "Paste", () => { this._pasteContent(); } );
1054
+ m.add( "" );
1055
+ m.add( "Format/JSON", () => {
1056
+ let json = this.toJSONFormat(this.getText());
1057
+ this.code.lines = json.split("\n");
1058
+ this.processLines();
1059
+ } );
1060
+ }
1024
1061
  });
1025
1062
 
1026
1063
  this.canOpenContextMenu = false;
@@ -1048,7 +1085,7 @@ class CodeEditor {
1048
1085
  this.hideAutoCompleteBox();
1049
1086
 
1050
1087
  if(!skip_refresh)
1051
- this._refreshCodeInfo( ln + 1, cursor.position );
1088
+ this._refreshCodeInfo( ln, cursor.position );
1052
1089
  }
1053
1090
 
1054
1091
  processSelection( e, keep_range ) {
@@ -1303,36 +1340,33 @@ class CodeEditor {
1303
1340
  lidx = cursor.line; // Update this, since it's from the old code
1304
1341
  }
1305
1342
 
1306
- // Append key
1343
+ // Append key
1307
1344
 
1308
- this.code.lines[lidx] = [
1309
- this.code.lines[lidx].slice(0, cursor.position),
1310
- key,
1311
- this.code.lines[lidx].slice(cursor.position)
1312
- ].join('');
1345
+ const isPairKey = (Object.values( this.pairKeys ).indexOf( key ) > -1) && !this.wasKeyPaired;
1346
+ const sameKeyNext = isPairKey && (this.code.lines[lidx][cursor.position] === key);
1347
+
1348
+ if( !sameKeyNext )
1349
+ {
1350
+ this.code.lines[lidx] = [
1351
+ this.code.lines[lidx].slice(0, cursor.position),
1352
+ key,
1353
+ this.code.lines[lidx].slice(cursor.position)
1354
+ ].join('');
1355
+ }
1313
1356
 
1314
1357
  this.cursorToRight( key );
1315
1358
 
1316
1359
  // Some custom cases for auto key pair (), {}, "", '', ...
1317
-
1318
- const pairKeys = ["\"", "'", "(", "{"];
1319
- if( pairKeys.indexOf( key ) > -1 && !this.wasKeyPaired )
1360
+
1361
+ const keyMustPair = (this.pairKeys[ key ] !== undefined);
1362
+ if( keyMustPair && !this.wasKeyPaired )
1320
1363
  {
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
1364
  // Make sure to detect later that the key is paired automatically to avoid loops...
1333
1365
  this.wasKeyPaired = true;
1334
1366
 
1335
- this.root.dispatchEvent(new KeyboardEvent('keydown', { 'key': pair }));
1367
+ if(sameKeyNext) return;
1368
+
1369
+ this.root.dispatchEvent(new KeyboardEvent('keydown', { 'key': this.pairKeys[ key ] }));
1336
1370
  this.cursorToLeft( key, cursor );
1337
1371
  return;
1338
1372
  }
@@ -1424,58 +1458,103 @@ class CodeEditor {
1424
1458
  };
1425
1459
  }
1426
1460
 
1427
- processLines( from ) {
1461
+ scanWordSuggestions() {
1428
1462
 
1429
- if( !from )
1430
- {
1431
- this.gutter.innerHTML = "";
1432
- this.code.innerHTML = "";
1433
- this.code.tokens = {};
1434
- }
1463
+ this.code.tokens = {};
1435
1464
 
1436
- for( let i = from ?? 0; i < this.code.lines.length; ++i )
1465
+ for( let i = 0; i < this.code.lines.length; ++i )
1437
1466
  {
1438
- this.processLine( i );
1467
+ const linestring = this.code.lines[ i ];
1468
+ const tokens = this._getTokensFromString( linestring, true );
1469
+ tokens.forEach( t => this.code.tokens[ t ] = 1 );
1439
1470
  }
1471
+ }
1472
+
1473
+ processLines( from ) {
1440
1474
 
1441
- // Clean up...
1442
- if( from )
1475
+ // const start = performance.now();
1476
+
1477
+ this.gutter.innerHTML = "";
1478
+ this.code.innerHTML = "";
1479
+
1480
+ for( let i = 0; i < this.code.lines.length; ++i )
1443
1481
  {
1444
- while( this.code.lines.length != this.gutter.children.length )
1445
- this.gutter.lastChild.remove();
1446
- while( this.code.lines.length != this.code.children.length )
1447
- this.code.lastChild.remove();
1482
+ this.processLine( i, true );
1448
1483
  }
1449
1484
 
1485
+ // console.log( performance.now() - start );
1450
1486
  }
1451
1487
 
1452
- processLine( linenum ) {
1488
+ processLine( linenum, force ) {
1489
+
1490
+ // if(!force)
1491
+ // {
1492
+ // this.processLines();
1493
+ // return;
1494
+ // }
1453
1495
 
1454
1496
  delete this._building_string; // multi-line strings not supported by now
1455
1497
 
1456
1498
  // It's allowed to process only 1 line to optimize
1457
1499
  let linestring = this.code.lines[ linenum ];
1458
- var _lines = this.code.querySelectorAll('pre');
1459
- var pre = null, single_update = false;
1460
- if( _lines[linenum] ) {
1461
- pre = _lines[linenum];
1462
- single_update = true;
1463
- }
1464
-
1465
- if(!pre)
1500
+
1501
+ var pre = document.createElement('pre');
1502
+ pre.dataset['linenum'] = linenum;
1503
+
1504
+ // Line gutter
1505
+ var linenumspan = document.createElement('span');
1506
+ linenumspan.innerHTML = (linenum + 1);
1507
+
1508
+ if( force )
1466
1509
  {
1467
- var pre = document.createElement('pre');
1468
- pre.dataset['linenum'] = linenum;
1469
- this.code.appendChild(pre);
1470
- }
1471
- else
1510
+ this.gutter.appendChild(linenumspan);
1511
+ this.code.appendChild( pre );
1512
+ } else
1472
1513
  {
1473
- pre.children[0].remove(); // Remove token list
1514
+ this.gutter.childNodes[ linenum ].remove();
1515
+ this.code.childNodes[ linenum ].remove();
1516
+ this.gutter.insertChildAtIndex( linenumspan, linenum );
1517
+ this.code.insertChildAtIndex( pre, linenum );
1474
1518
  }
1475
1519
 
1476
1520
  var linespan = document.createElement('span');
1477
1521
  pre.appendChild(linespan);
1478
1522
 
1523
+ const to_process = this._getTokensFromString( linestring );
1524
+
1525
+ let line_inner_html = "";
1526
+
1527
+ // Process all tokens
1528
+ for( var i = 0; i < to_process.length; ++i )
1529
+ {
1530
+ let it = i - 1;
1531
+ let prev = to_process[it];
1532
+ while( prev == ' ' ) {
1533
+ it--;
1534
+ prev = to_process[it];
1535
+ }
1536
+
1537
+ it = i + 1;
1538
+ let next = to_process[it];
1539
+ while( next == ' ' || next == '"') {
1540
+ it++;
1541
+ next = to_process[it];
1542
+ }
1543
+
1544
+ let token = to_process[i];
1545
+ if( token.substr(0, 2) == '/*' )
1546
+ this._building_block_comment = true;
1547
+ if( token.substr(token.length - 2) == '*/' )
1548
+ delete this._building_block_comment;
1549
+
1550
+ line_inner_html += this.processToken(token, prev, next);
1551
+ }
1552
+
1553
+ linespan.innerHTML = line_inner_html;
1554
+ }
1555
+
1556
+ _getTokensFromString( linestring, skipNonWords ) {
1557
+
1479
1558
  // Check if line comment
1480
1559
  const is_comment = linestring.split('//');
1481
1560
  linestring = ( is_comment.length > 1 ) ? is_comment[0] : linestring;
@@ -1485,7 +1564,15 @@ class CodeEditor {
1485
1564
 
1486
1565
  for( let t of tokens )
1487
1566
  {
1488
- let iter = t.matchAll(/[\[\](){}<>.,;:"']/g);
1567
+ if( !t.length || (skipNonWords && ( t.includes('"') || t.length < 3 )) )
1568
+ continue;
1569
+
1570
+ if( t == ' ' ) {
1571
+ to_process.push( t );
1572
+ continue;
1573
+ }
1574
+
1575
+ let iter = t.matchAll(/(::|[\[\](){}<>.,;:"'])/g);
1489
1576
  let subtokens = iter.next();
1490
1577
  if( subtokens.value )
1491
1578
  {
@@ -1493,56 +1580,23 @@ class CodeEditor {
1493
1580
  while( subtokens.value != undefined )
1494
1581
  {
1495
1582
  const _pt = t.substring(idx, subtokens.value.index);
1496
- to_process.push( _pt );
1583
+ if( _pt.length ) to_process.push( _pt );
1497
1584
  to_process.push( subtokens.value[0] );
1498
- idx = subtokens.value.index + 1;
1585
+ idx = subtokens.value.index + subtokens.value[0].length;
1499
1586
  subtokens = iter.next();
1500
1587
  if(!subtokens.value) {
1501
1588
  const _at = t.substring(idx);
1502
- to_process.push( _at );
1589
+ if( _at.length ) to_process.push( _at );
1503
1590
  }
1504
1591
  }
1505
1592
  }
1506
- else
1507
- to_process.push( t );
1593
+ else to_process.push( t );
1508
1594
  }
1509
1595
 
1510
- if( is_comment.length > 1 )
1596
+ if( is_comment.length > 1 && !skipNonWords )
1511
1597
  to_process.push( "//" + is_comment[1] );
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
- }
1522
-
1523
- it = i + 1;
1524
- let next = to_process[it];
1525
- while( next == '' || next == ' ' || next == '"') {
1526
- it++;
1527
- next = to_process[it];
1528
- }
1529
1598
 
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
- }
1599
+ return to_process;
1546
1600
  }
1547
1601
 
1548
1602
  _mustHightlightWord( token, kindArray ) {
@@ -1550,10 +1604,11 @@ class CodeEditor {
1550
1604
  return kindArray[this.highlight] && kindArray[this.highlight].indexOf(token) > -1;
1551
1605
  }
1552
1606
 
1553
- processToken(token, linespan, prev, next) {
1607
+ processToken(token, prev, next) {
1554
1608
 
1555
1609
  let sString = false;
1556
- let highlight = this.highlight.replace(/\s/g, '').toLowerCase();
1610
+ let highlight = this.highlight.replace(/\s/g, '').replaceAll("+", "p").toLowerCase();
1611
+ let inner_html = "", token_classname = "";
1557
1612
 
1558
1613
  if(token == '"' || token == "'")
1559
1614
  {
@@ -1563,75 +1618,68 @@ class CodeEditor {
1563
1618
 
1564
1619
  if(token == ' ')
1565
1620
  {
1566
- linespan.innerHTML += token;
1621
+ inner_html += token;
1567
1622
  }
1568
1623
  else
1569
1624
  {
1570
- var span = document.createElement('span');
1571
- span.innerHTML = token;
1572
-
1573
1625
  if( this._building_block_comment )
1574
- span.classList.add("cm-com");
1626
+ token_classname += "cm-com";
1575
1627
 
1576
1628
  else if( this._building_string )
1577
- span.classList.add("cm-str");
1629
+ token_classname += "cm-str";
1578
1630
 
1579
1631
  else if( this._mustHightlightWord( token, this.keywords ) )
1580
- span.classList.add("cm-kwd");
1632
+ token_classname += "cm-kwd";
1581
1633
 
1582
1634
  else if( this._mustHightlightWord( token, this.builtin ) )
1583
- span.classList.add("cm-bln");
1635
+ token_classname += "cm-bln";
1584
1636
 
1585
1637
  else if( this._mustHightlightWord( token, this.statementsAndDeclarations ) )
1586
- span.classList.add("cm-std");
1638
+ token_classname += "cm-std";
1587
1639
 
1588
- else if( this._mustHightlightWord( token, this.symbols ) )
1589
- span.classList.add("cm-sym");
1640
+ else if( this._mustHightlightWord( token, this.symbols ) )
1641
+ token_classname += "cm-sym";
1590
1642
 
1591
1643
  else if( token.substr(0, 2) == '//' )
1592
- span.classList.add("cm-com");
1644
+ token_classname += "cm-com";
1593
1645
 
1594
1646
  else if( token.substr(0, 2) == '/*' )
1595
- span.classList.add("cm-com");
1647
+ token_classname += "cm-com";
1596
1648
 
1597
1649
  else if( token.substr(token.length - 2) == '*/' )
1598
- span.classList.add("cm-com");
1650
+ token_classname += "cm-com";
1599
1651
 
1600
1652
  else if( this.isNumber(token) || this.isNumber( token.replace(/[px]|[em]|%/g,'') ) )
1601
- span.classList.add("cm-dec");
1653
+ token_classname += "cm-dec";
1602
1654
 
1603
1655
  else if( this.isCSSClass(token, prev, next) )
1604
- span.classList.add("cm-kwd");
1656
+ token_classname += "cm-kwd";
1605
1657
 
1606
- else if ( this.isType(token, prev, next) ) {
1607
- span.classList.add("cm-typ");
1608
- this.code.tokens[ token ] = CodeEditor.WORD_TYPE_CLASS;
1609
- }
1658
+ else if ( this.isType(token, prev, next) )
1659
+ token_classname += "cm-typ";
1610
1660
 
1611
- else if ( token[0] != '@' && next == '(' ) {
1612
- span.classList.add("cm-mtd");
1613
- this.code.tokens[ token ] = CodeEditor.WORD_TYPE_METHOD;
1614
- }
1661
+ else if ( token[0] != '@' && next == '(' )
1662
+ token_classname += "cm-mtd";
1663
+
1664
+ else if ( highlight == 'cpp' && token.includes('#') ) // C++ preprocessor
1665
+ token_classname += "cm-ppc";
1666
+
1667
+ else if ( highlight == 'cpp' && prev != 'WDWD:' && next == '::' ) // C++ Class
1668
+ token_classname += "cm-typ";
1615
1669
 
1616
1670
  else if ( highlight == 'css' && prev == ':' && (next == ';' || next == '!important') ) // CSS value
1617
- span.classList.add("cm-str");
1671
+ token_classname += "cm-str";
1618
1672
 
1619
1673
  else if ( highlight == 'css' && prev == undefined && next == ':' ) // CSS attribute
1620
- span.classList.add("cm-typ");
1621
- else {
1674
+ token_classname += "cm-typ";
1622
1675
 
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
- }
1629
-
1630
- span.classList.add(highlight);
1631
- linespan.appendChild(span);
1676
+ token_classname += " " + highlight;
1677
+ inner_html += "<span class=' " + token_classname + "'>" + token + "</span>";
1632
1678
  }
1633
1679
 
1634
1680
  if(sString) delete this._building_string;
1681
+
1682
+ return inner_html;
1635
1683
  }
1636
1684
 
1637
1685
  isCSSClass( token, prev, next ) {
@@ -1752,8 +1800,10 @@ class CodeEditor {
1752
1800
 
1753
1801
  deleteSelection( cursor ) {
1754
1802
 
1755
- if(this.disable_edition)
1803
+ // I think it's not necessary but...
1804
+ if(this.disableEdition)
1756
1805
  return;
1806
+
1757
1807
  // Some selections don't depend on mouse up..
1758
1808
  if(this.selection) this.selection.invertIfNecessary();
1759
1809
 
@@ -1796,7 +1846,7 @@ class CodeEditor {
1796
1846
  cursor.style.left = "calc(" + (cursor._left - this.getScrollLeft()) + "px + " + this.xPadding + ")";
1797
1847
  cursor.position++;
1798
1848
  this.restartBlink();
1799
- this._refreshCodeInfo( cursor.line + 1, cursor.position );
1849
+ this._refreshCodeInfo( cursor.line, cursor.position );
1800
1850
 
1801
1851
  // Add horizontal scroll
1802
1852
 
@@ -1817,7 +1867,7 @@ class CodeEditor {
1817
1867
  cursor.position--;
1818
1868
  cursor.position = Math.max(cursor.position, 0);
1819
1869
  this.restartBlink();
1820
- this._refreshCodeInfo( cursor.line + 1, cursor.position );
1870
+ this._refreshCodeInfo( cursor.line, cursor.position );
1821
1871
 
1822
1872
  doAsync(() => {
1823
1873
  var first_char = (this.code.scrollLeft / this.charWidth)|0;
@@ -1837,7 +1887,7 @@ class CodeEditor {
1837
1887
  if(resetLeft)
1838
1888
  this.resetCursorPos( CodeEditor.CURSOR_LEFT, cursor );
1839
1889
 
1840
- this._refreshCodeInfo( cursor.line + 1, cursor.position );
1890
+ this._refreshCodeInfo( cursor.line, cursor.position );
1841
1891
 
1842
1892
  doAsync(() => {
1843
1893
  var first_line = (this.code.scrollTop / this.lineHeight)|0;
@@ -1856,7 +1906,7 @@ class CodeEditor {
1856
1906
  if(resetLeft)
1857
1907
  this.resetCursorPos( CodeEditor.CURSOR_LEFT, cursor );
1858
1908
 
1859
- this._refreshCodeInfo( cursor.line + 1, cursor.position );
1909
+ this._refreshCodeInfo( cursor.line, cursor.position );
1860
1910
 
1861
1911
  doAsync(() => {
1862
1912
  var last_line = ((this.code.scrollTop + this.code.offsetHeight) / this.lineHeight)|0;
@@ -2073,10 +2123,10 @@ class CodeEditor {
2073
2123
  );
2074
2124
 
2075
2125
  // Add words in current tab plus remove current word
2076
- // suggestions = suggestions.concat( Object.keys(this.code.tokens).filter( a => a != word ) );
2126
+ suggestions = suggestions.concat( Object.keys(this.code.tokens).filter( a => a != word ) );
2077
2127
 
2078
- // Remove single chars and duplicates...
2079
- suggestions = suggestions.filter( (value, index) => value.length > 1 && suggestions.indexOf(value) === index );
2128
+ // Remove 1/2 char words and duplicates...
2129
+ suggestions = suggestions.filter( (value, index) => value.length > 2 && suggestions.indexOf(value) === index );
2080
2130
 
2081
2131
  // Order...
2082
2132
  suggestions = suggestions.sort( (a, b) => a.localeCompare(b) );