lexgui 0.7.3 → 0.7.5
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/extensions/codeeditor.js +519 -170
- package/build/extensions/videoeditor.js +12 -1
- package/build/lexgui.css +29 -11
- package/build/lexgui.js +26 -7
- package/build/lexgui.min.css +1 -1
- package/build/lexgui.min.js +1 -1
- package/build/lexgui.module.js +26 -7
- package/build/lexgui.module.min.js +1 -1
- package/changelog.md +26 -1
- package/examples/code-editor.html +33 -19
- package/package.json +1 -1
|
@@ -151,7 +151,7 @@ class ScrollBar {
|
|
|
151
151
|
this.type = type;
|
|
152
152
|
|
|
153
153
|
this.root = document.createElement( 'div' );
|
|
154
|
-
this.root.className = "lexcodescrollbar";
|
|
154
|
+
this.root.className = "lexcodescrollbar hidden";
|
|
155
155
|
|
|
156
156
|
if( type & ScrollBar.SCROLLBAR_VERTICAL )
|
|
157
157
|
this.root.classList.add( 'vertical' );
|
|
@@ -338,7 +338,7 @@ class CodeEditor {
|
|
|
338
338
|
|
|
339
339
|
let panel = new LX.Panel();
|
|
340
340
|
|
|
341
|
-
panel.addTitle( "EXPLORER" );
|
|
341
|
+
panel.addTitle( options.explorerName ?? "EXPLORER" );
|
|
342
342
|
|
|
343
343
|
let sceneData = {
|
|
344
344
|
'id': 'WORKSPACE',
|
|
@@ -403,11 +403,11 @@ class CodeEditor {
|
|
|
403
403
|
|
|
404
404
|
if( !this.disableEdition )
|
|
405
405
|
{
|
|
406
|
-
this.tabs.root.addEventListener( 'dblclick', (e) => {
|
|
406
|
+
this.tabs.root.parentElement.addEventListener( 'dblclick', (e) => {
|
|
407
407
|
if( options.allowAddScripts ?? true )
|
|
408
408
|
{
|
|
409
409
|
e.preventDefault();
|
|
410
|
-
this.
|
|
410
|
+
this._onCreateNewFile();
|
|
411
411
|
}
|
|
412
412
|
} );
|
|
413
413
|
}
|
|
@@ -966,11 +966,14 @@ class CodeEditor {
|
|
|
966
966
|
var spaces = firstNonspaceIndex( this.code.lines[ ln ]);
|
|
967
967
|
var tabs = Math.floor( spaces / this.tabSpaces );
|
|
968
968
|
|
|
969
|
-
if( _c0 == '{' && _c1 == '}' )
|
|
969
|
+
if( _c0 == '{' && _c1 == '}' )
|
|
970
|
+
{
|
|
970
971
|
this.code.lines.splice( cursor.line, 0, "" );
|
|
971
972
|
this._addSpaceTabs( cursor, tabs + 1 );
|
|
972
973
|
this.code.lines[ cursor.line + 1 ] = " ".repeat(spaces) + this.code.lines[ cursor.line + 1 ];
|
|
973
|
-
}
|
|
974
|
+
}
|
|
975
|
+
else
|
|
976
|
+
{
|
|
974
977
|
this._addSpaceTabs( cursor, tabs );
|
|
975
978
|
}
|
|
976
979
|
|
|
@@ -1206,9 +1209,10 @@ class CodeEditor {
|
|
|
1206
1209
|
this.openedTabs = { };
|
|
1207
1210
|
|
|
1208
1211
|
const onLoadAll = () => {
|
|
1212
|
+
|
|
1209
1213
|
// Create inspector panel when the initial state is complete
|
|
1210
1214
|
// and we have at least 1 tab opened
|
|
1211
|
-
this.statusPanel = this._createStatusPanel();
|
|
1215
|
+
this.statusPanel = this._createStatusPanel( options );
|
|
1212
1216
|
if( this.statusPanel )
|
|
1213
1217
|
{
|
|
1214
1218
|
area.attach( this.statusPanel );
|
|
@@ -1228,6 +1232,7 @@ class CodeEditor {
|
|
|
1228
1232
|
const s = getComputedStyle( r );
|
|
1229
1233
|
this.fontSize = parseInt( s.getPropertyValue( "--code-editor-font-size" ) );
|
|
1230
1234
|
this.charWidth = this._measureChar( "a", true );
|
|
1235
|
+
this.processLines();
|
|
1231
1236
|
}
|
|
1232
1237
|
|
|
1233
1238
|
LX.emit( "@font-size", this.fontSize );
|
|
@@ -1240,10 +1245,10 @@ class CodeEditor {
|
|
|
1240
1245
|
|
|
1241
1246
|
this.gutter.style.marginTop = `${ this._verticalTopOffset }px`;
|
|
1242
1247
|
this.gutter.style.height = `calc(100% - ${ this._fullVerticalOffset }px)`;
|
|
1243
|
-
this.vScrollbar.root.style.marginTop = `${ this.
|
|
1248
|
+
this.vScrollbar.root.style.marginTop = `${ this._verticalTopOffset }px`;
|
|
1244
1249
|
this.vScrollbar.root.style.height = `calc(100% - ${ this._fullVerticalOffset }px)`;
|
|
1245
1250
|
this.hScrollbar.root.style.bottom = `${ this._verticalBottomOffset }px`;
|
|
1246
|
-
this.codeArea.root.style.height = `calc(100% - ${ this.
|
|
1251
|
+
this.codeArea.root.style.height = `calc(100% - ${ this._fullVerticalOffset }px)`;
|
|
1247
1252
|
}, 50 );
|
|
1248
1253
|
|
|
1249
1254
|
});
|
|
@@ -1253,7 +1258,9 @@ class CodeEditor {
|
|
|
1253
1258
|
|
|
1254
1259
|
if( options.allowAddScripts ?? true )
|
|
1255
1260
|
{
|
|
1256
|
-
this.
|
|
1261
|
+
this.onCreateFile = options.onCreateFile;
|
|
1262
|
+
|
|
1263
|
+
this.addTab( "+", false, "Create file" );
|
|
1257
1264
|
}
|
|
1258
1265
|
|
|
1259
1266
|
if( options.files )
|
|
@@ -1264,11 +1271,16 @@ class CodeEditor {
|
|
|
1264
1271
|
|
|
1265
1272
|
for( let url of options.files )
|
|
1266
1273
|
{
|
|
1267
|
-
this.loadFile( url, { callback: () => {
|
|
1274
|
+
this.loadFile( url, { callback: ( name, text ) => {
|
|
1268
1275
|
filesLoaded++;
|
|
1269
1276
|
if( filesLoaded == numFiles )
|
|
1270
1277
|
{
|
|
1271
1278
|
onLoadAll();
|
|
1279
|
+
|
|
1280
|
+
if( options.onFilesLoaded )
|
|
1281
|
+
{
|
|
1282
|
+
options.onFilesLoaded( this, numFiles );
|
|
1283
|
+
}
|
|
1272
1284
|
}
|
|
1273
1285
|
}});
|
|
1274
1286
|
}
|
|
@@ -1322,12 +1334,15 @@ class CodeEditor {
|
|
|
1322
1334
|
|
|
1323
1335
|
this.cursorToLine( cursor, newLines.length ); // Already substracted 1
|
|
1324
1336
|
this.cursorToPosition( cursor, lastLine.length );
|
|
1325
|
-
|
|
1337
|
+
|
|
1338
|
+
this.mustProcessLines = true;
|
|
1326
1339
|
|
|
1327
1340
|
if( lang )
|
|
1328
1341
|
{
|
|
1329
1342
|
this._changeLanguage( lang );
|
|
1330
1343
|
}
|
|
1344
|
+
|
|
1345
|
+
this._processLinesIfNecessary();
|
|
1331
1346
|
}
|
|
1332
1347
|
|
|
1333
1348
|
appendText( text, cursor ) {
|
|
@@ -1401,7 +1416,7 @@ class CodeEditor {
|
|
|
1401
1416
|
} );
|
|
1402
1417
|
}
|
|
1403
1418
|
|
|
1404
|
-
loadFile( file, options = {} ) {
|
|
1419
|
+
async loadFile( file, options = {} ) {
|
|
1405
1420
|
|
|
1406
1421
|
const _innerAddTab = ( text, name, title ) => {
|
|
1407
1422
|
|
|
@@ -1429,10 +1444,6 @@ class CodeEditor {
|
|
|
1429
1444
|
this.addExplorerItem( { id: name, skipVisibility: true, icon: this._getFileIcon( name, ext ) } );
|
|
1430
1445
|
this.explorer.innerTree.frefresh( name );
|
|
1431
1446
|
}
|
|
1432
|
-
else
|
|
1433
|
-
{
|
|
1434
|
-
|
|
1435
|
-
}
|
|
1436
1447
|
}
|
|
1437
1448
|
else
|
|
1438
1449
|
{
|
|
@@ -1448,17 +1459,19 @@ class CodeEditor {
|
|
|
1448
1459
|
|
|
1449
1460
|
if( options.callback )
|
|
1450
1461
|
{
|
|
1451
|
-
options.callback( text );
|
|
1462
|
+
options.callback( name, text );
|
|
1452
1463
|
}
|
|
1453
1464
|
};
|
|
1454
1465
|
|
|
1455
1466
|
if( file.constructor == String )
|
|
1456
1467
|
{
|
|
1457
1468
|
let filename = file;
|
|
1469
|
+
|
|
1458
1470
|
LX.request({ url: filename, success: text => {
|
|
1459
1471
|
const name = filename.substring(filename.lastIndexOf( '/' ) + 1);
|
|
1460
1472
|
_innerAddTab( text, name, filename );
|
|
1461
1473
|
} });
|
|
1474
|
+
|
|
1462
1475
|
}
|
|
1463
1476
|
else // File Blob
|
|
1464
1477
|
{
|
|
@@ -1598,7 +1611,8 @@ class CodeEditor {
|
|
|
1598
1611
|
}
|
|
1599
1612
|
|
|
1600
1613
|
this._updateDataInfoPanel( "@highlight", lang );
|
|
1601
|
-
|
|
1614
|
+
|
|
1615
|
+
this.mustProcessLines = true;
|
|
1602
1616
|
|
|
1603
1617
|
const ext = langExtension ?? CodeEditor.languages[ lang ].ext;
|
|
1604
1618
|
const icon = this._getFileIcon( null, ext );
|
|
@@ -1663,7 +1677,7 @@ class CodeEditor {
|
|
|
1663
1677
|
this._changeLanguage( 'Plain Text' );
|
|
1664
1678
|
}
|
|
1665
1679
|
|
|
1666
|
-
_createStatusPanel() {
|
|
1680
|
+
_createStatusPanel( options ) {
|
|
1667
1681
|
|
|
1668
1682
|
if( this.skipInfo )
|
|
1669
1683
|
{
|
|
@@ -1688,7 +1702,7 @@ class CodeEditor {
|
|
|
1688
1702
|
|
|
1689
1703
|
let rightStatusPanel = new LX.Panel( { height: "auto" } );
|
|
1690
1704
|
rightStatusPanel.sameLine();
|
|
1691
|
-
rightStatusPanel.addLabel( this.code
|
|
1705
|
+
rightStatusPanel.addLabel( this.code?.title ?? "", { id: "EditorFilenameStatusComponent", fit: true, signal: "@tab-name" });
|
|
1692
1706
|
rightStatusPanel.addButton( null, "Ln 1, Col 1", this.showSearchLineBox.bind( this ), { id: "EditorSelectionStatusComponent", fit: true, signal: "@cursor-data" });
|
|
1693
1707
|
rightStatusPanel.addButton( null, "Spaces: " + this.tabSpaces, ( value, event ) => {
|
|
1694
1708
|
LX.addContextMenu( "Spaces", event, m => {
|
|
@@ -1715,13 +1729,24 @@ class CodeEditor {
|
|
|
1715
1729
|
panel.attach( rightStatusPanel.root );
|
|
1716
1730
|
|
|
1717
1731
|
const itemVisibilityMap = {
|
|
1718
|
-
"Font Size Zoom": true,
|
|
1719
|
-
"Editor Filename": true,
|
|
1720
|
-
"Editor Selection": true,
|
|
1721
|
-
"Editor Indentation": true,
|
|
1722
|
-
"Editor Language": true,
|
|
1732
|
+
"Font Size Zoom": options.statusShowFontSizeZoom ?? true,
|
|
1733
|
+
"Editor Filename": options.statusShowEditorFilename ?? true,
|
|
1734
|
+
"Editor Selection": options.statusShowEditorSelection ?? true,
|
|
1735
|
+
"Editor Indentation": options.statusShowEditorIndentation ?? true,
|
|
1736
|
+
"Editor Language": options.statusShowEditorLanguage ?? true,
|
|
1723
1737
|
};
|
|
1724
1738
|
|
|
1739
|
+
const _setVisibility = ( itemName ) => {
|
|
1740
|
+
const b = panel.root.querySelector( `#${ itemName.replaceAll( " ", "" ) }StatusComponent` );
|
|
1741
|
+
console.assert( b, `${ itemName } has no status button!` );
|
|
1742
|
+
b.classList.toggle( "hidden", !itemVisibilityMap[ itemName ] );
|
|
1743
|
+
}
|
|
1744
|
+
|
|
1745
|
+
for( const [ itemName, v ] of Object.entries( itemVisibilityMap ) )
|
|
1746
|
+
{
|
|
1747
|
+
_setVisibility( itemName );
|
|
1748
|
+
}
|
|
1749
|
+
|
|
1725
1750
|
panel.root.addEventListener( "contextmenu", (e) => {
|
|
1726
1751
|
|
|
1727
1752
|
if( e.target && ( e.target.classList.contains( "lexpanel" ) || e.target.classList.contains( "lexinlinecomponents" ) ) )
|
|
@@ -1735,9 +1760,7 @@ class CodeEditor {
|
|
|
1735
1760
|
icon: "Check",
|
|
1736
1761
|
callback: () => {
|
|
1737
1762
|
itemVisibilityMap[ itemName ] = !itemVisibilityMap[ itemName ];
|
|
1738
|
-
|
|
1739
|
-
console.assert( b, `${ itemName } has no status button!` );
|
|
1740
|
-
b.classList.toggle( "hidden", !itemVisibilityMap[ itemName ] );
|
|
1763
|
+
_setVisibility( itemName );
|
|
1741
1764
|
}
|
|
1742
1765
|
}
|
|
1743
1766
|
if( !itemVisibilityMap[ itemName ] ) delete item.icon;
|
|
@@ -1808,10 +1831,23 @@ class CodeEditor {
|
|
|
1808
1831
|
|
|
1809
1832
|
this.processFocus( false );
|
|
1810
1833
|
|
|
1811
|
-
LX.
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
});
|
|
1834
|
+
new LX.DropdownMenu( e.target, [
|
|
1835
|
+
{ name: "Create file", icon: "FilePlus", callback: this._onCreateNewFile.bind( this ) },
|
|
1836
|
+
{ name: "Load file", icon: "FileUp", callback: this.loadTabFromFile.bind( this ) },
|
|
1837
|
+
], { side: "bottom", align: "start" });
|
|
1838
|
+
}
|
|
1839
|
+
|
|
1840
|
+
_onCreateNewFile() {
|
|
1841
|
+
|
|
1842
|
+
let options = {};
|
|
1843
|
+
|
|
1844
|
+
if( this.onCreateFile )
|
|
1845
|
+
{
|
|
1846
|
+
options = this.onCreateFile( this );
|
|
1847
|
+
}
|
|
1848
|
+
|
|
1849
|
+
const name = options.name ?? "unnamed.js";
|
|
1850
|
+
this.addTab( name, true, name, { language: options.language ?? "JavaScript" } );
|
|
1815
1851
|
}
|
|
1816
1852
|
|
|
1817
1853
|
_onSelectTab( isNewTabButton, event, name ) {
|
|
@@ -1848,18 +1884,38 @@ class CodeEditor {
|
|
|
1848
1884
|
{
|
|
1849
1885
|
this._changeLanguageFromExtension( LX.getExtension( name ) );
|
|
1850
1886
|
}
|
|
1887
|
+
|
|
1888
|
+
this.processLines();
|
|
1851
1889
|
}
|
|
1852
1890
|
|
|
1853
1891
|
_onContextMenuTab( isNewTabButton, event, name, ) {
|
|
1854
1892
|
|
|
1855
1893
|
if( isNewTabButton )
|
|
1894
|
+
{
|
|
1856
1895
|
return;
|
|
1896
|
+
}
|
|
1857
1897
|
|
|
1858
|
-
LX.
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1898
|
+
new LX.DropdownMenu( event.target, [
|
|
1899
|
+
{ name: "Close", kbd: "MWB", callback: () => { this.tabs.delete( name ) } },
|
|
1900
|
+
{ name: "Close Others", callback: () => {
|
|
1901
|
+
for( const [ key, data ] of Object.entries( this.tabs.tabs ) )
|
|
1902
|
+
{
|
|
1903
|
+
if( key === '+' || key === name ) continue;
|
|
1904
|
+
this.tabs.delete( key )
|
|
1905
|
+
}
|
|
1906
|
+
} },
|
|
1907
|
+
{ name: "Close All", callback: () => {
|
|
1908
|
+
for( const [ key, data ] of Object.entries( this.tabs.tabs ) )
|
|
1909
|
+
{
|
|
1910
|
+
if( key === '+' ) continue;
|
|
1911
|
+
this.tabs.delete( key )
|
|
1912
|
+
}
|
|
1913
|
+
} },
|
|
1914
|
+
null,
|
|
1915
|
+
{ name: "Copy Path", icon: "Copy", callback: () => {
|
|
1916
|
+
navigator.clipboard.writeText( this.openedTabs[ name ].path ?? "" );
|
|
1917
|
+
} }
|
|
1918
|
+
], { side: "bottom", align: "start", event });
|
|
1863
1919
|
}
|
|
1864
1920
|
|
|
1865
1921
|
addTab( name, selected, title, options = {} ) {
|
|
@@ -1879,20 +1935,25 @@ class CodeEditor {
|
|
|
1879
1935
|
|
|
1880
1936
|
// Create code content
|
|
1881
1937
|
let code = document.createElement( 'div' );
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1938
|
+
Object.assign( code, {
|
|
1939
|
+
path: options.path ?? "",
|
|
1940
|
+
className: 'code',
|
|
1941
|
+
lines: [ "" ],
|
|
1942
|
+
language: options.language ?? "Plain Text",
|
|
1943
|
+
cursorState: {},
|
|
1944
|
+
undoSteps: [],
|
|
1945
|
+
redoSteps: [],
|
|
1946
|
+
lineScopes: [],
|
|
1947
|
+
lineSymbols: [],
|
|
1948
|
+
lineSignatures: [],
|
|
1949
|
+
symbolsTable: new Map(),
|
|
1950
|
+
tabName: name,
|
|
1951
|
+
title: title ?? name,
|
|
1952
|
+
tokens: {}
|
|
1953
|
+
} );
|
|
1954
|
+
|
|
1955
|
+
code.style.left = "0px",
|
|
1956
|
+
code.style.top = "0px",
|
|
1896
1957
|
|
|
1897
1958
|
code.addEventListener( 'dragenter', function(e) {
|
|
1898
1959
|
e.preventDefault();
|
|
@@ -1942,15 +2003,18 @@ class CodeEditor {
|
|
|
1942
2003
|
{
|
|
1943
2004
|
this.code = code;
|
|
1944
2005
|
this.resetCursorPos( CodeEditor.CURSOR_LEFT_TOP );
|
|
1945
|
-
this.
|
|
2006
|
+
this.mustProcessLines = true;
|
|
1946
2007
|
}
|
|
1947
2008
|
|
|
1948
2009
|
if( options.language )
|
|
1949
2010
|
{
|
|
1950
2011
|
code.languageOverride = options.language;
|
|
1951
2012
|
this._changeLanguage( code.languageOverride );
|
|
2013
|
+
this.mustProcessLines = true;
|
|
1952
2014
|
}
|
|
1953
2015
|
|
|
2016
|
+
this._processLinesIfNecessary();
|
|
2017
|
+
|
|
1954
2018
|
this._updateDataInfoPanel( "@tab-name", name );
|
|
1955
2019
|
|
|
1956
2020
|
// Bc it could be overrided..
|
|
@@ -1993,6 +2057,8 @@ class CodeEditor {
|
|
|
1993
2057
|
delete this._tabStorage[ name ];
|
|
1994
2058
|
}
|
|
1995
2059
|
|
|
2060
|
+
this._processLinesIfNecessary();
|
|
2061
|
+
|
|
1996
2062
|
return;
|
|
1997
2063
|
}
|
|
1998
2064
|
|
|
@@ -2005,9 +2071,12 @@ class CodeEditor {
|
|
|
2005
2071
|
|
|
2006
2072
|
// Select as current...
|
|
2007
2073
|
this.code = code;
|
|
2074
|
+
this.mustProcessLines = true;
|
|
2075
|
+
|
|
2008
2076
|
this.resetCursorPos( CodeEditor.CURSOR_LEFT_TOP );
|
|
2009
2077
|
this.processLines();
|
|
2010
2078
|
this._changeLanguageFromExtension( LX.getExtension( name ) );
|
|
2079
|
+
this._processLinesIfNecessary();
|
|
2011
2080
|
this._updateDataInfoPanel( "@tab-name", code.tabName );
|
|
2012
2081
|
}
|
|
2013
2082
|
|
|
@@ -2044,6 +2113,8 @@ class CodeEditor {
|
|
|
2044
2113
|
delete this._tabStorage[ name ];
|
|
2045
2114
|
}
|
|
2046
2115
|
|
|
2116
|
+
this._processLinesIfNecessary();
|
|
2117
|
+
|
|
2047
2118
|
return;
|
|
2048
2119
|
}
|
|
2049
2120
|
|
|
@@ -2098,7 +2169,7 @@ class CodeEditor {
|
|
|
2098
2169
|
document.body.appendChild( input );
|
|
2099
2170
|
input.click();
|
|
2100
2171
|
input.addEventListener('change', e => {
|
|
2101
|
-
if
|
|
2172
|
+
if( e.target.files[ 0 ] )
|
|
2102
2173
|
{
|
|
2103
2174
|
this.loadFile( e.target.files[ 0 ] );
|
|
2104
2175
|
}
|
|
@@ -3029,10 +3100,24 @@ class CodeEditor {
|
|
|
3029
3100
|
return Math.max(...this.code.lines.map( v => v.length ));
|
|
3030
3101
|
}
|
|
3031
3102
|
|
|
3103
|
+
_processLinesIfNecessary() {
|
|
3104
|
+
if( this.mustProcessLines )
|
|
3105
|
+
{
|
|
3106
|
+
this.mustProcessLines = false;
|
|
3107
|
+
this.processLines();
|
|
3108
|
+
}
|
|
3109
|
+
}
|
|
3110
|
+
|
|
3032
3111
|
processLines( mode ) {
|
|
3033
3112
|
|
|
3113
|
+
if( !this.code )
|
|
3114
|
+
{
|
|
3115
|
+
return;
|
|
3116
|
+
}
|
|
3117
|
+
|
|
3034
3118
|
var htmlCode = "";
|
|
3035
3119
|
this._blockCommentCache.length = 0;
|
|
3120
|
+
this.mustProcessLines = false;
|
|
3036
3121
|
|
|
3037
3122
|
// Reset all lines content
|
|
3038
3123
|
this.code.innerHTML = "";
|
|
@@ -3080,13 +3165,6 @@ class CodeEditor {
|
|
|
3080
3165
|
|
|
3081
3166
|
processLine( lineNumber, force, skipPropagation ) {
|
|
3082
3167
|
|
|
3083
|
-
// Check if we are in block comment sections..
|
|
3084
|
-
if( !force && this._inBlockCommentSection( lineNumber ) )
|
|
3085
|
-
{
|
|
3086
|
-
this.processLines();
|
|
3087
|
-
return;
|
|
3088
|
-
}
|
|
3089
|
-
|
|
3090
3168
|
if( this._scopeStack )
|
|
3091
3169
|
{
|
|
3092
3170
|
this.code.lineScopes[ lineNumber ] = [ ...this._scopeStack ];
|
|
@@ -3100,6 +3178,12 @@ class CodeEditor {
|
|
|
3100
3178
|
const lang = CodeEditor.languages[ this.highlight ];
|
|
3101
3179
|
const localLineNum = this.toLocalLine( lineNumber );
|
|
3102
3180
|
const lineString = this.code.lines[ lineNumber ];
|
|
3181
|
+
if( lineString === undefined )
|
|
3182
|
+
{
|
|
3183
|
+
return;
|
|
3184
|
+
}
|
|
3185
|
+
|
|
3186
|
+
this._lastProcessedLine = lineNumber;
|
|
3103
3187
|
|
|
3104
3188
|
// multi-line strings not supported by now
|
|
3105
3189
|
delete this._buildingString;
|
|
@@ -3132,6 +3216,18 @@ class CodeEditor {
|
|
|
3132
3216
|
let lineInnerHtml = "";
|
|
3133
3217
|
let pushedScope = false;
|
|
3134
3218
|
|
|
3219
|
+
const newSignature = this._getLineSignatureFromTokens( tokensToEvaluate );
|
|
3220
|
+
const cachedSignature = this.code.lineSignatures[ lineNumber ];
|
|
3221
|
+
const mustUpdateScopes = ( cachedSignature !== newSignature ) && !force;
|
|
3222
|
+
const blockComments = lang.blockComments ?? true;
|
|
3223
|
+
const blockCommentsTokens = lang.blockCommentsTokens ?? this.defaultBlockCommentTokens;
|
|
3224
|
+
|
|
3225
|
+
// Reset scope stack if structural changes in current line
|
|
3226
|
+
if( mustUpdateScopes )
|
|
3227
|
+
{
|
|
3228
|
+
this._scopeStack = [ { name: "", type: "global" } ];
|
|
3229
|
+
}
|
|
3230
|
+
|
|
3135
3231
|
// Process all tokens
|
|
3136
3232
|
for( let i = 0; i < tokensToEvaluate.length; ++i )
|
|
3137
3233
|
{
|
|
@@ -3152,34 +3248,44 @@ class CodeEditor {
|
|
|
3152
3248
|
}
|
|
3153
3249
|
|
|
3154
3250
|
const token = tokensToEvaluate[ i ];
|
|
3251
|
+
const tokenIndex = i;
|
|
3252
|
+
const tokenStartIndex = this._currentTokenPositions[ tokenIndex ];;
|
|
3155
3253
|
|
|
3156
|
-
if(
|
|
3254
|
+
if( blockComments )
|
|
3157
3255
|
{
|
|
3158
|
-
|
|
3159
|
-
if( token.substr( 0, blockCommentsToken.length ) == blockCommentsToken )
|
|
3256
|
+
if( token.substr( 0, blockCommentsTokens[ 0 ].length ) == blockCommentsTokens[ 0 ] )
|
|
3160
3257
|
{
|
|
3161
|
-
this._buildingBlockComment = lineNumber;
|
|
3258
|
+
this._buildingBlockComment = [ lineNumber, tokenStartIndex ];
|
|
3162
3259
|
}
|
|
3163
3260
|
}
|
|
3164
3261
|
|
|
3165
|
-
//
|
|
3262
|
+
// Compare line signature for structural changes
|
|
3263
|
+
// to pop current scope if necessary
|
|
3166
3264
|
if( token === "}" && this._scopeStack.length > 1 )
|
|
3167
3265
|
{
|
|
3168
3266
|
this._scopeStack.pop();
|
|
3169
3267
|
}
|
|
3170
3268
|
|
|
3171
3269
|
lineInnerHtml += this._evaluateToken( {
|
|
3172
|
-
token
|
|
3173
|
-
prev
|
|
3270
|
+
token,
|
|
3271
|
+
prev,
|
|
3174
3272
|
prevWithSpaces: tokensToEvaluate[ i - 1 ],
|
|
3175
|
-
next
|
|
3273
|
+
next,
|
|
3176
3274
|
nextWithSpaces: tokensToEvaluate[ i + 1 ],
|
|
3177
|
-
tokenIndex
|
|
3178
|
-
isFirstToken: (
|
|
3179
|
-
isLastToken: (
|
|
3275
|
+
tokenIndex,
|
|
3276
|
+
isFirstToken: ( tokenIndex == 0 ),
|
|
3277
|
+
isLastToken: ( tokenIndex == tokensToEvaluate.length - 1 ),
|
|
3180
3278
|
tokens: tokensToEvaluate
|
|
3181
3279
|
} );
|
|
3182
3280
|
|
|
3281
|
+
if( blockComments && this._buildingBlockComment != undefined
|
|
3282
|
+
&& token.substr( 0, blockCommentsTokens[ 1 ].length ) == blockCommentsTokens[ 1 ] )
|
|
3283
|
+
{
|
|
3284
|
+
const [ commentLineNumber, tokenPos ] = this._buildingBlockComment;
|
|
3285
|
+
this._blockCommentCache.push( [ new LX.vec2( commentLineNumber, lineNumber ), new LX.vec2( tokenPos, tokenStartIndex ) ] );
|
|
3286
|
+
delete this._buildingBlockComment;
|
|
3287
|
+
}
|
|
3288
|
+
|
|
3183
3289
|
if( token !== "{" )
|
|
3184
3290
|
{
|
|
3185
3291
|
continue;
|
|
@@ -3187,26 +3293,39 @@ class CodeEditor {
|
|
|
3187
3293
|
|
|
3188
3294
|
// Store current scopes
|
|
3189
3295
|
|
|
3190
|
-
// Get some context about the scope from previous lines
|
|
3191
3296
|
let contextTokens = [
|
|
3192
|
-
...this._getTokensFromLine( this.code.lines[ lineNumber ].substring( 0,
|
|
3297
|
+
...this._getTokensFromLine( this.code.lines[ lineNumber ].substring( 0, tokenStartIndex ) )
|
|
3193
3298
|
];
|
|
3194
3299
|
|
|
3195
|
-
|
|
3300
|
+
// Add token context from above lines in case we don't have information
|
|
3301
|
+
// in the same line to get the scope data
|
|
3302
|
+
if( !prev )
|
|
3196
3303
|
{
|
|
3197
|
-
let
|
|
3198
|
-
if( !kLineString ) break;
|
|
3199
|
-
const closeIdx = kLineString.lastIndexOf( '}' );
|
|
3200
|
-
if( closeIdx > -1 )
|
|
3304
|
+
for( let k = 1; k < 50; k++ )
|
|
3201
3305
|
{
|
|
3202
|
-
kLineString =
|
|
3203
|
-
|
|
3306
|
+
let kLineString = this.code.lines[ lineNumber - k ];
|
|
3307
|
+
if( !kLineString )
|
|
3308
|
+
{
|
|
3309
|
+
break;
|
|
3310
|
+
}
|
|
3204
3311
|
|
|
3205
|
-
|
|
3312
|
+
const openIdx = kLineString.lastIndexOf( '{' );
|
|
3313
|
+
const closeIdx = kLineString.lastIndexOf( '}' );
|
|
3314
|
+
if( openIdx > -1 )
|
|
3315
|
+
{
|
|
3316
|
+
kLineString = kLineString.substr( openIdx );
|
|
3317
|
+
}
|
|
3318
|
+
else if( closeIdx > -1 )
|
|
3319
|
+
{
|
|
3320
|
+
kLineString = kLineString.substr( closeIdx );
|
|
3321
|
+
}
|
|
3206
3322
|
|
|
3207
|
-
|
|
3208
|
-
|
|
3209
|
-
|
|
3323
|
+
contextTokens = [ ...this._getTokensFromLine( kLineString ), ...contextTokens ];
|
|
3324
|
+
|
|
3325
|
+
if( kLineString.length !== this.code.lines[ lineNumber - k ] )
|
|
3326
|
+
{
|
|
3327
|
+
break;
|
|
3328
|
+
}
|
|
3210
3329
|
}
|
|
3211
3330
|
}
|
|
3212
3331
|
|
|
@@ -3249,28 +3368,111 @@ class CodeEditor {
|
|
|
3249
3368
|
}
|
|
3250
3369
|
}
|
|
3251
3370
|
|
|
3252
|
-
if
|
|
3371
|
+
// Only push if it's not already reflected in the cached scopes
|
|
3372
|
+
const lastScope = this._scopeStack.at( -1 );
|
|
3373
|
+
if( lastScope?.lineNumber !== lineNumber )
|
|
3253
3374
|
{
|
|
3254
|
-
this._scopeStack.push( { name: scopeName ?? "", type: scopeType } );
|
|
3255
|
-
}
|
|
3256
|
-
else
|
|
3257
|
-
{
|
|
3258
|
-
this._scopeStack.push( { name: "", type: "anonymous" } ); // anonymous scope
|
|
3375
|
+
this._scopeStack.push( { name: scopeName ?? "", type: scopeType ?? "anonymous", lineNumber } );
|
|
3259
3376
|
}
|
|
3260
3377
|
|
|
3261
3378
|
pushedScope = true;
|
|
3262
3379
|
}
|
|
3263
3380
|
|
|
3381
|
+
// Update scopes cache
|
|
3382
|
+
this.code.lineScopes[ lineNumber ] = [ ...this._scopeStack ];
|
|
3383
|
+
|
|
3264
3384
|
const symbols = this._parseLineForSymbols( lineNumber, lineString, tokensToEvaluate, pushedScope );
|
|
3265
|
-
|
|
3385
|
+
|
|
3386
|
+
return this._updateLine( force, lineNumber, lineInnerHtml, skipPropagation, symbols, tokensToEvaluate );
|
|
3387
|
+
}
|
|
3388
|
+
|
|
3389
|
+
_getLineSignatureFromTokens( tokens ) {
|
|
3390
|
+
const structuralChars = new Set( [ '{', '}'] );
|
|
3391
|
+
const sign = tokens.filter( t => structuralChars.has( t ) );
|
|
3392
|
+
return sign.join( "_" );
|
|
3266
3393
|
}
|
|
3267
3394
|
|
|
3268
|
-
|
|
3395
|
+
_updateBlockComments( section, lineNumber, tokens ) {
|
|
3269
3396
|
|
|
3270
|
-
|
|
3397
|
+
const lang = CodeEditor.languages[ this.highlight ];
|
|
3398
|
+
const blockCommentsTokens = lang.blockCommentsTokens ?? this.defaultBlockCommentTokens;
|
|
3399
|
+
const lineOpensBlock = ( section[ 0 ].x === lineNumber );
|
|
3400
|
+
const lineClosesBlock = ( section[ 0 ].y === lineNumber );
|
|
3401
|
+
const lineInsideBlock = ( section[ 0 ].x !== lineNumber ) && ( section[ 0 ].y !== lineNumber );
|
|
3402
|
+
|
|
3403
|
+
delete this._buildingBlockComment;
|
|
3404
|
+
|
|
3405
|
+
/*
|
|
3406
|
+
Check if delimiters have been removed and process lines backwards/forward
|
|
3407
|
+
until reaching new delimiters
|
|
3408
|
+
*/
|
|
3409
|
+
|
|
3410
|
+
if( lineOpensBlock )
|
|
3271
3411
|
{
|
|
3272
|
-
|
|
3412
|
+
const r = tokens.filter( t => t.substr( 0, blockCommentsTokens[ 0 ].length ) == blockCommentsTokens[ 0 ] );
|
|
3413
|
+
if( !r.length )
|
|
3414
|
+
{
|
|
3415
|
+
this._buildingBlockComment = [ lineNumber - 1, 0 ];
|
|
3416
|
+
|
|
3417
|
+
this.mustProcessPreviousLine = ( tokens ) => {
|
|
3418
|
+
const idx = tokens.indexOf( blockCommentsTokens[ 0 ] );
|
|
3419
|
+
return ( idx === -1 );
|
|
3420
|
+
}
|
|
3421
|
+
|
|
3422
|
+
this.processLine( lineNumber - 1, false, true );
|
|
3423
|
+
|
|
3424
|
+
section[ 0 ].x = this._lastProcessedLine;
|
|
3425
|
+
|
|
3426
|
+
const lastProcessedString = this.code.lines[ this._lastProcessedLine ];
|
|
3427
|
+
const idx = lastProcessedString.indexOf( blockCommentsTokens[ 0 ] );
|
|
3428
|
+
section[ 1 ].x = idx > 0 ? idx : 0;
|
|
3429
|
+
}
|
|
3430
|
+
else
|
|
3431
|
+
{
|
|
3432
|
+
const tokenIndex = tokens.indexOf( blockCommentsTokens[ 0 ] );
|
|
3433
|
+
const tokenStartIndex = this._currentTokenPositions[ tokenIndex ];
|
|
3434
|
+
section[ 1 ].x = tokenStartIndex;
|
|
3435
|
+
console.log(tokenStartIndex)
|
|
3436
|
+
// Process current line to update new sections
|
|
3437
|
+
this.processLine( lineNumber, false, true );
|
|
3438
|
+
}
|
|
3273
3439
|
}
|
|
3440
|
+
else if( lineClosesBlock )
|
|
3441
|
+
{
|
|
3442
|
+
const r = tokens.filter( t => t.substr( 0, blockCommentsTokens[ 1 ].length ) == blockCommentsTokens[ 1 ] );
|
|
3443
|
+
if( !r.length )
|
|
3444
|
+
{
|
|
3445
|
+
this._buildingBlockComment = [ section[ 0 ].x, section[ 1 ].x ];
|
|
3446
|
+
|
|
3447
|
+
this.mustProcessNextLine = ( tokens ) => {
|
|
3448
|
+
const idx = tokens.indexOf( blockCommentsTokens[ 1 ] );
|
|
3449
|
+
return ( idx === -1 );
|
|
3450
|
+
}
|
|
3451
|
+
|
|
3452
|
+
this.processLine( lineNumber + 1, false, true );
|
|
3453
|
+
|
|
3454
|
+
section[ 0 ].y = this._lastProcessedLine;
|
|
3455
|
+
|
|
3456
|
+
const lastProcessedString = this.code.lines[ this._lastProcessedLine ];
|
|
3457
|
+
const idx = lastProcessedString.indexOf( blockCommentsTokens[ 1 ] );
|
|
3458
|
+
section[ 1 ].y = idx > 0 ? idx : ( lastProcessedString.length - 1 );
|
|
3459
|
+
}
|
|
3460
|
+
else
|
|
3461
|
+
{
|
|
3462
|
+
const tokenIndex = tokens.indexOf( blockCommentsTokens[ 1 ] );
|
|
3463
|
+
const tokenStartIndex = this._currentTokenPositions[ tokenIndex ];
|
|
3464
|
+
section[ 1 ].y = tokenStartIndex;
|
|
3465
|
+
// Process current line to update new sections
|
|
3466
|
+
this.processLine( lineNumber, false, true );
|
|
3467
|
+
}
|
|
3468
|
+
}
|
|
3469
|
+
else if( lineInsideBlock )
|
|
3470
|
+
{
|
|
3471
|
+
// Here it can't modify delimiters..
|
|
3472
|
+
}
|
|
3473
|
+
}
|
|
3474
|
+
|
|
3475
|
+
_processExtraLineIfNecessary( lineNumber, tokens, oldSymbols, skipPropagation ) {
|
|
3274
3476
|
|
|
3275
3477
|
if( !this._scopeStack )
|
|
3276
3478
|
{
|
|
@@ -3278,11 +3480,45 @@ class CodeEditor {
|
|
|
3278
3480
|
return;
|
|
3279
3481
|
}
|
|
3280
3482
|
|
|
3483
|
+
// Update block comments if necessary
|
|
3484
|
+
{
|
|
3485
|
+
const commentBlockSection = this._inBlockCommentSection( lineNumber, 1e10, -1e10 );
|
|
3486
|
+
if( tokens && commentBlockSection !== undefined )
|
|
3487
|
+
{
|
|
3488
|
+
this._updateBlockComments( commentBlockSection, lineNumber, tokens );
|
|
3489
|
+
|
|
3490
|
+
// Get again correct scope
|
|
3491
|
+
this._scopeStack = [ ...this.code.lineScopes[ lineNumber ] ];
|
|
3492
|
+
}
|
|
3493
|
+
}
|
|
3494
|
+
|
|
3495
|
+
if( ( (lineNumber + 1) === this.code.lines.length ) || !this.code.lineScopes[ lineNumber + 1 ] )
|
|
3496
|
+
{
|
|
3497
|
+
return;
|
|
3498
|
+
}
|
|
3499
|
+
|
|
3500
|
+
const newSignature = this._getLineSignatureFromTokens( tokens );
|
|
3501
|
+
const cachedSignature = this.code.lineSignatures[ lineNumber ];
|
|
3502
|
+
const mustUpdateScopes = ( cachedSignature !== newSignature );
|
|
3503
|
+
const sameScopes = codeScopesEqual( this._scopeStack, this.code.lineScopes[ lineNumber + 1 ] );
|
|
3504
|
+
|
|
3281
3505
|
// Only update scope stack if something changed when editing a single line
|
|
3282
|
-
|
|
3506
|
+
// Compare line signature for structural changes
|
|
3507
|
+
if( ( mustUpdateScopes || this._scopesUpdated ) && ( !sameScopes && !skipPropagation ) )
|
|
3283
3508
|
{
|
|
3284
|
-
|
|
3509
|
+
if( mustUpdateScopes )
|
|
3510
|
+
{
|
|
3511
|
+
this._scopesUpdated = true;
|
|
3512
|
+
}
|
|
3513
|
+
|
|
3514
|
+
this.code.lineScopes[ lineNumber + 1 ] = [ ...this._scopeStack ];
|
|
3515
|
+
this.processLine( lineNumber + 1 );
|
|
3285
3516
|
|
|
3517
|
+
delete this._scopesUpdated;
|
|
3518
|
+
}
|
|
3519
|
+
else if( sameScopes )
|
|
3520
|
+
{
|
|
3521
|
+
// In case of same scope, check for occurrencies of the old symbols, to reprocess that lines
|
|
3286
3522
|
for( const sym of oldSymbols )
|
|
3287
3523
|
{
|
|
3288
3524
|
const tableSymbol = this.code.symbolsTable.get( sym.name );
|
|
@@ -3301,20 +3537,15 @@ class CodeEditor {
|
|
|
3301
3537
|
this.processLine( occ.line, false, true );
|
|
3302
3538
|
}
|
|
3303
3539
|
}
|
|
3304
|
-
|
|
3305
|
-
return;
|
|
3306
3540
|
}
|
|
3307
|
-
|
|
3308
|
-
this.code.lineScopes[ lineNumber + 1 ] = [ ...this._scopeStack ];
|
|
3309
|
-
this.processLine( lineNumber + 1 );
|
|
3310
3541
|
}
|
|
3311
3542
|
|
|
3312
|
-
_updateLine( force, lineNumber, html, skipPropagation, symbols = [] ) {
|
|
3543
|
+
_updateLine( force, lineNumber, html, skipPropagation, symbols = [], tokens = [] ) {
|
|
3313
3544
|
|
|
3314
3545
|
const gutterLineHtml = `<span class='line-gutter'>${ lineNumber + 1 }</span>`;
|
|
3315
3546
|
const oldSymbols = this._updateLineSymbols( lineNumber, symbols );
|
|
3316
|
-
const lineScope = CodeEditor.debugScopes ? this.code.lineScopes[ lineNumber ].map( s => `${ s.type }` ).join( ", " ) : "";
|
|
3317
|
-
const lineSymbols = CodeEditor.debugSymbols ? this.code.lineSymbols[ lineNumber ].map( s => `${ s.name }(${ s.kind })` ).join( ", " ) : "";
|
|
3547
|
+
const lineScope = CodeEditor.debugScopes && this.code.lineScopes[ lineNumber ] ? this.code.lineScopes[ lineNumber ].map( s => `${ s.type }` ).join( ", " ) : "";
|
|
3548
|
+
const lineSymbols = CodeEditor.debugSymbols && this.code.lineSymbols[ lineNumber ] ? this.code.lineSymbols[ lineNumber ].map( s => `${ s.name }(${ s.kind })` ).join( ", " ) : "";
|
|
3318
3549
|
const debugString = lineScope + ( lineScope.length ? " - " : "" ) + lineSymbols;
|
|
3319
3550
|
|
|
3320
3551
|
if( !force ) // Single line update
|
|
@@ -3323,17 +3554,46 @@ class CodeEditor {
|
|
|
3323
3554
|
|
|
3324
3555
|
if( !skipPropagation )
|
|
3325
3556
|
{
|
|
3326
|
-
this._processExtraLineIfNecessary( lineNumber, oldSymbols );
|
|
3557
|
+
this._processExtraLineIfNecessary( lineNumber, tokens, oldSymbols, skipPropagation );
|
|
3558
|
+
}
|
|
3559
|
+
|
|
3560
|
+
if( this.mustProcessNextLine )
|
|
3561
|
+
{
|
|
3562
|
+
if( this.mustProcessNextLine( tokens ) && ( ( lineNumber + 1 ) < this.code.lines.length ) )
|
|
3563
|
+
{
|
|
3564
|
+
this.processLine( lineNumber + 1, false, true );
|
|
3565
|
+
}
|
|
3566
|
+
else
|
|
3567
|
+
{
|
|
3568
|
+
delete this.mustProcessNextLine;
|
|
3569
|
+
}
|
|
3570
|
+
}
|
|
3571
|
+
|
|
3572
|
+
if( this.mustProcessPreviousLine )
|
|
3573
|
+
{
|
|
3574
|
+
if( this.mustProcessPreviousLine( tokens ) && ( ( lineNumber - 1 ) >= 0 ) )
|
|
3575
|
+
{
|
|
3576
|
+
this.processLine( lineNumber - 1, false, true );
|
|
3577
|
+
}
|
|
3578
|
+
else
|
|
3579
|
+
{
|
|
3580
|
+
delete this.mustProcessPreviousLine;
|
|
3581
|
+
}
|
|
3582
|
+
}
|
|
3583
|
+
|
|
3584
|
+
if( CodeEditor.debugProcessedLines )
|
|
3585
|
+
{
|
|
3586
|
+
this.code.childNodes[ lineNumber ]?.classList.add( "debug" );
|
|
3327
3587
|
}
|
|
3328
3588
|
|
|
3329
3589
|
this._setActiveLine( lineNumber );
|
|
3330
3590
|
this._clearTmpVariables();
|
|
3331
3591
|
}
|
|
3332
|
-
else // Update all lines at once
|
|
3333
|
-
{
|
|
3334
3592
|
|
|
3335
|
-
|
|
3336
|
-
|
|
3593
|
+
this.code.lineSignatures[ lineNumber ] = this._getLineSignatureFromTokens( tokens );
|
|
3594
|
+
|
|
3595
|
+
// Update all lines at once
|
|
3596
|
+
return force ? `<pre>${ ( gutterLineHtml + html + debugString ) }</pre>` : undefined;
|
|
3337
3597
|
}
|
|
3338
3598
|
|
|
3339
3599
|
/**
|
|
@@ -3343,7 +3603,7 @@ class CodeEditor {
|
|
|
3343
3603
|
|
|
3344
3604
|
const scope = this._scopeStack.at( pushedScope ? -2 : -1 );
|
|
3345
3605
|
|
|
3346
|
-
if( !scope )
|
|
3606
|
+
if( !scope || this._inBlockCommentSection( lineNumber ) )
|
|
3347
3607
|
{
|
|
3348
3608
|
return [];
|
|
3349
3609
|
}
|
|
@@ -3351,7 +3611,19 @@ class CodeEditor {
|
|
|
3351
3611
|
const scopeName = scope.name;
|
|
3352
3612
|
const scopeType = scope.type;
|
|
3353
3613
|
const symbols = [];
|
|
3614
|
+
const symbolsMap = new Map();
|
|
3354
3615
|
const text = lineString.trim();
|
|
3616
|
+
const previousLineScope = this.code.lineScopes[ lineNumber - 1 ];
|
|
3617
|
+
|
|
3618
|
+
const _pushSymbol = ( s ) => {
|
|
3619
|
+
const signature = `${ s.name }_${ s.kind }_${ s.scope }_${ s.line }`;
|
|
3620
|
+
if( symbolsMap.has( signature ) )
|
|
3621
|
+
{
|
|
3622
|
+
return;
|
|
3623
|
+
}
|
|
3624
|
+
symbolsMap.set( signature, s );
|
|
3625
|
+
symbols.push( s );
|
|
3626
|
+
};
|
|
3355
3627
|
|
|
3356
3628
|
// Don't make symbols from preprocessor lines
|
|
3357
3629
|
if( text.startsWith( "#" ) )
|
|
@@ -3359,6 +3631,8 @@ class CodeEditor {
|
|
|
3359
3631
|
return [];
|
|
3360
3632
|
}
|
|
3361
3633
|
|
|
3634
|
+
const nativeTypes = CodeEditor.nativeTypes[ this.highlight ];
|
|
3635
|
+
|
|
3362
3636
|
const topLevelRegexes = [
|
|
3363
3637
|
[/^class\s+([A-Za-z0-9_]+)/, "class"],
|
|
3364
3638
|
[/^struct\s+([A-Za-z0-9_]+)/, "struct"],
|
|
@@ -3366,30 +3640,33 @@ class CodeEditor {
|
|
|
3366
3640
|
[/^interface\s+([A-Za-z0-9_]+)/, "interface"],
|
|
3367
3641
|
[/^type\s+([A-Za-z0-9_]+)/, "type"],
|
|
3368
3642
|
[/^function\s+([A-Za-z0-9_]+)/, "method"],
|
|
3643
|
+
[/^fn\s+([A-Za-z0-9_]+)/, "method"],
|
|
3644
|
+
[/^def\s+([A-Za-z0-9_]+)/, "method"],
|
|
3369
3645
|
[/^([A-Za-z0-9_]+)\s*=\s*\(?.*\)?\s*=>/, "method"] // arrow functions
|
|
3370
3646
|
];
|
|
3371
3647
|
|
|
3648
|
+
// Add regexes to detect methods, variables ( including "id : nativeType" )
|
|
3372
3649
|
{
|
|
3373
|
-
const nativeTypes = CodeEditor.nativeTypes[ this.highlight ];
|
|
3374
3650
|
if( nativeTypes )
|
|
3375
3651
|
{
|
|
3376
|
-
|
|
3377
|
-
|
|
3378
|
-
|
|
3652
|
+
topLevelRegexes.push( [ new RegExp( `^(?:${nativeTypes.join('|')})\\s+([A-Za-z0-9_]+)\s*[\(]+` ), 'method' ] );
|
|
3653
|
+
|
|
3654
|
+
if( this.highlight === "WGSL" )
|
|
3655
|
+
{
|
|
3656
|
+
topLevelRegexes.push( [ new RegExp( `[A-Za-z0-9]+(\\s*)+:(\\s*)+(${nativeTypes.join('|')})` ), 'variable', ( m ) => m[ 0 ].split( ":" )[ 0 ].trim() ] );
|
|
3657
|
+
}
|
|
3379
3658
|
}
|
|
3380
3659
|
|
|
3381
3660
|
const declarationKeywords = CodeEditor.declarationKeywords[ this.highlight ] ?? [ "const", "let", "var" ];
|
|
3382
|
-
|
|
3383
|
-
topLevelRegexes.push( [ new RegExp( regex ), 'variable' ] );
|
|
3661
|
+
topLevelRegexes.push( [ new RegExp( `^(?:${ declarationKeywords.join('|') })\\s+([A-Za-z0-9_]+)` ), 'variable' ] );
|
|
3384
3662
|
}
|
|
3385
3663
|
|
|
3386
|
-
for( let [ regex, kind ] of topLevelRegexes )
|
|
3664
|
+
for( let [ regex, kind, fn ] of topLevelRegexes )
|
|
3387
3665
|
{
|
|
3388
3666
|
const m = text.match( regex );
|
|
3389
3667
|
if( m )
|
|
3390
3668
|
{
|
|
3391
|
-
|
|
3392
|
-
break;
|
|
3669
|
+
_pushSymbol( { name: fn ? fn( m ) : m[ 1 ], kind, scope: scopeName, line: lineNumber } );
|
|
3393
3670
|
}
|
|
3394
3671
|
}
|
|
3395
3672
|
|
|
@@ -3398,15 +3675,28 @@ class CodeEditor {
|
|
|
3398
3675
|
[/this.([A-Za-z_][A-Za-z0-9_]*)\s*\=/, "class-property"],
|
|
3399
3676
|
];
|
|
3400
3677
|
|
|
3401
|
-
for( let [ regex, kind ] of usageRegexes )
|
|
3678
|
+
for( let [ regex, kind, fn ] of usageRegexes )
|
|
3402
3679
|
{
|
|
3403
3680
|
const m = text.match( regex );
|
|
3404
3681
|
if( m )
|
|
3405
3682
|
{
|
|
3406
|
-
|
|
3683
|
+
_pushSymbol( { name: fn ? fn( m ) : m[ 1 ], kind, scope: scopeName, line: lineNumber } );
|
|
3407
3684
|
}
|
|
3408
3685
|
}
|
|
3409
3686
|
|
|
3687
|
+
// Detect method calls
|
|
3688
|
+
const regex = /([A-Za-z0-9_]+)\s*\(/g;
|
|
3689
|
+
let match;
|
|
3690
|
+
while( match = regex.exec( text ) )
|
|
3691
|
+
{
|
|
3692
|
+
const name = match[ 1 ];
|
|
3693
|
+
const before = text.slice( 0, match.index );
|
|
3694
|
+
if( /(new|function|fn|def)\s+$/.test( before ) ) continue; // skip constructor calls
|
|
3695
|
+
if( [ "constructor", "location", ...( nativeTypes ?? [] ) ].indexOf( name ) > -1 ) continue; // skip hardcoded non method symbol
|
|
3696
|
+
if( previousLineScope && previousLineScope.at( -1 )?.type === "class" ) continue; // skip class methods
|
|
3697
|
+
_pushSymbol( { name, kind: "method-call", scope: scopeName, line: lineNumber } );
|
|
3698
|
+
}
|
|
3699
|
+
|
|
3410
3700
|
// Stop after matches for top-level declarations and usage symbols
|
|
3411
3701
|
if( symbols.length )
|
|
3412
3702
|
{
|
|
@@ -3425,14 +3715,15 @@ class CodeEditor {
|
|
|
3425
3715
|
{
|
|
3426
3716
|
if( next === "(" && /^[a-zA-Z_]\w*$/.test( token ) && prev === undefined )
|
|
3427
3717
|
{
|
|
3428
|
-
|
|
3718
|
+
if( token === "constructor" ) continue; // skip constructor symbol
|
|
3719
|
+
_pushSymbol( { name: token, kind: "method", scope: scopeName, line: lineNumber } );
|
|
3429
3720
|
}
|
|
3430
3721
|
}
|
|
3431
3722
|
else if( scopeType.startsWith("enum") )
|
|
3432
3723
|
{
|
|
3433
3724
|
if( !isSymbol( token ) && !this._isNumber( token ) && !this._mustHightlightWord( token, CodeEditor.statements ) )
|
|
3434
3725
|
{
|
|
3435
|
-
|
|
3726
|
+
_pushSymbol({ name: token, kind: "enum_value", scope: scopeName, line: lineNumber });
|
|
3436
3727
|
}
|
|
3437
3728
|
}
|
|
3438
3729
|
}
|
|
@@ -3547,13 +3838,14 @@ class CodeEditor {
|
|
|
3547
3838
|
let idx = 0;
|
|
3548
3839
|
while( subtokens.value != undefined )
|
|
3549
3840
|
{
|
|
3550
|
-
const _pt = lineString.substring(idx, subtokens.value.index);
|
|
3841
|
+
const _pt = lineString.substring( idx, subtokens.value.index );
|
|
3551
3842
|
if( _pt.length ) pushToken( _pt );
|
|
3552
3843
|
pushToken( subtokens.value[ 0 ] );
|
|
3553
3844
|
idx = subtokens.value.index + subtokens.value[ 0 ].length;
|
|
3554
3845
|
subtokens = iter.next();
|
|
3555
|
-
if(!subtokens.value)
|
|
3556
|
-
|
|
3846
|
+
if( !subtokens.value )
|
|
3847
|
+
{
|
|
3848
|
+
const _at = lineString.substring( idx );
|
|
3557
3849
|
if( _at.length ) pushToken( _at );
|
|
3558
3850
|
}
|
|
3559
3851
|
}
|
|
@@ -3620,6 +3912,22 @@ class CodeEditor {
|
|
|
3620
3912
|
offset = offsetIdx;
|
|
3621
3913
|
}
|
|
3622
3914
|
}
|
|
3915
|
+
else if( this.highlight == 'WGSL' )
|
|
3916
|
+
{
|
|
3917
|
+
let offset = 0;
|
|
3918
|
+
let atIdx = tokens.indexOf( '@' );
|
|
3919
|
+
|
|
3920
|
+
while( atIdx > -1 )
|
|
3921
|
+
{
|
|
3922
|
+
const offsetIdx = atIdx + offset;
|
|
3923
|
+
|
|
3924
|
+
tokens[ offsetIdx ] += ( tokens[ offsetIdx + 1 ] ?? "" );
|
|
3925
|
+
tokens.splice( offsetIdx + 1, 1 );
|
|
3926
|
+
|
|
3927
|
+
atIdx = tokens.slice( offsetIdx ).indexOf( '$' );
|
|
3928
|
+
offset = offsetIdx;
|
|
3929
|
+
}
|
|
3930
|
+
}
|
|
3623
3931
|
|
|
3624
3932
|
return tokens;
|
|
3625
3933
|
}
|
|
@@ -3664,10 +3972,12 @@ class CodeEditor {
|
|
|
3664
3972
|
|
|
3665
3973
|
let { token, prev, next, tokenIndex, isFirstToken, isLastToken } = ctxData;
|
|
3666
3974
|
|
|
3667
|
-
const lang = CodeEditor.languages[ this.highlight ]
|
|
3668
|
-
|
|
3669
|
-
|
|
3670
|
-
|
|
3975
|
+
const lang = CodeEditor.languages[ this.highlight ];
|
|
3976
|
+
const highlight = this.highlight.replace( /\s/g, '' ).replaceAll( "+", "p" ).toLowerCase();
|
|
3977
|
+
const customStringKeys = Object.assign( {}, this.stringKeys );
|
|
3978
|
+
const lineNumber = this._currentLineNumber;
|
|
3979
|
+
const tokenStartIndex = this._currentTokenPositions[ tokenIndex ];
|
|
3980
|
+
const inBlockComment = ( this._buildingBlockComment ?? this._inBlockCommentSection( lineNumber, tokenStartIndex, token.length ) !== undefined )
|
|
3671
3981
|
|
|
3672
3982
|
var usePreviousTokenToCheckString = false;
|
|
3673
3983
|
|
|
@@ -3685,7 +3995,7 @@ class CodeEditor {
|
|
|
3685
3995
|
// Manage strings
|
|
3686
3996
|
this._stringEnded = false;
|
|
3687
3997
|
|
|
3688
|
-
if( usePreviousTokenToCheckString || (
|
|
3998
|
+
if( usePreviousTokenToCheckString || ( !inBlockComment && ( lang.tags ?? false ? ( this._enclosedByTokens( token, tokenIndex, '<', '>' ) ) : true ) ) )
|
|
3689
3999
|
{
|
|
3690
4000
|
const _checkIfStringEnded = t => {
|
|
3691
4001
|
const idx = Object.values( customStringKeys ).indexOf( t );
|
|
@@ -3711,9 +4021,9 @@ class CodeEditor {
|
|
|
3711
4021
|
|
|
3712
4022
|
// Update context data for next tests
|
|
3713
4023
|
ctxData.discardToken = false;
|
|
3714
|
-
ctxData.inBlockComment =
|
|
4024
|
+
ctxData.inBlockComment = inBlockComment;
|
|
3715
4025
|
ctxData.markdownHeader = this._markdownHeader;
|
|
3716
|
-
ctxData.inString = this._buildingString;
|
|
4026
|
+
ctxData.inString = ( this._buildingString !== undefined );
|
|
3717
4027
|
ctxData.singleLineCommentToken = lang.singleLineCommentToken ?? this.defaultSingleLineCommentToken;
|
|
3718
4028
|
ctxData.lang = lang;
|
|
3719
4029
|
ctxData.scope = this._scopeStack.at( -1 );
|
|
@@ -3728,16 +4038,8 @@ class CodeEditor {
|
|
|
3728
4038
|
// Get highlighting class based on language common and specific rules
|
|
3729
4039
|
let tokenClass = this._getTokenHighlighting( ctxData, highlight );
|
|
3730
4040
|
|
|
3731
|
-
const blockCommentsTokens = lang.blockCommentsTokens ?? this.defaultBlockCommentTokens;
|
|
3732
|
-
if( ( lang.blockComments ?? true ) && this._buildingBlockComment != undefined
|
|
3733
|
-
&& token.substr( 0, blockCommentsTokens[ 1 ].length ) == blockCommentsTokens[ 1 ] )
|
|
3734
|
-
{
|
|
3735
|
-
this._blockCommentCache.push( new LX.vec2( this._buildingBlockComment, lineNumber ) );
|
|
3736
|
-
delete this._buildingBlockComment;
|
|
3737
|
-
}
|
|
3738
|
-
|
|
3739
4041
|
// We finished constructing a string
|
|
3740
|
-
if( this._buildingString && ( this._stringEnded || isLastToken ) )
|
|
4042
|
+
if( this._buildingString && ( this._stringEnded || isLastToken ) && !inBlockComment )
|
|
3741
4043
|
{
|
|
3742
4044
|
token = this._getCurrentString();
|
|
3743
4045
|
tokenClass = "cm-str";
|
|
@@ -3801,17 +4103,32 @@ class CodeEditor {
|
|
|
3801
4103
|
}
|
|
3802
4104
|
}
|
|
3803
4105
|
|
|
3804
|
-
_inBlockCommentSection(
|
|
4106
|
+
_inBlockCommentSection( lineNumber, tokenPosition, tokenLength ) {
|
|
4107
|
+
|
|
4108
|
+
const lang = CodeEditor.languages[ this.highlight ];
|
|
4109
|
+
const blockCommentsTokens = lang.blockCommentsTokens ?? this.defaultBlockCommentTokens;
|
|
3805
4110
|
|
|
3806
|
-
for(
|
|
4111
|
+
for( let section of this._blockCommentCache )
|
|
3807
4112
|
{
|
|
3808
|
-
|
|
4113
|
+
const lineRange = section[ 0 ];
|
|
4114
|
+
const posRange = section[ 1 ];
|
|
4115
|
+
|
|
4116
|
+
// Outside the lines range
|
|
4117
|
+
const meetsLineRange = ( lineNumber >= lineRange.x && lineNumber <= lineRange.y );
|
|
4118
|
+
if( !meetsLineRange )
|
|
3809
4119
|
{
|
|
3810
|
-
|
|
4120
|
+
continue;
|
|
3811
4121
|
}
|
|
3812
|
-
}
|
|
3813
4122
|
|
|
3814
|
-
|
|
4123
|
+
if( ( lineNumber != lineRange.x && lineNumber != lineRange.y ) || // Inside the block, not first nor last line
|
|
4124
|
+
( lineNumber == lineRange.x && tokenPosition >= posRange.x &&
|
|
4125
|
+
(( lineNumber == lineRange.y && ( tokenPosition + tokenLength ) <= ( posRange.y + blockCommentsTokens[ 1 ].length ) ) || lineNumber !== lineRange.y) ) ||
|
|
4126
|
+
( lineNumber == lineRange.y && ( ( tokenPosition + tokenLength ) <= ( posRange.y + blockCommentsTokens[ 1 ].length ) ) ) &&
|
|
4127
|
+
(( lineNumber == lineRange.x && tokenPosition >= posRange.x ) || lineNumber !== lineRange.x) )
|
|
4128
|
+
{
|
|
4129
|
+
return section;
|
|
4130
|
+
}
|
|
4131
|
+
}
|
|
3815
4132
|
}
|
|
3816
4133
|
|
|
3817
4134
|
_isKeyword( ctxData ) {
|
|
@@ -4479,7 +4796,7 @@ class CodeEditor {
|
|
|
4479
4796
|
|
|
4480
4797
|
if( flag & CodeEditor.RESIZE_SCROLLBAR_V )
|
|
4481
4798
|
{
|
|
4482
|
-
scrollHeight = this.code.lines.length * this.lineHeight
|
|
4799
|
+
scrollHeight = this.code.lines.length * this.lineHeight;
|
|
4483
4800
|
this.codeSizer.style.minHeight = scrollHeight + "px";
|
|
4484
4801
|
}
|
|
4485
4802
|
|
|
@@ -4538,7 +4855,7 @@ class CodeEditor {
|
|
|
4538
4855
|
}
|
|
4539
4856
|
|
|
4540
4857
|
this.hScrollbar.root.classList.toggle( 'hidden', !needsHorizontalScrollbar );
|
|
4541
|
-
this.codeArea.root.style.height = `calc(100% - ${ this.
|
|
4858
|
+
this.codeArea.root.style.height = `calc(100% - ${ this._fullVerticalOffset + ( needsHorizontalScrollbar ? ScrollBar.SCROLLBAR_HORIZONTAL_HEIGHT : 0 ) }px)`;
|
|
4542
4859
|
}
|
|
4543
4860
|
}
|
|
4544
4861
|
|
|
@@ -4754,8 +5071,6 @@ class CodeEditor {
|
|
|
4754
5071
|
...Array.from( CodeEditor.utils[ this.highlight ] ?? [] )
|
|
4755
5072
|
];
|
|
4756
5073
|
|
|
4757
|
-
suggestions = suggestions.concat( Object.keys(this.code.tokens).filter( a => a != word ) );
|
|
4758
|
-
|
|
4759
5074
|
const scopeStack = [ ...this.code.lineScopes[ cursor.line ] ];
|
|
4760
5075
|
const scope = scopeStack.at( -1 );
|
|
4761
5076
|
if( scope.type.startsWith( "enum" ) )
|
|
@@ -4769,10 +5084,8 @@ class CodeEditor {
|
|
|
4769
5084
|
suggestions = suggestions.concat( otherValues.slice( 0, -1 ) );
|
|
4770
5085
|
}
|
|
4771
5086
|
|
|
4772
|
-
const prefix = word.toLowerCase();
|
|
4773
|
-
|
|
4774
5087
|
// Remove 1/2 char words and duplicates...
|
|
4775
|
-
suggestions = Array.from( new Set( suggestions )).filter( s => s.length > 2 && s.toLowerCase().includes(
|
|
5088
|
+
suggestions = Array.from( new Set( suggestions )).filter( s => s.length > 2 && s.toLowerCase().includes( word.toLowerCase() ) );
|
|
4776
5089
|
|
|
4777
5090
|
// Order...
|
|
4778
5091
|
|
|
@@ -4782,21 +5095,49 @@ class CodeEditor {
|
|
|
4782
5095
|
return 2; // worst
|
|
4783
5096
|
}
|
|
4784
5097
|
|
|
4785
|
-
suggestions = suggestions.sort( ( a, b ) => scoreSuggestion( a,
|
|
5098
|
+
suggestions = suggestions.sort( ( a, b ) => ( scoreSuggestion( a, word ) - scoreSuggestion( b, word ) ) || a.localeCompare( b ) );
|
|
4786
5099
|
|
|
4787
5100
|
for( let s of suggestions )
|
|
4788
5101
|
{
|
|
4789
|
-
|
|
5102
|
+
const pre = document.createElement( 'pre' );
|
|
4790
5103
|
this.autocomplete.appendChild( pre );
|
|
4791
5104
|
|
|
4792
|
-
|
|
4793
|
-
if( this._mustHightlightWord( s, CodeEditor.utils ) )
|
|
4794
|
-
icon = "Box";
|
|
4795
|
-
else if( this._mustHightlightWord( s, CodeEditor.types ) )
|
|
4796
|
-
icon = "Code";
|
|
5105
|
+
const symbol = this.code.symbolsTable.get( s );
|
|
4797
5106
|
|
|
4798
|
-
|
|
5107
|
+
let iconName = "CaseLower";
|
|
5108
|
+
let iconClass = "foo";
|
|
5109
|
+
|
|
5110
|
+
if( symbol )
|
|
5111
|
+
{
|
|
5112
|
+
switch( symbol[ 0 ].kind ) // Get first occurrence
|
|
5113
|
+
{
|
|
5114
|
+
case "variable":
|
|
5115
|
+
iconName = "Cuboid";
|
|
5116
|
+
iconClass = "lightblue";
|
|
5117
|
+
break;
|
|
5118
|
+
case "method":
|
|
5119
|
+
iconName = "Box";
|
|
5120
|
+
iconClass = "heliotrope";
|
|
5121
|
+
break;
|
|
5122
|
+
case "class":
|
|
5123
|
+
iconName = "CircleNodes";
|
|
5124
|
+
iconClass = "orange";
|
|
5125
|
+
break;
|
|
5126
|
+
}
|
|
5127
|
+
}
|
|
5128
|
+
else
|
|
5129
|
+
{
|
|
5130
|
+
if( this._mustHightlightWord( s, CodeEditor.utils ) )
|
|
5131
|
+
iconName = "ToolCase";
|
|
5132
|
+
else if( this._mustHightlightWord( s, CodeEditor.types ) )
|
|
5133
|
+
{
|
|
5134
|
+
iconName = "Type";
|
|
5135
|
+
iconClass = "lightblue";
|
|
5136
|
+
}
|
|
5137
|
+
}
|
|
4799
5138
|
|
|
5139
|
+
pre.appendChild( LX.makeIcon( iconName, { iconClass: "mr-1", svgClass: "sm " + iconClass } ) );
|
|
5140
|
+
s
|
|
4800
5141
|
pre.addEventListener( 'click', () => {
|
|
4801
5142
|
this.autoCompleteWord( s );
|
|
4802
5143
|
} );
|
|
@@ -5284,7 +5625,8 @@ CodeEditor.languages = {
|
|
|
5284
5625
|
};
|
|
5285
5626
|
|
|
5286
5627
|
CodeEditor.nativeTypes = {
|
|
5287
|
-
'C++': ['int', 'float', 'double', 'bool', 'long', 'short', 'char', 'wchar_t', 'void']
|
|
5628
|
+
'C++': ['int', 'float', 'double', 'bool', 'long', 'short', 'char', 'wchar_t', 'void'],
|
|
5629
|
+
'WGSL': ['bool', 'u32', 'i32', 'f16', 'f32', 'vec2', 'vec3', 'vec4', 'vec2f', 'vec3f', 'vec4f', 'mat2x2f', 'mat3x3f', 'mat4x4f', 'array', 'vec2u', 'vec3u', 'vec4u', 'ptr', 'sampler']
|
|
5288
5630
|
};
|
|
5289
5631
|
|
|
5290
5632
|
CodeEditor.declarationKeywords = {
|
|
@@ -5308,10 +5650,9 @@ CodeEditor.keywords = {
|
|
|
5308
5650
|
'GLSL': ['true', 'false', 'function', 'int', 'float', 'vec2', 'vec3', 'vec4', 'mat2x2', 'mat3x3', 'mat4x4', 'struct'],
|
|
5309
5651
|
'CSS': ['body', 'html', 'canvas', 'div', 'input', 'span', '.', 'table', 'tr', 'td', 'th', 'label', 'video', 'img', 'code', 'button', 'select', 'option', 'svg', 'media', 'all',
|
|
5310
5652
|
'i', 'a', 'li', 'h1', 'h2', 'h3', 'h4', 'h5', 'last-child', 'tbody', 'pre', 'monospace', 'font-face'],
|
|
5311
|
-
'WGSL': ['var', 'let', 'true', 'false', 'fn', '
|
|
5312
|
-
'
|
|
5313
|
-
'
|
|
5314
|
-
'texture_storage_2d_array', 'texture_storage_3d', 'vec2u', 'vec3u', 'vec4u', 'ptr'],
|
|
5653
|
+
'WGSL': [...CodeEditor.nativeTypes["WGSL"], 'var', 'let', 'true', 'false', 'fn', 'atomic', 'struct', 'sampler_comparison', 'texture_depth_2d', 'texture_depth_2d_array', 'texture_depth_cube',
|
|
5654
|
+
'texture_depth_cube_array', 'texture_depth_multisampled_2d', 'texture_external', 'texture_1d', 'texture_2d', 'texture_2d_array', 'texture_3d', 'texture_cube', 'texture_cube_array',
|
|
5655
|
+
'texture_storage_1d', 'texture_storage_2d', 'texture_storage_2d_array', 'texture_storage_3d'],
|
|
5315
5656
|
'Rust': ['as', 'const', 'crate', 'enum', 'extern', 'false', 'fn', 'impl', 'in', 'let', 'mod', 'move', 'mut', 'pub', 'ref', 'self', 'Self', 'static', 'struct', 'super', 'trait', 'true',
|
|
5316
5657
|
'type', 'unsafe', 'use', 'where', 'abstract', 'become', 'box', 'final', 'macro', 'override', 'priv', 'typeof', 'unsized', 'virtual'],
|
|
5317
5658
|
'Python': ['False', 'def', 'None', 'True', 'in', 'is', 'and', 'lambda', 'nonlocal', 'not', 'or'],
|
|
@@ -5330,7 +5671,14 @@ CodeEditor.utils = { // These ones don't have hightlight, used as suggestions to
|
|
|
5330
5671
|
'Python': ['abs', 'all', 'any', 'ascii', 'bin', 'bool', 'bytearray', 'bytes', 'callable', 'chr', 'classmethod', 'compile', 'complex', 'delattr', 'dict', 'dir', 'divmod',
|
|
5331
5672
|
'enumerate', 'eval', 'exec', 'filter', 'float', 'format', 'frozenset', 'getattr', 'globals', 'hasattr', 'hash', 'help', 'hex', 'id', 'input', 'int', 'isinstance',
|
|
5332
5673
|
'issubclass', 'iter', 'len', 'list', 'locals', 'map', 'max', 'memoryview', 'min', 'next', 'object', 'oct', 'open', 'ord', 'pow', 'print', 'property', 'range', 'repr',
|
|
5333
|
-
'reversed', 'round', 'set', 'setattr', 'slice', 'sorted', 'staticmethod', 'str', 'sum', 'super', 'tuple', 'type', 'vars', 'zip']
|
|
5674
|
+
'reversed', 'round', 'set', 'setattr', 'slice', 'sorted', 'staticmethod', 'str', 'sum', 'super', 'tuple', 'type', 'vars', 'zip'],
|
|
5675
|
+
'CSS': [ ...Object.keys( document.body.style ).map( LX.toKebabCase ), 'block', 'inline', 'inline-block', 'flex', 'grid', 'none', 'inherit', 'initial', 'unset', 'revert', 'sticky',
|
|
5676
|
+
'relative', 'absolute', 'fixed', 'static', 'auto', 'visible', 'hidden', 'scroll', 'clip', 'ellipsis', 'nowrap', 'wrap', 'break-word', 'solid', 'dashed', 'dotted', 'double',
|
|
5677
|
+
'groove', 'ridge', 'inset', 'outset', 'left', 'right', 'center', 'top', 'bottom', 'start', 'end', 'justify', 'stretch', 'space-between', 'space-around', 'space-evenly',
|
|
5678
|
+
'baseline', 'middle', 'normal', 'bold', 'lighter', 'bolder', 'italic', 'blur', 'uppercase', 'lowercase', 'capitalize', 'transparent', 'currentColor', 'pointer', 'default',
|
|
5679
|
+
'move', 'grab', 'grabbing', 'not-allowed', 'none', 'cover', 'contain', 'repeat', 'no-repeat', 'repeat-x', 'repeat-y', 'round', 'space', 'linear-gradient', 'radial-gradient',
|
|
5680
|
+
'conic-gradient', 'url', 'calc', 'min', 'max', 'clamp', 'red', 'blue', 'green', 'black', 'white', 'gray', 'silver', 'yellow', 'orange', 'purple', 'pink', 'cyan', 'magenta',
|
|
5681
|
+
'lime', 'teal', 'navy', 'transparent', 'currentcolor', 'inherit', 'initial', 'unset', 'revert', 'none', 'auto', 'fit-content', 'min-content', 'max-content']
|
|
5334
5682
|
};
|
|
5335
5683
|
|
|
5336
5684
|
CodeEditor.types = {
|
|
@@ -5351,6 +5699,7 @@ CodeEditor.builtIn = {
|
|
|
5351
5699
|
'JavaScript': ['document', 'console', 'window', 'navigator', 'performance'],
|
|
5352
5700
|
'CSS': ['*', '!important'],
|
|
5353
5701
|
'C++': ['vector', 'list', 'map'],
|
|
5702
|
+
'WGSL': ['@vertex', '@fragment'],
|
|
5354
5703
|
'HTML': ['type', 'xmlns', 'PUBLIC', 'http-equiv', 'src', 'style', 'lang', 'href', 'rel', 'content', 'xml', 'alt'], // attributes
|
|
5355
5704
|
'Markdown': ['type', 'src', 'style', 'lang', 'href', 'rel', 'content', 'valign', 'alt'], // attributes
|
|
5356
5705
|
'PHP': ['echo', 'print'],
|