resources/asciidoctor/lib/alternative_language_lookup/listing.rb (98 lines of code) (raw):
# frozen_string_literal: true
require_relative 'alternative'
require_relative '../log_util'
module AlternativeLanguageLookup
##
# Information about a listing in the original document.
class Listing
RESULT_SUFFIX = '-result'
RESULT_SUFFIX_LENGTH = RESULT_SUFFIX.length
include LogUtil
attr_reader :block
attr_reader :lang
attr_reader :is_result
attr_reader :alternatives
def initialize(block)
@block = block
@lang = block.attr 'language'
return unless @lang
@is_result = @lang.end_with? RESULT_SUFFIX
lookups = block.document.attr 'alternative_language_lookups'
@alternatives = lookups[key_lang]
@listing_index = nil # We'll look it up when we need it
@colist_offset = 1
end
def process
return unless alternatives
block.attributes['digest'] = digest
found_langs = []
alternatives.each do |lookup|
add_alternative_if_present found_langs, lookup
end
report found_langs
cleanup_original_after_add found_langs unless found_langs.empty?
end
def add_alternative_if_present(found_langs, lookup)
return unless (found = lookup.index[digest])
# TODO: we can probably cache this. There are lots of dupes.
alt_lang = lookup.alternative_lang_for @is_result
alternative = Alternative.new document, alt_lang, found[:path]
alternative_listing = alternative.listing @block.parent
return unless alternative_listing
alternative_colist = alternative.colist @block.parent
insert alternative_listing, alternative_colist
found_langs << lookup.alternative_lang
end
def insert(alternative_listing, alternative_colist)
find_listing unless @listing_index
parent.blocks.insert @listing_index, alternative_listing
@listing_index += 1
return unless alternative_colist
parent.blocks.insert @listing_index + @colist_offset, alternative_colist
@colist_offset += 1
end
def find_listing
# Find the right spot in the parent's blocks to add any alternatives:
# right after this block's callouts if it has any, otherwise just after
# this block.
@listing_index = parent.blocks.find_index(@block)
if @listing_index
# While we're here check if there is a callout list.
colist = parent.blocks[@listing_index + 1]
@colist = colist&.context == :colist ? colist : nil
else
message = "Invalid document: parent doesn't include child!"
error location: source_location, message: message
# In grand Asciidoctor tradition we'll *try* to make some
# output though
@listing_index = 0
@colist = nil
end
end
def cleanup_original_after_add(found_langs)
# We're obligated to reindex the sections inside parent because we've
# chaged its blocks.
parent.reindex_sections
# Add some roles which will translate into classes to the original
# listing block and the callout. We'll use these to hide the default
# language when you pick an override language.
has_roles = found_langs.map { |lang| "has-#{lang}" }.join ' '
@block.attributes['role'] = "default #{has_roles}"
return unless @colist
@colist.attributes['role'] = "default #{has_roles} lang-#{@lang}"
end
def report(found_langs)
report = document.attr 'alternative_language_report'
report&.report self, found_langs
summary = document.attr 'alternative_language_summary'
summary&.on_listing self, found_langs
end
def parent
@block.parent
end
def document
@block.document
end
def source_location
@block.source_location
end
def source
@source ||= @block.source
end
def digest
@digest ||= Digest::MurmurHash3_x64_128.hexdigest source
end
##
# `key_lang` normalises `lang` into the lookup key for alternatives.
def key_lang
if @is_result
@lang[0, @lang.length - RESULT_SUFFIX_LENGTH]
else
@lang
end
end
end
end