summaryrefslogtreecommitdiff
path: root/src/compiler/scala/tools/nsc/doc/Settings.scala
blob: 4458889d55c8fdca32f5d5ce7c6af3768341b70b (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
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
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
/* NSC -- new Scala compiler
 * Copyright 2005-2011 LAMP/EPFL
 * @author  Martin Odersky
 */

package scala.tools.nsc
package doc

import java.io.File
import java.lang.System
import language.postfixOps

/** An extended version of compiler settings, with additional Scaladoc-specific options.
  * @param error A function that prints a string to the appropriate error stream. */
class Settings(error: String => Unit) extends scala.tools.nsc.Settings(error) {

  /** A setting that defines in which format the documentation is output. ''Note:'' this setting is currently always
    * `html`. */
  val docformat = ChoiceSetting (
    "-doc-format",
    "format",
    "Selects in which format documentation is rendered",
    List("html"),
    "html"
  )

  /** A setting that defines the overall title of the documentation, typically the name of the library being
    * documented. ''Note:'' This setting is currently not used. */
  val doctitle = StringSetting (
    "-doc-title",
    "title",
    "The overall name of the Scaladoc site",
    ""
  )

  /** A setting that defines the overall version number of the documentation, typically the version of the library being
    * documented. ''Note:'' This setting is currently not used. */
  val docversion = StringSetting (
    "-doc-version",
    "version",
    "An optional version number, to be appended to the title",
    ""
  )

  val docfooter = StringSetting (
    "-doc-footer",
    "footer",
    "A footer on every ScalaDoc page, by default the EPFL/Typesafe copyright notice. Can be overridden with a custom footer.",
    ""
  )

  val docUncompilable = StringSetting (
    "-doc-no-compile",
    "path",
    "A directory containing sources which should be parsed, no more (e.g. AnyRef.scala)",
    ""
  )

  lazy val uncompilableFiles = docUncompilable.value match {
    case ""     => Nil
    case path   => io.Directory(path).deepFiles filter (_ hasExtension "scala") toList
  }

  /** A setting that defines a URL to be concatenated with source locations and show a link to source files.
   * If needed the sourcepath option can be used to exclude undesired initial part of the link to sources */
  val docsourceurl = StringSetting (
    "-doc-source-url",
    "url",
    "A URL pattern used to build links to template sources; use variables, for example: ?{TPL_NAME} ('Seq'), ?{TPL_OWNER} ('scala.collection'), ?{FILE_PATH} ('scala/collection/Seq')",
    ""
  )

  val useStupidTypes = BooleanSetting (
    "-Yuse-stupid-types",
    "Print the types of inherited members as seen from their original definition context. Hint: you don't want to do that!"
  )

  val docgenerator = StringSetting (
    "-doc-generator",
    "class-name",
    "The fully qualified name of a doclet class, which will be used to generate the documentation",
    "scala.tools.nsc.doc.html.Doclet"
  )

  val docRootContent = PathSetting (
    "-doc-root-content",
    "The file from which the root package documentation should be imported.",
    ""
  )

  val docImplicits = BooleanSetting (
    "-implicits",
    "Document members inherited by implicit conversions."
  )

  val docImplicitsDebug = BooleanSetting (
    "-implicits-debug",
    "Show debugging information for members inherited by implicit conversions."
  )

  val docImplicitsShowAll = BooleanSetting (
    "-implicits-show-all",
    "Show members inherited by implicit conversions that are impossible in the default scope. " +
    "(for example conversions that require Numeric[String] to be in scope)"
  )

  val docDiagrams = BooleanSetting (
    "-diagrams",
    "Create inheritance diagrams for classes, traits and packages."
  )

  val docDiagramsDebug = BooleanSetting (
    "-diagrams-debug",
    "Show debugging information for the diagram creation process."
  )

  val docDiagramsDotPath = PathSetting (
    "-diagrams-dot-path",
    "The path to the dot executable used to generate the inheritance diagrams. Ex: /usr/bin/dot",
    "dot" // by default, just pick up the system-wide dot
  )

  // Somewhere slightly before r18708 scaladoc stopped building unless the
  // self-type check was suppressed.  I hijacked the slotted-for-removal-anyway
  // suppress-vt-warnings option and renamed it for this purpose.
  noSelfCheck.value = true

  // For improved help output.
  def scaladocSpecific = Set[Settings#Setting](
    docformat, doctitle, docfooter, docversion, docUncompilable, docsourceurl, docgenerator, docRootContent, useStupidTypes,
    docDiagrams, docDiagramsDebug, docDiagramsDotPath,
    docImplicits, docImplicitsDebug, docImplicitsShowAll
  )
  val isScaladocSpecific: String => Boolean = scaladocSpecific map (_.name)

  override def isScaladoc = true

  // unset by the testsuite, we don't need to count the entities in the model
  var reportModel = true

  /**
   *  This is the hardcoded area of Scaladoc. This is where "undesirable" stuff gets eliminated. I know it's not pretty,
   *  but ultimately scaladoc has to be useful. :)
   */
  object hardcoded {

    /** The common context bounds and some humanly explanations. Feel free to add more explanations
     *  `<root>.scala.package.Numeric` is the type class
     *  `tparam` is the name of the type parameter it gets (this only describes type classes with 1 type param)
     *  the function result should be a humanly-understandable description of the type class
     */
    val knownTypeClasses: Map[String, String => String] = Map() +
      ("<root>.scala.package.Numeric"       -> ((tparam: String) => tparam + " is a numeric class, such as Int, Long, Float or Double")) +
      ("<root>.scala.package.Integral"      -> ((tparam: String) => tparam + " is an integral numeric class, such as Int or Long")) +
      ("<root>.scala.package.Fractional"    -> ((tparam: String) => tparam + " is a fractional numeric class, such as Float or Double")) +
      ("<root>.scala.reflect.Manifest"      -> ((tparam: String) => tparam + " is accompanied by a Manifest, which is a runtime representation of its type that survives erasure")) +
      ("<root>.scala.reflect.ClassManifest" -> ((tparam: String) => tparam + " is accompanied by a ClassManifest, which is a runtime representation of its type that survives erasure")) +
      ("<root>.scala.reflect.OptManifest"   -> ((tparam: String) => tparam + " is accompanied by an OptManifest, which can be either a runtime representation of its type or the NoManifest, which means the runtime type is not available")) +
      ("<root>.scala.reflect.ClassTag"      -> ((tparam: String) => tparam + " is accompanied by a ClassTag, which is a runtime representation of its type that survives erasure")) +
      ("<root>.scala.reflect.AbsTypeTag"    -> ((tparam: String) => tparam + " is accompanied by an AbsTypeTag, which is a runtime representation of its type that survives erasure")) +
      ("<root>.scala.reflect.TypeTag"       -> ((tparam: String) => tparam + " is accompanied by a TypeTag, which is a runtime representation of its type that survives erasure"))

    /**
     * Set of classes to exclude from index and diagrams
     * TODO: Should be configurable
     */
    def isExcluded(qname: String) = {
      ( ( qname.startsWith("scala.Tuple") || qname.startsWith("scala.Product") ||
         qname.startsWith("scala.Function") || qname.startsWith("scala.runtime.AbstractFunction")
       ) && !(
        qname == "scala.Tuple1" || qname == "scala.Tuple2" ||
        qname == "scala.Product" || qname == "scala.Product1" || qname == "scala.Product2" ||
        qname == "scala.Function" || qname == "scala.Function1" || qname == "scala.Function2" ||
        qname == "scala.runtime.AbstractFunction0" || qname == "scala.runtime.AbstractFunction1" ||
        qname == "scala.runtime.AbstractFunction2"
      )
     )
    }

    /** Common conversion targets that affect any class in Scala */
    val commonConversionTargets = List(
      "scala.Predef.any2stringfmt",
      "scala.Predef.any2stringadd",
      "scala.Predef.any2ArrowAssoc",
      "scala.Predef.any2Ensuring")

    /** There's a reason all these are specialized by hand but documenting each of them is beyond the point */
    val arraySkipConversions = List(
      "scala.Predef.refArrayOps",
      "scala.Predef.intArrayOps",
      "scala.Predef.doubleArrayOps",
      "scala.Predef.longArrayOps",
      "scala.Predef.floatArrayOps",
      "scala.Predef.charArrayOps",
      "scala.Predef.byteArrayOps",
      "scala.Predef.shortArrayOps",
      "scala.Predef.booleanArrayOps",
      "scala.Predef.unitArrayOps",
      "scala.LowPriorityImplicits.wrapRefArray",
      "scala.LowPriorityImplicits.wrapIntArray",
      "scala.LowPriorityImplicits.wrapDoubleArray",
      "scala.LowPriorityImplicits.wrapLongArray",
      "scala.LowPriorityImplicits.wrapFloatArray",
      "scala.LowPriorityImplicits.wrapCharArray",
      "scala.LowPriorityImplicits.wrapByteArray",
      "scala.LowPriorityImplicits.wrapShortArray",
      "scala.LowPriorityImplicits.wrapBooleanArray",
      "scala.LowPriorityImplicits.wrapUnitArray",
      "scala.LowPriorityImplicits.genericWrapArray")

    // included as names as here we don't have access to a Global with Definitions :(
    def valueClassList = List("unit", "boolean", "byte", "short", "char", "int", "long", "float", "double")
    def valueClassFilterPrefixes = List("scala.LowPriorityImplicits", "scala.Predef")

    /** Dirty, dirty, dirty hack: the value params conversions can all kick in -- and they are disambiguated by priority
     *  but showing priority in scaladoc would make no sense -- so we have to manually remove the conversions that we
     *  know will never get a chance to kick in. Anyway, DIRTY DIRTY DIRTY! */
    def valueClassFilter(value: String, conversionName: String): Boolean = {
      val valueName = value.toLowerCase
      val otherValues = valueClassList.filterNot(_ == valueName)

      for (prefix <- valueClassFilterPrefixes)
        if (conversionName.startsWith(prefix))
          for (otherValue <- otherValues)
            if (conversionName.startsWith(prefix + "." + otherValue))
              return false

      true
    }
  }
}