Markdown Preview Enhanced 将掘金MD主题搬过来

我们都知道,一些使用markdown语法的博客系统喜欢用YAML front matter表达文章信息。

---

title: "Markdown Preview Enhanced  将掘金MD主题搬过来"

author: "Bambi"

date: 2023-06-11

theme: fancy

---

就像上面这样,其中theme字段定义了markdown文档的主题样式。掘金的编辑器就有这个功能,而且掘金的主题集众多优秀掘友的创意于一身,让我十分爱不释手。

把掘金MD主题搬到我的编辑器

不过相较于五花八门的博客系统,平时写笔记我用的更多的还是vscode编辑器。而且除了写技术笔记之外,我还会用markdown语法去写一些需要对外展示的内容,比如简历。这时掘金的主题更能显示出优势。毕竟如果只是写笔记,普通的黑色主题足矣。

于是,我就想能不能把掘金里面这些好看的主题和方便的front matter搬到我的编辑器里面随时取用。通过比对我选择了Markdown Preview Enhanced这款预览插件,因为他有比较丰富的自定义功能。不过想要享用掘金的主题效果,还要稍微动手自定义一番。

目标效果

这就是在vscode中的最终效果,可以像在掘金编辑器里面一样,通过front matter配置theme实时享用鲜美的掘金主题。
demo.gif

Markdown Preview Enhanced

目前MPE(简称)是可以支持通过Settings切换多套MD主题的,可是这些主题我认为都没有掘金的主题香。于是咱们继续看他的自定义功能:

image.png
显然这个功能可以满足我们配置多套css的需求,只需要将喜欢的掘金主题从GitHub上整理到自己的电脑即可。

但是找遍MPE的文档,也没有看见更加配置化的介入方法了。也就是说我们没办法像掘金编辑器一样,用front mattertheme字段优雅的配置这个样式。而必须要像写代码一样@import来实现,这是违背markdown易读易写的宗旨的。

在自己的编辑器中,实现用front matter一键切换掘金主题

我需要像下面这样,输入主题名即可配置主题

---

title: "Markdown Preview Enhanced  将掘金MD主题搬过来"

author: "Bambi"

date: 2023-06-11

theme: fancy

---

目前,MPE本身是不能识别theme字段的,但是他预留了定制化markdown效果的Extend Parser!使用其中的onWillParseMarkdown接口,就可以在parser.js自定义markdown的写法了!

image.png

下面就是我基于onWillParseMarkdown接口的实现,只需要识别出theme配置,再插入插件看得懂的@import语法即可。

parser.js

module.exports = {

  onWillParseMarkdown: function(markdown) {

    return new Promise((resolve, reject)=> {

      // YAMLCfgList 整个YAML的配置的数组
      const YAMLCfgList = markdown?.match(/---\n([\s\S]*?)\n---/)?.[1]?.split('\n'); 
      // ThemeYAMLCfg theme字段在YAML中的配置字符串
      const ThemeYAMLCfg = YAMLCfgList?.find(one => /^[^:]*theme\:[\s\S]*/.test(one));
      // theme 主题名
      const theme = ThemeYAMLCfg?.split(':')[1]?.trim();
      // 如果配置了theme,就在YAML配置后面换行插入@import语句,URL是less文件所在的相对路径
      if (theme) {
        const relativePath = `../_style/${theme}.less`;
        const md = markdown.replace(/(---\n([\s\S]*?)\n---)/, `$1\n@import \"${relativePath}\" \n`)
        return resolve(md)
      }

      // 如果没有配置theme,正常输出原文
      return resolve(markdown)
    })
  },
  ...
}

这里要注意几个小问题:

  1. 目前MPE@import语法是不支持绝对路径的,只支持相对路径。所以主题最好是和.md文件同目录。我这里因为需要实现一个日常配置,不可能每次都把.less丢进去。我这里的解决办法是建一个指定的目录来存放md文档,主题文件也固定放在这里:

    • 在用户目录下面新建一个doc目录,作为日常写文档的指定路径。
    • 在doc目录下建一个_style文件,把喜欢的掘金主题丢进去即可。
    • 在doc目录下建一个你需要的分类目录,存放相应的.md文件,所以代码中固定的路径是这样的:../_style/${theme}.less。如果以后想给文档更灵活分类,层级变多的话,需要需要再优化一下,我这里是初版就不拓展了。
    用户目录/
    └── doc/
        ├── _style/
        │   └── fancy.less
        │   └── ...
        └── example/
            └── demo.md
            └── ...

2. @import语句一定要插入到front matter后面,front matter不在头部会导致md预览不能识别。所以我这里:$1\n@import \"${relativePath}\" \n,代表在$1选中的语句后面换行插入@import。

const md = markdown.replace(/(---\n(\[\s\S]\*?)\n---)/, `$1\n@import \"${relativePath}\" \n`)
  1. 目前MPE喜爱的样式语法是.less,而掘金的主题在GitHub上实现为.scss,所以这里需要做一下语言转换,我是使用verytoolz的在线工具直接转换的。

解决报错

嗯,到此为止,这个输入掘金主题名可以在vscode使用掘金主题的插件效果就实现了。不过还有个别扭的地方,就是主题名输入的不正确的时候,预览顶部会出现一行获取不到文件的报错信息。

zadrfs.jpg

这个加入一个文件是否存在的判断即可解决。

const absolutePath = `/Users/你的用户目录/doc/_style/${theme}.less`;
const fs = require('fs');
// 判断这个主题在_style目录是否存在,如果存在就做转换处理
if (fs.existsSync(absolutePath)) {
  const md = markdown.replace...
  return resolve(md)
}
  • 这里要注意的是,MPE的这个parser.js文件,并不在我们的doc目录下,他在MPE自己的目录里面,所以我们在这里使用fs模块,一定要使用绝对路径哈。

局限

此方法暂不支持dark模式下的预览,MPESettings最好不要动,即使动了也不要选dark主题。目前两种主题是有互相影响的,并没有实现完全实现解耦。后续我有时间会再优化这个问题。

妙用

MPE导出到PDF格式是非常方便的,可以配好主题之后,直接在预览页上右键导出PDF。如果样式需要微调,去_style里面调整也很方便。

最终parser.js完整代码

module.exports = {

  onWillParseMarkdown: function(markdown) {

    return new Promise((resolve, reject)=> {

      const YAMLCfgList = markdown?.match(/---\n([\s\S]*?)\n---/)?.[1]?.split('\n');
      const ThemeYAMLCfg = YAMLCfgList?.find(one => /^[^:]*theme\:[\s\S]*/.test(one));
      const theme = ThemeYAMLCfg?.split(':')[1]?.trim();
      if (theme) {
        const absolutePath = `/Users/你的用户目录/doc/_style/${theme}.less`;
        const relativePath = `../_style/${theme}.less`;
        const fs = require('fs');
        if (fs.existsSync(absolutePath)) {
          const md = markdown.replace(/(---\n([\s\S]*?)\n---)/, `$1\n@import \"${relativePath}\" \n`)
          return resolve(md)
        }
      }

      return resolve(markdown)
    })
  },
  ...
}

© 版权声明
THE END
喜欢就支持一下吧
点赞0

Warning: mysqli_query(): (HY000/3): Error writing file '/tmp/MYuYWDW4' (Errcode: 28 - No space left on device) in /www/wwwroot/583.cn/wp-includes/class-wpdb.php on line 2345
admin的头像-五八三
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

图形验证码
取消
昵称代码图片