I would like to automate the numbering in my markdown file using pure Jinja2 implementation.
I have been able to achieve single-level numbering using the following:
{% set number = 1 %}
{% macro set_number() -%}
{{ number }}
{%- set number = number + 1 -%}
{%- endmacro %}
And then, when i call set_number()
; for example:
## Test Heading {{ set_number() }}
it renders just fine.
However, it is second-level numbering that i am struggling with. I would like to have a numbering scheme such as 1, 2a, 2b, 2c, 3, 4a, 4b... and so on. I have tried the following code, but it doesn't work.
Option 1
{% set number = 1 %}
{% set sub_number = 'a' %}
{% macro set_number() -%}
{{ number }}{{ sub_number }}
{%- set sub_number = sub_number|int + 1 %}
{%- set sub_number_2 = sub_number|string %}
{%- if sub_number_2 > 'z' -%}
{%- set number = number + 1 -%}
{%- set sub_number = 'a' -%}
{%- endif -%}
{%- endmacro %}
And then, when i call the function; for example:
## Test heading {{ set_number() }}
## Test heading {{ set_number() }}
## Test heading {{ set_number() }}
## Test heading {{ set_number() }}
The output of option 1 is as follows:
Test heading 1a
Test heading 11
Test heading 12
Test heading 13
Test heading 14
Option 2
I also tried the following, but it does not work. The Python function chr()
and ord()
do not work:
{% set number = 1 %}
{% set sub_number = 'a' %}
{% macro set_number() -%}
{{ number }}{{ sub_number }}
{%- set sub_number = chr(ord(sub_number) + 1) %}
{%- if sub_number > 'z' -%}
{%- set number = number + 1 -%}
{%- set sub_number = 'a' -%}
{%- endif -%}
{%- endmacro %}
Can someone please guide me here.
Jinja has a cycler
filter that can be used for this if we provide the letters as a list. We can use letter.current
attribute the check whether we need to increase the header number by one.
{% set heading = namespace(number=0) %}
{% set letter = cycler(*'abcdefghijklmnopqrstuvwxyz'|list) %}
{% macro set_header() -%}
{%- if letter.current == 'a' %}
{%- set heading.number = heading.number + 1 %}
{%- endif %}
{{ heading.number }}{{ letter.next() }}
{%- endmacro %}
This will produce: 1a, 1b, 1c, ... 1z, 2a, 2b.
In this version we can turn on the letter subheader with the sub=True
parameter of our macro. We also need a new tracking variable in the namespace object (heading.last_sub
) that tells us when we are in a letter series.
{% set heading = namespace(number=0, last_sub=None) %}
{% set letter = cycler(*'abcdefghijklmnopqrstuvwxyz'|list) %}
{%- macro set_header(sub=False) %}
{%- if sub == False or heading.last_sub == False %}
{%- set heading.number = heading.number + 1 %}
{%- set reset = letter.reset() %}
{%- endif %}
{{ heading.number }}{% if sub %}{{ letter.next() }}{% endif %}
{%- set heading.last_sub = sub %}
{%- endmacro %}
For this code:
{{ set_header() }}
{{ set_header() }}
{{ set_header(True) }}
{{ set_header(True) }}
{{ set_header(True) }}
{{ set_header() }}
{{ set_header() }}
{{ set_header(True) }}
{{ set_header(True) }}
it will produce the following series: 1, 2, 3a, 3b, 3c, 4, 5, 6a, 6b.