Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

shift-heading-level-by not adjusting numbering correctly in quarto 1.6 #12048

Open
t-kalinowski opened this issue Feb 9, 2025 · 9 comments
Open
Labels
bug Something isn't working

Comments

@t-kalinowski
Copy link

Bug description

Given this quarto file in a book project:

# h1

foo

## h2

foo 

### h3  

foo 

#### h4

foo 

##### h5

foo

if shift-heading-level-by: -1 is provided, quarto 1.3 produces this:

Image

However, quarto 1.6 (the current release) produces this:

Image

Note that with quarto 1.6, the h3 heading is still numbered as an h3 heading, and not as a level 2 heading as expected.

In an actual book project, this manifests as all subsections numbers having a .0. phantom level 2 heading.

Steps to reproduce

No response

Expected behavior

No response

Actual behavior

No response

Your environment

  • OS: Ubuntu

Quarto check output

$ quarto check
Quarto 1.6.40
[✓] Checking environment information...
      Quarto cache location: /home/tomasz/.cache/quarto
[✓] Checking versions of quarto binary dependencies...
      Pandoc version 3.4.0: OK
      Dart Sass version 1.70.0: OK
      Deno version 1.46.3: OK
      Typst version 0.11.0: OK
[✓] Checking versions of quarto dependencies......OK
[✓] Checking Quarto installation......OK
      Version: 1.6.40
      Path: /opt/quarto/bin

[✓] Checking tools....................OK
      TinyTeX: v2024.09
      Chromium: (not installed)

[✓] Checking LaTeX....................OK
      Using: TinyTex
      Path: /home/tomasz/.TinyTeX/bin/x86_64-linux
      Version: 2024

[✓] Checking basic markdown render....OK

[✓] Checking Python 3 installation....OK
      Version: 3.10.12
      Path: /usr/bin/python3
      Jupyter: 4.9.1
      Kernels: python3

(|) Checking Jupyter engine render....Traceback (most recent call last):
  File "/opt/quarto/share/jupyter/jupyter.py", line 21, in <module>
    from notebook import notebook_execute, RestartKernel
  File "/opt/quarto/share/jupyter/notebook.py", line 19, in <module>
    import nbformat
ModuleNotFoundError: No module named 'nbformat'
There is a requirements.txt file in this directory. Is this for a venv that you need to restore?

[✓] Checking Jupyter engine render....OK

@t-kalinowski t-kalinowski added the bug Something isn't working label Feb 9, 2025
@t-kalinowski t-kalinowski changed the title shift-heading-level-by not adjust numbering correctly in quarto 1.6 shift-heading-level-by not adjusting numbering correctly in quarto 1.6 Feb 9, 2025
@cderv
Copy link
Collaborator

cderv commented Feb 11, 2025

@t-kalinowski what do you expect shift-heading-level-by to do in a book context ?
Are you using this for tweaking the numbering ?

I understand the first results from Quarto 1.3 is what you expect with 1. then 2. directly ?

In book, a .qmd doc is a chapter, and level 1 header (# h1) is used as the chapter title. Shifting by -1 would make ## (h2 level) be as # (h1 level) and so it would lead to two chapter title.

I know we had some discussion about shift-heading-level-by in the past and this is still something we need to decide how to handle, especially in book. This is initially a Pandoc level configuration, but Book format is Quarto specific and obviously this needs some specific consideration to do the right thing.

Disallow support for shift-heading-level-by in Book project is a question. Knowing more about the reason to use it seems important.

Thank you !

Related Discussion

@t-kalinowski
Copy link
Author

t-kalinowski commented Feb 11, 2025

My primary motivation is to get rid of the .0. in all the chapter section numberings:

Image

These are all level three ### headings in the qmd. I could manually adjust all the headings in the qmds to be level 2 headings, but I previously used shift-heading-level-by to make it so that those chapter sections would be numbered 4.1, 4.2, 4.3, 4.4.

@mcanouil
Copy link
Collaborator

mcanouil commented Feb 11, 2025

What header level are you using? To get this result, it means you skipped one level.

InputOutput
# Summary

In summary, this book has no content whatsoever.

## About the Author

This is a fake author.
Image
---
title: Summary
---

In summary, this book has no content whatsoever.

## About the Author

This is a fake author.
Image

@t-kalinowski
Copy link
Author

These are all level three ### headings in the qmd

@mcanouil
Copy link
Collaborator

What is the reason to use level three headers instead of the expected level two?

@cderv
Copy link
Collaborator

cderv commented Feb 12, 2025

Looking at this more closely, outside of book context, I think this highlight a different in behavior with how Pandoc works.

I am taking this document as example with no level 2 in the document and asking to shift any level by 2 to consider them as level 1. to

---
title: "Test"
format: html
number-sections: true
shift-heading-level-by: -1
---

```{=html}
<style>
h1 { color: red; }
h2 { color: green; }
h3 { color: blue; }
h4 { color: purple; }
h5 { color: orange; }
</style>
```
### h3  

foo 

#### h4

foo 

##### h5

foo

Rendering with Quarto gives this results

Image

where heades have correct style corresponding to their new levels but the numbering is not right as 0. means an existant level one has been considered.

Running same document with Pandoc

pandoc -t html -s -o test.html -N --shift-heading-level-by=-2 test.qmd

have correct numbering.

Image

I think this is all related to shift-heading-level-by option not correctly being handle in very simple case in Quarto.

Simpler example

---
title: "Test"
format: html
number-sections: true
---

## First

foo 

## Second

foo 

## Third

foo

Documents looks good with the correct numbering

Image

Now this should be equivalent IMO

---
title: "Test"
format: html
number-sections: true
shift-heading-level-by: -1
---

### First

foo 

### Second

foo 

### Third

foo

But see the numbering:

Image

So either

  • We should fix shift-heading-level-by
  • We should disallow using shift-heading-level-by in quarto context.

The latter implies that quarto expectation are that Markdown levels used are correct. Or that users shift document levels using a Lua filter

Header = function(h)
  h.level = h.level -1
  return h
end

@t-kalinowski using a Lua filter instead of the Pandoc option maybe working solution for your current situation. Could even be shifting only some level (skiping h.level == 1 for example).

This shift-heading-level-by remind me of another issue so I'll try to understand why we derived from Pandoc behavior on this one. (possibly we are taking in charge the numbering instead of Pandoc)

@t-kalinowski
Copy link
Author

Thank you @cderv, that MRE looks like it isolated the issue!

That lua filter looks like it'll do the job, I'll try using that approach for now.

In case it's helpful for others in the future, I drafted a short R snippet for manually converting all headings in a project. It's a little crude run once script and doesn't handle nested code blocks. Only run this if you're using version control!

library(magrittr)
library(stringi)

for (file in Sys.glob(c("*.qmd", "*.md"))) {

  lines <- readLines(file)
  is_code <- as.logical(cumsum(startsWith(lines, "```")) %% 2)

  for(lvl in 1:7) {
    prefix <- paste0(strrep("#", lvl), " ")
    is_heading <- startsWith(lines, prefix) & !is_code
    lines[is_heading] %<>% stri_sub(2)
    if(any(is_h0 <- !startsWith(lines[is_heading], "#")))
      warning("file: ", file, " lvl 0 headings introduced: ", lines[is_heading][is_h0])
  }
  writeLines(lines, file)
}

What is the reason to use level three headers instead of the expected level two?

This is a quarto project that previously used level 3 headers, and now is unable to after a recent quarto update.

I vaguely recall there was some friction I encountered w/ manually exporting to asciidoc (quarto ascidoc export wasn't a feature yet), and some specific requirements about headings from the publisher.

@t-kalinowski
Copy link
Author

t-kalinowski commented Feb 12, 2025

The lua filter works great!

Image

For others coming across this:

In _quarto.yml I have

format:
  html:
    filters:
      # work around bug with `shift-level-headings-by`
      # https://github.com/quarto-dev/quarto-cli/issues/12048
      - scripts/shift-heading-levels.lua
    theme:
      light: cosmo
      dark: darkly

and scripts/shift-heading-levels.lua is:

Header = function(h)
  if h.level > 1 then
    h.level = h.level - 1
  end
  return h
end

@cderv
Copy link
Collaborator

cderv commented Feb 12, 2025

The lua filter works great!

Awesome ! That is the best solution for now IMO.

It let me time to look at the problem deeper

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

3 participants