Mécanisme de mise en œuvre de la fonction de couleur multi-thème vscode

La page vscode est divisée en deux parties, une partie est fournie par le plug-in et l'autre partie est le corps principal. Ensuite, vscode doit envisager de combiner ces deux parties pour la gestion en termes de mise en œuvre multi-thèmes, ce qui est relativement plus compliqué que la simple mise en œuvre de fonctions multi-thèmes sur des pages Web.

L'essentiel est réalisé

Voyons d'abord comment le style de la partie principale de vscode est dessiné

registerThemingParticipant((theme, collector) => {
    
    
	const activitybarTextForeground = theme.getColor(foreground);
	if (activitybarTextForeground) {
    
    
		/**
		 * color --> vscode原生
		 * background-color --> 插件
		 */
		collector.addRule(`
			.monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-item .action-label {
				color: ${
      
      activitybarTextForeground} !important;
			}
		`);
		...
	}

C'est pour le code de style de la partie activitybar, themepour obtenir la couleur, collectorcollecter le style, et enfin l'insérer dans le style global pour terminer le réglage du style.

Regardons getColorà l'intérieur de la méthode

src/vs/workbench/services/themes/common/colorThemeData.ts

public getColor(colorId: ColorIdentifier, useDefault?: boolean): Color | undefined {
    
    
	let color: Color | undefined = this.customColorMap[colorId];
	if (color) {
    
    
		return color;
	}
	color = this.colorMap[colorId];
	if (useDefault !== false && types.isUndefined(color)) {
    
    
		color = this.getDefault(colorId);
	}
	return color;
}

D'où vient colorMap ? Voici le point clé !
Les multi-thèmes de vscode sont en fait gérés via des plugins de thèmes.Toutes
insérez la description de l'image ici
insérez la description de l'image ici
les couleurs sont extraites des fichiers json du répertoire des thèmes.

{
    
    
	"type": "dark",
	"colors": {
    
    
		"dropdown.background": "#525252",
		"list.activeSelectionBackground": "#707070",
		"quickInputList.focusBackground": "#707070",
		"list.inactiveSelectionBackground": "#4e4e4e",
		...
		}
	}	

Voici les variables de couleur à éviter.

L'enregistrement des couleurs est dans la plupart de ce fichier
src/vs/platform/theme/common/colorRegistry.ts

...
// 基础颜色
export const secondForeground = registerColor('second.foreground', {
    
     light: '#737373', dark: '#fff', hcDark: '#fff', hcLight: '#737373' }, nls.localize('secondForeground', "Color for text separators."));
...

vscodeLes thèmes sont grossièrement divisés en quatre catégories : thème sombre, thème clair, thème de surbrillance sombre et thème de surbrillance clair .

Par conséquent, quatre valeurs par défaut sont définies ici, et si la valeur ne peut pas être obtenue dans le plug-in, la valeur par défaut sera trouvée.

Ok, voici le réglage de couleur de la partie principale, regardons le réglage de couleur dans le plug-in.

section plug-in

.search-warapper .searchInput .search-btn {
    
    
	...
	background-color: var(--vscode-productMain-color);
}

La partie plugin utilise la fonction var de css.

CSS var函数est une syntaxe pour les valeurs de propriété personnalisées qui est utilisée pour insérer la valeur d'une propriété personnalisée, mais pas une partie de la valeur d'une autre propriété. Il vous permet de changer de style sans changer la feuille de style, ce qui améliore la maintenabilité et la réutilisation. Les valeurs des variables sont héritées des classes parentes.

insérez la description de l'image ici
Tous les styles obtenus à partir du plugin de thème sont écrits dans le style html.

Maintenant j'ai tout compris ~

Changement de style de thème

insérez la description de l'image ici
réveiller le sélecteur de couleurs
src/vs/workbench/contrib/themes/browser/themes.contribution.ts

override async run(accessor: ServicesAccessor) {
    
    
		const themeService = accessor.get(IWorkbenchThemeService);

		const installMessage = localize('installColorThemes', "Install Additional Color Themes...");
		const browseMessage = '$(plus) ' + localize('browseColorThemes', "Browse Additional Color Themes...");
		const placeholderMessage = localize('themes.selectTheme', "Select Color Theme (Up/Down Keys to Preview)");
		const marketplaceTag = 'category:themes';
		const setTheme = (theme: IWorkbenchTheme | undefined, settingsTarget: ThemeSettingTarget) => themeService.setColorTheme(theme as IWorkbenchColorTheme, settingsTarget);
		const getMarketplaceColorThemes = (publisher: string, name: string, version: string) => themeService.getMarketplaceColorThemes(publisher, name, version);

		const instantiationService = accessor.get(IInstantiationService);
		const picker = instantiationService.createInstance(InstalledThemesPicker, installMessage, browseMessage, placeholderMessage, marketplaceTag, setTheme, getMarketplaceColorThemes);

		const themes = await themeService.getColorThemes();
		const currentTheme = themeService.getColorTheme();

		const picks: QuickPickInput<ThemeItem>[] = [
			...toEntries(themes.filter(t => t.type === ColorScheme.LIGHT), localize('themes.category.light', "light themes")),
			...toEntries(themes.filter(t => t.type === ColorScheme.DARK), localize('themes.category.dark', "dark themes")),
			...toEntries(themes.filter(t => isHighContrast(t.type)), localize('themes.category.hc', "high contrast themes")),
		];
		await picker.openQuickPick(picks, currentTheme);
	}

Cet événement est déclenché lors de la sélection vers le haut et vers le bas

quickpick.onDidChangeActive(themes => selectTheme(themes[0]?.theme, false));

Continuez à suivre dans
src/vs/workbench/services/themes/browser/workbenchThemeService.ts

public setColorTheme(themeIdOrTheme: string | undefined | IWorkbenchColorTheme, settingsTarget: ThemeSettingTarget): Promise<IWorkbenchColorTheme | null> {
    
    
		return this.colorThemeSequencer.queue(async () => {
    
    
			return this.internalSetColorTheme(themeIdOrTheme, settingsTarget);
		});
	}
private async internalSetColorTheme(themeIdOrTheme: string | undefined | IWorkbenchColorTheme, settingsTarget: ThemeSettingTarget): Promise<IWorkbenchColorTheme | null> {
    
    
		if (!themeIdOrTheme) {
    
    
			return null;
		}
		const themeId = types.isString(themeIdOrTheme) ? validateThemeId(themeIdOrTheme) : themeIdOrTheme.id;
		if (this.currentColorTheme.isLoaded && themeId === this.currentColorTheme.id) {
    
    
			if (settingsTarget !== 'preview') {
    
    
				this.currentColorTheme.toStorage(this.storageService);
			}
			return this.settings.setColorTheme(this.currentColorTheme, settingsTarget);
		}

		let themeData = this.colorThemeRegistry.findThemeById(themeId);
		if (!themeData) {
    
    
			if (themeIdOrTheme instanceof ColorThemeData) {
    
    
				themeData = themeIdOrTheme;
			} else {
    
    
				return null;
			}
		}
		try {
    
    
			await themeData.ensureLoaded(this.extensionResourceLoaderService);
			themeData.setCustomizations(this.settings);
			return this.applyTheme(themeData, settingsTarget);
		} catch (error) {
    
    
			throw new Error(nls.localize('error.cannotloadtheme', "Unable to load {0}: {1}", themeData.location?.toString(), error.message));
		}

	}

Jetez un œil à ce qui est fait dans la méthode themeData.ensureLoade

src/vs/workbench/services/themes/common/colorThemeData.ts

public ensureLoaded(extensionResourceLoaderService: IExtensionResourceLoaderService): Promise<void> {
    
    
		return !this.isLoaded ? this.load(extensionResourceLoaderService) : Promise.resolve(undefined);
	}

	public reload(extensionResourceLoaderService: IExtensionResourceLoaderService): Promise<void> {
    
    
		return this.load(extensionResourceLoaderService);
	}

	private load(extensionResourceLoaderService: IExtensionResourceLoaderService): Promise<void> {
    
    
		if (!this.location) {
    
    
			return Promise.resolve(undefined);
		}
		this.themeTokenColors = [];
		this.clearCaches();

		const result = {
    
    
			colors: {
    
    },
			textMateRules: [],
			semanticTokenRules: [],
			semanticHighlighting: false
		};
		return _loadColorTheme(extensionResourceLoaderService, this.location, result).then(_ => {
    
    
			this.isLoaded = true;
			this.semanticTokenRules = result.semanticTokenRules;
			this.colorMap = result.colors; //生成colorMap
			this.themeTokenColors = result.textMateRules;
			this.themeSemanticHighlighting = result.semanticHighlighting;
		});
	}

La colorMap de la partie principale de vscode ci-dessus est générée ici

puis descends

	private updateDynamicCSSRules(themeData: IColorTheme) {
    
    
		...
		themingRegistry.getThemingParticipants().forEach(p => p(themeData, ruleCollector, this.environmentService));

		const colorVariables: string[] = [];
		for (const item of getColorRegistry().getColors()) {
    
    
			const color = themeData.getColor(item.id, true);
			if (color) {
    
    
				colorVariables.push(`${
      
      asCssVariableName(item.id)}: ${
      
      color.toString()};`);
			}
		}
		ruleCollector.addRule(`.monaco-workbench { ${
      
      colorVariables.join('\n')} }`);

		_applyRules([...cssRules].join('\n'), colorThemeRulesClassName);
	}

ici

themingRegistry.getThemingParticipants().forEach(p => p(themeData, ruleCollector, this.environmentService));

Très important, le code du collecteur de style est rappelé ici, et il est remis dans le collecteur

registerThemingParticipant((theme, collector) => {
    
    
	const activitybarTextForeground = theme.getColor(foreground);
	if (activitybarTextForeground) {
    
    
		/**
		 * color --> vscode原生
		 * background-color --> 插件
		 */
		collector.addRule(`
			.monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-item .action-label {
				color: ${
      
      activitybarTextForeground} !important;
			}
		`);
		...
	}

src/vs/workbench/services/themes/navigateur/workbenchThemeService.ts

function _applyRules(styleSheetContent: string, rulesClassName: string) {
    
    
	const themeStyles = document.head.getElementsByClassName(rulesClassName);
	if (themeStyles.length === 0) {
    
    
		const elStyle = document.createElement('style');
		elStyle.type = 'text/css';
		elStyle.className = rulesClassName;
		elStyle.textContent = styleSheetContent;
		document.head.appendChild(elStyle);
	} else {
    
    
		(<HTMLStyleElement>themeStyles[0]).textContent = styleSheetContent;
	}
}

Ici, vous pouvez voir que le style est réécrit dans le style.
Le changement de thème est terminé !

Frère Meng accorde de l'attention

Je suppose que tu aimes

Origine blog.csdn.net/woyebuzhidao321/article/details/131495841
conseillé
Classement