@@ -1034,6 +1034,7 @@ const {
10341034 mslDownloadUrl,
10351035 standardMslLoaded,
10361036 loadedLibraryCachePaths,
1037+ latestLazyLibraryClassTree,
10371038 downloadMslZipToOpfs,
10381039 loadCachedMslZipFromOpfs,
10391040 loadStandardMslZipFromOpfs,
@@ -1061,6 +1062,44 @@ const globalProcessBusy = computed(() => workerBusy.value || Boolean(libraryBusy
10611062const globalProcessLabel = computed (
10621063 () => libraryBusyLabel .value || workerBusyLabel .value || ' Processing' ,
10631064)
1065+ const lastAppliedLazyLibraryTreeSignature = ref (' ' )
1066+
1067+ function applyLazyLibraryTreeToEditor(): boolean {
1068+ if (latestLazyLibraryClassTree .value .length === 0 ) return false
1069+ const treeSignature = latestLazyLibraryClassTree .value
1070+ .map ((node ) => String (node .qualified_name || node .name || ' ' ))
1071+ .join (' |' )
1072+ if (
1073+ treeSignature &&
1074+ treeSignature === lastAppliedLazyLibraryTreeSignature .value &&
1075+ libraryTreeNodes .value .length > 0
1076+ ) {
1077+ return true
1078+ }
1079+ const mappedNodes = mapRumocaClassTree (latestLazyLibraryClassTree .value )
1080+ lastAppliedLazyLibraryTreeSignature .value = treeSignature
1081+ libraryTreeNodes .value = mappedNodes
1082+ standardMslLoaded .value = mappedNodes .some ((node ) => node .qualifiedName === ' Modelica' )
1083+ appendModelicaLog ({
1084+ level: ' success' ,
1085+ phase: ' general' ,
1086+ message: ` Loaded Modelica library tree from lazy index: ${mappedNodes .length } root nodes ` ,
1087+ details: {
1088+ lazyRootNodeCount: latestLazyLibraryClassTree .value .length ,
1089+ rootNodeCount: mappedNodes .length ,
1090+ standardMslLoaded: standardMslLoaded .value ,
1091+ },
1092+ })
1093+ return true
1094+ }
1095+
1096+ watch (
1097+ latestLazyLibraryClassTree ,
1098+ () => {
1099+ applyLazyLibraryTreeToEditor ()
1100+ },
1101+ { flush: ' sync' },
1102+ )
10641103
10651104const fileNameFromPath = (path : string ): string => {
10661105 const normalized = String (path || ' ' )
@@ -1756,6 +1795,19 @@ const phaseForWorkerRequestType = (type: string): WorkerLiveLogEntry['phase'] =>
17561795 return ' general'
17571796}
17581797
1798+ const shouldLogWorkerCompletion = (event : ModelicaWorkerActivityEvent ): boolean => {
1799+ if (event .status === ' failed' ) return true
1800+ if ((event .elapsedMs ?? 0 ) >= 1000 ) return true
1801+ return [
1802+ ' extract_diagram' ,
1803+ ' materialize_diagram_classes' ,
1804+ ' load_msl_zip' ,
1805+ ' merge_msl_zip' ,
1806+ ' restore_source_root_binary_cache' ,
1807+ ' list_classes' ,
1808+ ].includes (event .requestType )
1809+ }
1810+
17591811function onWorkerActivity(event : ModelicaWorkerActivityEvent ) {
17601812 if (event .requestType === ' lsp_completion_with_timing' ) return
17611813 if (event .status === ' started' ) {
@@ -1782,6 +1834,21 @@ function onWorkerActivity(event: ModelicaWorkerActivityEvent) {
17821834 workerLiveEntries .value = workerLiveEntries .value .filter (
17831835 (entry ) => entry .requestId !== event .requestId ,
17841836 )
1837+ if (shouldLogWorkerCompletion (event )) {
1838+ appendModelicaLog ({
1839+ level: event .status === ' failed' ? ' error' : ' info' ,
1840+ phase: phaseForWorkerRequestType (event .requestType ),
1841+ message:
1842+ event .status === ' failed'
1843+ ? ` ${event .label } failed after ${event .elapsedMs ?? 0 } ms: ${event .error ?? ' unknown error' } `
1844+ : ` ${event .label } finished in ${event .elapsedMs ?? 0 } ms ` ,
1845+ details: {
1846+ requestId: event .requestId ,
1847+ requestType: event .requestType ,
1848+ elapsedMs: event .elapsedMs ,
1849+ },
1850+ })
1851+ }
17851852}
17861853
17871854onMounted (() => {
@@ -3077,23 +3144,49 @@ const clearAll = () => {
30773144}
30783145
30793146async function refreshLibraryTree() {
3147+ if (applyLazyLibraryTreeToEditor ()) return
30803148 const worker = modelicaWorker .value
30813149 if (! worker ) {
30823150 libraryTreeNodes .value = []
30833151 standardMslLoaded .value = false
30843152 return
30853153 }
3154+ const startedAt = performance .now ()
30863155 try {
3156+ appendModelicaLog ({
3157+ level: ' info' ,
3158+ phase: ' general' ,
3159+ message: ' Refreshing Modelica library tree' ,
3160+ details: {
3161+ existingRootNodeCount: libraryTreeNodes .value .length ,
3162+ },
3163+ })
30873164 const raw = await worker .listClasses ()
3165+ const listClassesMs = Math .round (performance .now () - startedAt )
3166+ const mapStartedAt = performance .now ()
30883167 const mappedNodes = mapRumocaClassTree (raw .classes )
3168+ const mapTreeMs = Math .round (performance .now () - mapStartedAt )
3169+ const rawClassCount = Array .isArray (raw .classes ) ? raw .classes .length : 0
30893170 libraryTreeNodes .value = mappedNodes
30903171 standardMslLoaded .value = mappedNodes .some ((node ) => node .qualifiedName === ' Modelica' )
3172+ appendModelicaLog ({
3173+ level: ' success' ,
3174+ phase: ' general' ,
3175+ message: ` Refreshed Modelica library tree in ${Math .round (performance .now () - startedAt )} ms: ${mappedNodes .length } root nodes ` ,
3176+ details: {
3177+ listClassesMs ,
3178+ mapTreeMs ,
3179+ rawClassCount ,
3180+ rootNodeCount: mappedNodes .length ,
3181+ standardMslLoaded: standardMslLoaded .value ,
3182+ },
3183+ })
30913184 } catch (error ) {
30923185 standardMslLoaded .value = false
30933186 appendModelicaLog ({
30943187 level: ' warning' ,
30953188 phase: ' general' ,
3096- message: ` Failed to refresh library tree: ${(error as Error ).message } ` ,
3189+ message: ` Failed to refresh library tree after ${ Math . round ( performance . now () - startedAt )} ms : ${(error as Error ).message } ` ,
30973190 })
30983191 }
30993192}
@@ -3698,6 +3791,12 @@ const stopExecution = () => {
36983791}
36993792
37003793onMounted (async () => {
3794+ const mountedStartedAt = performance .now ()
3795+ appendModelicaLog ({
3796+ level: ' info' ,
3797+ phase: ' general' ,
3798+ message: ' Modelica editor startup: begin state hydration' ,
3799+ })
37013800 // 1) Global state (not bound to a specific model)
37023801 // - layout
37033802 // - template editor state
@@ -3720,6 +3819,17 @@ onMounted(async () => {
37203819 showAllInPrompt ,
37213820 currentProjectId ,
37223821 })
3822+ appendModelicaLog ({
3823+ level: ' info' ,
3824+ phase: ' general' ,
3825+ message: ` Modelica editor startup: global state hydrated in ${Math .round (performance .now () - mountedStartedAt )} ms ` ,
3826+ details: {
3827+ useModelicaStandardLibrary: useModelicaStandardLibrary .value ,
3828+ requiredLibraryCount: requiredLibraries .value .length ,
3829+ mslCachedZipPath: mslCachedZipPath .value ,
3830+ standardMslCachedZipPath: standardMslCachedZipPath .value ,
3831+ },
3832+ })
37233833 if (layoutContainsLegacyWorkbenchViews (initialLayout .value )) {
37243834 initialLayout .value = createDefaultLayout ()
37253835 }
@@ -3731,6 +3841,15 @@ onMounted(async () => {
37313841 await syncStateWithOPFSFolder (` modelicaProject_${currentProjectId .value } ` , {
37323842 projectFile ,
37333843 })
3844+ appendModelicaLog ({
3845+ level: ' info' ,
3846+ phase: ' general' ,
3847+ message: ` Modelica editor startup: project state hydrated in ${Math .round (performance .now () - mountedStartedAt )} ms ` ,
3848+ details: {
3849+ currentProjectId: currentProjectId .value ,
3850+ hasProjectFile: Boolean (projectFile .value ),
3851+ },
3852+ })
37343853
37353854 // Hydrate project state into the editor
37363855 try {
@@ -3787,6 +3906,17 @@ onMounted(async () => {
37873906
37883907 // Initial project discovery
37893908 await refreshAvailableProjects ()
3909+ appendModelicaLog ({
3910+ level: ' info' ,
3911+ phase: ' general' ,
3912+ message: ` Modelica editor startup: project discovery finished in ${Math .round (performance .now () - mountedStartedAt )} ms ` ,
3913+ details: {
3914+ availableProjectCount: availableProjectIds .value .length ,
3915+ currentProjectId: currentProjectId .value ,
3916+ useModelicaStandardLibrary: useModelicaStandardLibrary .value ,
3917+ requiredLibraries: requiredLibraries .value ,
3918+ },
3919+ })
37903920 // Keep projectFile updated when the editor changes (OPFS will persist it)
37913921 watchDebounced (
37923922 [
@@ -3831,11 +3961,23 @@ onMounted(async () => {
38313961 }
38323962
38333963 const initModelicaWorker = async (): Promise <ModelicaWorkerClient > => {
3964+ const startedAt = performance .now ()
3965+ const requestedThreads = getRequestedWorkerThreads ()
3966+ appendModelicaLog ({
3967+ level: ' info' ,
3968+ phase: ' loadWasm' ,
3969+ message: ` Initializing Modelica worker (requested threads=${requestedThreads }) ` ,
3970+ details: {
3971+ crossOriginIsolated: globalThis .crossOriginIsolated === true ,
3972+ hardwareConcurrency:
3973+ typeof navigator !== ' undefined' ? navigator .hardwareConcurrency : undefined ,
3974+ },
3975+ })
38343976 const worker = new ModelicaWorkerClient ()
38353977 modelicaWorker .value = worker
38363978 unsubscribeWorkerActivity ?.()
38373979 unsubscribeWorkerActivity = worker .onActivity (onWorkerActivity )
3838- const initInfo = await worker .init (getRequestedWorkerThreads () )
3980+ const initInfo = await worker .init (requestedThreads )
38393981 configureModelicaLspExtensions (worker )
38403982 wasmLoaded .value = true
38413983 if (initInfo .version ) rumocaWasmVersion .value = initInfo .version
@@ -3849,15 +3991,53 @@ onMounted(async () => {
38493991 rumocaSimulationModelDiscoveryAvailable .value = Boolean (
38503992 initInfo .simulationModelDiscoveryAvailable ,
38513993 )
3994+ appendModelicaLog ({
3995+ level: ' success' ,
3996+ phase: ' loadWasm' ,
3997+ message: ` Initialized Modelica worker in ${Math .round (performance .now () - startedAt )} ms ` ,
3998+ details: {
3999+ requestedThreads ,
4000+ rayonEnabled: initInfo .rayonEnabled ,
4001+ version: initInfo .version ,
4002+ gitCommit: initInfo .gitCommit ,
4003+ simulationAvailable: initInfo .simulationAvailable ,
4004+ simulationModelDiscoveryAvailable: initInfo .simulationModelDiscoveryAvailable ,
4005+ },
4006+ })
38524007 return worker
38534008 }
38544009
38554010 // 3) Modelica worker
38564011 try {
4012+ const workerStartupStartedAt = performance .now ()
38574013 const worker = await initModelicaWorker ()
4014+ const documentCountStartedAt = performance .now ()
38584015 const documentCount = await worker .getSourceRootDocumentCount ()
4016+ appendModelicaLog ({
4017+ level: ' info' ,
4018+ phase: ' general' ,
4019+ message: ` Checked Modelica worker source-root document count in ${Math .round (performance .now () - documentCountStartedAt )} ms: ${documentCount } ` ,
4020+ details: {
4021+ documentCount ,
4022+ useModelicaStandardLibrary: useModelicaStandardLibrary .value ,
4023+ requiredLibraries: requiredLibraries .value ,
4024+ },
4025+ })
38594026 const persistedLibraryLoadRequested =
38604027 Boolean (useModelicaStandardLibrary .value ) || requiredLibraries .value .length > 0
4028+ appendModelicaLog ({
4029+ level: ' info' ,
4030+ phase: ' general' ,
4031+ message: persistedLibraryLoadRequested
4032+ ? ' Modelica editor startup: persisted library load requested'
4033+ : ' Modelica editor startup: no persisted library load requested' ,
4034+ details: {
4035+ documentCount ,
4036+ useModelicaStandardLibrary: useModelicaStandardLibrary .value ,
4037+ requiredLibraries: requiredLibraries .value ,
4038+ mslCachedZipPath: mslCachedZipPath .value ,
4039+ },
4040+ })
38614041 if (documentCount > 0 && persistedLibraryLoadRequested ) {
38624042 mslLoaded .value = true
38634043 mslFileCount .value = documentCount
@@ -3893,7 +4073,7 @@ onMounted(async () => {
38934073 appendModelicaLog ({
38944074 level: ' success' ,
38954075 phase: ' general' ,
3896- message: ' Modelica worker loaded successfully! Ready to compile.' ,
4076+ message: ` Modelica worker loaded successfully in ${ Math . round ( performance . now () - workerStartupStartedAt )} ms ! Ready to compile. ` ,
38974077 })
38984078 } catch (error ) {
38994079 appendModelicaLog ({
0 commit comments