aboutsummaryrefslogtreecommitdiff
path: root/doc-tool/src/dotty/tools/dottydoc/staticsite/filters.scala
blob: a4662e735ca9e1d92185864f173ff18923ba56e1 (plain) (blame)
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
package dotty.tools
package dottydoc
package staticsite

import model.references._
import java.util.{ Map => JMap }

import liqp.filters.Filter

/** Custom liquid template filters */
object filters {

  /** Used to reverse arrays:
    *
    * ```html
    * {% assign array = "1,2,3,4,5" | split: "," %}
    * {{ array | reverse }}
    * ```
    */
  final class Reverse extends Filter("reverse") {
    override def apply(value: Any, params: AnyRef*): AnyRef = {
      val array = super.asArray(value)
      if (array.length == 0) null
      else array.reverse
    }
  }

  /** Renders a `Reference` as HTML. Example:
    *
    * ```html
    * {{ ref | renderRef }}
    * ```
    *
    * where `ref` is:
    *
    * ```scala
    * TypeReference("Seq", MaterializedLink("Seq", "../../scala/collection/Seq.html"), Nil)
    * ```
    *
    * will render:
    *
    * ```html
    * <a href="../../scala/collection/Seq.html">Seq</a>
    * <span class="no-left no-right">[</span>
    * A
    * <span class="no-left">]</span>
    * ```
    */
  final class RenderReference extends Filter("renderRef") {
    // might need to be rewritten to be stack safe
    private def renderReference(ref: Reference): String = ref match {
      case TypeReference(_, tpeLink, paramLinks) => {
        if (paramLinks.nonEmpty) {
          s"""|${renderLink(tpeLink)}
              |<span class="no-left no-right">[</span>
              |${ paramLinks.map(renderReference).mkString("""<span class="">, </span>""") }
              |<span class="no-left">]</span>""".stripMargin
        }
        else renderLink(tpeLink)
      }

      case AndOrTypeReference(left, sep, right) =>
        s"""${renderReference(left)}<span class="and-or-separator"> $sep </span>${renderReference(right)}"""

      case FunctionReference(args, returnValue) => {
        val params =
          if (args.isEmpty) "<span>() =&gt; </span>"
          else if (args.tail.isEmpty) renderReference(args.head) + """<span class="right-arrow"> =&gt; </span>"""
          else args.map(renderReference).mkString("<span>(</span>", "<span>, </span>", "<span>) =&gt; </span>")

        params + renderReference(returnValue)
      }

      case TupleReference(args) =>
        s"""|<span class="no-right">(</span>
            |${ args.map(renderReference).mkString("<span>, </span>") }
            |<span class="no-left">)</span>""".stripMargin

      case BoundsReference(low, high) =>
        s"""${ renderReference(low) }<span class="bounds"> &lt;: </span>${ renderReference(high) }"""

      case NamedReference(title, _, _, _) =>
        /*dottydoc.*/println(s"received illegal named reference in rendering: $ref")
        title

      case ConstantReference(title) => title
    }

    override def apply(value: Any, params: AnyRef*): AnyRef = value match {
      case value: JMap[String, _] @unchecked =>
        val ref = value.get("scala").asInstanceOf[Reference]
        if (ref ne null) renderReference(ref)
        else null
      case _ =>
        /*dottydoc.*/println(s"couldn't render: '$value'")
        null
    }
  }

  /** Renders a `MaterializableLink` into a HTML anchor tag. If the link is
    * `NoLink` it will just return a string with the link's title.
    */
  final class RenderLink extends Filter("renderLink") {
    override def apply(value: Any, params: AnyRef*): AnyRef = value match {
      case value: JMap[String, _] @unchecked =>
        renderLink(value.get("scala").asInstanceOf[MaterializableLink])
      case _ =>
        /*dottydoc.*/println(s"couldn't render: '$value'")
        null
    }
  }

  private[this] def renderLink(link: MaterializableLink): String = link match {
    case MaterializedLink(title, target) =>
      s"""<a href="$target">$title</a>"""
    case _ => link.title
  }
}