interface RegistryEntry { suffix: string; editor: string; } export class FileEditorRegistry { static readonly DefaultEntries: RegistryEntry[] = [ { suffix: 'rojo', editor: 'RojoSettingsPanel' }, { suffix: 'html', editor: 'HTMLEditorPanel' }, { suffix: 'htm', editor: 'HTMLEditorPanel' }, { suffix: 'js', editor: 'CodePanel' }, { suffix: 'ts', editor: 'CodePanel' }, { suffix: 'css', editor: 'CodePanel' }, { suffix: 'json', editor: 'CodePanel' }, { suffix: 'md', editor: 'CodePanel' }, { suffix: 'txt', editor: 'CodePanel' }, { suffix: 'svg', editor: 'CodePanel' }, { suffix: 'xml', editor: 'CodePanel' }, { suffix: 'yaml', editor: 'CodePanel' }, { suffix: 'yml', editor: 'CodePanel' }, { suffix: 'sh', editor: 'CodePanel' }, { suffix: 'py', editor: 'CodePanel' }, { suffix: 'cs', editor: 'CodePanel' }, { suffix: 'gd', editor: 'CodePanel' }, { suffix: 'gdshader', editor: 'CodePanel' }, { suffix: 'gdshaderinc', editor: 'CodePanel' }, { suffix: 'gdinclude', editor: 'CodePanel' }, { suffix: 'glsl', editor: 'CodePanel' }, { suffix: 'tscn', editor: 'CodePanel' }, { suffix: 'tres', editor: 'CodePanel' }, { suffix: 'gdextension', editor: 'CodePanel' }, ]; static readonly EditorTagNames: Record = { 'RojoSettingsPanel': 'rojo-settings-panel', 'HTMLEditorPanel': 'html-editor-panel', 'CodePanel': 'code-panel', }; projectEntries: RegistryEntry[] | null = null; _loaded = false; async load( projectId: string ): Promise { if ( this._loaded ) return; this._loaded = true; try { const res = await fetch( `/api/files/${projectId}/workspace/editor/file-editors.json` ); if ( ! res.ok ) return; const data = await res.json(); if ( Array.isArray( data ) ) this.projectEntries = data; } catch {} } resolve( filePath: string ): string | null { const filename = filePath.slice( filePath.lastIndexOf( '/' ) + 1 ); if ( this.projectEntries !== null ) { const editor = this._matchSuffix( filename, this.projectEntries ); if ( editor !== null ) return this._resolveTag( editor ); } const editor = this._matchSuffix( filename, FileEditorRegistry.DefaultEntries ); if ( editor !== null ) return this._resolveTag( editor ); return null; } _resolveTag( editorName: string ): string { return FileEditorRegistry.EditorTagNames[ editorName ] ?? editorName; } _matchSuffix( filename: string, entries: RegistryEntry[] ): string | null { for ( const entry of entries ) { if ( filename.endsWith( '.' + entry.suffix ) ) { return entry.editor; } } return null; } }