def sub_macros(text)
return text if text.nil? || text.empty?
result = text.dup
found = {}
found[:square_bracket] = result.include?('[')
found[:round_bracket] = result.include?('(')
found[:colon] = result.include?(':')
found[:at] = result.include?('@')
found[:macroish] = (found[:square_bracket] && found[:colon])
found[:macroish_short_form] = (found[:square_bracket] && found[:colon] && result.include?(':['))
found[:uri] = (found[:colon] && result.include?('://'))
use_link_attrs = @document.attributes.has_key?('linkattrs')
experimental = @document.attributes.has_key?('experimental')
if experimental
if found[:macroish_short_form] && (result.include?('kbd:') || result.include?('btn:'))
result.gsub!(REGEXP[:kbd_btn_macro]) {
m = $~
if (captured = m[0]).start_with? '\\'
next captured[1..-1]
end
if captured.start_with?('kbd')
keys = unescape_bracketed_text m[1]
if keys == '+'
keys = ['+']
else
keys = keys.split(REGEXP[:kbd_delim]).inject([]) {|c, key|
if key.end_with?('++')
c << key[0..-3].strip
c << '+'
else
c << key.strip
end
c
}
end
Inline.new(self, :kbd, nil, :attributes => {'keys' => keys}).render
elsif captured.start_with?('btn')
label = unescape_bracketed_text m[1]
Inline.new(self, :button, label).render
end
}
end
if found[:macroish] && result.include?('menu:')
result.gsub!(REGEXP[:menu_macro]) {
m = $~
if (captured = m[0]).start_with? '\\'
next captured[1..-1]
end
menu = m[1]
items = m[2]
if items.nil?
submenus = []
menuitem = nil
else
if (delim = items.include?('>') ? '>' : (items.include?(',') ? ',' : nil))
submenus = items.split(delim).map(&:strip)
menuitem = submenus.pop
else
submenus = []
menuitem = items.rstrip
end
end
Inline.new(self, :menu, nil, :attributes => {'menu' => menu, 'submenus' => submenus, 'menuitem' => menuitem}).render
}
end
if result.include?('"') && result.include?('>')
result.gsub!(REGEXP[:menu_inline_macro]) {
m = $~
if (captured = m[0]).start_with? '\\'
next captured[1..-1]
end
input = m[1]
menu, *submenus = input.split('>').map(&:strip)
menuitem = submenus.pop
Inline.new(self, :menu, nil, :attributes => {'menu' => menu, 'submenus' => submenus, 'menuitem' => menuitem}).render
}
end
end
if found[:macroish] && result.include?('image:')
result.gsub!(REGEXP[:image_macro]) {
m = $~
if m[0].start_with? '\\'
next m[0][1..-1]
end
target = sub_attributes(m[1])
@document.register(:images, target)
attrs = parse_attributes(unescape_bracketed_text(m[2]), ['alt', 'width', 'height'])
if !attrs['alt']
attrs['alt'] = File.basename(target, File.extname(target))
end
Inline.new(self, :image, nil, :target => target, :attributes => attrs).render
}
end
if found[:macroish_short_form] || found[:round_bracket]
result.gsub!(REGEXP[:indexterm_macro]) {
m = $~
if m[0].start_with? '\\'
next m[0][1..-1]
end
terms = unescape_bracketed_text(m[1] || m[2]).split(',').map(&:strip)
document.register(:indexterms, [*terms])
Inline.new(self, :indexterm, text, :attributes => {'terms' => terms}).render
}
result.gsub!(REGEXP[:indexterm2_macro]) {
m = $~
if m[0].start_with? '\\'
next m[0][1..-1]
end
text = unescape_bracketed_text(m[1] || m[2])
document.register(:indexterms, [text])
Inline.new(self, :indexterm, text, :type => :visible).render
}
end
if found[:uri]
result.gsub!(REGEXP[:link_inline]) {
m = $~
if m[2].start_with? '\\'
next "#{m[1]}#{m[2][1..-1]}#{m[3]}"
elsif m[1] == 'link:' && m[3].nil?
next m[0]
end
prefix = (m[1] != 'link:' ? m[1] : '')
target = m[2]
suffix = ''
if prefix.start_with?('<') && target.end_with?('>')
prefix = prefix[4..-1]
target = target[0..-5]
elsif prefix.start_with?('(') && target.end_with?(')')
target = target[0..-2]
suffix = ')'
elsif target.end_with?('):')
target = target[0..-3]
suffix = '):'
end
@document.register(:links, target)
attrs = nil
if !m[3].to_s.empty?
if use_link_attrs && (m[3].start_with?('"') || m[3].include?(','))
attrs = parse_attributes(sub_attributes(m[3].gsub('\]', ']')), [])
text = attrs[1]
else
text = sub_attributes(m[3].gsub('\]', ']'))
end
if text.end_with? '^'
text = text.chop
attrs ||= {}
attrs['window'] = '_blank' unless attrs.has_key?('window')
end
else
text = ''
end
"#{prefix}#{Inline.new(self, :anchor, (!text.empty? ? text : target), :type => :link, :target => target, :attributes => attrs).render}#{suffix}"
}
end
if found[:macroish] && (result.include?('link:') || result.include?('mailto:'))
result.gsub!(REGEXP[:link_macro]) {
m = $~
if m[0].start_with? '\\'
next m[0][1..-1]
end
raw_target = m[1]
mailto = m[0].start_with?('mailto:')
target = mailto ? "mailto:#{raw_target}" : raw_target
attrs = nil
if use_link_attrs && (m[2].start_with?('"') || m[2].include?(','))
attrs = parse_attributes(sub_attributes(m[2].gsub('\]', ']')), [])
text = attrs[1]
if mailto
if attrs.has_key? 2
target = "#{target}?subject=#{Helpers.encode_uri(attrs[2])}"
if attrs.has_key? 3
target = "#{target}&body=#{Helpers.encode_uri(attrs[3])}"
end
end
end
else
text = sub_attributes(m[2].gsub('\]', ']'))
end
if text.end_with? '^'
text = text.chop
attrs ||= {}
attrs['window'] = '_blank' unless attrs.has_key?('window')
end
@document.register(:links, target)
Inline.new(self, :anchor, (!text.empty? ? text : raw_target), :type => :link, :target => target, :attributes => attrs).render
}
end
if found[:at]
result.gsub!(REGEXP[:email_inline]) {
m = $~
address = m[0]
case address[0..0]
when '\\'
next address[1..-1]
when '>', ':'
next address
end
target = "mailto:#{address}"
@document.register(:links, target)
Inline.new(self, :anchor, address, :type => :link, :target => target).render
}
end
if found[:macroish_short_form] && result.include?('footnote')
result.gsub!(REGEXP[:footnote_macro]) {
m = $~
if m[0].start_with? '\\'
next m[0][1..-1]
end
if m[1] == 'footnote'
text = restore_passthroughs(m[2])
id = nil
index = @document.counter('footnote-number')
@document.register(:footnotes, Document::Footnote.new(index, id, text))
type = nil
target = nil
else
id, text = m[2].split(',', 2).map(&:strip)
if !text.nil?
text = restore_passthroughs(text)
index = @document.counter('footnote-number')
@document.register(:footnotes, Document::Footnote.new(index, id, text))
type = :ref
target = nil
else
footnote = @document.references[:footnotes].find {|fn| fn.id == id }
target = id
id = nil
index = footnote.index
text = footnote.text
type = :xref
end
end
Inline.new(self, :footnote, text, :attributes => {'index' => index}, :id => id, :target => target, :type => type).render
}
end
if found[:macroish] || result.include?('<<')
result.gsub!(REGEXP[:xref_macro]) {
m = $~
if m[0].start_with? '\\'
next m[0][1..-1]
end
if !m[1].nil?
id, reftext = m[1].split(',', 2).map(&:strip)
id.sub!(REGEXP[:dbl_quoted], '\2')
reftext.sub!(REGEXP[:m_dbl_quoted], '\2') unless reftext.nil?
else
id = m[2]
reftext = !m[3].empty? ? m[3] : nil
end
Inline.new(self, :anchor, reftext, :type => :xref, :target => id).render
}
end
if found[:square_bracket] && result.include?('[[[')
result.gsub!(REGEXP[:biblio_macro]) {
m = $~
if m[0].start_with? '\\'
next m[0][1..-1]
end
id = reftext = m[1]
Inline.new(self, :anchor, reftext, :type => :bibref, :target => id).render
}
end
if found[:square_bracket] && result.include?('[[')
result.gsub!(REGEXP[:anchor_macro]) {
m = $~
if m[0].start_with? '\\'
next m[0][1..-1]
end
id, reftext = m[1].split(',').map(&:strip)
id.sub!(REGEXP[:dbl_quoted], '\2')
if reftext.nil?
reftext = "[#{id}]"
else
reftext.sub!(REGEXP[:m_dbl_quoted], '\2')
end
if !@document.references[:ids].has_key? id
Debug.debug { "Missing reference for anchor #{id}" }
end
Inline.new(self, :anchor, reftext, :type => :ref, :target => id).render
}
end
result
end