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

PDF just one chapter, with correct chap/sect numbering #166

Closed
stallio opened this issue May 29, 2015 · 8 comments
Closed

PDF just one chapter, with correct chap/sect numbering #166

stallio opened this issue May 29, 2015 · 8 comments
Assignees
Milestone

Comments

@stallio
Copy link

stallio commented May 29, 2015

I want to make a PDF of just one chapter from a book, when that chapter is not necessarily chapter 1, and yet have the chapter/section numbering be correct (so if it's chapter 2, the first section would be 2.1, etc.)

I can think of a couple ways this could work:

  1. Some way to define/override the value for :sectnum (probably an attribute)
  2. Insert dummy sections before the first level-1 section but somehow suppress them from printing

Is there some way to do option 2 that I'm missing?

@mojavelinux
Copy link
Member

I wouldn't want to encourage you to do option 2 as that is a very non-semantic hack. Option 1 is a much better pursuit.

This need actually comes up in all outputs, not just PDF, so we likely want to solve it in core. I'm thinking something like sectnumoffset so that it pushes the start value from 1 by this amount. This would be a pretty easy change to make, I think.

In the meantime, the best way to do this is by writing a Treeprocessor extension. With a Treeprocessor, you can walk all the block-level nodes and modify them. In this case, you would just descend the section notes and assign a new section number.

require 'asciidoctor/extensions'

include ::Asciidoctor

Extensions.register do
  # A treeprocessor that increments each level-1 section number by the value of
  # the `sectnumoffset` attribute. The numbers of all subsections will be
  # incremented automatically since those values are calculated dynamically.
  treeprocessor do
    process do |document|
      if (sectnumoffset = (document.attr 'sectnumoffset', 0).to_i) > 0
        ((document.find_by context: :section) || []).each do |sect|
          next unless sect.level == 1
          sect.number += sectnumoffset
        end
      end
      nil
    end
  end
end

I've added this extension to the extensions lab.

Here's the issue in core to track. asciidoctor/asciidoctor#1113

@mojavelinux mojavelinux added this to the future milestone Jul 4, 2015
@mojavelinux mojavelinux self-assigned this Jul 4, 2015
@stallio
Copy link
Author

stallio commented Aug 21, 2015

This is pretty similar to #188

@stallio
Copy link
Author

stallio commented Sep 8, 2015

I finally got around to figuring out how to install and run this treeprocessor. Thanks!

It doesn't seem to work on appendixes, though. If I try to use :sectnumoffset: on an appendix, it says "can't convert FixedNum to String" (because appendixes use letters instead of numbers for their chapter number).

@mojavelinux
Copy link
Member

@stallio Uh oh. Could you file an issue in the extensions lab and cite and example document to test. This Treeprocessor now lives there.

https://github.com/asciidoctor/asciidoctor-extensions-lab

I'll provide another technique for rendering a single chapter that gets all the numbering right. Load the document using the API, delete all the other chapters from the AST (or copy the chapter you want to another AST), then render the result. Perhaps we can add that to the extensions-lab for demonstration purposes. You can see something similar in the multipage HTML converter. See https://github.com/asciidoctor/asciidoctor-extensions-lab/blob/master/lib/multipage-html5-converter.rb

@mojavelinux
Copy link
Member

...granted, that trick is somewhat ugly, but it certainly gets the job done :)

@arosien
Copy link

arosien commented Sep 10, 2020

The sectnumoffset extension works for me when outputting HTML, but gives me this error when outputting PDF:

/usr/lib/ruby/gems/2.6.0/gems/rouge-3.15.0/lib/rouge.rb:55:in `block in <top (required)>': asciidoctor: FAILED: /documents/book/excerpt-concurrent-state.adoc: Failed to load AsciiDoc document - uninitialized constant Rouge::Lexers (NameError)
        from /usr/lib/ruby/gems/2.6.0/gems/rouge-3.15.0/lib/rouge.rb:55:in `each'
        from /usr/lib/ruby/gems/2.6.0/gems/rouge-3.15.0/lib/rouge.rb:55:in `<top (required)>'
        from /usr/lib/ruby/2.6.0/rubygems/core_ext/kernel_require.rb:130:in `require'
        from /usr/lib/ruby/2.6.0/rubygems/core_ext/kernel_require.rb:130:in `rescue in require'
        from /usr/lib/ruby/2.6.0/rubygems/core_ext/kernel_require.rb:34:in `require'
        from /usr/lib/ruby/gems/2.6.0/gems/polyglot-0.3.5/lib/polyglot.rb:65:in `require'
        from /usr/lib/ruby/gems/2.6.0/gems/asciidoctor-2.0.10/lib/asciidoctor/rouge_ext.rb:2:in `<top (required)>'
        from /usr/lib/ruby/2.6.0/rubygems/core_ext/kernel_require.rb:54:in `require'
        from /usr/lib/ruby/2.6.0/rubygems/core_ext/kernel_require.rb:54:in `require'
        from /usr/lib/ruby/gems/2.6.0/gems/polyglot-0.3.5/lib/polyglot.rb:65:in `require'
        from /usr/lib/ruby/gems/2.6.0/gems/asciidoctor-2.0.10/lib/asciidoctor/helpers.rb:27:in `require_library'
        from /usr/lib/ruby/gems/2.6.0/gems/asciidoctor-2.0.10/lib/asciidoctor/syntax_highlighter/rouge.rb:78:in `load_library'
        from /usr/lib/ruby/gems/2.6.0/gems/asciidoctor-2.0.10/lib/asciidoctor/syntax_highlighter/rouge.rb:74:in `library_available?'
        from /usr/lib/ruby/gems/2.6.0/gems/asciidoctor-2.0.10/lib/asciidoctor/syntax_highlighter/rouge.rb:12:in `highlight?'
        from /usr/lib/ruby/gems/2.6.0/gems/asciidoctor-2.0.10/lib/asciidoctor/substitutors.rb:1288:in `commit_subs'
        from /usr/lib/ruby/gems/2.6.0/gems/asciidoctor-2.0.10/lib/asciidoctor/parser.rb:918:in `next_block'
        from /usr/lib/ruby/gems/2.6.0/gems/asciidoctor-2.0.10/lib/asciidoctor/parser.rb:379:in `next_section'
        from /usr/lib/ruby/gems/2.6.0/gems/asciidoctor-2.0.10/lib/asciidoctor/parser.rb:364:in `next_section'
        from /usr/lib/ruby/gems/2.6.0/gems/asciidoctor-2.0.10/lib/asciidoctor/parser.rb:364:in `next_section'
        from /usr/lib/ruby/gems/2.6.0/gems/asciidoctor-2.0.10/lib/asciidoctor/parser.rb:364:in `next_section'
        from /usr/lib/ruby/gems/2.6.0/gems/asciidoctor-2.0.10/lib/asciidoctor/parser.rb:97:in `parse'
        from /usr/lib/ruby/gems/2.6.0/gems/asciidoctor-2.0.10/lib/asciidoctor/document.rb:549:in `parse'
        from /usr/lib/ruby/gems/2.6.0/gems/asciidoctor-2.0.10/lib/asciidoctor/load.rb:83:in `load'
        from /usr/lib/ruby/gems/2.6.0/gems/asciidoctor-2.0.10/lib/asciidoctor/convert.rb:78:in `convert'
        from /usr/lib/ruby/gems/2.6.0/gems/asciidoctor-2.0.10/lib/asciidoctor/convert.rb:183:in `block in convert_file'
        from /usr/lib/ruby/gems/2.6.0/gems/asciidoctor-2.0.10/lib/asciidoctor/convert.rb:183:in `open'
        from /usr/lib/ruby/gems/2.6.0/gems/asciidoctor-2.0.10/lib/asciidoctor/convert.rb:183:in `convert_file'
        from /usr/lib/ruby/gems/2.6.0/gems/asciidoctor-2.0.10/lib/asciidoctor/cli/invoker.rb:128:in `block in invoke!'
        from /usr/lib/ruby/gems/2.6.0/gems/asciidoctor-2.0.10/lib/asciidoctor/cli/invoker.rb:111:in `each'
        from /usr/lib/ruby/gems/2.6.0/gems/asciidoctor-2.0.10/lib/asciidoctor/cli/invoker.rb:111:in `invoke!'
        from /usr/lib/ruby/gems/2.6.0/gems/asciidoctor-2.0.10/bin/asciidoctor:15:in `<top (required)>'
        from /usr/bin/asciidoctor:23:in `load'
        from /usr/bin/asciidoctor:23:in `<main>'
/usr/lib/ruby/2.6.0/rubygems/core_ext/kernel_require.rb:54:in `require': cannot load such file -- rouge (LoadError)
        from /usr/lib/ruby/2.6.0/rubygems/core_ext/kernel_require.rb:54:in `require'
        from /usr/lib/ruby/gems/2.6.0/gems/polyglot-0.3.5/lib/polyglot.rb:65:in `require'
        from /usr/lib/ruby/gems/2.6.0/gems/asciidoctor-2.0.10/lib/asciidoctor/rouge_ext.rb:2:in `<top (required)>'
        from /usr/lib/ruby/2.6.0/rubygems/core_ext/kernel_require.rb:54:in `require'
        from /usr/lib/ruby/2.6.0/rubygems/core_ext/kernel_require.rb:54:in `require'
        from /usr/lib/ruby/gems/2.6.0/gems/polyglot-0.3.5/lib/polyglot.rb:65:in `require'
        from /usr/lib/ruby/gems/2.6.0/gems/asciidoctor-2.0.10/lib/asciidoctor/helpers.rb:27:in `require_library'
        from /usr/lib/ruby/gems/2.6.0/gems/asciidoctor-2.0.10/lib/asciidoctor/syntax_highlighter/rouge.rb:78:in `load_library'
        from /usr/lib/ruby/gems/2.6.0/gems/asciidoctor-2.0.10/lib/asciidoctor/syntax_highlighter/rouge.rb:74:in `library_available?'
        from /usr/lib/ruby/gems/2.6.0/gems/asciidoctor-2.0.10/lib/asciidoctor/syntax_highlighter/rouge.rb:12:in `highlight?'
        from /usr/lib/ruby/gems/2.6.0/gems/asciidoctor-2.0.10/lib/asciidoctor/substitutors.rb:1288:in `commit_subs'
        from /usr/lib/ruby/gems/2.6.0/gems/asciidoctor-2.0.10/lib/asciidoctor/parser.rb:918:in `next_block'
        from /usr/lib/ruby/gems/2.6.0/gems/asciidoctor-2.0.10/lib/asciidoctor/parser.rb:379:in `next_section'
        from /usr/lib/ruby/gems/2.6.0/gems/asciidoctor-2.0.10/lib/asciidoctor/parser.rb:364:in `next_section'
        from /usr/lib/ruby/gems/2.6.0/gems/asciidoctor-2.0.10/lib/asciidoctor/parser.rb:364:in `next_section'
        from /usr/lib/ruby/gems/2.6.0/gems/asciidoctor-2.0.10/lib/asciidoctor/parser.rb:364:in `next_section'
        from /usr/lib/ruby/gems/2.6.0/gems/asciidoctor-2.0.10/lib/asciidoctor/parser.rb:97:in `parse'
        from /usr/lib/ruby/gems/2.6.0/gems/asciidoctor-2.0.10/lib/asciidoctor/document.rb:549:in `parse'
        from /usr/lib/ruby/gems/2.6.0/gems/asciidoctor-2.0.10/lib/asciidoctor/load.rb:83:in `load'
        from /usr/lib/ruby/gems/2.6.0/gems/asciidoctor-2.0.10/lib/asciidoctor/convert.rb:78:in `convert'
        from /usr/lib/ruby/gems/2.6.0/gems/asciidoctor-2.0.10/lib/asciidoctor/convert.rb:183:in `block in convert_file'
        from /usr/lib/ruby/gems/2.6.0/gems/asciidoctor-2.0.10/lib/asciidoctor/convert.rb:183:in `open'
        from /usr/lib/ruby/gems/2.6.0/gems/asciidoctor-2.0.10/lib/asciidoctor/convert.rb:183:in `convert_file'
        from /usr/lib/ruby/gems/2.6.0/gems/asciidoctor-2.0.10/lib/asciidoctor/cli/invoker.rb:128:in `block in invoke!'
        from /usr/lib/ruby/gems/2.6.0/gems/asciidoctor-2.0.10/lib/asciidoctor/cli/invoker.rb:111:in `each'
        from /usr/lib/ruby/gems/2.6.0/gems/asciidoctor-2.0.10/lib/asciidoctor/cli/invoker.rb:111:in `invoke!'
        from /usr/lib/ruby/gems/2.6.0/gems/asciidoctor-2.0.10/bin/asciidoctor:15:in `<top (required)>'
        from /usr/bin/asciidoctor:23:in `load'
        from /usr/bin/asciidoctor:23:in `<main>'

I use docker-asciidoctor and am running asciidoctor-pdf with additional flags -r ./lib/sectnumoffset-treeprocessor.rb -a sectnums -a sectnumoffset=9 --trace.

If I remove those extra flags the PDF renders fine, so somehow this extension is interfering somehow, maybe some ordering issue?

@mojavelinux
Copy link
Member

@arosien The issue you are seeing has nothing to do with Asciidoctor PDF. It's a problem with the version of Rouge you are using and a conflict with internal Asciidoctor behavior. I'll follow-up in the issue you posted to the extension lab. See asciidoctor/asciidoctor-extensions-lab#122

@mojavelinux
Copy link
Member

I want to make a PDF of just one chapter from a book, when that chapter is not necessarily chapter 1, and yet have the chapter/section numbering be correct (so if it's chapter 2, the first section would be 2.1, etc.)

This is also possible using the following command:

asciidoctor-pdf -a doctype=book -a chapter-number=1@ -a sectnums ch02.adoc

At this point, I've shared everything I can offer to accomplish this goal. There's nothing else actionable for this converter, so I'm marking it as resolved.

@mojavelinux mojavelinux modified the milestones: future, support May 1, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants