@@ -158,19 +158,16 @@ def handle_regexp_RDOCLINK(target)
158158 def handle_regexp_TIDYLINK ( target )
159159 text = target . text
160160
161- return text unless
162- text =~ /^\{ (.*)\} \[ (.*?)\] $/ or text =~ /^(\S +)\[ (.*?)\] $/
163-
164- label = $1
165- url = CGI . escapeHTML ( $2)
161+ if tidy_link_capturing?
162+ return finish_tidy_link ( text )
163+ end
166164
167- if /^rdoc-image:/ =~ label
168- label = handle_RDOCLINK ( label )
169- else
170- label = CGI . escapeHTML ( label )
165+ if text . start_with? ( '{' ) && !text . include? ( '}' )
166+ start_tidy_link text
167+ return ''
171168 end
172169
173- gen_url url , label
170+ convert_complete_tidy_link ( text )
174171 end
175172
176173 # :section: Visitor
@@ -458,4 +455,158 @@ def to_html(item)
458455 super convert_flow @am . flow item
459456 end
460457
458+ private
459+
460+ def convert_flow ( flow )
461+ res = [ ]
462+
463+ flow . each do |item |
464+ case item
465+ when String then
466+ append_flow_fragment res , convert_string ( item )
467+ when RDoc ::Markup ::AttrChanger then
468+ off_tags res , item
469+ on_tags res , item
470+ when RDoc ::Markup ::RegexpHandling then
471+ append_flow_fragment res , convert_regexp_handling ( item )
472+ else
473+ raise "Unknown flow element: #{ item . inspect } "
474+ end
475+ end
476+
477+ res . join
478+ end
479+
480+ def append_flow_fragment ( res , fragment )
481+ return if fragment . nil? || fragment . empty?
482+
483+ emit_tidy_link_fragment ( res , fragment )
484+ end
485+
486+ def append_to_tidy_label ( fragment )
487+ return unless @tidy_link_buffer
488+
489+ @tidy_link_buffer << fragment
490+ end
491+
492+ ##
493+ # Matches an entire tidy link with a braced label "{label}[url]".
494+ #
495+ # Capture 1: label contents.
496+ # Capture 2: URL text.
497+ # Capture 3: trailing content.
498+ TIDY_LINK_WITH_BRACES = /\A \{ (.*?)\} \[ (.*?)\] (.*)\z /
499+
500+ ##
501+ # Matches the tail of a braced tidy link when the opening brace was
502+ # consumed earlier while accumulating the label text.
503+ #
504+ # Capture 1: remaining label content.
505+ # Capture 2: URL text.
506+ # Capture 3: trailing content.
507+ TIDY_LINK_WITH_BRACES_TAIL = /\A (.*?)\} \[ (.*?)\] (.*)\z /
508+
509+ ##
510+ # Matches a tidy link with a single-word label "label[url]".
511+ #
512+ # Capture 1: the single-word label (no whitespace).
513+ # Capture 2: URL text between the brackets.
514+ TIDY_LINK_SINGLE_WORD = /\A (\S +)\[ (.*?)\] (.*)\z /
515+
516+ def convert_complete_tidy_link ( text )
517+ return text unless
518+ text =~ TIDY_LINK_WITH_BRACES or text =~ TIDY_LINK_SINGLE_WORD
519+
520+ label = $1
521+ url = CGI . escapeHTML ( $2)
522+
523+ label_html = if /^rdoc-image:/ =~ label
524+ handle_RDOCLINK ( label )
525+ else
526+ render_tidy_link_label ( label )
527+ end
528+
529+ gen_url url , label_html
530+ end
531+
532+ def emit_tidy_link_fragment ( res , fragment )
533+ if tidy_link_capturing?
534+ append_to_tidy_label fragment
535+ else
536+ res << fragment
537+ end
538+ end
539+
540+ def finish_tidy_link ( text )
541+ label_tail , url , trailing = extract_tidy_link_parts ( text )
542+
543+ append_to_tidy_label CGI . escapeHTML ( label_tail ) unless label_tail . empty?
544+
545+ return '' unless url
546+
547+ label_html = @tidy_link_buffer
548+
549+ @tidy_link_buffer = nil
550+
551+ link = gen_url ( url , label_html )
552+
553+ return link if trailing . empty?
554+
555+ link + CGI . escapeHTML ( trailing )
556+ end
557+
558+ def extract_tidy_link_parts ( text )
559+ if text =~ TIDY_LINK_WITH_BRACES
560+ [ $1, CGI . escapeHTML ( $2) , $3]
561+ elsif text =~ TIDY_LINK_WITH_BRACES_TAIL
562+ [ $1, CGI . escapeHTML ( $2) , $3]
563+ elsif text =~ TIDY_LINK_SINGLE_WORD
564+ [ $1, CGI . escapeHTML ( $2) , $3]
565+ else
566+ [ text , nil , '' ]
567+ end
568+ end
569+
570+ def on_tags ( res , item )
571+ each_attr_tag ( item . turn_on ) do |tag |
572+ emit_tidy_link_fragment ( res , annotate ( tag . on ) )
573+ @in_tt += 1 if tt? tag
574+ end
575+ end
576+
577+ def off_tags ( res , item )
578+ each_attr_tag ( item . turn_off , true ) do |tag |
579+ emit_tidy_link_fragment ( res , annotate ( tag . off ) )
580+ @in_tt -= 1 if tt? tag
581+ end
582+ end
583+
584+ def start_tidy_link ( text )
585+ @tidy_link_buffer = String . new
586+ append_to_tidy_label CGI . escapeHTML ( text . delete_prefix ( '{' ) )
587+ end
588+
589+ def tidy_link_capturing?
590+ !!@tidy_link_buffer
591+ end
592+
593+ def render_tidy_link_label ( label )
594+ RDoc ::Markup ::LinkLabelToHtml . render ( label , @options , @from_path )
595+ end
596+ end
597+
598+ ##
599+ # Formatter dedicated to rendering tidy link labels without mutating the
600+ # calling formatter's state.
601+
602+ class RDoc ::Markup ::LinkLabelToHtml < RDoc ::Markup ::ToHtml
603+ def self . render ( label , options , from_path )
604+ new ( options , from_path ) . to_html ( label )
605+ end
606+
607+ def initialize ( options , from_path = nil )
608+ super ( options )
609+
610+ self . from_path = from_path if from_path
611+ end
461612end
0 commit comments