extensions/markdown-language-features/server/src/workspace.ts/VsCodeClientWorkspace/constructor
class VsCodeClientWorkspace:	constructor(
		private readonly connection: Connection,
		private readonly config: LsConfiguration,
		private readonly documents: TextDocuments<TextDocument>,
		private readonly notebooks: NotebookDocuments<TextDocument>,
		private readonly logger: md.ILogger,
	) {
		documents.onDidOpen(e => {
			if (!this.isRelevantMarkdownDocument(e.document)) {
				return;
			}

			this.logger.log(md.LogLevel.Trace, 'VsCodeClientWorkspace: TextDocument.onDidOpen', `${e.document.uri}`);

			const uri = URI.parse(e.document.uri);
			const doc = this._documentCache.get(uri);

			if (doc) {
				// File already existed on disk
				doc.setInMemoryDoc(e.document);

				// The content visible to the language service may have changed since the in-memory doc
				// may differ from the one on-disk. To be safe we always fire a change event.
				this._onDidChangeMarkdownDocument.fire(doc);
			} else {
				// We're creating the file for the first time
				const doc = new VsCodeDocument(e.document.uri, { inMemoryDoc: e.document });
				this._documentCache.set(uri, doc);
				this._onDidCreateMarkdownDocument.fire(doc);
			}
		});

		documents.onDidChangeContent(e => {
			if (!this.isRelevantMarkdownDocument(e.document)) {
				return;
			}

			this.logger.log(md.LogLevel.Trace, 'VsCodeClientWorkspace: TextDocument.onDidChanceContent', `${e.document.uri}`);

			const uri = URI.parse(e.document.uri);
			const entry = this._documentCache.get(uri);
			if (entry) {
				entry.setInMemoryDoc(e.document);
				this._onDidChangeMarkdownDocument.fire(entry);
			}
		});

		documents.onDidClose(async e => {
			if (!this.isRelevantMarkdownDocument(e.document)) {
				return;
			}

			this.logger.log(md.LogLevel.Trace, 'VsCodeClientWorkspace: TextDocument.onDidClose', `${e.document.uri}`);

			const uri = URI.parse(e.document.uri);
			const doc = this._documentCache.get(uri);
			if (!doc) {
				// Document was never opened
				return;
			}

			doc.setInMemoryDoc(undefined);
			if (doc.isDetached()) {
				// The document has been fully closed
				this.doDeleteDocument(uri);
				return;
			}

			// Check that if file has been deleted on disk.
			// This can happen when directories are renamed / moved. VS Code's file system watcher does not
			// notify us when this happens.
			if (!(await this.statBypassingCache(uri))) {
				if (this._documentCache.get(uri) === doc && !doc.hasInMemoryDoc()) {
					this.doDeleteDocument(uri);
					return;
				}
			}

			// The document still exists on disk
			// To be safe, tell the service that the document has changed because the
			// in-memory doc contents may be different than the disk doc contents.
			this._onDidChangeMarkdownDocument.fire(doc);
		});

		connection.onDidChangeWatchedFiles(async ({ changes }) => {
			for (const change of changes) {
				const resource = URI.parse(change.uri);
				this.logger.log(md.LogLevel.Trace, 'VsCodeClientWorkspace: onDidChangeWatchedFiles', `${change.type}: ${resource}`);
				switch (change.type) {
					case FileChangeType.Changed: {
						const entry = this._documentCache.get(resource);
						if (entry) {
							// Refresh the on-disk state
							const document = await this.openMarkdownDocumentFromFs(resource);
							if (document) {
								this._onDidChangeMarkdownDocument.fire(document);
							}
						}
						break;
					}
					case FileChangeType.Created: {
						const entry = this._documentCache.get(resource);
						if (entry) {
							// Create or update the on-disk state
							const document = await this.openMarkdownDocumentFromFs(resource);
							if (document) {
								this._onDidCreateMarkdownDocument.fire(document);
							}
						}
						break;
					}
					case FileChangeType.Deleted: {
						const entry = this._documentCache.get(resource);
						if (entry) {
							entry.setOnDiskDoc(undefined);
							if (entry.isDetached()) {
								this.doDeleteDocument(resource);
							}
						}
						break;
					}
				}
			}
		});

		connection.onRequest(protocol.fs_watcher_onChange, params => {
			this.logger.log(md.LogLevel.Trace, 'VsCodeClientWorkspace: fs_watcher_onChange', `${params.kind}: ${params.uri}`);

			const watcher = this._watchers.get(params.id);
			if (!watcher) {
				return;
			}

			switch (params.kind) {
				case 'create': watcher.onDidCreate.fire(URI.parse(params.uri)); return;
				case 'change': watcher.onDidChange.fire(URI.parse(params.uri)); return;
				case 'delete': watcher.onDidDelete.fire(URI.parse(params.uri)); return;
			}
		});
	}