@@ -158,19 +158,16 @@ def handle_regexp_RDOCLINK(target)
158
158
def handle_regexp_TIDYLINK ( target )
159
159
text = target . text
160
160
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
166
164
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 ''
171
168
end
172
169
173
- gen_url url , label
170
+ convert_complete_tidy_link ( text )
174
171
end
175
172
176
173
# :section: Visitor
@@ -458,4 +455,158 @@ def to_html(item)
458
455
super convert_flow @am . flow item
459
456
end
460
457
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
461
612
end
0 commit comments