| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126 |
- // Migrated from static methods of Document in Document.js
- import { DocumentContainer } from '@/features/ide-react/editor/document-container'
- import { debugConsole } from '@/utils/debugging'
- import { Socket } from '@/features/ide-react/connection/types/socket'
- import { IdeEventEmitter } from '@/features/ide-react/create-ide-event-emitter'
- import EditorWatchdogManager from '@/features/ide-react/connection/editor-watchdog-manager'
- export class OpenDocuments {
- private openDocs = new Map<string, DocumentContainer>()
- // eslint-disable-next-line no-useless-constructor
- constructor(
- private readonly socket: Socket,
- private readonly globalEditorWatchdogManager: EditorWatchdogManager,
- private readonly events: IdeEventEmitter
- ) {}
- getDocument(docId: string) {
- // Try to clean up existing docs before reopening them. If the doc has no
- // buffered ops then it will be deleted by _cleanup() and a new instance
- // of the document created below. This prevents us trying to follow the
- // joinDoc:existing code path on an existing doc that doesn't have any
- // local changes and getting an error if its version is too old.
- if (this.openDocs.has(docId)) {
- debugConsole.log(
- `[getDocument] Cleaning up existing document instance for ${docId}`
- )
- this.openDocs.get(docId)?.cleanUp()
- }
- if (!this.openDocs.has(docId)) {
- debugConsole.log(
- `[getDocument] Creating new document instance for ${docId}`
- )
- this.createDoc(docId)
- } else {
- debugConsole.log(
- `[getDocument] Returning existing document instance for ${docId}`
- )
- }
- return this.openDocs.get(docId)
- }
- private createDoc(docId: string) {
- const doc = new DocumentContainer(
- docId,
- this.socket,
- this.globalEditorWatchdogManager,
- this.events,
- this.detachDoc.bind(this)
- )
- this.openDocs.set(docId, doc)
- }
- detachDoc(docId: string, doc: DocumentContainer) {
- if (this.openDocs.get(docId) === doc) {
- debugConsole.log(
- `[detach] Removing document with ID (${docId}) from openDocs`
- )
- this.openDocs.delete(docId)
- } else {
- // It's possible that this instance has error, and the doc has been reloaded.
- // This creates a new instance in Document.openDoc with the same id. We shouldn't
- // clear it because it's not this instance.
- debugConsole.log(
- `[_cleanUp] New instance of (${docId}) created. Not removing`
- )
- }
- }
- hasUnsavedChanges() {
- for (const doc of this.openDocs.values()) {
- if (doc.hasBufferedOps()) {
- return true
- }
- }
- return false
- }
- flushAll() {
- for (const doc of this.openDocs.values()) {
- doc.flush()
- }
- }
- unsavedDocIds() {
- const ids = []
- for (const [docId, doc] of this.openDocs) {
- if (!doc.pollSavedStatus()) {
- ids.push(docId)
- }
- }
- return ids
- }
- async awaitBufferedOps(signal: AbortSignal) {
- if (this.hasUnsavedChanges()) {
- const { promise, resolve } = Promise.withResolvers<void>()
- let resolved = false
- const listener = () => {
- if (!this.hasUnsavedChanges()) {
- debugConsole.log('saved')
- window.removeEventListener('doc:saved', listener)
- resolved = true
- resolve()
- }
- }
- window.addEventListener('doc:saved', listener)
- signal.addEventListener('abort', () => {
- if (!resolved) {
- debugConsole.log('aborted')
- window.removeEventListener('doc:saved', listener)
- resolve()
- }
- })
- this.flushAll()
- await promise
- }
- }
- }
|