终于搞定了 knuth-plass 排版算法的 emacs 实现,同时对算法进行了进一步的改进,支持 CJK 和拉丁系语言的混合排版,详细设置和用法可以看 github 的 readme。下面是效果图:
很帅!
就是用起来会不会有点麻烦,好像要主动调用才能够进行排版?我有没理解错误?
让 AI 帮我写了一个简单的配置:
(defun my-justify-with-emacs-kp ()
(interactive)
(let ((text (buffer-string)) ; 获取缓冲区中的所有文本
(line-pixel 500)) ; 设置每行像素宽度
(delete-region (point-min) (point-max)) ; 清空缓冲区
(insert (ekp-pixel-justify text line-pixel)))) ; 插入排版后的文本
(global-set-key (kbd "C-c j") 'my-justify-with-emacs-kp) ; 将命令绑定到 "C-c j" 快捷键
对,是要主动调用函数,因为这是提供排版功能的基础包,主要提供两个核心函数来给其他开发者使用。至于其他的更加交互式的功能应该由上层的包自己实现。
我不打算去实现这些上层的包,因为我主要的应用场景是将排版后的文本应用到文本块的布局中去。就是你之前问我的,可以设置文本块边框、padding、margin、背景色、对齐等功能的包,以及可以对多个文本块进行任意的组合布局。这个包完善的也差不多了,后续会发布出来。
上面的这个包也是ETAF文本布局系统中的一部分,一环套一环。
我记得你之前研究过 ewoc,所以 emacs widget 和你现在所提供的排版引擎有什么不同?
手动点赞大佬
这几个东西不是一个层面的:
- emacs-kp 专注排版,是基础功能;
- emacs widget 是emacs内置的提供组件的库,可能部分组件涉及到长文本展示会用到排版,当然如果不追求美观,直接在行尾暴力断行也不是不行;
- ewoc 更类似于现代前端框架(vue,react…)中的“数据驱动”的概念,即把文本界面的渲染绑定到数据中,实现界面的增量更新。
这些概念统统结合起来,其实就是要在 emacs 中实现一个基于文本的应用程序的前端框架,这就是 ETAF 要做的事情。之所以要做这个,就是因为内置的 widget 不太好用,而且功能很局限。ETAF要做的是在emacs中实现一整个基于现代前端理念的文本框架。
是这样的,因为 justify 是基于原始文本的。这个包只提供了两个函数用来对一个字符串进行对齐这个基础功能,就相当于一个api,任何其他的我认为都是业务功能的包需要自己来实现的。
了解,大佬的文本布局系统赶紧出一个 POC 版本让小弟们测试起来,急须。
急需 +1
哈哈,我抓紧~
(ekp-pixel-justify TEXT line-pixel)
会清除 TEXT 里原有的 properties。大佬有没有考虑在 ekp-pixel-justify 方法内部保留原 TEXT 中的 properties。
(因为ekp-pixel-justify 会修改 TEXT 中的空格数目,比较难 justify 之后还原之前的 properties)
(defun emacs-kp-render ()
(interactive)
(let ((text (buffer-string))
(line-pixel 800)
buffer-read-only)
(save-excursion
(delete-region (point-min) (point-max))
(insert (ekp-pixel-justify text line-pixel)))))
(add-hook 'eww-after-render-hook #'emacs-kp-render)
用 ekp-pixel-justify 来重排 eww, 排版的挺好。 目前的两个问题是:
- 会在中文词语中间插入一些零宽空格,在文字间移动,或者复制文本需要额外的操作
- 无法保留原本的 eww face。
原版
重排
(ekp-param-fmtstr)
打印一下参数,看一下最后三位是什么,比如是 “8-4-3-6-3-2-0-2-0”,最后三位表示 CJK 的理想宽度,可拉伸宽度,可压缩宽度,如果不希望CJK字符之间有空格,可以使用 ekp-param-set
函数设置CJK拉伸宽度为 0。(我默认设置为了2)。
但是对于以中文为主的排版,设置CJK之间不允许拉伸可能会出现行尾不对齐直接断行的情况,动态规划会优先寻找最优排版,但如果出现很长的单词或者恰巧在某些特殊的像素位置,文本中没有足够的拉伸或压缩空间时,就会出现不对齐的情况,这种情况无法避免。
因此,相较于随机指定一个像素可能带来的上诉情况,使用 range 函数在一个小范围内寻找最优排版可能是一个比较好的方式。range函数的问题在于计算的效率和像素范围是成正比的,我打算后面用 rust 动态模块的多线程解决这个问题。
保留原本样式的问题,我空了想办法优化一下。
BTW:并非零宽空格,是有像素宽度的,可以 C-h p
看到设置的宽度。
测试了一波,还是保持 CJK 拉伸比较好。好看最重要。复制粘贴的问题,手动写一个函数清除掉多余的空格。
如果后续可以实现保留原本样式就完美了。