Skip to content

Commit 85464a9

Browse files
committed
Use ymap to observe language changes
1 parent 45cbf1e commit 85464a9

File tree

1 file changed

+33
-25
lines changed

1 file changed

+33
-25
lines changed

frontend/src/domain/context/CollaborationContext.tsx

Lines changed: 33 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,19 @@ export const CollaborationProvider: React.FC<{ children: ReactNode }> = ({ child
3030
const bindingRef = useRef<MonacoBinding | null>(null);
3131
const providerRef = useRef<WebsocketProvider | null>(null);
3232
const ydocRef = useRef<Y.Doc | null>(null);
33+
const yMapRef = useRef<Y.Map<string> | null>(null);
3334

3435
const initialiseEditor = (roomId: string, editor: monaco.editor.IStandaloneCodeEditor, monaco: Monaco) => {
3536
editorRef.current = editor;
3637
monacoRef.current = monaco;
38+
39+
initialiseLanguages(monaco);
40+
const { yDoc, provider, yMap } = initialiseYdoc(roomId);
41+
bindEditorToDoc(editor, yDoc, provider);
42+
setUpObserver(yMap);
43+
};
44+
45+
const initialiseLanguages = (monaco: Monaco) => {
3746
const allLanguages = monaco.languages.getLanguages();
3847

3948
// TODO: Filter all the useless ones like HTML
@@ -43,61 +52,60 @@ export const CollaborationProvider: React.FC<{ children: ReactNode }> = ({ child
4352
value: lang.id
4453
}))
4554
);
55+
};
4656

47-
const doc = new Y.Doc();
48-
ydocRef.current = doc;
49-
57+
const initialiseYdoc = (roomId: string): { yDoc: Y.Doc; yMap: Y.Map<string>; provider: WebsocketProvider } => {
58+
const yDoc = new Y.Doc();
59+
const yMap: Y.Map<string> = yDoc.getMap("sharedMap");
60+
ydocRef.current = yDoc;
61+
yMapRef.current = yMap;
5062
// TODO: Replace serverUrl once BE ready
5163
// Test locally across browers with 'HOST=localhost PORT 1234 npx y-websocket'
52-
const provider = new WebsocketProvider("ws://localhost:1234", roomId, doc);
64+
const provider = new WebsocketProvider("ws://localhost:1234", roomId, yDoc);
5365
provider.on("status", (event: any) => {
5466
console.log(event.status);
5567
});
5668
providerRef.current = provider;
57-
const type = doc.getText("monaco");
58-
const editorModel = editor.getModel();
69+
return { yDoc, yMap, provider };
70+
};
5971

72+
const bindEditorToDoc = (editor: monaco.editor.IStandaloneCodeEditor, yDoc: Y.Doc, provider: WebsocketProvider) => {
73+
const type = yDoc.getText("monaco");
74+
const editorModel = editor.getModel();
6075
if (editorModel == null) {
6176
toast.error("There was an issue with initialising the code editor");
6277
return;
6378
}
6479
const binding = new MonacoBinding(type, editorModel, new Set([editor]), provider.awareness);
6580
bindingRef.current = binding;
81+
};
6682

67-
// Initialise awareness states
68-
provider.awareness.setLocalStateField(USER_ID, userId);
69-
70-
// TODO: initialise with correct language on page reload
71-
provider.awareness.setLocalStateField(SELECTED_LANGUAGE, selectedLanguage);
72-
73-
provider.awareness.on("change", ({ updated }: { updated: any }) => {
74-
// On change language
75-
updated.forEach((id: number) => {
76-
const trigger = provider.awareness.getStates().get(id); // Get the user who initiated the change
77-
if (trigger && trigger.selectedLanguage) {
78-
// Ignore all state updates caused by the current user
79-
if (trigger.userId !== userId) {
80-
setSelectedLanguage(trigger.selectedLanguage);
83+
const setUpObserver = (yMap: Y.Map<string>) => {
84+
yMap.observe((event) => {
85+
event.changes.keys.forEach((change, key) => {
86+
if (key === SELECTED_LANGUAGE) {
87+
const language = yMap.get(SELECTED_LANGUAGE);
88+
if (language) {
89+
setSelectedLanguage(language);
8190
}
8291
}
8392
});
8493
});
8594
};
8695

87-
const handleChangeLanguage = (lang: string) => {
88-
setSelectedLanguage(lang);
89-
providerRef.current?.awareness.setLocalStateField(SELECTED_LANGUAGE, lang);
90-
};
9196
useEffect(() => {
9297
return () => {
9398
bindingRef.current?.destroy();
94-
providerRef.current?.awareness.setLocalState(null);
9599
providerRef.current?.disconnect();
96100
editorRef.current?.dispose();
97101
ydocRef.current?.destroy();
98102
};
99103
}, []);
100104

105+
const handleChangeLanguage = (lang: string) => {
106+
yMapRef.current?.set(SELECTED_LANGUAGE, lang);
107+
};
108+
101109
return (
102110
<CollaborationContext.Provider value={{ initialiseEditor, selectedLanguage, languages, handleChangeLanguage }}>
103111
{children}

0 commit comments

Comments
 (0)