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, theme
pour obtenir la couleur, collector
collecter 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
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."));
...
vscode
Les 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.
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
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é !