外观
DRAFT ETML: 文本块滚动原理详解
约 1004 字大约 3 分钟
elispbuffer
2025-08-17
何谓 "文本块滚动"
当我们给一段长文本限定了文本块宽度(width)之后,当文本块宽度(width)小于文本宽度(text-width)时,文本会被分割为宽度相等的多行,此时便形成了文本块。再限制一下文本块的高度,当文本块高度(height)小于文本的总行数(text-height)时,便会出现文本 height+1 行到 text-height 行之间(包含)的内容溢出文本块的情况。该如何处理溢出的文本?
有两种方式:1.直接截断,隐藏多余的文本行;2.通过滚动方式查看剩余的文本(类似浏览器网页的滚动),这种便是""文本块的滚动",接下来循序渐进介绍实现原理。
文本滚动
对给定的文本限定宽度后便形成了多行宽度相等的文本块,关于文本的渲染相关内容请看: ETML: Emacs buffer 文本块渲染。
文本块渲染之后的静态文本展示在文本块内的是:从文本首行依次向下的多行文本。要想让文本动起来,就要让 "文本块内展示的文本(shown-content)"与"实际的文本(content)" 发生偏移。即当文本块的首行显示实际文本的第二行时,相对于初始的状态就实现了文本向下滚动的效果,以此类推。
我们需要一个 scroll-offset-y
变量来表示:"实际的文本"相对于"展示的文本"的偏移量,该值初始为 0,增大表示向下滚动,减小表示向上滚动。因此,我们只需要为 etml-block
模型添加该属性来渲染指定 offset 时的文本块。不断调整 offset,再重新渲染文本块便实现了简单的文本滚动效果。
实现起来也非常直观:每次取文本列表的 scroll-offset-y
到 (+ scroll-offset-y (1- height))
行的文本渲染到文本块中。
滚动条实现
当文本溢出文本块的高度时,需要一个滚动条表示当前文本可以滚动,接下来我们来考虑如何实现一个滚动条。
设置如下变量来渲染一个滚动条:
- 滚动条的宽度:
scroll-bar-pixel
- 滚动条的颜色:
scroll-bar-color
- 滚动条的方向:
scroll-bar-direction
- 滚动条与边框的距离:
scroll-bar-gap
- 滚动条的样式:
scroll-bar-full
除了上面的参数,渲染时还需要考虑"滚动条的高度"。根据日常经验,我们可以观察到"滚动条的高度"和"可滚动的高度"有关系:当可滚动高度越小时,滚动条高度越长;可滚动高度越大时,滚动条高度越短。
我们可以通过递推来找到这两者之间的关系:
- 当可滚动高度为
1
时,滚动条高度为height-1
,此时滚动1
次滚动条到达底部。 - 当可滚动高度为
2
时,滚动条高度为height-2
,此时滚动2
次滚动条到达底部。 - 当可滚动高度为
height-1
时,滚动条高度为1
,此时滚动height-1
次滚动条到达底部。
由于滚动条最小高度只能为1,当可滚动高度大于 height-1
时,如何处理?
此时滚动条的一次滚动不再对应文本的一次滚动,即可能会出现文本滚动多行才对应滚动条的一次移动。接下来考虑如何计算两者的对应关系?