summaryrefslogtreecommitdiff
path: root/lib/rdoc/markup/to_html_hyperlink.rb
blob: 58adaa8cb02d968ad35d78214de64d5354fc8345 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
require 'rdoc/markup/to_html'

##
# Subclass of the RDoc::Markup::ToHtml class that supports looking up words in
# the AllReferences list. Those that are found (like AllReferences in this
# comment) will be hyperlinked

class RDoc::Markup::ToHtmlHyperlink < RDoc::Markup::ToHtml

  attr_accessor :context

  ##
  # We need to record the html path of our caller so we can generate
  # correct relative paths for any hyperlinks that we find

  def initialize(from_path, context, show_hash)
    super()

    # class names, variable names, or instance variables
    @markup.add_special(/(
                           # A::B.meth(**) (for operator in Fortran95)
                           \w+(::\w+)*[.\#]\w+(\([\.\w+\*\/\+\-\=\<\>]+\))?
                           # meth(**) (for operator in Fortran95)
                         | \#\w+(\([.\w\*\/\+\-\=\<\>]+\))?
                         | \b([A-Z]\w*(::\w+)*[.\#]\w+)  #    A::B.meth
                         | \b([A-Z]\w+(::\w+)*)          #    A::B
                         | \#\w+[!?=]?                   #    #meth_name
                         | \\?\b\w+([_\/\.]+\w+)*[!?=]?  #    meth_name
                         )/x,
                        :CROSSREF)

    # external hyperlinks
    @markup.add_special(/((link:|https?:|mailto:|ftp:|www\.)\S+\w)/, :HYPERLINK)

    # and links of the form  <text>[<url>]
    @markup.add_special(/(((\{.*?\})|\b\S+?)\[\S+?\.\S+?\])/, :TIDYLINK)

    @from_path = from_path
    @context = context
    @show_hash = show_hash

    @seen = {}
  end

  ##
  # We're invoked when any text matches the CROSSREF pattern
  # (defined in MarkUp). If we fine the corresponding reference,
  # generate a hyperlink. If the name we're looking for contains
  # no punctuation, we look for it up the module/class chain. For
  # example, HyperlinkHtml is found, even without the Generator::
  # prefix, because we look for it in module Generator first.

  def handle_special_CROSSREF(special)
    name = special.text

    return @seen[name] if @seen.include? name

    if name[0,1] == '#' then
      lookup = name[1..-1]
      name = lookup unless @show_hash
    else
      lookup = name
    end

    # Find class, module, or method in class or module.
    if /([A-Z]\w*)[.\#](\w+[!?=]?)/ =~ lookup then
      container = $1
      method = $2
      ref = @context.find_symbol container, method
    elsif /([A-Za-z]\w*)[.\#](\w+(\([\.\w+\*\/\+\-\=\<\>]+\))?)/ =~ lookup then
      container = $1
      method = $2
      ref = @context.find_symbol container, method
    else
      ref = @context.find_symbol lookup
    end

    out = if lookup =~ /^\\/ then
            $'
          elsif ref and ref.document_self then
            "<a href=\"#{ref.as_href(@from_path)}\">#{name}</a>"
          else
            name
          end

    @seen[name] = out

    out
  end

  ##
  # Generate a hyperlink for url, labeled with text. Handle the
  # special cases for img: and link: described under handle_special_HYPEDLINK

  def gen_url(url, text)
    if url =~ /([A-Za-z]+):(.*)/ then
      type = $1
      path = $2
    else
      type = "http"
      path = url
      url  = "http://#{url}"
    end

    if type == "link" then
      url = if path[0, 1] == '#' then # is this meaningful?
              path
            else
              HTML.gen_url @from_path, path
            end
    end

    if (type == "http" or type == "link") and
       url =~ /\.(gif|png|jpg|jpeg|bmp)$/ then
      "<img src=\"#{url}\" />"
    else
      "<a href=\"#{url}\">#{text.sub(%r{^#{type}:/*}, '')}</a>"
    end
  end

  ##
  # And we're invoked with a potential external hyperlink mailto:
  # just gets inserted. http: links are checked to see if they
  # reference an image. If so, that image gets inserted using an
  # <img> tag. Otherwise a conventional <a href> is used.  We also
  # support a special type of hyperlink, link:, which is a reference
  # to a local file whose path is relative to the --op directory.

  def handle_special_HYPERLINK(special)
    url = special.text
    gen_url url, url
  end

  ##
  # Here's a hypedlink where the label is different to the URL
  #  <label>[url]

  def handle_special_TIDYLINK(special)
    text = special.text

    return text unless text =~ /\{(.*?)\}\[(.*?)\]/ or text =~ /(\S+)\[(.*?)\]/

    label = $1
    url   = $2
    gen_url url, label
  end

end