lib/infoboxer/parser/inline.rb
# frozen_string_literal: true
module Infoboxer
class Parser
module Inline
include Tree
def inline(until_pattern = nil)
start = @context.lineno
nodes = Nodes[]
guarded_loop do
chunk = @context.scan_until(re.inline_until_cache[until_pattern])
nodes << chunk
break if @context.matched_inline?(until_pattern)
nodes << inline_formatting(@context.matched) unless @context.matched.empty?
if @context.eof?
break unless until_pattern
@context.fail!("#{until_pattern.source} not found, starting from #{start}")
end
if @context.eol?
nodes << "\n"
@context.next!
end
end
nodes
end
def short_inline(until_pattern = nil)
nodes = Nodes[]
guarded_loop do
# FIXME: quick and UGLY IS HELL JUST TRYING TO MAKE THE SHIT WORK
chunk =
if @context.inline_eol_sign == /^\]/ # rubocop:disable Style/CaseLikeIf
@context.scan_until(re.short_inline_until_cache_brackets[until_pattern])
elsif @context.inline_eol_sign == /^\]\]/
@context.scan_until(re.short_inline_until_cache_brackets2[until_pattern])
else
@context.scan_until(re.short_inline_until_cache[until_pattern])
end
nodes << chunk
break if @context.matched_inline?(until_pattern)
nodes << inline_formatting(@context.matched)
break if @context.inline_eol?(until_pattern)
end
nodes
end
def long_inline(until_pattern = nil)
nodes = Nodes[]
guarded_loop do
chunk = @context.scan_until(re.inline_until_cache[until_pattern])
nodes << chunk
break if @context.matched?(until_pattern)
nodes << inline_formatting(@context.matched) unless @context.matched.empty?
if @context.eof?
break unless until_pattern
@context.fail!("#{until_pattern.source} not found")
end
if @context.eol?
@context.next!
paragraphs(until_pattern).each do |p|
nodes << p
end
break
end
end
nodes
end
private
def inline_formatting(match) # rubocop:disable Metrics/MethodLength, Metrics/CyclomaticComplexity, Metrics/AbcSize
case match
when "'''''"
BoldItalic.new(short_inline(/'''''/))
when "'''"
Bold.new(short_inline(/'''/))
when "''"
Italic.new(short_inline(/''/))
when '[['
if @context.check(re.file_namespace)
image
else
wikilink
end
when /\[(.+)/
external_link(Regexp.last_match(1))
when '{{'
template
when /<nowiki([^>]*)>/
nowiki(Regexp.last_match(1))
when %r{<ref([^>]*)/>}
reference(Regexp.last_match(1), true)
when /<ref([^>]*)>/
reference(Regexp.last_match(1))
when /<math>/
math
when /<gallery([^>]*)>/
gallery(Regexp.last_match(1))
when '<'
html || Text.new(match) # it was not HTML, just accidental <
else
match # FIXME: TEMP
end
end
# http://en.wikipedia.org/wiki/Help:Link#Wikilinks
# [[abc]]
# [[a|b]]
def wikilink
link = @context.scan_continued_until(/\||\]\]/)
if @context.matched == '|'
@context.push_eol_sign(/^\]\]/)
caption = inline(/\]\]/)
@context.pop_eol_sign
end
name, namespace = link.split(':', 2).reverse
lnk, params =
if @context.traits.namespace?(namespace)
[link, {namespace: namespace}]
elsif @context.traits.interwiki?(namespace)
[name, {interwiki: namespace}]
else
[link, {}]
end
puts @context.rest if lnk.nil?
Wikilink.new(lnk, caption, **params)
end
# http://en.wikipedia.org/wiki/Help:Link#External_links
# [http://www.example.org]
# [http://www.example.org link name]
def external_link(protocol)
link = @context.scan_continued_until(/\s+|\]/)
if @context.matched =~ /\s+/
@context.push_eol_sign(/^\]/)
caption = short_inline(/\]/)
@context.pop_eol_sign
end
ExternalLink.new(protocol + link, caption)
end
def reference(param_str, closed = false)
children = closed ? Nodes[] : long_inline(%r{</ref>})
Ref.new(children, **parse_params(param_str))
end
def math
Math.new(@context.scan_continued_until(%r{</math>}))
end
def nowiki(tag_rest)
if tag_rest.end_with?('/')
Text.new('')
else
Text.new(@context.scan_continued_until(%r{</nowiki>}))
end
end
def gallery(tag_rest)
params = parse_params(tag_rest)
images = []
guarded_loop do
@context.next! if @context.eol?
path = @context.scan_until(%r{</gallery>|\||$})
attrs = @context.matched == '|' ? gallery_image_attrs : {}
unless path.empty?
# FIXME: what if path NOT matches the namespace?
images << Tree::Image.new(path.sub(/^#{re.file_namespace.source}/i, ''), **attrs)
end
break if @context.matched == '</gallery>'
end
Gallery.new(images, **params)
end
def gallery_image_attrs
nodes = []
guarded_loop do
nodes << short_inline(%r{\||</gallery>})
break if @context.eol? || @context.matched?(%r{</gallery>})
end
nodes.map(&method(:image_attr))
.inject(&:merge)
.reject { |_k, v| v.nil? || v.empty? }
end
end
require_relative 'image'
require_relative 'html'
require_relative 'template'
include Infoboxer::Parser::Image
include Infoboxer::Parser::HTML
include Infoboxer::Parser::Template
end
end