aboutsummaryrefslogtreecommitdiff
path: root/doc-tool/src/dotty/tools/dottydoc/util/MemberLookup.scala
blob: bb09a709012b87d23fccfc713578c98c7dcf41b4 (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
package dotty.tools
package dottydoc
package util

import dotc.config.Printers.dottydoc
import dotc.core.Contexts.Context
import dotc.core.Flags
import dotc.core.Names._
import dotc.core.Symbols._
import dotc.core.Names._
import dotc.util.Positions._
import model.internal._
import model.comment._
import model._

trait MemberLookup {
  /** Performs a lookup based on the provided (pruned) query string
   *
   *  Will return a `Tooltip` if unsucessfull, otherwise a LinkToEntity or
   *  LinkToExternal
   */
  def lookup(entity: Entity, packages: Map[String, Package], query: String): Option[Entity] = {
    val notFound: Option[Entity] = None
    val querys = query.split("\\.").toList

    /** Looks for the specified entity among `ent`'s members */
    def localLookup(ent: Entity with Members, searchStr: String): Option[Entity] =
      ent
        .members
        .collect { case x if x.name == searchStr => x }
        .sortBy(_.path.last)
        .headOption

    /** Looks for an entity down in the structure, if the search list is Nil,
     *  the search stops
     */
    def downwardLookup(ent: Entity with Members, search: List[String]): Option[Entity] =
      search match {
        case Nil => notFound
        case x :: Nil =>
          localLookup(ent, x)
        case x :: xs  =>
          ent
            .members
            .collect {
              case e: Entity with Members if e.name == x => e
              case e: Entity with Members if e.name == x.init && x.last == '$' => e
            }
            .headOption
            .fold(notFound)(e => downwardLookup(e, xs))
      }

    /** Finds package with longest matching name, then does downwardLookup in
     *  the package
     */
    def globalLookup: Option[Entity] = {
      def longestMatch(list: List[String]): List[String] =
        if (list eq Nil) Nil
        else
          packages
          .get(list.mkString("."))
          .map(_ => list)
          .getOrElse(longestMatch(list.dropRight(1)))

      longestMatch(querys) match {
        case Nil => notFound
        case xs  => downwardLookup(packages(xs.mkString(".")), querys diff xs)
      }
    }

    (querys, entity) match {
      case (xs, NonEntity) => globalLookup
      case (x :: Nil, e: Entity with Members) =>
        localLookup(e, x)
      case (x :: _, e: Entity with Members) if x == entity.name =>
        downwardLookup(e, querys)
      case (x :: xs, _) =>
        if (xs.nonEmpty) globalLookup
        else lookup(entity, packages, "scala." + query)
    }
  }

  def makeEntityLink(
    entity: Entity,
    packages: Map[String, Package],
    title: Inline,
    query: String
  ): EntityLink = {
    val link =
      lookup(entity, packages, query)
      .map(LinkToEntity)
      .getOrElse(Tooltip(query))

    EntityLink(title, link)
  }
}