最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • nodejs 如何实现控制台打印高亮代码

    正文概述 掘金(zxg_神说要有光)   2021-05-11   408

    当代码运行报错时,我们会打印错误,错误中有堆栈信息,可以定位到对应的代码位置。但有的时候我们希望能够更直接准确的打印报错位置的代码。比如这样:

    nodejs 如何实现控制台打印高亮代码

    这个可以使用 @babel/code-frames 来做到:

    const { codeFrameColumns } = require('@babel/code-frame');
    
    const res = codeFrameColumns(code, {
      start: { line: 2, column: 1 },
      end: { line: 3, column: 5 },
    }, {
      highlightCode: true,
      message: '这里出错了'
    });
    
    console.log(res);
    

    有没有感觉比较神奇,它是怎么做到的打印出上面的代码格式的(code frame)?

    本文我们就来探究下原理。

    主要会解答三个问题:

    • 如何打印出标记相应位置代码的 code frame(就是上图的打印格式)
    • 如何实现语法高亮
    • 如何在控制台打印颜色

    如何打印 code frame

    我们先不管高亮,实现这样的格式的打印:

    nodejs 如何实现控制台打印高亮代码

    有啥思路没?

    其实也比较容易想到,传入了源代码、标记开始和结束的行列号,那么我们就能够计算出显示标记(marker)的行是哪些,以及这些行的哪些列,然后依次对每一行代码做处理,如果本行没有标记则保持原样,如果本行有标记的话,那么就在开始打印一个 marker “>”,并且在下面打印一行 marker "^",最后一个标记行还要打印错误信息。

    我们来看一下 @babel/code-frame 的实现:

    首先,分割字符串成每一行的数组,然后根据传入的位置计算出 marker 所在的位置。

    比如图中第二行的第 1 到 12 列,第三行的 0 到 5 列。

    nodejs 如何实现控制台打印高亮代码

    然后对每一行做处理,如果本行有标记,则拼成 marker + gutter(行号) + 代码的格式,下面再打印一行 marker,最后的 marker 行打印 message。没有标记不处理。

    nodejs 如何实现控制台打印高亮代码

    这样最终拼出的就是这样的 code frame:

    nodejs 如何实现控制台打印高亮代码

    我们实现了 code frame 的拼接,暂时忽略了高亮,那么怎么做语法高亮呢?

    如何实现语法高亮

    实现语法高亮需要理解代码,但是如果只是高亮,词法分析就足够了。babel 也是这么做的,@babel/highlight 包里面完成了高亮代码的逻辑。

    先看效果:

    const a = 1;
    const b = 2;
    console.log(a + b);
    

    上面的源码被分成了 token 数组:

    [
      [ 'whitespace', '\n' ], [ 'keyword', 'const' ],
      [ 'whitespace', ' ' ],  [ 'name', 'a' ],
      [ 'whitespace', ' ' ],  [ 'punctuator', '=' ],
      [ 'whitespace', ' ' ],  [ 'number', '1' ],
      [ 'punctuator', ';' ],  [ 'whitespace', '\n' ],
      [ 'keyword', 'const' ], [ 'whitespace', ' ' ],
      [ 'name', 'b' ],        [ 'whitespace', ' ' ],
      [ 'punctuator', '=' ],  [ 'whitespace', ' ' ],
      [ 'number', '2' ],      [ 'punctuator', ';' ],
      [ 'whitespace', '\n' ], [ 'name', 'console' ],
      [ 'punctuator', '.' ],  [ 'name', 'log' ],
      [ 'bracket', '(' ],     [ 'name', 'a' ],
      [ 'whitespace', ' ' ],  [ 'punctuator', '+' ],
      [ 'whitespace', ' ' ],  [ 'name', 'b' ],
      [ 'bracket', ')' ],     [ 'punctuator', ';' ],
      [ 'whitespace', '\n' ]
    ]
    

    token 怎么分的呢?

    一般来说词法分析就是有限状态自动机(DFA),但是这里实现比较简单,是通过正则匹配的:

    js-tokens 这个包暴露出来一个正则,一个函数,正则是用来识别 token 的,其中有很多个分组,而函数里面是对不同的分组下标返回了不同的类型,这样就能完成 token 的识别和分类。

    nodejs 如何实现控制台打印高亮代码

    在 @babel/highlight 包里也是这样用的:

    nodejs 如何实现控制台打印高亮代码

    (正则来做词法分析有很多限制条件,比如不能处理递归的情况,所以这种方式不是通用的,通用词法分析还是得用状态机 DFA。)

    有了分类之后,不同 token 显示不同颜色,建立个 map 就行了。

    @babel/highlight 也是这么做的:

    nodejs 如何实现控制台打印高亮代码

    我们知道了怎么做语法高亮,使用 chalk 的 api 就可以打印颜色,那控制台打印颜色的原理是什么呢?

    如何在控制台打印颜色

    控制台打印的是 ASCII 码,并不是所有的编码都对应可见字符,ASCII 码有一部分字符是对应控制字符的,比如 27 是 ESC,就是我们键盘上的 ESC 键,是 escape 的缩写,按下它可以完成一些控制功能,这里我们可以通过打印 ESC 的 ASCII 码来进入控制打印颜色的状态。

    格式是这样的:

    nodejs 如何实现控制台打印高亮代码

    打印一个 ESC 的 ASCII 码,之后是 [ 代表开始,m 代表结束,中间是用 ; 分隔的 n 个控制字符,可以控制很多样式,比如前景色、背景色、加粗、下划线等等。

    ESC 的 ASCII 码是 27,有好几种写法:一种是字符表示的 \e ,一种是 16 进制的 \0x1b(27 对应的 16进制),一种是 8 进制的 \033,这三种都表示 ESC。

    我们来试验一下: 1 表示加粗、36 表示前景色为青色、4 表示下划线,下面三种写法等价:

    \e[36;1;4m
    \033[36;1;4m
    \0x1b[36;1;4m
    

    我们来试一下:

    nodejs 如何实现控制台打印高亮代码 都打印了正确的样式!

    当然,加了样式还要去掉,可以加一个 \e[0m 就可以了(\033[0m,\0x1b[0m 等价)。

    chalk(nodejs 的在终端打印颜色的库)的不同方法就是封装了这些 ASCII 码的颜色控制字符。

    上面每行代码被高亮过以后的代码是:

    nodejs 如何实现控制台打印高亮代码

    这样也就实现了不同颜色的打印。

    总结

    至此,我们能实现开头的效果了:支持 code frame 的打印,支持语法高亮,能够打印颜色

    nodejs 如何实现控制台打印高亮代码

    本文我们探究了这种效果的实现原理,先从 code frame 是怎么拼接的,然后每一行的代码是怎么做高亮的,之后是高亮具体是怎么打印颜色的。

    不管是 code frame 的打印,还是语法高亮或者控制台打印颜色,都是特别常见的功能,希望这篇文章能够帮你彻底掌握这 3 方面的原理。


    起源地下载网 » nodejs 如何实现控制台打印高亮代码

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元