diff --git a/CHANGELOG.md b/CHANGELOG.md index 961ceb4c..401a06c8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +* Allow passing `Range` objects to the `nesting_level` option to have + a higher level of customization for table of contents: + + ~~~ruby + Redcarpet::Render::HTML_TOC.new(nesting_level: 2..5) + ~~~ + ## Version 3.4.0 * Rely on djb2 hashing generating anchors with non-ASCII chars. diff --git a/README.markdown b/README.markdown index 50db74e0..c16454b3 100644 --- a/README.markdown +++ b/README.markdown @@ -182,8 +182,8 @@ which will output a table of contents in HTML based on the headers of the Markdown document. When instantiating this render object, you can optionally pass a `nesting_level` -option which takes an integer and allows you to make it render only headers -until a specific level. +option which takes an integer or a range and allows you to make it render only +headers at certain levels. Redcarpet also includes a plaintext renderer, `Redcarpet::Render::StripDown`, that strips out all the formatting: diff --git a/ext/redcarpet/html.c b/ext/redcarpet/html.c index 9eab059d..bd61c3d9 100644 --- a/ext/redcarpet/html.c +++ b/ext/redcarpet/html.c @@ -326,7 +326,8 @@ rndr_header(struct buf *ob, const struct buf *text, int level, void *opaque) if (ob->size) bufputc(ob, '\n'); - if ((options->flags & HTML_TOC) && (level <= options->toc_data.nesting_level)) { + if ((options->flags & HTML_TOC) && level >= options->toc_data.nesting_bounds[0] && + level <= options->toc_data.nesting_bounds[1]) { bufprintf(ob, ""); @@ -675,7 +676,8 @@ toc_header(struct buf *ob, const struct buf *text, int level, void *opaque) { struct html_renderopt *options = opaque; - if (level <= options->toc_data.nesting_level) { + if (level >= options->toc_data.nesting_bounds[0] && + level <= options->toc_data.nesting_bounds[1]) { /* set the level offset if this is the first header * we're parsing for the document */ if (options->toc_data.current_level == 0) @@ -824,7 +826,8 @@ sdhtml_renderer(struct sd_callbacks *callbacks, struct html_renderopt *options, /* Prepare the options pointer */ memset(options, 0x0, sizeof(struct html_renderopt)); options->flags = render_flags; - options->toc_data.nesting_level = 99; + options->toc_data.nesting_bounds[0] = 1; + options->toc_data.nesting_bounds[1] = 6; /* Prepare the callbacks */ memcpy(callbacks, &cb_default, sizeof(struct sd_callbacks)); diff --git a/ext/redcarpet/html.h b/ext/redcarpet/html.h index a3eb10fa..1e13cb36 100644 --- a/ext/redcarpet/html.h +++ b/ext/redcarpet/html.h @@ -35,7 +35,7 @@ struct html_renderopt { struct { int current_level; int level_offset; - int nesting_level; + int nesting_bounds[2]; } toc_data; unsigned int flags; diff --git a/ext/redcarpet/rc_render.c b/ext/redcarpet/rc_render.c index 592dad34..09756472 100644 --- a/ext/redcarpet/rc_render.c +++ b/ext/redcarpet/rc_render.c @@ -511,10 +511,22 @@ static VALUE rb_redcarpet_htmltoc_init(int argc, VALUE *argv, VALUE self) sdhtml_toc_renderer(&rndr->callbacks, (struct html_renderopt *)&rndr->options.html, render_flags); rb_redcarpet__overload(self, rb_cRenderHTML_TOC); - if (!(NIL_P(nesting_level))) - rndr->options.html.toc_data.nesting_level = NUM2INT(nesting_level); - else - rndr->options.html.toc_data.nesting_level = 6; + /* Check whether we are dealing with a Range object by + checking whether the object responds to min and max */ + if (rb_respond_to(nesting_level, rb_intern("min")) && + rb_respond_to(nesting_level, rb_intern("max"))) { + int min = NUM2INT(rb_funcall(nesting_level, rb_intern("min"), 0)); + int max = NUM2INT(rb_funcall(nesting_level, rb_intern("max"), 0)); + + rndr->options.html.toc_data.nesting_bounds[0] = min; + rndr->options.html.toc_data.nesting_bounds[1] = max; + } else if (FIXNUM_P(nesting_level)) { + rndr->options.html.toc_data.nesting_bounds[0] = 1; + rndr->options.html.toc_data.nesting_bounds[1] = NUM2INT(nesting_level); + } else { + rndr->options.html.toc_data.nesting_bounds[0] = 1; + rndr->options.html.toc_data.nesting_bounds[1] = 6; + } return Qnil; } diff --git a/test/html_toc_render_test.rb b/test/html_toc_render_test.rb index 6bef90b4..f06b1836 100644 --- a/test/html_toc_render_test.rb +++ b/test/html_toc_render_test.rb @@ -33,6 +33,20 @@ def test_granular_toc_render assert !output.include?("A sub-sub title") end + def test_granular_toc_render_with_range + output = render(@markdown, with: { nesting_level: 2..5 }).strip + + assert output.start_with?("") + + assert output.match("Another one") + assert output.match("A sub-sub-title") + assert output.match("見出し") + + refute output.match("A title") + refute output.match("A really tiny title") + end + def test_toc_heading_id output = render(@markdown)