Index: html_formatter.rb =================================================================== --- html_formatter.rb (リビジョン 621) +++ html_formatter.rb (作業コピー) @@ -6,251 +6,216 @@ require 'hiki/interwiki' require 'hiki/aliaswiki' require 'hiki/hiki_formatter' -require 'uri' +require 'style/default/hikidoc' module Hiki class HTMLFormatter_default < HikiFormatter - def initialize( s, db, plugin, conf, prefix = 'l') - @html = s - @db = db - @plugin = plugin - @conf = conf - @prefix = prefix - @references = Array::new - @interwiki = InterWiki::new( @db.load( @conf.interwiki_name ) ) - @aliaswiki = AliasWiki::new( @db.load( @conf.aliaswiki_name ) ) - get_auto_links if @conf.auto_link + def initialize( parser, db, plugin, conf, prefix = 'l') + @parser = parser + @conf = conf + @output = HikiDocOutput.new(">", db, plugin, conf, prefix) + convert end + attr_reader :toc, :references def to_s - s = @html - s = replace_inline_image( s ) - s = replace_wikiname( s ) if @conf.use_wikiname - s = replace_link( s ) - s = replace_auto_link( s ) if @conf.auto_link - s = replace_heading( s ) - s = replace_plugin( s ) if @conf.use_plugin - @html_converted = s - s + @html_converted end - def references - @references.uniq - end + private + + def convert + @html_converted = @parser.call(@output, @conf.use_wiki_name) + @toc = gen_toc(@html_converted) + @references = @output.references + end - HEADING_RE = %r!.*.*?(.*?)! + HEADING_RE = %r!.*.*?(.*?)! TAG_RE = %r!(<.+?>)! - def toc + def gen_toc(html) s = "\n" * level) s end - private + class HikiDocOutput < HikiDoc::HTMLOutput + def initialize(suffix, db, plugin, conf, prefix) + super(suffix || '/>') + @toc = '' + @references = [] - def replace_inline_image( text ) - text.gsub( /(.+?)<\/a>/i ) do |str| - %Q|#{$3}| + @db = db + @plugin = plugin + @conf = conf + @prefix = prefix + @interwiki = InterWiki::new( db.load( conf.interwiki_name ) ) + @aliaswiki = AliasWiki::new( db.load( conf.aliaswiki_name ) ) + @reverse_dic= gen_reverse_dic + @auto_links_re = get_auto_links_re if conf.auto_link end - end + attr_reader :toc, :references - def replace_auto_link( text ) - return text if @auto_links.empty? - replace_inline( text ) do |str| - str.gsub!( @auto_links_re ) do |match| - @plugin.hiki_anchor( @auto_links[match].unescapeHTML.escape, match ) - end + def reset + @toc = '' + @references = [] + @heading_level = 1 + @heading_serial = 0 + @blockquote_level = 0 + super end - end - WIKINAME_RE = /(\b(?:[A-Z][a-z0-9]+){2,}[A-Z]*\b)/n - - def replace_wikiname( text ) - replace_inline( text ) do |str| - str.gsub!( WIKINAME_RE ) do |i| - %Q|#{i}| - end + def finish + @toc << ("\n" * @heading_level) + @references.uniq! + super end - end - PLUGIN_OPEN_RE = /<(span|div) class="plugin">/ - PLUGIN_CLOSE_RE = %r!! - LINK_OPEN_RE = /! - PRE_OPEN_RE = /
/
-    PRE_CLOSE_RE = %r!
! + TAG_RE = %r!(<.+?>)! - def replace_inline( text ) - status = [] - ret = text.split( TAG_RE ).collect do |str| - case str - when PLUGIN_OPEN_RE - status << :plugin - when LINK_OPEN_RE - status << :a - when PRE_OPEN_RE - status << :pre - when PLUGIN_CLOSE_RE, LINK_CLOSE_RE, PRE_CLOSE_RE - status.pop - when TAG_RE - # do nothing + def headline(level, title) + @f.print "" + + if @blockquote_level != 0 + @f.print title else - if status.empty? - yield( str ) + # toc + if @heading_level < level + @toc << ("
    \n" * (level - @heading_level)) + @heading_level = level + elsif level < @heading_level + @toc << ("
\n" * (@heading_level - level)) + @heading_level = level end + @toc << %Q!
  • #{title.gsub(TAG_RE,'').strip.escapeHTML}
  • \n! + + # heading + case level + when 2 + @f.print %Q! #{title}! + when 3 + @f.print %Q! #{title}! + else + @f.print %Q! #{title}! + end + @heading_serial += 1; end - str + + @f.puts "" end - ret.join - end - URI_RE = /\A#{URI.regexp( %w( http https ftp file mailto ) )}\z/ + def blockquote_open + @blockquote_level += 1 + super + end - def replace_link( text ) - text.gsub( %r|(.+?)| ) do |str| - k, u = $2, $1 - if URI_RE =~ u # uri - @plugin.make_anchor(u, k, 'external') + def blockquote_close + @blockquote_level -= 1 + super + end + + def block_plugin(src) + if(@conf.use_plugin) + @f.puts @plugin.block_context{ apply_plugin( src, @plugin, @conf ) } else - u = u.unescapeHTML - u = @aliaswiki.aliaswiki_names.key( u ) || u # alias wiki - if /(.*)(#l\d+)\z/ =~ u - u, anchor = $1, $2 - else - anchor = '' - end - if @db.exist?( u ) # page name - k = @plugin.page_name( k ) if k == u - @references << u - @plugin.hiki_anchor( u.escape + anchor, k ) - elsif orig = @db.select{|i| i[:title] == u}.first # page title - k = @plugin.page_name( k ) if k == u - u = orig - @references << u - @plugin.hiki_anchor( u.escape + anchor, k ) - elsif outer_alias = @interwiki.outer_alias( u ) # outer alias - @plugin.make_anchor(outer_alias[0] + anchor, k, 'external') - elsif /:/ =~ u # inter wiki ? - s, p = u.split( /:/, 2 ) - if s.empty? # normal link - @plugin.make_anchor( p.escapeHTML + anchor, k, 'external') - elsif inter_link = @interwiki.interwiki( s, p.unescapeHTML, "#{s}:#{p}" ) - @plugin.make_anchor(inter_link[0], k, 'external') - else - missing_page_anchor( k, u ) - end - else - missing_page_anchor( k, u ) - end + @f.puts %Q(
    {{#{escape_html(src)}}}
    ) end end - end - def missing_page_anchor( k, u ) - if @plugin.creatable? - missing_anchor_title = @conf.msg_missing_anchor_title % [ u.escapeHTML ] - "#{k}?" - else - k + def inline_plugin(src) + if(@conf.use_plugin) + @plugin.inline_context{ apply_plugin( src, @plugin, @conf ) } + else + %Q({{#{escape_html(src)}}}) + end end - end - BLOCKQUOTE_OPEN_RE = /
    / - BLOCKQUOTE_CLOSE_RE = %r!
    ! - HEADING_OPEN_RE = // - HEADING_CLOSE_RE = %r!! + def wiki_name(name) + hyperlink(name, text(name)) + end - def replace_heading( text ) - status = [] - num = -1 - ret = text.split( TAG_RE ).collect do |str| - case str - when BLOCKQUOTE_OPEN_RE - status << :blockquote - when BLOCKQUOTE_CLOSE_RE - status.pop - when HEADING_OPEN_RE - unless status.include?( :blockquote ) - num += 1 - level = $1.to_i - status << level - case level - when 2 - str << %Q! ! - when 3 - str << %Q! ! + URI_RE = /(?:https?|ftp|file|mailto|javascript):[A-Za-z0-9;\/?:@&=+$,\-_.!~*\'()#%]+/ + + def hyperlink(uri, label) + if URI_RE =~ uri # uri + @plugin.make_anchor(escape_html(uri), label, 'external') + else + page, anchor = uri.split("\##{@prefix}", 2) + anchor = anchor.nil? || anchor !~ /\A\d+\z/ ? '' : "\##{@prefix}#{anchor}" + + if((p = @reverse_dic[page]) and @db.exist?(p)) # title or alias or page name + label = escape_html(@plugin.page_name(p)) if unescape_html(label) == p + @references << p + @plugin.hiki_anchor( escape_html( p.escape + anchor ), label ) + elsif outer_alias = @interwiki.outer_alias( page ) # outer alias + @plugin.make_anchor(escape_html(outer_alias[0] + anchor), label, 'external') + elsif colon = page.index(':') # inter wiki ? + if colon == 0 # normal link + @plugin.make_anchor( escape_html(page[1,page.length] + anchor), label, 'external') + elsif inter_link = @interwiki.interwiki( page[0,colon], page[colon+1,page.length], label ) + @plugin.make_anchor(inter_link[0], label, 'external') else - str << %Q! ! + missing_page_anchor( label, page ) end + else + missing_page_anchor( label, page ) end - when HEADING_CLOSE_RE - unless status.include?( :blockquote ) - level = status.pop - str = "#{str}" if level == 2 - end end + end + + # make sure that text() is not called under hyperlink(). + def text(str) + return escape_html(str) unless @auto_links_re + pages = @reverse_dic + str.gsub!( @auto_links_re ) {|match| + @plugin.hiki_anchor( pages[match].escape.escapeHTML, escape_html(match) ) + } str end - ret.join - end - def replace_plugin( text ) - text.gsub( %r!<(span|div) class="plugin">\{\{(.+?)\}\}!m ) do |str| - tag, plugin_str = $1, $2 - begin - case tag - when 'span' - result = @plugin.inline_context{ apply_plugin( plugin_str, @plugin, @conf ) } - when 'div' - result = @plugin.block_context{ apply_plugin( plugin_str, @plugin, @conf ) } - end - result.class == String ? result : '' - rescue Exception => e - $& + e.message + private + + def gen_reverse_dic + pages = {} + @db.pages.each do |p| + pages[p] = p + title = @plugin.page_name( p ).unescapeHTML + pages[title] = p unless title == p end + @aliaswiki.aliaswiki_names.each do |orig, alas| + pages[alas] = orig + end + pages end - end - def get_auto_links - pages = {} - @db.pages.each do |p| - page_h = escape_html( p ) - pages[page_h] = page_h - title_h = @plugin.page_name( p ).gsub( /"/, '"' ) - pages[title_h] = page_h unless title_h == page_h + def get_auto_links_re + pages = @reverse_dic + pages && !pages.empty? ? Regexp.union( * pages.keys.sort_by{|i| -i.size} ) : nil end - @aliaswiki.aliaswiki_names.each do |key, value| - orig_h = escape_html( key ) - alias_h = escape_html( value ) - pages[alias_h] = orig_h + + def missing_page_anchor( k, u ) + if @plugin.creatable? + missing_anchor_title = @conf.msg_missing_anchor_title % [ u.escapeHTML ] + "#{k}?" + else + k + end end - @auto_links_re = Regexp.union( * pages.keys.sort_by{|i| -i.size} ) - @auto_links = pages end - - def escape_html( text ) - text.gsub( /&/, '&' ). - gsub( //, '>' ) - end end end Index: parser.rb =================================================================== --- parser.rb (リビジョン 621) +++ parser.rb (作業コピー) @@ -24,12 +24,14 @@ end def parse( s, top_level = 2 ) - HikiDoc.to_html( s, - :level => top_level, - :use_wiki_name => false, - :allow_bracket_inline_image => false, - :plugin_syntax => method(:valid_plugin_syntax?) - ) + lambda {|formatter, use_wiki_name| + HikiDoc.new(formatter, { + :level => top_level, + :use_wiki_name => use_wiki_name, + :allow_bracket_inline_image => true, + :plugin_syntax => method(:valid_plugin_syntax?) + }).compile(s) + } end private