ETML: 文本块渲染用法
文章目录
何谓 “文本块”
这里的文本块指的是“多行宽度相等的文本”。
当我们将一段文本(可能是多行)限定在宽度内时,根据文本原始宽度(text-width)和指定宽度(width)的不同会有下面两种情况:
-
width >= text-width
限定宽度超过了文本宽度,使用像素空格补齐剩余宽度。 -
width < text-width
限定宽度小于文本宽度,需要对文本换行以保证每行宽度都等于限定的宽度。
文本块模型
除了基础的文本展示块,文本块还支持一些额外的属性,下面是完整的文本块属性模型:
(defclass etml-block ()
((content :initarg :content :initform "")
(width :initarg :width :initform nil)
(justify :initarg :justify :initform 'left)
(height :initarg :height :initform nil)
(align :initarg :align :initform 'top)
(padding :initarg :padding :initform nil)
(bgcolor :initarg :bgcolor :initform nil)
(border :initarg :border :initform nil)
(margin :initarg :margin :initform nil)))
各个属性用法
content
原始文本内容,是一个字符串。
width
限定文本的宽度。支持两种格式的宽度:
- integer
n
表示文本的前n
个字符的像素宽度; - cons-cell
'(n)
表示n
像素宽度
justify
文本在水平方向的对齐方式。仅当文本原始宽度(text-width)大于限定宽度(width)时生效。支持设置三种 symbol 值: 'left
,'center
,'right
,分别表示文本靠左、居中和靠右。
height
限定文本的高度。Integer n
表示文本限定为从首行开始的 n
行。
align
文本在垂直方向的对齐方式。仅当已经限定了宽度之后的文本高度(text-height)小于限定高度(height)时生效。支持设置三种 symbol 值: 'top
,'center
,'bottom
,分别表示文本靠上、居中和靠下。
padding
文本在四个方向的 padding
值。水平方向的指也支持两种格式,同 width
属性。垂直方向的值为正整数 或 小于1的浮点数:正整数表示 padding 的空白行数;浮点数表示 padding 小于1的行高(当该行有多个文本块时可能会失效),通过设置 line-height
属性来实现,与文本的首行或尾行实际上使用的同一行。
以上说的各个方向的 padding 值支持的数字类型和含义。对于 :padding
属性,支持以下丰富的形式进行设置:
nil
: 表示不设置 padding,会被解析为'(:left 0 :right 0 :top 0 :bottom 0)
。t
: 表示设置一个默认的 padding,会被解析为'(:left (4) :right (4) :top 0 :bottom 0)
。cons-cell
: car 部分的值表示水平方向的 padding,cdr 部分的值表示垂直方向的 padding。plist
: 表示分别设置指定方向的 padding 的值。plist 的格式就是上面解析之后的形式。
bgcolor
文本块背景色。仅在 border 以内的区域设置背景色,即包含:padding 和 文本部分。
border
设置四个方向的边框。使用 face :overline
属性实现上边框,face :underline
属性实现下边框,颜色反转的1像素空格实现左右边框。由于实现原理限制,上下边框只支持设置颜色,不支持设置宽度。
支持以下丰富的格式:
-
nil
表示不设置边框,会被解析为:'(:left (:width 0) :right (:width 0) :top (:width 0) :bottom (:width 0))
-
t
表示四个方向边框都设置默认颜色(当前 frame 的前景色),会被解析为:`(:left (:color ,default-color :width 1) :right (:color ,default-color :width 1) :top (:color ,default-color :width 1) :bottom (:color ,default-color :width 1))
-
color
表示四个方向边框都设置为color
颜色,会被解析为`(:left (:color ,color :width 1) :right (:color ,color :width 1) :top (:color ,color :width 1) :bottom (:color ,color :width 1))
-
cons-cell
的 car部分表示亮色背景下的边框颜色,cdr部分表示暗色背景下的边框颜色。会根据当前背景色解析边框为对应的颜色,格式同上。 -
plist
用于分别设置各个方向的边框颜色。单个方向的边框也支持上面的四种格式。例如下面是一个融合的例子:'(:left nil :right t :top "grey" :bottom ("#111" . "#fff"))
margin
文本在四个方向的 margin
值。除了上下 margin 不支持小于1的设置,其余格式同 padding
的设置。
KP算法
当限定宽度小于文本宽度时,会使用 knuth-plass 断行算法对文本进行排版,以实现美观的两端对齐的多行文本。该算法的 emacs-lisp 在这里: https://github.com/Kinneyzhang/emacs-kp 。该算法可以实现 CJK 与拉丁系语言的混合排版。
文本块渲染
使用上面的文本块模型创建 block 之后,就可以使用 etml-block-render
函数生成渲染后的字符串了。
下面是一个例子及渲染后的文本块图片:
(defvar etml-block-basic-str1
"作为神之编辑器(Editor of the Gods),Emacs 早已超越了普通文本编辑器的范畴。它是由Richard Stallman于1976年创建的GNU项目核心组件,其名字源自 Editor MACroS。在过去的半个世纪里,Emacs演化成了一个self-documenting, customizable, extensible的生态系统,用户可通过Emacs Lisp (elisp) 重新定义编辑行为。M-x 是每个Emacer的魔法咒语——按下Alt(或Meta键)加x即可召唤任意命令,比如M-x butterfly这样的复活节彩蛋。中国开发者常戏称其为“永远的操作系统”,因为你可以通过org-mode管理TODO list、用magit操作Git仓库、甚至用EMMS播放MP3音乐。在Unix哲学中,Emacs坚持“一个编辑器统治所有”(One Editor to Rule Them All)的理念,这与VS Code等现代编辑器形成鲜明对比。C-x C-f打开文件,C-x C-s保存文档,看似复杂的组合键一旦形成肌肉记忆,效率就会呈指数级飙升。著名Python库Black的开发者曾公开表示:\"My .emacs is my second brain.\"")
(etml-test-pop-buffer "*test-basic-block*"
(insert
(etml-block-render
(etml-block
:content etml-block-basic-str1
:width 35
:border '("#aaaaaa" . "lightGreen")
:bgcolor '("#FFF9F0" . "#222222")
:padding '(1 . 1)
:margin '(1 . 1)))))

