How to indent paragraphs based on heading levels

I’m working on my template project, AbyssBook (GitHub - CrossDark/AbyssBook: A dark template for typeset), and I want to indent headings and the corresponding paragraphs based on the heading’s level. The deeper the heading, the more indented it will be.

I’ve done the indentation of the title using heading.where(),but I’m having difficulty indenting the paragraphs.

Hello @CrossDark ,

Welcome to the Forum,

Would you be able to post perhaps a screenshot of the desired result? Or a code snippet of your attempt?

Would you like only the first paragraph after a heading to be indented? Or all subsequent paragraphs?

Note that there are some threads on this forum like How to apply paragraph styling based on heading levels? that could put you on the right track, including some code examples.

2 Likes

Not at the computer right now, but maybe something along the lines of

#show heading: it => {
  h(1em * it.level) + it
}

This only works for the heading, I think for the paragraph indent you’d need to acquire the current heading and then adjuts the indent accordingly.

2 Likes

I’m currently using this code to implement indentation for headings, but I haven’t implemented paragraph indentation yet.

// 设置二级标题
    show heading.where(level: 2): it => {
      pad(it, left: 0.5em, top: 0.2em, bottom: 0.2em)
    } 

    // 设置三级标题
    show heading.where(level: 3): it => {
      pad(it, left: 1em)
    } 

    // 设置四级标题
    show heading.where(level: 4): it => {
      pad(it, left: 1.5em)
    } 

    // 设置五级标题
    show heading.where(level: 5): it => {
      pad(it, left: 2em)
    } 

emm it doesn’t seem to work

It’s helpful if you can describe in what way it is not working.

In this case the code compiled and seemed like it might work (it.level was the correct integer level), but there was no visible effect on the output.

Here’s an attempt at modifying Electron_Wizard’s code which looks ok in the document, but screws up the outline:

Expand
#show heading: it => {
  set block(inset: (left: 1em * it.level))
  it
}

= L1
== L2
=== L3
== L2
= L1
== L2
=== L3

To expand on that answer, to likewise indent paragraphs, you could use the following:

#show heading: it => {
  set block(inset: (left: 8pt * it.level))
  it
}
#show par: it => context {
  let h = query(selector(heading).before(here())).at(-1, default: none)
  if h == none { return it }
  block(inset: (left: 8pt * h.level), it)
}

I have used 8pt instead of 1em for the inset, as the em unit is different for headings and paragraphs. Also, set block or similar doesn’t work here for reasons I can go into if you want, so I instead wrapped the paragraph in a block with that inset.

2 Likes

The paragraph style has indeed taken effect, but the heading remains unchanged.

But if I add a normal paragraph in headings, it works

// 按照标题的层级缩进
    show heading: it => {
      set block(inset: (left: 8em * it.level))
      it
      "普通文本"
    }
 // 按照段落对应的标题成绩缩进
    show par: it => context {
      let h = query(selector(heading).before(here())).at(-1, default: none)
      if h == none {
        return it
      }
      block(inset: (left: 0.5em * h.level), it)
    }

Works just fine.

Perhaps you have other show rules involved. Without seeing the complete document, it is rather complicated to see where the issue is.

1 Like

The full code is a bit lengthy. Would you mind checking it out on GitHub?

It is generally easier for the person who knows the code to reduce it enough so that other people can inspect it, than other people who have no knowledge of the code or what’s relevant to the issue reading through a huge codebase. Thus it is considered good form for the person asking to post all relevant code, and indeed that is also part of the question guidelines:

It would be great if you could post the smallest possible code samples that allow people to see what your problem is.


Luckily in this case it’s easy to guess what the problem is—the heading numbering. Adding this single line demonstrates the problem:

#set heading(numbering: "1.")

It seems the set block approach breaks down there, but wrapping in a block still works:

#set heading(numbering: "1.")
#show heading: it => {
  block(inset: (left: 8pt * it.level), it)
}
#show par: it => context {
  let h = query(selector(heading).before(here())).at(-1, default: none)
  if h == none { return it }
  block(inset: (left: 8pt * h.level), it)
}

= L1
#lorem(30)

== L2
#lorem(30)

=== L3
#lorem(30)

== L2
#lorem(30)

= L1
#lorem(30)

== L2
#lorem(30)

=== L3
#lorem(30)
3 Likes

Thanks, headings and paragraphs are now properly indented. However, the list is not indented.

I’m checking if I’ve made any additional settings for the list.

Continuing on @SillyFreak’s solution, you would have to add something like:

#show enum: it => context {
  let h = query(selector(heading).before(here())).at(-1, default: none)
  if h == none { return it }

  block(inset: (left: 8pt * h.level), it)
}

you could even use

#show selector.or(par, enum): ...
1 Like

Thanks,lists are now properly indented, but there is excessive space between the list numbers and their corresponding content.

    // 显示段落和列表时根据对应的标题层级缩进
    // Indent paragraphs based on corresponding heading level
    show selector.or(par, enum): it => context { // 查找标题和段落并传递给it变量
      let h = query(selector(heading).before(here())).at(-1, default: none) // 获取前一个标题 / Get previous heading
      if h == none {
        return it               // 如果没有标题,返回原段落 / Return original paragraph if no heading
      }
      block(inset: (left: 1em * (h.level + 1)), it) // 根据标题级别缩进,额外再缩进一级与标题区分 / Indent based on heading level + 1
    }

When posting code, use typc instead.