@@ -120,12 +120,68 @@ export class CodeEditor {
120120
121121 this . listenToTabChange ( ) ;
122122 this . setSelectedTabOnTutorialChange ( ) ;
123+ this . listenToFileOpenRequests ( ) ;
123124 } ) ;
124125
125126 cleanupFn ( ( ) => this . codeMirrorEditor . disable ( ) ) ;
126127 } ) ;
127128 }
128129
130+ private listenToFileOpenRequests ( ) {
131+ // Handler for opening files at specific locations
132+ const openFile = ( file : string , line : number , character : number ) => {
133+ // Normalize the file path - Vite uses /app/... but editor uses src/app/...
134+ let normalizedPath = file ;
135+ if ( file . startsWith ( '/' ) ) {
136+ // Remove leading slash and prepend 'src'
137+ normalizedPath = 'src' + file ;
138+ }
139+
140+ // Find the file in the files list
141+ const targetFile = this . files ( ) . find ( ( f ) => f . filename === normalizedPath ) ;
142+ if ( targetFile ) {
143+ // Switch to the file's tab
144+ const fileIndex = this . files ( ) . indexOf ( targetFile ) ;
145+ this . matTabGroup ( ) . selectedIndex = fileIndex ;
146+
147+ // Explicitly change the current file in the editor
148+ this . codeMirrorEditor . changeCurrentFile ( targetFile . filename ) ;
149+
150+ // Wait for the tab to switch and file to load, then scroll to the line
151+ setTimeout ( ( ) => {
152+ this . codeMirrorEditor . scrollToLine ( line - 1 , character ) ; // Convert to 0-based
153+ } , 200 ) ;
154+ } else {
155+ // console.warn('File not found in editor:', normalizedPath);
156+ }
157+ } ;
158+
159+ // Listen for CustomEvent (backward compatibility)
160+ const handleCustomEvent = ( event : Event ) => {
161+ const customEvent = event as CustomEvent < { file : string ; line : number ; character : number } > ;
162+ const { file, line, character} = customEvent . detail ;
163+ openFile ( file , line , character ) ;
164+ } ;
165+
166+ // Listen for postMessage from preview iframe (Vite error overlay)
167+ const handlePostMessage = ( event : MessageEvent ) => {
168+ // Check if this is an openFileAtLocation message
169+ if ( event . data ?. type === 'openFileAtLocation' ) {
170+ const { file, line, character} = event . data ;
171+ openFile ( file , line , character ) ;
172+ }
173+ } ;
174+
175+ window . addEventListener ( 'openFileAtLocation' , handleCustomEvent ) ;
176+ window . addEventListener ( 'message' , handlePostMessage ) ;
177+
178+ // Cleanup listeners on destroy
179+ this . destroyRef . onDestroy ( ( ) => {
180+ window . removeEventListener ( 'openFileAtLocation' , handleCustomEvent ) ;
181+ window . removeEventListener ( 'message' , handlePostMessage ) ;
182+ } ) ;
183+ }
184+
129185 protected openCurrentSolutionInFirebaseStudio ( ) : void {
130186 this . firebaseStudioLauncher . openCurrentSolutionInFirebaseStudio ( ) ;
131187 }
0 commit comments