Nanoc::Filter.define(:sidenotes) do |content, params| @footnotes = {} # First pass: collect all footnote definitions content.scan(/\[\^([^\]]+)\]:\s*(.+?)($|\n\n)/) do |ref, text, _| @footnotes[ref] = text.strip end # Second pass: replace footnote references with sidenote markup result = content.gsub(/\[\^([^\]]+)\](?!:)/) do |match| ref = $1 next match unless @footnotes[ref] # Skip if no matching footnote definition <<~HTML #{@footnotes[ref]} HTML end # Finally, remove the original footnote definitions result.gsub(/\[\^([^\]]+)\]:\s*(.+?)($|\n\n)/, '') end