1111from jupyter_ydoc import ydocs as YDOCS
1212from pycrdt_websocket .websocket_server import YRoom
1313from pycrdt_websocket .ystore import BaseYStore , YDocNotFound
14+ from pycrdt import MapEvent
1415
1516from .loaders import FileLoader
1617from .utils import JUPYTER_COLLABORATION_EVENTS_URI , LogLevel , OutOfBandChanges
@@ -157,6 +158,7 @@ async def initialize(self) -> None:
157158 if self .ystore :
158159 await self .ystore .encode_state_as_update (self .ydoc )
159160
161+ self ._document .dirty = False
160162 self .ready = True
161163 self ._emit (LogLevel .INFO , "initialize" , "Room initialized" )
162164
@@ -206,6 +208,7 @@ async def _on_outofband_change(self) -> None:
206208 return
207209
208210 self ._document .source = model ["content" ]
211+ self ._document .dirty = False
209212
210213 def _on_document_change (self , target : str , event : Any ) -> None :
211214 """
@@ -222,6 +225,12 @@ def _on_document_change(self, target: str, event: Any) -> None:
222225 document. This tasks are debounced (60 seconds by default) so we
223226 need to cancel previous tasks before creating a new one.
224227 """
228+ if target == "state" and isinstance (event , MapEvent ) and list (event .keys .keys ()) == ["dirty" ]:
229+ # do not write when we are just setting the `dirty` attribute to
230+ # `False` for the JupyterLab UI. this prevents a save loop, as this
231+ # is set when the Ydoc is saved.
232+ return
233+
225234 if self ._maybe_save_task and not self ._maybe_save_task .done ():
226235 # only one `self._maybe_save_task` needs to be running.
227236 # if this method is called after the save delay, then we need to set
@@ -266,6 +275,7 @@ async def _maybe_save_document(self) -> None:
266275 }
267276 ))
268277 await self ._save_task
278+ self ._document .dirty = False
269279 self ._emit (LogLevel .INFO , "save" , "Content saved." )
270280
271281 if self ._should_resave :
@@ -286,6 +296,7 @@ async def _maybe_save_document(self) -> None:
286296 return None
287297
288298 self ._document .source = model ["content" ]
299+ self ._document .dirty = False
289300 self ._emit (LogLevel .INFO , "overwrite" , "Out-of-band changes while saving." )
290301
291302 except Exception as e :
0 commit comments