11import { useRef , useEffect , useState } from "react" ;
22import { Editor } from "@monaco-editor/react" ;
33import * as monaco from "monaco-editor" ;
4+ import { MonacoBinding } from "y-monaco" ;
45import {
56 useEditorCollaboration ,
67 type CollaborationUser ,
78} from "../../../Contexts/EditorContext" ;
89import { useTheme } from "../../../Contexts/ThemeProvider" ;
910import type { FileNode } from "../ProjectManagementPanel/file.types" ;
1011import CollaborativeCursor from "./CollaborativeCursor" ;
11- import { VFSMonacoIntegration } from "../../../lib/integration/vfs-monaco-integration" ;
12- import { useFileTree } from "../ProjectManagementPanel/useFileTree" ;
13-
14- // Import our modular functions
15- import {
16- configureMonacoBeforeMount ,
17- configureMonacoLanguageServices ,
18- } from "./modules/monaco-config" ;
19- import {
20- setupVFSWithMonacoTypeScript ,
21- registerVFSCompletionProviders ,
22- } from "./modules/monaco-vfs-setup" ;
23- import {
24- updateMonacoDiagnostics ,
25- createDebouncedDiagnostics ,
26- type DiagnosticsCount ,
27- } from "./modules/monaco-diagnostics" ;
28- import {
29- bindEditorToFile ,
30- setupCollaborationListeners ,
31- cleanupCollaboration ,
32- type CollaborationRefs ,
33- } from "./modules/monaco-collaboration" ;
34- import { getLanguageFromFileName } from "./modules/monaco-utils" ;
3512
3613interface MonacoEditorProps {
3714 selectedFile ?: FileNode | null ;
@@ -45,9 +22,7 @@ export default function MonacoEditor({
4522 onFileContentChange,
4623} : MonacoEditorProps ) {
4724 const { theme } = useTheme ( ) ;
48- const { vfsBridge } = useFileTree ( ) ;
4925
50- // Refs
5126 const editorRef = useRef < monaco . editor . IStandaloneCodeEditor | null > ( null ) ;
5227 const currentBindingRef = useRef < MonacoBinding | null > ( null ) ;
5328 const currentFileRef = useRef < string | null > ( null ) ;
@@ -66,12 +41,10 @@ export default function MonacoEditor({
6641 updateCursorPosition,
6742 } = useEditorCollaboration ( ) ;
6843
69- // Handle file changes
7044 useEffect ( ( ) => {
7145 setFileUsers ( [ ] ) ;
7246
73- if ( selectedFile && selectedFile . type === "file" ) {
74- // Update language first
47+ if ( selectedFile && selectedFile . type === "file" && editorRef . current ) {
7548 setLanguage ( getLanguageFromFileName ( selectedFile . name ) ) ;
7649
7750 if ( currentFileRef . current !== selectedFile . id ) {
@@ -163,37 +136,55 @@ export default function MonacoEditor({
163136 const handleEditorDidMount = (
164137 editorInstance : monaco . editor . IStandaloneCodeEditor
165138 ) : void => {
166- try {
167- editorRef . current = editorInstance ;
168- console . log ( "Monaco Editor mounted successfully" ) ;
169-
170- // Configure Monaco language services
171- configureMonacoLanguageServices ( ) ;
172-
173- // Set up VFS integration with Monaco TypeScript service
174- setupVFSWithMonacoTypeScript ( vfsBridge , integrationRef ) ;
139+ editorRef . current = editorInstance ;
175140
176- // Register VFS completion providers
177- registerVFSCompletionProviders ( integrationRef ) ;
178-
179- // Set up initial content
180- if ( selectedFile && selectedFile . type === "file" ) {
181- // Bind to the selected file
182- bindEditorToFile (
183- selectedFile ,
184- editorRef ,
185- collaborationRefs ,
186- collaborationService ,
187- vfsBridge ,
188- onFileContentChange ,
189- debouncedUpdateDiagnostics
190- ) ;
141+ if ( selectedFile && selectedFile . type === "file" ) {
142+ bindEditorToFile ( selectedFile ) ;
143+ } else {
144+ // Set placeholder content
145+ const model = editorInstance . getModel ( ) ;
146+ if ( model ) {
147+ model . setValue ( initialValue ) ;
191148 }
192- } catch ( error ) {
193- console . error ( "Error in handleEditorDidMount:" , error ) ;
194149 }
195150 } ;
196151
152+ const getLanguageFromFileName = ( fileName : string ) : string => {
153+ const extension = fileName . split ( "." ) . pop ( ) ?. toLowerCase ( ) ;
154+ const languageMap : Record < string , string > = {
155+ js : "javascript" ,
156+ jsx : "javascript" ,
157+ ts : "typescript" ,
158+ tsx : "typescript" ,
159+ py : "python" ,
160+ java : "java" ,
161+ json : "json" ,
162+ md : "markdown" ,
163+ html : "html" ,
164+ css : "css" ,
165+ scss : "scss" ,
166+ sass : "sass" ,
167+ less : "less" ,
168+ xml : "xml" ,
169+ yaml : "yaml" ,
170+ yml : "yaml" ,
171+ sql : "sql" ,
172+ sh : "shell" ,
173+ bash : "shell" ,
174+ php : "php" ,
175+ rb : "ruby" ,
176+ go : "go" ,
177+ rs : "rust" ,
178+ cpp : "cpp" ,
179+ c : "c" ,
180+ cs : "csharp" ,
181+ kt : "kotlin" ,
182+ swift : "swift" ,
183+ dart : "dart" ,
184+ } ;
185+ return languageMap [ extension || "" ] || "plaintext" ;
186+ } ;
187+
197188 const getDisplayContent = ( ) => {
198189 if ( selectedFile ?. type === "file" ) {
199190 // For files, let the binding handle the content
@@ -219,18 +210,6 @@ export default function MonacoEditor({
219210 < div className = "flex items-center gap-2" >
220211 < span className = { `text-sm ${ theme . text } ` } > { selectedFile . name } </ span >
221212 < span className = { `text-xs ${ theme . textMuted } ` } > ({ language } )</ span >
222- { diagnosticsCount . errors > 0 && (
223- < span className = "text-red-500 text-xs" >
224- { diagnosticsCount . errors } error
225- { diagnosticsCount . errors !== 1 ? "s" : "" }
226- </ span >
227- ) }
228- { diagnosticsCount . warnings > 0 && (
229- < span className = "text-yellow-500 text-xs" >
230- { diagnosticsCount . warnings } warning
231- { diagnosticsCount . warnings !== 1 ? "s" : "" }
232- </ span >
233- ) }
234213 </ div >
235214
236215 < div className = "flex items-center gap-2" >
@@ -274,104 +253,37 @@ export default function MonacoEditor({
274253
275254 { /* Editor */ }
276255 < div className = "flex-1" >
277- < div style = { { height : "100%" } } >
278- < Editor
279- height = "100%"
280- language = { language }
281- theme = { theme . monacoTheme }
282- // Use key to force re-render when file changes
283- key = { selectedFile ?. id || "no-file" }
284- defaultValue = { getDisplayContent ( ) }
285- onMount = { handleEditorDidMount }
286- beforeMount = { configureMonacoBeforeMount }
287- options = { {
288- minimap : { enabled : true } ,
289- fontSize : 14 ,
290- lineNumbers : "on" ,
291- roundedSelection : false ,
292- scrollBeyondLastLine : false ,
293- automaticLayout : true ,
294- wordWrap : "on" ,
295- tabSize : 2 ,
296- insertSpaces : true ,
297- formatOnPaste : true ,
298- formatOnType : true ,
299- suggestOnTriggerCharacters : true ,
300- acceptSuggestionOnEnter : "on" ,
301- quickSuggestions : {
302- other : true ,
303- comments : true ,
304- strings : true ,
305- } ,
306- autoClosingBrackets : "always" ,
307- autoClosingQuotes : "always" ,
308- autoIndent : "full" ,
309- bracketPairColorization : { enabled : true } ,
310- codeLens : true ,
311- colorDecorators : true ,
312- cursorBlinking : "blink" ,
313- cursorSmoothCaretAnimation : "on" ,
314- definitionLinkOpensInPeek : false ,
315- dragAndDrop : true ,
316- folding : true ,
317- foldingHighlight : true ,
318- foldingStrategy : "auto" ,
319- fontLigatures : true ,
320- guides : {
321- bracketPairs : "active" ,
322- highlightActiveIndentation : true ,
323- indentation : true ,
324- } ,
325- hover : { enabled : true } ,
326- inlineSuggest : { enabled : true } ,
327- lightbulb : { enabled : "on" as any } ,
328- links : true ,
329- mouseWheelZoom : true ,
330- occurrencesHighlight : "singleFile" ,
331- overviewRulerBorder : true ,
332- parameterHints : { enabled : true } ,
333- peekWidgetDefaultFocus : "editor" ,
334- renderLineHighlight : "line" ,
335- renderWhitespace : "selection" ,
336- showFoldingControls : "mouseover" ,
337- smoothScrolling : true ,
338- snippetSuggestions : "top" ,
339- suggest : {
340- showWords : false ,
341- showMethods : true ,
342- showFunctions : true ,
343- showConstructors : true ,
344- showFields : true ,
345- showVariables : true ,
346- showClasses : true ,
347- showStructs : true ,
348- showInterfaces : true ,
349- showModules : true ,
350- showProperties : true ,
351- showEvents : true ,
352- showOperators : true ,
353- showUnits : true ,
354- showValues : true ,
355- showConstants : true ,
356- showEnums : true ,
357- showEnumMembers : true ,
358- showKeywords : true ,
359- showColors : true ,
360- showFiles : true ,
361- showReferences : true ,
362- showFolders : true ,
363- showTypeParameters : true ,
364- showIssues : true ,
365- showUsers : true ,
366- showSnippets : true ,
367- } ,
368- renderValidationDecorations : "on" ,
369- useTabStops : true ,
370- // Show read-only when no file is selected
371- readOnly : ! selectedFile || selectedFile . type !== "file" ,
372- } }
373- />
374- </ div >
256+ < Editor
257+ height = "100%"
258+ language = { language }
259+ theme = { theme . monacoTheme }
260+ // Use key to force re-render when file changes
261+ key = { selectedFile ?. id || "no-file" }
262+ defaultValue = { getDisplayContent ( ) }
263+ onMount = { handleEditorDidMount }
264+ options = { {
265+ minimap : { enabled : true } ,
266+ fontSize : 14 ,
267+ lineNumbers : "on" ,
268+ roundedSelection : false ,
269+ scrollBeyondLastLine : false ,
270+ automaticLayout : true ,
271+ wordWrap : "on" ,
272+ tabSize : 2 ,
273+ insertSpaces : true ,
274+ formatOnPaste : true ,
275+ formatOnType : true ,
276+ suggestOnTriggerCharacters : true ,
277+ acceptSuggestionOnEnter : "on" ,
278+ quickSuggestions : {
279+ other : true ,
280+ comments : true ,
281+ strings : true ,
282+ } ,
283+ // Show read-only when no file is selected
284+ readOnly : ! selectedFile || selectedFile . type !== "file" ,
285+ } }
286+ />
375287 </ div >
376288
377289 { /* Placeholder when no file is selected */ }
0 commit comments