Sucha's Blog ~ Archive for June, 2019

19年6月22日 周六 13:05

更新 ThisSite 描述

scratch#ThisSite 写于网站搭建的第一天,蛮有纪念意义的,虽然 UI 未变,但换了 rendering 工具后,相关描述也得添加进去,当初围绕 Emacs 构建的一整套知识管理工具(因为当时 Emacs 确实好玩),现在慢慢的变成 IDE 不再重要了。

不过本站中,我最喜欢的页面,当然还是 muse#haha,-.-

19年6月15日 周六 13:18

WelcomePage 的生成

之前博客首页 WelcomePage 的生成,是在 proj 的 prepare 阶段,通过获取最新月份数据,动态产生内容,之后通过 body 函数提供给 cmark-gfm 来生成最终的 html。

这里带来的问题是,对应的 Permalink 是不准确的,指向到首页去了。

为了解决这个问题,只好在全部内容生成之后,再搜集首页需要的数据;另外一种解决的办法,是用在语法上对首页的 Permalink 做特别处理,但这样太复杂了。

最后,是给 MarkdownProjectCompositor 中每个 proj 处理完所有 files 后,增加一个 after 处理函数,可以在最后,对生成内容做采集。

这样,首页的 Permalink 指向才是准确的。

还有,现在用 markdown-editor 来写感觉很不错啊,有图为例

19年6月10日 周一 22:26

MarkdownProjectCompositor

这里介绍一下 MarkdownProjectCompositor 对源文件的组织方式、处理流程,以及一些针对 Markdown 语法的扩展功能,最后说一下配置细节。

源文件组织方式

可以参考配置文件1,定义了源文件目录、生成目录,同时定义了多个源文件子目录为 proj 工程目录,每个 proj 工程目录可以自定义不同 proj prepare 函数,每个源文件的 body 预处理函数、header 及 footer 样式。

这样可以有效处理主页源码、以及博客源码,处理各自不同的扩展语法,在 compostor 这一层,关注流程及数据传递,具体的扩展功能,是通过配置文件中复杂的功能函数来实现的。

在 proj 这一层,主要是获取子目录下的所有文件,交给 prepare 函数动态插入、删除文件,为接下来内容的动态生成做准备。

处理流程

每个 Markdown 文件的 rendering 过程,被分为 4 个阶段,分别是 body 预处理生成中间文件,输出 header、中间文件 rendering、输出 footer 后组成生成文件。

1. body 源码预处理

首先读取 Markdown 的源文件内容,将其作为参数传递给配置文件中某个 proj 定义的 body 函数做预处理,在这里用户可以处理自定义的标签,将其转为各种 Markdown rendering engine 支持的标准格式后,将内容交给 compositor 写入中间文件。

2. header 生成文件头

可以在这里区分不同的 proj,插入不同内容的文件头,比如主页的,博客的文件头,带上不同的样式表,同样支持动态生成内容。

3. rendering 中间文件

使用配置的 markdown rendering engine 处理这个中间文件,将生成内容添加到生成文件中。

4. footer 生成文件尾

这里类似 header 函数。

语法扩展

其实上篇博文的最后有介绍,这里介绍语法,注意为了不被解析,用了 \

[这篇文章]\(blog\#2019-06\#p1)
\#\contents 4
这里有个标注[Desc]\(#fn1)
...
[Desc]\(#fn1):解释这个标注
 #date 18年6月10日 周一 22:26
 #category Programming

配置、使用细节

配置文件会使用 lua 的 dofile() 函数加载,返回类似的 table 就好,所以配置文件可以非常复杂,大大扩展 Markdown 语法。

使用方法如下,可选参数 PROJ_BASE_DIR,当 confg.lua 中的 source、build 配置为相对路径时可以使用,如果有跨平台写 Markdown 同学,应该需要这个吧。

$ lua MarkdownProjectCompositor.lua config.lua [PROJ_BASE_DIR]

基本的配置下面有,注意 proj 中含有 res = true 的,意味着仅仅列举文件,但不做生成,用于上述扩展语法中做 proj 间的引用。

prepare 函数上面有介绍,当 proj 的 files 被填充后,会跑一次;body 用于生成临时源文件,自定义的语法在这里做转换,其他函数都有介绍过了。

最后的 user 不是必须的,但如果扩展了语法之类的,那可能就需要用到了,在 config 中带上,后面确保可以引用到。

最后的最后,当然是用生成当前主页、及博客的 config.lua 来压轴。

[1] config example:

local config = {
   source = "/Markdown/Source/Path", -- will be modified by compositor
   bulid = "/Html/Output/Path",      -- will be modified by compositor
   suffix = ".html",                 -- output suffix
   program = "cmark-gfm",            -- program used
   params = " -t html --unsafe --github-pre-lang ",    -- params
   tmpfile = "/tmp/MarkdownProjectCompositorTempFile", -- temp file
   projs = {
      {
         res = true,      -- resouces dir, when true do not build output
         dir = "SourceSubPath",
         files = {
            -- file names filled by compositor
         },
         prepare = function( config, proj )
            -- prepare proj, sort/insert/delete proj files to be processed by cmark
         end,
         body = function( config, proj, filename, content )
            -- return modified source content before cmark process
         end,
         header = function( config, porj, filename )
            -- return content append in dest head
         end,
         footer = function( config, proj, filename )
            -- return content append in dest tail
         end,
      },
   },
   -- user defines below
   user = {
      readFile = function( path )
      end,
      writeFile = function( path, content )
      end,
      siteHeader = function( config, proj, filename )
      end,
      siteFooter = function( config, proj, filename )
      end,
   },
}
return config

19年6月09日 周日 23:59

更换 Markdown Engine 为 cmark-gfm

将本地 Markdown 渲染引擎换成了 cmark-gfm,在这个基础上建立了类 EmacsWikiMode 的工程生成工具 MarkdownProjectCompositor

之前这个主页包括博客,是 2004 年底因为好奇 Wiki 语法而搭建起来的本地 HTML 文件,后来又学会了使用 FTP 上传免费的空间,绑定二级域名。

接着又学会了如何买域名,大学时代迷恋 Unix、Linux、Emacs 等等这一切对于普通人来说奇奇怪怪的东西,除了头脑发热在学校 BBS 上各种水文, 还在这里分门别类做了记录,慢慢的东西就多起来了。

这十多年间,不变的是,我得使用 Emacs 作为一个所见所得的编辑器,通过 EmacsWikiMode 来写 Markdown, 为此自己在这个 mode 之上建立了 EmacsWikiJournal 来专门写博客,基本上, 这个过程还是很方便的

Markdown 最初的语法,都来自于 JOHN GRUBER 在 2004 年的 Markdown: Syntax

因为 EmacsWikiMode 引用得早吧,所以在此之上,构建了很多独特的功能,比如自动生成目录摘要,比如将 Markdown 组织为各个工程,使用不同的配置文件头、 文件尾来生成 HTML,这样不同目录下的 HTML 可以使用不同的 CSS。而且,不同工程之间还可以很方便的引用。以及各种语法的高亮,将其输出为 HTML 文件。

也是蛮早,我就想着将博客的文件按照 YYYY-MM 这样组织,可以经受时间推移的考验,可是没想到,最大的不确定性,来自于 Emacs 的支持。

一方面,EmacsWikiMode 早就年久失修,maintainer 在 N 年以前,就构建了一个叫做 muse 的工程另起炉灶了。而 Emacs 社区本身,转到了 OrgMode 这一条路上 面,再说,其实一直都有 OutlineMode 可以用,也还勉勉强强。

加上外面各种 Markdown 桌面软件,网页端工具提供方便的界面,EmacsWikiMode 早就没有人用了,而我自己使用的频次也是越拉越少。

可悲的是,随着 Emacs 版本更新,大概在 version 24 的时候,EmacsWikiMode 在使用上就各种问题,version 25 之后,几乎无法生成了。

虽然是低频使用,但考虑到需要很长时间的支持,emacs-lisp 这种语言就得花费很多时间去维护,其作为 Emacs 环境编程工具,功能接口变动较大, 如果是 C 等等语言、库变动少的,基本上靠着 POSIX Like 的系统接口,维护成本可以很低。当然效率是另外一方面的加分吧。

所以,替换 Markdown 的 renderinig engine,随着 Emacs 上 EmacsWikiMode 的可用性变得迫切起来,最终来了这次大改。

因为之前 EmacsWikiMode 功能丰富,加上自救对于 cmark 还不熟悉,所以功能上有取舍。另外之前为了在上面构建 EmacsWikiJournal,其实在 HTML 文件结构上 面,以及 Markdown 的语法上面,都有一些不妥的地方,这里一并修改过来了。

先说一些缺失的:

一些依旧支持,并做了改进的:

[1] emacs-lisp 语法高亮图
[2] 新的博客结构