简易版chalk

简易版chalk

参考文档

  • chalk/chalk: 🖍 Terminal string styling done right (github.com)

  • 【MINI 系列】五颜六色的控制台)

  • ANSI转义序列 - 维基百科,自由的百科全书 (wikipedia.org)

“ANSI 转义序列(ANSI escape sequences)是一种带内信号的转义序列标准,用于控制视频文本终端上的光标位置、颜色和其他选项。在文本中嵌入确定的字节序列,大部分以 ESC 转义字符和"["字符开始,终端会把这些字节序列解释为相应的指令,而不是普通的字符编码。”

根据描述我们知道需要使用一些特殊的转义字符来实现不同字体风格、颜色、背景色。

1、字体风格

根据wiki选择图形再现(SGR)参数的描述编写 Ansi 码表,同时获取一下码表的key

在这里插入图片描述

/*** ESC 按键的 Ansi 码*/
export const ESC_CODE: string = "\u001B"/*** 图形再现参数的 Ansi 码表1(开启)*/
const Style1 = {// 前景色'foreground': '38;2;',// 背景色'background': '48;2;',// 加粗'bold': '1',// 暗淡'dim': '2',// 倾斜'italic': '3',// 下划线'underline': '4',// 闪烁'flick': '5',// 快速闪烁'fast_flick': '6',// 反转'inverse': '7',// 隐藏'hidden': '8',// 删除线'strikethrough': '9',// 上划线'overline': '53',
};/*** 图形再现参数的 Ansi 码表2(关闭)*/
const Style2 = {// 前景色'foreground': '39',// 背景色'background': '49',// 加粗'bold': '22',// 暗淡'dim': '22',// 倾斜'italic': '23',// 下划线'underline': '24',// 闪烁'flick': '25',// 快速闪烁'fast_flick': '25',// 反转'inverse': '27',// 隐藏'hidden': '28',// 删除线'strikethrough': '29',// 上划线'overline': '55',
};export type Style1 = keyof typeof Style1
export const EscapeSequence1 = (key: Style1, ...args: any[]) => {const code = Style1[key];// return String.raw`${ESC_CODE}[${code}${args.join(';')}m`;return `${ESC_CODE}[${code}${args.join(';')}m`;
}export type Style2 = keyof typeof Style2
export const EscapeSequence2 = (key: Style2) => {const code = Style2[key]// return String.raw`${ESC_CODE}[${code}m`;return `${ESC_CODE}[${code}m`;
}export type Styles = Style1 & Style2

2、颜色

这里不再像chalk一样支持3/4位颜色、8位颜色,而是仅仅支持真彩色(TrueColor),根据wiki颜色的描述补充 Ansi 码表的foregroundbackground

在这里插入图片描述

这里需要先判断一下终端是否支持真彩色(并未给出所有平台的判断方案)。

import process from "node:process";
import os from "node:os";
import {execSync} from 'child_process';/*** 判断是否支持当前环境是否支持 TrueColor* @returns {boolean} 是否支持 TrueColor*/
export default (): boolean => {if (process.platform === 'win32') {// Windows 10 build 14931 is the first release that supports 16m/TrueColor.const osRelease = os.release().split('.');return Number(osRelease[0]) >= 10 && Number(osRelease[2]) >= 14_931;} else if (process.platform === 'darwin') {const result = execSync('tput colors');const numColors = parseInt(result.toString().trim(), 10);return numColors >= 256;}return false;
}

颜色名称根据 CSS3 种的 147 个名称去定义。

/*** CSS3 标准中的 147 中颜色定义*/
export const ColorMapping = {"aliceblue": "#f0f8ff","antiquewhite": "#faebd7","aqua": "#00ffff","aquamarine": "#7fffd4","azure": "#f0ffff","beige": "#f5f5dc","bisque": "#ffe4c4","black": "#000000","blanchedalmond": "#ffebcd","blue": "#0000ff","blueviolet": "#8a2be2","brown": "#a52a2a","burlywood": "#deb887","cadetblue": "#5f9ea0","chartreuse": "#7fff00","chocolate": "#d2691e","coral": "#ff7f50","cornflowerblue": "#6495ed","cornsilk": "#fff8dc","crimson": "#dc143c","cyan": "#00ffff","darkblue": "#00008b","darkcyan": "#008b8b","darkgoldenrod": "#b8860b","darkgray": "#a9a9a9","darkgreen": "#006400","darkgrey": "#a9a9a9","darkkhaki": "#bdb76b","darkmagenta": "#8b008b","darkolivegreen": "#556b2f","darkorange": "#ff8c00","darkorchid": "#9932cc","darkred": "#8b0000","darksalmon": "#e9967a","darkseagreen": "#8fbc8f","darkslateblue": "#483d8b","darkslategray": "#2f4f4f","darkslategrey": "#2f4f4f","darkturquoise": "#00ced1","darkviolet": "#9400d3","deeppink": "#ff1493","deepskyblue": "#00bfff","dimgray": "#696969","dimgrey": "#696969","dodgerblue": "#1e90ff","firebrick": "#b22222","floralwhite": "#fffaf0","forestgreen": "#228b22","fuchsia": "#ff00ff","gainsboro": "#dcdcdc","ghostwhite": "#f8f8ff","gold": "#ffd700","goldenrod": "#daa520","gray": "#808080","green": "#008000","greenyellow": "#adff2f","grey": "#808080","honeydew": "#f0fff0","hotpink": "#ff69b4","indianred": "#cd5c5c","indigo": "#4b0082","ivory": "#fffff0","khaki": "#f0e68c","lavender": "#e6e6fa","lavenderblush": "#fff0f5","lawngreen": "#7cfc00","lemonchiffon": "#fffacd","lightblue": "#add8e6","lightcoral": "#f08080","lightcyan": "#e0ffff","lightgoldenrodyellow": "#fafad2","lightgray": "#d3d3d3","lightgreen": "#90ee90","lightgrey": "#d3d3d3","lightpink": "#ffb6c1","lightsalmon": "#ffa07a","lightseagreen": "#20b2aa","lightskyblue": "#87cefa","lightslategray": "#778899","lightslategrey": "#778899","lightsteelblue": "#b0c4de","lightyellow": "#ffffe0","lime": "#00ff00","limegreen": "#32cd32","linen": "#faf0e6","magenta": "#ff00ff","maroon": "#800000","mediumaquamarine": "#66cdaa","mediumblue": "#0000cd","mediumorchid": "#ba55d3","mediumpurple": "#9370db","mediumseagreen": "#3cb371","mediumslateblue": "#7b68ee","mediumspringgreen": "#00fa9a","mediumturquoise": "#48d1cc","mediumvioletred": "#c71585","midnightblue": "#191970","mintcream": "#f5fffa","mistyrose": "#ffe4e1","moccasin": "#ffe4b5","navajowhite": "#ffdead","navy": "#000080","oldlace": "#fdf5e6","olive": "#808000","olivedrab": "#6b8e23","orange": "#ffa500","orangered": "#ff4500","orchid": "#da70d6","palegoldenrod": "#eee8aa","palegreen": "#98fb98","paleturquoise": "#afeeee","palevioletred": "#db7093","papayawhip": "#ffefd5","peachpuff": "#ffdab9","peru": "#cd853f","pink": "#ffc0cb","plum": "#dda0dd","powderblue": "#b0e0e6","purple": "#800080","red": "#ff0000","rosybrown": "#bc8f8f","royalblue": "#4169e1","saddlebrown": "#8b4513","salmon": "#fa8072","sandybrown": "#f4a460","seagreen": "#2e8b57","seashell": "#fff5ee","sienna": "#a0522d","silver": "#c0c0c0","skyblue": "#87ceeb","slateblue": "#6a5acd","slategray": "#708090","slategrey": "#708090","snow": "#fffafa","springgreen": "#00ff7f","steelblue": "#4682b4","tan": "#d2b48c","teal": "#008080","thistle": "#d8bfd8","tomato": "#ff6347","turquoise": "#40e0d0","violet": "#ee82ee","wheat": "#f5deb3","white": "#ffffff","whitesmoke": "#f5f5f5","yellow": "#ffff00","yellowgreen": "#9acd32"
}export type Colors = keyof typeof ColorMappingexport const isColorName = (str: string) => {return (str in ColorMapping);
}

根据wiki上的描述,需要把16进制的颜色转换为RGB才能正确的设置样式,这里需要写一个工具类。

/*** 将16进制的颜色转换为RGB返回* @param hex - 16进制的颜色* @returns {number, number, number} 16进制的颜色的RGB表示*/
export const hexToRgb = (hex: string) => {const matches = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex)!;return {r: parseInt(matches[1], 16),g: parseInt(matches[2], 16),b: parseInt(matches[3], 16)}
}

3、实现简易版chalk

import supportTrueColor from "./supportTrueColor.js";
import {EscapeSequence1, EscapeSequence2, Styles} from "./ansi.js";
import {ColorMapping, Colors, isColorName} from "./color.js";
import {hexToRgb} from "./utils.js";type colorType = "foreground" | "background"export class Chalk {private prefix: stringprivate suffix: stringconstructor() {if (!supportTrueColor()) {throw new Error("Not Supported TrueColor!")}this.prefix = ''this.suffix = ''}private escapeSequence(key: Styles, ...args: any[]) {this.prefix += EscapeSequence1(key, ...args)this.suffix += EscapeSequence2(key)}private rgb(t: colorType, r: number, g: number, b: number): this;private rgb(t: colorType, r: number, g: number, b: number, ...args: string[]): string;private rgb(t: colorType, r: number, g: number, b: number, ...args: string[]): string | this {this.escapeSequence(t as Styles, r, g, b);if (args.length > 0) {return this.build(...args);}return this;}build(...args: string[]) {const text = this.prefix + args.join(' ') + this.suffix;this.prefix = ''this.suffix = ''return text;}// stylestyle(s: Styles): this;style(s: Styles, ...args: string[]): string;style(s: Styles, ...args: string[]): string | this {this.escapeSequence(s)if (args.length > 0) {return this.build(...args);}return this;}// colorcolor(name: Colors): this;color(name: Colors, ...args: string[]): string;color(name: string): this;color(name: string, ...args: string[]): string;color(name: Colors | string, ...args: string[]): string | this {const {r, g, b} = isColorName(name) ? hexToRgb(ColorMapping[name as Colors]) : hexToRgb(name);return this.rgb("foreground", r, g, b, ...args)}// bgColorbgColor(name: Colors): this;bgColor(name: Colors, ...args: string[]): string;bgColor(name: string): this;bgColor(name: string, ...args: string[]): string;bgColor(name: Colors | string, ...args: string[]): string | this {const {r, g, b} = isColorName(name) ? hexToRgb(ColorMapping[name as Colors]) : hexToRgb(name);return this.rgb("background", r, g, b, ...args)}
}export default new Chalk();// const chalk = new Chalk();
// console.log(chalk.color("#ff9600").bgColor("skyblue").style("bold", "hello chalk!"));
// console.log(chalk.color("red").bgColor("pink").style("bold").build("hello chalk!"));

最后贴一下项目地址:https://github.com/xumeng03/chalk

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

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

相关文章

华为OD机试 - 小朋友来自多少小区(Java JS Python C)

题目描述 幼儿园组织活动,老师布置了一个任务: 每个小朋友去了解与自己同一个小区的小朋友还有几个。 我们将这些数量汇总到数组 garden 中。 请根据这些小朋友给出的信息,计算班级小朋友至少来自几个小区? 输入描述 输入:garden[] = {2, 2, 3} 输出描述 输出:7 备…

LangChain - 02 - 快速开始之模型提示和解析

参考 LangSmith Many of the applications you build with LangChain will contain multiple steps with multiple invocations of LLM calls. As these applications get more and more complex, it becomes crucial to be able to inspect what exactly is going on inside …

轻度听力损失的儿童需要早期干预吗?

一些宝宝在做听力筛查时总是不通过,进一步听力诊断发现宝宝有轻度的听力损失,刚知道这个消息时,家长可担心了,总想着宝宝是不是听不到啊?但是一段时间后,有些家长又会忽略宝宝的听力问题,因为部…

【记录版】SpringBoot常见配置项及其配置文件(持续更新...)

主题:SpringBoot Configuration 背景: SpringBoot作为整合框架,涉及到非常多的模块的配置,有时需要知道对应模块有哪些配置,做一些针对性的优化,但往往忘记其配置解析入口在哪。本篇仅做个人记录用&#…

ES 错误码

2xx状态码(如200)表示请求成功处理,并且不需要重试。 400状态码表示客户端发送了无效的请求,例如请求的语法有误或缺少必需的参数。在这种情况下,重试相同的请求很可能会导致相同的错误。因此,应该先检查并…

探索 Vuex 的世界:状态管理的新视角(下)

🤍 前端开发工程师(主业)、技术博主(副业)、已过CET6 🍨 阿珊和她的猫_CSDN个人主页 🕠 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 🍚 蓝桥云课签约作者、已在蓝桥云…

go grpc-go 连接变动,导致全服 gRPC 重连 BUG 排查

问题描述 项目中遇到一个问题,每当有节点变更时,整个 gRPC 网络连接会重建 然后我对该问题做了下排查 最后发现是 gRPC Resolver 使用上的一个坑 问题代码 func (r *xxResolver) update(nodes []*registry.Node) {state : resolver.State{Addresses…

PyQt6 QColorDialog颜色对话框控件

锋哥原创的PyQt6视频教程: 2024版 PyQt6 Python桌面开发 视频教程(无废话版) 玩命更新中~_哔哩哔哩_bilibili2024版 PyQt6 Python桌面开发 视频教程(无废话版) 玩命更新中~共计50条视频,包括:2024版 PyQt6 Python桌面开发 视频教程(无废话版…

基于SSM框架的电脑测评系统论文

基于 SSM框架的电脑测评系统 摘要 随着信息技术在管理上越来越深入而广泛的应用,作为一个一般的用户都开始注重与自己的信息展示平台,实现基于SSM框架的电脑测评系统在技术上已成熟。本文介绍了基于SSM框架的电脑测评系统的开发全过程。通过分析用户对于…

大数据HCIE成神之路之数据预处理(3)——数值离散化

数值离散化 1.1 无监督连续变量的离散化 – 聚类划分1.1.1 实验任务1.1.1.1 实验背景1.1.1.2 实验目标1.1.1.3 实验数据解析 1.1.2 实验思路1.1.3 实验操作步骤1.1.4 结果验证 1.2 无监督连续变量的离散化 – 等宽划分1.2.1 实验任务1.2.1.1 实验背景1.2.1.2 实验目标1.2.1.3 实…

Open5GSUeRANSim2:对安装在同一个VM上的OPEN5GS和UERANSIM进行配置和抓取wireshark报文

参考链接: Configuring SCTP & NGAP with UERANSIM and Open5GS on a Single VM for the Open5GS & UERANSIM Series https://www.youtube.com/watch?vINgEX5L5fkE&listPLZqpS76PykwIoqMdUt6noAor7eJw83bbp&index5 Configuring RRC with UERANSI…

泛微e-cology XmlRpcServlet文件读取漏洞复现

漏洞介绍 泛微新一代移动办公平台e-cology不仅组织提供了一体化的协同工作平台,将组织事务逐渐实现全程电子化,改变传统纸质文件、实体签章的方式。泛微OA E-Cology 平台XmRpcServlet接口处存在任意文件读取漏洞,攻击者可通过该漏洞读取系统重要文件 (如数据库配置…

fastadmin表格右侧操作栏增加审核成功和审核失败按钮,点击提交ajax到后端

fastadmin表格右侧操作栏增加审核成功和审核失败按钮,点击提交ajax到后端 效果如下 js {field: operate, title: __(Operate), table: table, events

安装Neo4j

jdk1.8对应的neo4j的版本是3.5 自行下载3.5版本的zip文件 地址 解压添加环境变量 变量名:NEO4J_HOME 变量值:D:\neo4j-community-3.5.0 (你自己的地址) PATH添加: %NEO4J_HOME%\bin (如果是挨着的注意前后英…

Linux c++开发-11-Socket TCP编程简单案例

服务端&#xff1a; #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <netinet/in.h> #include <sys/types.h>#include <errno.h>int main(void) {//1.socketint server_sock socket(A…

传统行业与人工智能融合:材料、化学、物理、生物的发展与未来展望

导言 传统行业如材料科学、化学、物理、生物学一直是科学领域的重要支柱。随着人工智能的快速发展&#xff0c;这些领域也在不断融合创新。本文将深入研究这些领域与人工智能的发展过程、遇到的问题及解决过程、未来的可用范围&#xff0c;以及在各国的应用和未来的研究趋势。 …

H-ui前端框架 —— layer.js

layer.js是由前端大牛贤心编写的web弹窗插件。 laye.js是个轻量级的网页弹出层组件..支持类型丰富的弹出层类型&#xff0c;如消息框、页面层、iframe层等&#xff0c;具有较好的兼容性和灵活性。 layer.js用法 1.引入layer.js文件。在HTML页面的头部引用layer.is文件&#x…

【uniapp】uniapp中本地存储sqlite数据库保姆级使用教程(附完整代码和注释)

数据库请求接口封装 uniapp中提供了plus.sqlite接口&#xff0c;在这里我们对常用的数据库请求操作进行了二次封装 这里的dbName、dbPath、recordsTable 可以根据你的需求自己命名 module.exports {/** * type {String} 数据库名称*/dbName: salary,/*** 数据库地址* type {…

【【迭代七次的CORDIC算法-Verilog实现】】

迭代七次的CORDIC算法-Verilog实现求解正弦余弦函数 COEDIC.v module CORDIC #(parameter DATA_WIDTH 4d8 , // we set data widthparameter PIPELINE 4d8)(input clk ,input …

在spring boot项目引入mybatis plus后的的案例实践

前景提要 1、项目背景 一个spring boot mybatis的项目&#xff0c;分页一直是PageHelper。 2、为什么要引入mybatis plus 1、简化单表的crud 2、对mybatis plus进行简单的设计&#xff0c;以满足现有系统的规范&#xff0c;方便开发 实践中出现的问题 1、版本不兼容 当…