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

Indir extension #100

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions README.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,9 @@ Highlights source blocks using the highlight command.
ImplicitApidocInlineMacro, link:lib/implicit-apidoc-inline-macro.rb[]::
Adds an inline macro for linking to the Javadoc of a class in the Java EE API.

IndirIncludeProcessor, link:lib/indir-include-processor.rb[]::
Adds a variable "indir", pointing at the directory of included asciidoc files.

LicenseUrlDocinfoProcessor, link:lib/license-url-docinfoprocessor.rb[]::
Adds a link to the license specified by the `license` attribute to the document header.

Expand Down
8 changes: 8 additions & 0 deletions lib/indir-include-processor.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
##
# Require this file to register and use the IndirIncludeProcessor.

RUBY_ENGINE == 'opal' ? (require 'indir-include-processor/extension') : (require_relative 'indir-include-processor/extension')

Asciidoctor::Extensions.register do
include_processor IndirIncludeProcessor
end
7 changes: 7 additions & 0 deletions lib/indir-include-processor/example/master.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
= Main Document

Main document's paragraph one, prior to included content.

include::sub/sub.adoc[leveloffset=+1]

Main document's paragraph two, after the included content.
15 changes: 15 additions & 0 deletions lib/indir-include-processor/example/sub/images/example.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
14 changes: 14 additions & 0 deletions lib/indir-include-processor/example/sub/sub.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
= Sub Document

ifndef::indir[:indir: .]

Sub document paragraph.

The variable `indir` has the value `{indir}`.
This variable can be useful for in standalone documents that can also be included into other documents.

image::{indir}/images/example.svg[]

The above image has been included using `image::\{indir\}/images/example.svg[]`.
The `indir` variable that is used in the image path always points to the directory of the current (possibly included) asciidoc file.
As a result, the image path is correct, no matter if `sub.adoc` is compiled standalone or included in `master.adoc`.
62 changes: 62 additions & 0 deletions lib/indir-include-processor/extension.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
##
# Asciidoctor extension that adds a variable "indir", pointing at the directory of included asciidoc files.
#
# The indir variable always points at the directory where the current asciidoc file is located.
# The value of the indir variable changes to always reflect the location of the current, included subdocument.
# (Note: This is in contrast to the docfile variable, which remains the same throughout an entire document).
# The indir variable can be used to construct image paths relative to included subdocuments.
#
# Background:
# This extension was created to ease the handling of image paths in nested subdocuments,
# see https://github.com/asciidoctor/asciidoctor/issues/650#issuecomment-433946605.
#
# Motivation:
# The usage scenario that motivates this extension is a nested folder structure with asciidoc files,
# with images stored next to the asciidoc file where they are used.
# For example, an asciidoc file "sub/sub1.adoc" may use an image located at "sub/images/img1.svg".
# In this scenario, we want to be able to compile the asciidoc files in two ways,
# as standalone documents, and included into a parent document.
# The image paths should resolve fine in both cases.
#
# Intended Usage of the Extension:
#
# 1. In the beginning of a subdocument, add this line:
# ifndef::indir[:indir: .]
#
# 2. Include images like this:
# image::{indir}/images/example.svg[]
#
# 3. When compiling a master document (that includes other subdocuments), require this extension.
# The extension will set the indir variable to always point at the directory of the included asciidoc file,
# to that the an image path like "{indir}/images/example.svg" is resolved relative to the included subdocument.
#
# Note that the subdocuments compile just fine without the extension.
# This can be handy to use an editor's built-in preview feature.
# The extension is only needed when compiling a master document (that includes other subdocuments).
#
# Caveats, Future Work:
# This extension, once registered, claims to handle any includes
# (because it does not overwrite the "handles?" method of its parent class, which always return true).
# In consequence, it is difficult to use this extension together with other include processor extensions.
# A better solution with finer-grained control could be based on https://github.com/jirutka/asciidoctor-include-ext.
class IndirIncludeProcessor < Asciidoctor::Extensions::IncludeProcessor
def process doc, reader, target, attributes
content = (open target).readlines

# Set variables at beginning of the included content
included_docfile = target
included_docdir = ::File.dirname target
content.unshift ''
content.unshift %(:indir: #{included_docdir})

# Reset the variables at the end of the included content
parent_docfile = doc.reader.include_stack&.dig(-1, 1) || (doc.attr 'docfile')
parent_docdir = ::File.dirname parent_docfile
content << ''
content << %(:indir: #{parent_docdir})

# Push included content for further processing
reader.push_include content, target, target, 1, attributes
reader
end
end