lexgui 0.6.5 → 0.6.7

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.
@@ -221,8 +221,9 @@ class CodeEditor {
221
221
 
222
222
  static __instances = [];
223
223
 
224
- static CURSOR_LEFT = 1;
225
- static CURSOR_TOP = 2;
224
+ static CURSOR_LEFT = 1;
225
+ static CURSOR_TOP = 2;
226
+ static CURSOR_LEFT_TOP = CodeEditor.CURSOR_LEFT | CodeEditor.CURSOR_TOP;
226
227
 
227
228
  static SELECTION_X = 1;
228
229
  static SELECTION_Y = 2
@@ -265,8 +266,6 @@ class CodeEditor {
265
266
 
266
267
  panel.addTitle( "EXPLORER" );
267
268
 
268
- this._tabStorage = {};
269
-
270
269
  let sceneData = {
271
270
  'id': 'WORKSPACE',
272
271
  'skipVisibility': true,
@@ -320,6 +319,7 @@ class CodeEditor {
320
319
  this.skipInfo = options.skipInfo ?? false;
321
320
  this.disableEdition = options.disableEdition ?? false;
322
321
 
322
+ this._tabStorage = {};
323
323
  this.tabs = this.area.addTabs( { onclose: (name) => {
324
324
  delete this.openedTabs[ name ];
325
325
  if( Object.keys( this.openedTabs ).length < 2 )
@@ -976,7 +976,7 @@ class CodeEditor {
976
976
  }
977
977
  else {
978
978
  cursor.selection.invertIfNecessary();
979
- this.resetCursorPos( CodeEditor.CURSOR_LEFT | CodeEditor.CURSOR_TOP, cursor );
979
+ this.resetCursorPos( CodeEditor.CURSOR_LEFT_TOP, cursor );
980
980
  this.cursorToLine( cursor, cursor.selection.fromY, true );
981
981
  this.cursorToPosition( cursor, cursor.selection.fromX );
982
982
  this.endSelection();
@@ -1057,7 +1057,7 @@ class CodeEditor {
1057
1057
  else
1058
1058
  {
1059
1059
  cursor.selection.invertIfNecessary();
1060
- this.resetCursorPos( CodeEditor.CURSOR_LEFT | CodeEditor.CURSOR_TOP, cursor );
1060
+ this.resetCursorPos( CodeEditor.CURSOR_LEFT_TOP, cursor );
1061
1061
  this.cursorToLine( cursor, cursor.selection.toY );
1062
1062
  this.cursorToPosition( cursor, cursor.selection.toX );
1063
1063
  this.endSelection();
@@ -1090,7 +1090,7 @@ class CodeEditor {
1090
1090
  this.addTab("+", false, "New File");
1091
1091
  }
1092
1092
 
1093
- this.addTab( options.name || "untitled", true, options.title, { language: "Plain Text" } );
1093
+ this.addTab( options.name || "untitled", true, options.title, { language: options.highlight ?? "Plain Text" } );
1094
1094
 
1095
1095
  // Create inspector panel
1096
1096
  let panel = this._createPanelInfo();
@@ -1771,7 +1771,7 @@ class CodeEditor {
1771
1771
  if( selected )
1772
1772
  {
1773
1773
  this.code = code;
1774
- this.resetCursorPos( CodeEditor.CURSOR_LEFT | CodeEditor.CURSOR_TOP );
1774
+ this.resetCursorPos( CodeEditor.CURSOR_LEFT_TOP );
1775
1775
  this.processLines();
1776
1776
  }
1777
1777
 
@@ -1845,10 +1845,26 @@ class CodeEditor {
1845
1845
 
1846
1846
  // Select as current...
1847
1847
  this.code = code;
1848
- this.resetCursorPos( CodeEditor.CURSOR_LEFT | CodeEditor.CURSOR_TOP );
1848
+ this.resetCursorPos( CodeEditor.CURSOR_LEFT_TOP );
1849
1849
  this.processLines();
1850
1850
  this._changeLanguageFromExtension( LX.getExtension( name ) );
1851
- this._updateDataInfoPanel( "@tab-name", code.tabname );
1851
+ this._updateDataInfoPanel( "@tab-name", code.tabName );
1852
+ }
1853
+
1854
+ closeTab( name, eraseAll ) {
1855
+
1856
+ this.tabs.delete( name );
1857
+
1858
+ if( eraseAll )
1859
+ {
1860
+ delete this.openedTabs[ name ];
1861
+ delete this.loadedTabs[ name ];
1862
+ delete this._tabStorage[ name ];
1863
+ }
1864
+ }
1865
+
1866
+ getSelectedTabName() {
1867
+ return this.tabs.selected;
1852
1868
  }
1853
1869
 
1854
1870
  loadTabFromFile() {
@@ -3491,7 +3507,7 @@ class CodeEditor {
3491
3507
  this._removeSecondaryCursors();
3492
3508
 
3493
3509
  var cursor = this._getCurrentCursor();
3494
- this.resetCursorPos( CodeEditor.CURSOR_LEFT | CodeEditor.CURSOR_TOP, cursor );
3510
+ this.resetCursorPos( CodeEditor.CURSOR_LEFT_TOP, cursor );
3495
3511
 
3496
3512
  this.startSelection( cursor );
3497
3513
 
@@ -0,0 +1,425 @@
1
+ // @jxarco
2
+
3
+ import { LX } from 'lexgui';
4
+
5
+ if( !LX )
6
+ {
7
+ throw( "lexgui.js missing!" );
8
+ }
9
+
10
+ const CPP_KEY_WORDS = ['int', 'float', 'double', 'bool', 'char', 'wchar_t', 'const', 'static_cast', 'dynamic_cast', 'new', 'delete', 'void', 'true', 'false', 'auto', 'struct', 'typedef', 'nullptr', 'NULL', 'unsigned', 'namespace'];
11
+ const CLASS_WORDS = ['uint32_t', 'uint64_t', 'uint8_t'];
12
+ const STATEMENT_WORDS = ['for', 'if', 'else', 'return', 'continue', 'break', 'case', 'switch', 'while', 'import', 'from'];
13
+
14
+ const JS_KEY_WORDS = ['var', 'let', 'const', 'static', 'function', 'null', 'undefined', 'new', 'delete', 'true', 'false', 'NaN', 'this'];
15
+ const HTML_ATTRIBUTES = ['html', 'charset', 'rel', 'src', 'href', 'crossorigin', 'type', 'lang'];
16
+ const HTML_TAGS = ['html', 'DOCTYPE', 'head', 'meta', 'title', 'link', 'script', 'body', 'style'];
17
+
18
+ let mainContainer = document.body;
19
+
20
+ function SET_DOM_TARGET( element )
21
+ {
22
+ mainContainer = element;
23
+ }
24
+
25
+ window.SET_DOM_TARGET = SET_DOM_TARGET;
26
+
27
+ function MAKE_LINE_BREAK()
28
+ {
29
+ mainContainer.appendChild( document.createElement('br') );
30
+ }
31
+
32
+ window.MAKE_LINE_BREAK = MAKE_LINE_BREAK;
33
+
34
+ function MAKE_HEADER( string, type, id )
35
+ {
36
+ console.assert(string && type);
37
+ let header = document.createElement(type);
38
+ header.innerHTML = string;
39
+ if(id) header.id = id;
40
+ mainContainer.appendChild( header );
41
+ }
42
+
43
+ window.MAKE_HEADER = MAKE_HEADER;
44
+
45
+ function MAKE_PARAGRAPH( string, sup )
46
+ {
47
+ console.assert(string);
48
+ let paragraph = document.createElement(sup ? 'sup' : 'p');
49
+ paragraph.className = "leading-relaxed";
50
+ paragraph.innerHTML = string;
51
+ mainContainer.appendChild( paragraph );
52
+ }
53
+
54
+ window.MAKE_PARAGRAPH = MAKE_PARAGRAPH;
55
+
56
+ function MAKE_CODE( text, language = "js" )
57
+ {
58
+ console.assert(text);
59
+
60
+ text.replaceAll('<', '&lt;');
61
+ text.replaceAll('>', '&gt;');
62
+
63
+ let highlight = "";
64
+ let content = "";
65
+
66
+ const getHTML = ( h, c ) => {
67
+ return `<span class="${ h }">${ c }</span>`;
68
+ };
69
+
70
+ for( let i = 0; i < text.length; ++i )
71
+ {
72
+ const char = text[ i ];
73
+ const string = text.substr( i );
74
+
75
+ const endLineIdx = string.indexOf( '\n' );
76
+ const line = string.substring( 0, endLineIdx > -1 ? endLineIdx : undefined );
77
+
78
+ if( char == '@' )
79
+ {
80
+ const str = line.substr( 1 );
81
+
82
+ if ( !( str.indexOf( '@' ) > -1 ) && !( str.indexOf( '[' ) > -1 ) )
83
+ {
84
+ continue;
85
+ }
86
+
87
+ let html = null;
88
+
89
+ const tagIndex = str.indexOf( '@' );
90
+ const skipTag = ( str[ tagIndex - 1 ] == '|' );
91
+
92
+ // Highlight is specified
93
+ if( text[ i + 1 ] == '[' )
94
+ {
95
+ highlight = str.substr( 1, 3 );
96
+ content = str.substring( 5, tagIndex );
97
+
98
+ if( skipTag )
99
+ {
100
+ const newString = str.substring( 6 + content.length );
101
+ const preContent = content;
102
+ const postContent = newString.substring( 0, newString.indexOf( '@' ) );
103
+ const finalContent = preContent.substring( 0, preContent.length - 1 ) + '@' + postContent;
104
+ html = getHTML( highlight, finalContent );
105
+
106
+ const ogContent = preContent + '@' + postContent;
107
+ text = text.replace( `@[${ highlight }]${ ogContent }@`, html );
108
+ }
109
+ else
110
+ {
111
+ html = getHTML( highlight, content );
112
+ text = text.replace( `@[${ highlight }]${ content }@`, html );
113
+ }
114
+ }
115
+ else
116
+ {
117
+ content = str.substring( 0, tagIndex );
118
+ if( skipTag )
119
+ {
120
+ const preContent = str.substring( 0, str.indexOf( '@' ) - 1 );
121
+ content = str.substring( preContent.length + 1 );
122
+ content = preContent + content.substring( 0, content.substring( 1 ).indexOf( '@' ) + 1 );
123
+ text = text.substr( 0, i ) + '@' + content + '@' + text.substr( i + content.length + 3 );
124
+ }
125
+
126
+ if( language == "cpp" && CPP_KEY_WORDS.includes( content ) )
127
+ {
128
+ highlight = "kwd";
129
+ }
130
+ else if( language == "js" && JS_KEY_WORDS.includes( content ) )
131
+ {
132
+ highlight = "kwd";
133
+ }
134
+ else if( CLASS_WORDS.includes( content ) )
135
+ {
136
+ highlight = "cls";
137
+ }
138
+ else if( STATEMENT_WORDS.includes( content ) )
139
+ {
140
+ highlight = "lit";
141
+ }
142
+ else if( HTML_TAGS.includes( content ) )
143
+ {
144
+ highlight = "tag";
145
+ }
146
+ else if( HTML_ATTRIBUTES.includes( content ) )
147
+ {
148
+ highlight = "atn";
149
+ }
150
+ else if( ( content[ 0 ] == '"' && content[ content.length - 1 ] == '"' ) ||
151
+ ( content[ 0 ] == "'" && content[ content.length - 1 ] == "'" ) ||
152
+ ( content[ 0 ] == "`" && content[ content.length - 1 ] == "`" ) )
153
+ {
154
+ highlight = "str";
155
+ }
156
+ else if( parseFloat( content ) != NaN )
157
+ {
158
+ highlight = "dec";
159
+ }
160
+ else
161
+ {
162
+ console.error( "ERROR[Code Parsing]: Unknown highlight type: " + content );
163
+ return;
164
+ }
165
+
166
+ html = getHTML( highlight, content );
167
+ text = text.replace( `@${ content }@`, html );
168
+ }
169
+
170
+ i += ( html.length - 1 );
171
+ }
172
+ }
173
+
174
+ let container = document.createElement('div');
175
+ container.className = "code-container";
176
+ let pre = document.createElement('pre');
177
+ let code = document.createElement('code');
178
+ code.innerHTML = text;
179
+
180
+ let button = document.createElement('button');
181
+ button.title = "Copy code sample";
182
+ button.appendChild(LX.makeIcon( "Copy" ));
183
+ button.addEventListener('click', COPY_SNIPPET.bind(this, button));
184
+ container.appendChild( button );
185
+
186
+ pre.appendChild( code );
187
+ container.appendChild( pre );
188
+ mainContainer.appendChild( container );
189
+ }
190
+
191
+ window.MAKE_CODE = MAKE_CODE;
192
+
193
+ function MAKE_LIST( list, type )
194
+ {
195
+ const validTypes = [ 'bullet', 'numbered' ];
196
+ console.assert( list && list.length > 0 && validTypes.includes(type), "Invalid list type or empty list" + type );
197
+ const typeString = type == 'bullet' ? 'ul' : 'ol';
198
+ let ul = document.createElement( typeString );
199
+ for( var el of list ) {
200
+ let li = document.createElement( 'li' );
201
+ li.className = "leading-loose";
202
+ li.innerHTML = el;
203
+ ul.appendChild( li );
204
+ }
205
+ mainContainer.appendChild( ul );
206
+ }
207
+
208
+ function MAKE_BULLET_LIST( list )
209
+ {
210
+ MAKE_LIST( list, 'bullet' );
211
+ }
212
+
213
+ window.MAKE_BULLET_LIST = MAKE_BULLET_LIST;
214
+
215
+ function MAKE_NUMBERED_LIST( list )
216
+ {
217
+ MAKE_LIST( list, 'numbered' );
218
+ }
219
+
220
+ window.MAKE_NUMBERED_LIST = MAKE_NUMBERED_LIST;
221
+
222
+ function ADD_CODE_LIST_ITEM( item, target )
223
+ {
224
+ target = target ?? window.listQueued;
225
+ let split = (item.constructor === Array);
226
+ if( split && item[0].constructor === Array ) {
227
+ MAKE_CODE_BULLET_LIST( item, target );
228
+ return;
229
+ }
230
+ let li = document.createElement('li');
231
+ li.className = "leading-loose";
232
+ li.innerHTML = split ? ( item.length == 2 ? INLINE_CODE( item[0] ) + ": " + item[1] : INLINE_CODE( item[0] + " <span class='desc'>(" + item[1] + ")</span>" ) + ": " + item[2] ) : INLINE_CODE( item );
233
+ target.appendChild( li );
234
+ }
235
+
236
+ window.ADD_CODE_LIST_ITEM = ADD_CODE_LIST_ITEM;
237
+
238
+ function MAKE_CLASS_METHOD( name, desc, params, ret )
239
+ {
240
+ START_CODE_BULLET_LIST();
241
+ let paramsHTML = "";
242
+ for( var p of params ) {
243
+ const name = p[ 0 ];
244
+ const type = p[ 1 ];
245
+ paramsHTML += name + ": <span class='desc'>" + type + "</span>" + ( params.indexOf( p ) != (params.length - 1) ? ', ' : '' );
246
+ }
247
+ let li = document.createElement('li');
248
+ li.innerHTML = INLINE_CODE( "<span class='method'>" + name + " (" + paramsHTML + ")" + ( ret ? (": " + ret) : "" ) + "</span>" );
249
+ window.listQueued.appendChild( li );
250
+ END_CODE_BULLET_LIST();
251
+ MAKE_PARAGRAPH( desc );
252
+ }
253
+
254
+ window.MAKE_CLASS_METHOD = MAKE_CLASS_METHOD;
255
+
256
+ function MAKE_CLASS_CONSTRUCTOR( name, params, language = "js" )
257
+ {
258
+ let paramsHTML = "";
259
+ for( var p of params ) {
260
+ const str1 = p[ 0 ]; // cpp: param js: name
261
+ const str2 = p[ 1 ]; // cpp: defaultValue js: type
262
+ if( language == "cpp" ) {
263
+ paramsHTML += str1 + ( str2 ? " = <span class='desc'>" + str2 + "</span>" : "" ) + ( params.indexOf( p ) != (params.length - 1) ? ', ' : '' );
264
+ } else if( language == "js" ) {
265
+ paramsHTML += str1 + ": <span class='desc'>" + str2 + "</span>" + ( params.indexOf( p ) != (params.length - 1) ? ', ' : '' );
266
+ }
267
+ }
268
+ let pr = document.createElement('p');
269
+ pr.innerHTML = INLINE_CODE( "<span class='constructor'>" + name + "(" + paramsHTML + ")" + "</span>" );
270
+ mainContainer.appendChild( pr );
271
+ }
272
+
273
+ window.MAKE_CLASS_CONSTRUCTOR = MAKE_CLASS_CONSTRUCTOR;
274
+
275
+ function MAKE_CODE_BULLET_LIST( list, target )
276
+ {
277
+ console.assert(list && list.length > 0);
278
+ let ul = document.createElement('ul');
279
+ for( var el of list ) {
280
+ ADD_CODE_LIST_ITEM( el, ul );
281
+ }
282
+ if( target ) {
283
+ target.appendChild( ul );
284
+ } else {
285
+ mainContainer.appendChild( ul );
286
+ }
287
+ }
288
+
289
+ window.MAKE_CODE_BULLET_LIST = MAKE_CODE_BULLET_LIST;
290
+
291
+ function START_CODE_BULLET_LIST()
292
+ {
293
+ let ul = document.createElement('ul');
294
+ window.listQueued = ul;
295
+ }
296
+
297
+ window.START_CODE_BULLET_LIST = START_CODE_BULLET_LIST;
298
+
299
+ function END_CODE_BULLET_LIST()
300
+ {
301
+ console.assert( window.listQueued );
302
+ mainContainer.appendChild( window.listQueued );
303
+ window.listQueued = undefined;
304
+ }
305
+
306
+ window.END_CODE_BULLET_LIST = END_CODE_BULLET_LIST;
307
+
308
+ function INLINE_LINK( string, href )
309
+ {
310
+ console.assert(string && href);
311
+ return `<a href="` + href + `">` + string + `</a>`;
312
+ }
313
+
314
+ window.INLINE_LINK = INLINE_LINK;
315
+
316
+ function INLINE_PAGE( string, page )
317
+ {
318
+ console.assert(string && page);
319
+ return `<a onclick="loadPage('` + page + `')">` + string + `</a>`;
320
+ }
321
+
322
+ window.INLINE_PAGE = INLINE_PAGE;
323
+
324
+ function INLINE_CODE( string, codeClass )
325
+ {
326
+ console.assert(string);
327
+ return `<code class="inline ${ codeClass ?? "" }">` + string + `</code>`;
328
+ }
329
+
330
+ window.INLINE_CODE = INLINE_CODE;
331
+
332
+ function COPY_SNIPPET( b )
333
+ {
334
+ b.innerHTML = "";
335
+ b.appendChild(LX.makeIcon( "Check" ));
336
+ b.classList.add('copied');
337
+
338
+ setTimeout( () => {
339
+ b.innerHTML = "";
340
+ b.appendChild(LX.makeIcon( "Copy" ));
341
+ b.classList.remove('copied');
342
+ }, 2000 );
343
+
344
+ navigator.clipboard.writeText( b.dataset['snippet'] ?? b.parentElement.innerText );
345
+ console.log("Copied!");
346
+ }
347
+
348
+ function INSERT_IMAGE( src, caption = "", parent )
349
+ {
350
+ let img = document.createElement('img');
351
+ img.src = src;
352
+ img.alt = caption;
353
+ img.className = "my-1";
354
+ ( parent ?? mainContainer ).appendChild( img );
355
+ }
356
+
357
+ window.INSERT_IMAGE = INSERT_IMAGE;
358
+
359
+ function INSERT_IMAGES( sources, captions = [], width, height )
360
+ {
361
+ const mobile = navigator && /Android|iPhone/i.test(navigator.userAgent);
362
+
363
+ if( !mobile )
364
+ {
365
+ let div = document.createElement('div');
366
+ div.style.width = width ?? "auto";
367
+ div.style.height = height ?? "256px";
368
+ div.className = "flex flex-row justify-center";
369
+
370
+ for( let i = 0; i < sources.length; ++i )
371
+ {
372
+ INSERT_IMAGE( sources[ i ], captions[ i ], div );
373
+ }
374
+
375
+ mainContainer.appendChild( div );
376
+ }
377
+ else
378
+ {
379
+ for( let i = 0; i < sources.length; ++i )
380
+ {
381
+ INSERT_IMAGE( sources[ i ], captions[ i ] );
382
+ }
383
+ }
384
+ }
385
+
386
+ window.INSERT_IMAGES = INSERT_IMAGES;
387
+
388
+ function INSERT_VIDEO( src, caption = "", controls = true, autoplay = false )
389
+ {
390
+ let video = document.createElement( 'video' );
391
+ video.src = src;
392
+ video.controls = controls;
393
+ video.autoplay = autoplay;
394
+ if( autoplay )
395
+ {
396
+ video.muted = true;
397
+ }
398
+ video.loop = true;
399
+ video.alt = caption;
400
+ mainContainer.appendChild( video );
401
+ }
402
+
403
+ window.INSERT_VIDEO = INSERT_VIDEO;
404
+
405
+ function MAKE_NOTE( string, warning, title, icon )
406
+ {
407
+ console.assert( string );
408
+
409
+ const note = LX.makeContainer( [], "border rounded-lg overflow-hidden text-md fg-secondary my-6", "", mainContainer );
410
+
411
+ let header = document.createElement( 'div' );
412
+ header.className = "flex bg-tertiary font-semibold px-3 py-2 gap-2 fg-secondary";
413
+ header.appendChild( LX.makeIcon( icon ?? ( warning ? "MessageSquareWarning" : "NotepadText" ) ) );
414
+ header.innerHTML += ( title ?? ( warning ? "Important" : "Note" ) );
415
+ note.appendChild( header );
416
+
417
+ const body = LX.makeContainer( [], "leading-6 p-3", string, note );
418
+ }
419
+
420
+ window.MAKE_NOTE = MAKE_NOTE;
421
+
422
+ export { SET_DOM_TARGET, MAKE_LINE_BREAK, MAKE_HEADER, MAKE_PARAGRAPH, MAKE_CODE, MAKE_BULLET_LIST,
423
+ MAKE_CLASS_METHOD, MAKE_CLASS_CONSTRUCTOR, MAKE_CODE_BULLET_LIST, START_CODE_BULLET_LIST, ADD_CODE_LIST_ITEM,
424
+ END_CODE_BULLET_LIST, INLINE_LINK, INLINE_PAGE, INLINE_CODE, INSERT_IMAGE, INSERT_IMAGES, INSERT_VIDEO, MAKE_NOTE
425
+ }