vscode多主题色功能实现机制

news2024/11/26 3:52:35

vscode的页面分为两部分,一部分是插件提供,一部分是主体。那么vscode在多主题实现上就要考虑把这两部分结合起来管理,相对来说要比单纯的网页实现多主题功能要复杂一些。

主体部分实现

我们先看下vscode主体部分样式是如何画出来了

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;
			}
		`);
		...
	}

这是出于activitybar部分的样式代码,theme获取颜色,collector收集样式,最后都会插入到全局的style里面完成样式设置。

我们到getColor方法里面看下

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;
}

colorMap来至哪里呢,重点来了!
vscode的多主题其实都是通过主题插件来管理的
在这里插入图片描述
在这里插入图片描述
所有颜色都是取于themes目录下的json文件。

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

这里面都是防止的颜色变量。

颜色的注册在大部分这个文件里面
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的主题大概分为四类深色主题、浅色主题、深色高亮主题、浅色高亮主题

所以这里设置了四个默认值,如果插件里面取不到值的话就会找默认值。

好,这里是主体部分的颜色设置,下面我们看看插件里面的颜色设置。

插件部分

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

插件部分使用的是css的var函数。

CSS var函数是一种自定义属性值的语法,用于插入自定义属性的值,而不是另一个属性的值的任何部分。它可以使您在不更改样式表的情况下更改样式,从而提高了可维护性和可重用性。 变量值继承至父类。

在这里插入图片描述
从主题插件里面获取到的样式全部写入了html的style里面。

这下就都懂了叭~

主题样式切换

在这里插入图片描述
唤醒颜色选择器
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);
	}

上下选择的时候触发了这个事件

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

继续跟进去
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));
		}

	}

看看在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;
		});
	}

上文中vscode主体部分colorMap就是在这里生成的

接着往下走

	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);
	}

这里的

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

很重要,这里重新调用了样式收集器代码,重新放进了collector里面

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/browser/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;
	}
}

这里可以看到样式重新写入了style里。
主题切换完成!

兄弟萌给个关注奥

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/720730.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Spring系列2 -- Spring的创建和使用

Spring 就是⼀个包含了众多工具方法的 IOC容器。既然是容器那么它就具备两个最基本的功能&#xff1a; 将对象存储到容器&#xff08;Spring&#xff09;中&#xff1b;从容器中将对象取出来。 在Java中对象也叫做Bean&#xff0c;后续我们就把对象称之为Bean&#xff1b; 目录…

数据结构--二叉树的定义和基本术语

数据结构–二叉树的定义和基本术语 二叉树的基本概念 二叉树是 n ( n ≥ 0 &#xff09; n (n\ge0&#xff09; n(n≥0&#xff09;个结点的有限集合: ①或者为 空二叉树 \color{red}空二叉树 空二叉树&#xff0c;即n 0。 ②或者由一个 根结点 \color{red}根结点 根结点和两…

ModaHub魔搭社区:腾讯发布的向量数据库Tencent Cloud VectorDB有哪些核心能力?

腾讯发布的向量数据库有哪些核心能力&#xff1f; 腾讯云刚刚发布的向量数据库Tencent Cloud VectorDB主要具备以下能力&#xff1a; 高性能向量存储、检索&#xff1a;腾讯云向量数据库具备高性能的向量存储和检索能力&#xff0c;单索引能够轻松支持10亿级别的向量规模。在…

十二、flex练习

需求&#xff1a;做出下面的样式 代码实现&#xff1a; <body><ul class"nav"><li><a href"#">HTML/CSS</a></li><li><a href"#">Browser Side</a></li><li><a href&q…

【Hello mysql】 数据库库操作

Mysql专栏&#xff1a;Mysql 本篇博客简介&#xff1a;介绍数据库的库操作 库的操作 创建数据库创建数据库案例字符集和校验规则查看系统默认字符集和校验规则查看数据库支持的字符集和校验规则 校验规则对于数据库的影响操纵数据库查看数据库显示创建语句修改数据库数据库删除…

【7月新刊】避雷!这4本期刊竟无影响因子?!7月期刊目录已更新 (多本期刊影响因子上涨)~

6月28日&#xff0c;科睿唯安发布了最新JCR报告&#xff0c;一时间几家欢喜几家愁&#xff0c;但有的作者却发现&#xff0c;自己投稿的期刊虽然被核心库收录却没有影响因子&#xff0c;不免慌了神。 总的来说&#xff0c;被核心库收录的期刊没有公布影响因子&#xff0c;一般…

实战干货,自动化测试框架mark标记详细实战,进阶高级测试...

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 pytest可以支持对…

键盘输入一个字符 a’,串口工具显示“b 实现现象:键盘输入一个字符串,串口工具回显输入的字符串

1.键盘输入一个字符 a’,串口工具显示"b 2.实现现象:键盘输入一个字符串&#xff0c;串口工具回显输入的字符串 uart4.h #ifndef __UART4__H__ #define __UART4__H__ #include "stm32mp1xx_uart.h" #include "stm32mp1xx_gpio.h" #include "st…

SQLite Expert Professional将ACCESS数据库文件导入到SQLITE

一、下载与安装 下载对应的位数的SQLite Expert&#xff1a;http://www.sqliteexpert.com/download.html &#xff0c;建议下载professional版本的&#xff0c;功能更加强大。 如果官网进不去可以到百度云下载&#xff1a;https://pan.baidu.com/s/17igndAqQ7SQ57LcjwS4WIQ …

RK3588 PWM调试记录---linux pwm子系统驱动框架

一、RK3588 PWM简介 RK3588一共有4组PWM,每组有4个通道&#xff0c;共可以产生4*416路PWM波形&#xff1b; PWM0 开始地址&#xff1a;0xfd8b0000 PWM1 开始地址&#xff1a;0xfebd0000 PWM2 开始地址&#xff1a;0xfebe0000 PWM3 开始地址&#xff1a;0xfebf0000 即每组PWM的…

追着 chatGPT 打的 Claude 跑不动了?!

claude 据说是 openai 公司的副总裁因理念不合&#xff0c;出走创建的 anthropic 公司发明的聊天机器人&#xff0c;和 chatGPT一样&#xff0c;智能聊天功能都很不错。 大致水平在 强chatGPT3.5 左右。 前期因为免费试用&#xff0c;反应速度非常快&#xff0c;对国内也没有…

2. 日志模块(上)

日志需求分析 无论对于业务系统还是中间件来说&#xff0c;日志都是必不可少的基础功能。完善、清晰地日志可以帮助我们观测系统运行的状态&#xff0c;并且快速定位问题。现在让我们站在 MyBatis 框架开发者的角度&#xff0c;来简单做一下日志功能的需求分析&#xff1a; 作…

1760_C语言中选择排序的实现

全部学习汇总&#xff1a; GreyZhang/c_basic: little bits of c. (github.com) 选择排序的实现思想跟冒泡排序的思想非常相近&#xff0c;二者的差一点在于&#xff1a;冒泡排序在比较交换的过程中交换的是两个位置的数据&#xff0c;而选择排序则是在遍历比较的过程中寻找最小…

web安全php基础_echo,print,print_r,var_dump 的用处及区别

echo & print 在 PHP 中有两个基本的输出方式&#xff1a; echo 和 print。 PHP echo 语句 echo 是一个语言结构&#xff0c;使用的时候可以不用加括号&#xff0c;也可以加上括号&#xff1a; echo 或 echo()。 显示字符串 下面的实例演示了如何使用 echo 命令输出字…

QtWebApp介绍、下载和搭建http轻量级服务器Demo

一、QtWebApp介绍 QtWepApp是一个C中的HTTP服务器库&#xff0c;其灵感来自Java Servlet。适用于Linux、Windows、Mac OS和Qt Framework支持的许多其他操作系统。   QtWebApp包含以下组件&#xff1a; • HTTP(S)1.0和1.1服务器 • 模板引擎 • 缓冲记录器   这些组件可以…

暑假第二天打卡

离散&#xff1a; &#xff08;1&#xff09;联结词集及其优先级 &#xff08;2&#xff09;真值表 真值表&#xff0c;最让人迷糊的就是p的真值是0&#xff0c;q的真值是0,p→q的真值是1&#xff0c;理解话虚假的前提可以推出任意结论 构造真值表关键在于从00……0开始&…

【单例模式】—— 每天一点小知识

&#x1f4a7; 单例模式 \color{#FF1493}{单例模式} 单例模式&#x1f4a7; &#x1f337; 仰望天空&#xff0c;妳我亦是行人.✨ &#x1f984; 个人主页——微风撞见云的博客&#x1f390; &#x1f433; 《数据结构与算法》专栏的文章图文并茂&#x1f995;生动形…

点大商城V2_2.4.6 全开源版 百度+支付宝+QQ+头条+小程序端+unipp开源前端系统安装教程

播播资源了解到点大商城V2是一款采用全新界面设计支持多端覆盖的小程序应用&#xff0c;支持H5、微信公众号、微信小程序、头条小程序、支付宝小程序、百度小程序&#xff0c;本次测试全套安装的是序是点大商城V2独立版&#xff0c;包含全部插件&#xff0c;代码全开源&#xf…

java项目之高校二手交易平台(ssm+jsp+mysql)

风定落花生&#xff0c;歌声逐流水&#xff0c;大家好我是风歌&#xff0c;混迹在java圈的辛苦码农。今天要和大家聊的是一款基于ssm的高校二手交易平台。项目源码以及部署相关请联系风歌&#xff0c;文末附上联系信息 。 &#x1f495;&#x1f495;作者&#xff1a;风歌&…

Android中级——IPC

IPC IPC是什么&#xff1f;多进程带来的问题IPC前提SerializableParcelableBinder Android中的IPCBundle文件共享MessengerAIDLContentProviderSocket不同IPC优缺点 Binder连接池 IPC是什么&#xff1f; Inter-Process Communcation&#xff0c;含义为进程间通信或者跨进程通信…