Skip to content

如何避免公式、图表等块元素的下一行缩进?

如何避免公式、图表等块元素的下一行缩进?

问题

在段落中加入行间数学公式,总会在后面加入一个新段落,导致出现段落首行缩进。

typst
#lorem(10), for example,
$ integral x + y = z $
shows that the integral of $x + y$ is $z$.
Typst compiled image

我们希望在创建行间数学公式,且公式后没有空行时,不出现新段落和首行缩进。

实用解决办法——遍历全文,抵消缩进

在所有show/set规则后加一段show规则,抵消全文各处多余的缩进。

typst
#set par(first-line-indent: (all: true, amount: 2em))

// 以下规则必须放在最后
#show: rest => {
  let immediately-after = false

  for it in rest.children {
    if immediately-after and it.func() == text {
      context h(-par.first-line-indent.amount)
    }
    it

    if it != [ ] {
      immediately-after = false
    }

    if (
      (it.func() == math.equation and it.block)
        or it.func() == list.item
        or it.func() == enum.item
    ) {
      immediately-after = true
    }
  }
}


应用以上规则后,公式后若不空行,例如
$ x $
则后文首行不缩进。

若空行,例如这样
$ y $

则后文另起一段,首行缩进。
Typst compiled image
原理

(为简单,这里仅以公式和换行为例;以上代码也适用于列表、空格等情况。)

现象:如果源代码在公式后连换两行(即空一行),则在 Typst 中公式后的元素为parbreak;若只换一行(即不空行),则为space;若只换一行且加了标签(例:前一行 $ x $ <eq> 后一行),则出现连续两个space

思路:设计 show 规则,匹配“公式,零个或任意多个space,文本”序列,抵消序列中文本的首行缩进。

具体操作:

  • 匹配到序列后,保留公式,在文本前加h(-par.first-line-indent.amount)
  • 不匹配时,原样显示。

效果: show 规则会让文章发生以下变化。

typst
#sequence(
  parbreak(),
  [应用以上规则后,公式后若不空行,例如],
  [ ],
  equation(block: true, body: [x]),
  [ ],
  context h(-2em), 
  [则后文首行不缩进。],
  parbreak(),
  [若空行,例如这样],
  [ ],
  equation(block: true, body: [y]),
  parbreak(),
  [则后文另起一段,首行缩进。],
  [ ],
)

来源:physy 在 #3206 的评论

这种方法有以下若干小问题,不过也基本够用了。

  • 如果后文以*strong*_emph_等开头,那么方法失效,仍会错误缩进。(可用#h(-2em)等方式手动解决)
  • 仅仅抵消了缩进,并未改变分段情况,语义仍不正确。
  • 公式上下仍然是段间距par.spacing,会比行间距par.leading大。
  • 不支持在文章半途切换par.first-line-indent

语义正确的解决办法——套 box

这种方法用起来很繁琐,且不支持公式跨页,但它不存在前法的四个问题。

下面以公式为例,但方法其实也适用于 tight list 和 figure 等。

基础情况

#box() 将行间数学公式包住,且不能有空行。

typst
#set par(first-line-indent: (amount: 2em, all: true))

#lorem(10), for example,
#box[$ integral x + y = z $] 
shows that the integral of $x + y$ is $z$.

#lorem(20)
Typst compiled image

若启用两端对齐

如果你启用了justify两端对齐,那么还需在box之前人为换行,以取消box前一行的调整。

typst
#set par(justify: true, first-line-indent: (amount: 2em, all: true))

= Bad

#lorem(10), for example, 
#box[$ integral x + y = z $]
shows that the integral of $x + y$ is $z$.

= Good

#lorem(10), for example, \ 
#box[$ integral x + y = z $]
shows that the integral of $x + y$ is $z$.
Typst compiled image

若公式无编号

若公式无编号,那么还需用width: 100%指定box占满宽度。

typst
#set par(first-line-indent: (amount: 2em, all: true))

= Bad

#lorem(10), for example,
#box[$ integral x + y = z $] 
shows that the integral of $x + y$ is $z$.

= Good

#lorem(10), for example,
#box(width: 100%)[$ integral x + y = z $] 
shows that the integral of $x + y$ is $z$.
Typst compiled image

另请参见

Comments
  • Latest
  • Oldest
  • Hottest
Powered by Waline v3.8.0

基于 MIT 许可发布