extensions/html-language-features/client/src/languageParticipants.ts/getLanguageParticipants
export function getLanguageParticipants(): LanguageParticipants {
	const onDidChangeEmmiter = new EventEmitter<void>();
	let languages = new Set<string>();
	let autoInsert = new Set<string>();

	function update() {
		const oldLanguages = languages, oldAutoInsert = autoInsert;

		languages = new Set();
		languages.add('html');
		autoInsert = new Set();
		autoInsert.add('html');

		for (const extension of extensions.allAcrossExtensionHosts) {
			const htmlLanguageParticipants = extension.packageJSON?.contributes?.htmlLanguageParticipants as LanguageParticipantContribution[];
			if (Array.isArray(htmlLanguageParticipants)) {
				for (const htmlLanguageParticipant of htmlLanguageParticipants) {
					const languageId = htmlLanguageParticipant.languageId;
					if (typeof languageId === 'string') {
						languages.add(languageId);
						if (htmlLanguageParticipant.autoInsert !== false) {
							autoInsert.add(languageId);
						}
					}
				}
			}
		}
		return !isEqualSet(languages, oldLanguages) || !isEqualSet(oldLanguages, oldAutoInsert);
	}
	update();

	const changeListener = extensions.onDidChange(_ => {
		if (update()) {
			onDidChangeEmmiter.fire();
		}
	});

	return {
		onDidChange: onDidChangeEmmiter.event,
		get documentSelector() { return Array.from(languages); },
		hasLanguage(languageId: string) { return languages.has(languageId); },
		useAutoInsert(languageId: string) { return autoInsert.has(languageId); },
		dispose: () => changeListener.dispose()
	};
}