Skip to content

Commit 501db66

Browse files
authored
Merge pull request #2023 from dotty-staging/topic/dottydoc-html-enhancements2
[doc] some html enhancements for matsuri
2 parents 43612f9 + 9914d1a commit 501db66

13 files changed

+288
-17
lines changed

doc-tool/resources/_layouts/api-page.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ <h1 class="section {% if entity.hasVisibleMembers == false %}empty{% endif %}">
9595
{% for member in entity.members %}
9696
<div id="{{ member.signature }}" class="member {% if member.isPrivate %}private{% elsif member.isProtected %}protected{% endif %}">
9797
<div class="member-title">
98-
<span class="expand-button" onclick="toggleMemberBody(this, '{{ member.signature }}');">[+]</span>
98+
<span class="expand-button {% if member.hasShortenedDocstring == false %}invisible{% endif %}" onclick="toggleMemberBody(this, '{{ member.signature }}');">[+]</span>
9999
<span class="member-annotations">
100100
{% for annot in member.annotations %}@{{ annot | split: '.' | last }} {% endfor %}
101101
</span>

doc-tool/resources/css/api-page.css

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,11 @@ div.entity-section > div.member > div.member-title > span.expand-button:hover {
122122
user-select: none;
123123
}
124124

125+
div.entity-section > div.member > div.member-title > span.expand-button.invisible,
126+
div.entity-section > div.member > div.member-title > span.expand-button.invisible:hover {
127+
color: transparent;
128+
}
129+
125130
div.entity-section > div.member > div.member-body {
126131
margin: 5px 0 0 39px;
127132
}

doc-tool/src/dotty/tools/dottydoc/DocCompiler.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ class DocCompiler extends Compiler {
3232
new LinkSuperTypes,
3333
new LinkCompanions,
3434
new AlternateConstructors,
35-
new SortMembers))
35+
new SortMembers)),
36+
List(new StatisticsPhase)
3637
)
3738
}

doc-tool/src/dotty/tools/dottydoc/DocDriver.scala

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import model.Package
99
import dotc.config._
1010
import dotc.core.Comments.ContextDoc
1111
import staticsite.Site
12+
import dotc.printing.Highlighting._
1213

1314
/** `DocDriver` implements the main entry point to the Dotty documentation
1415
* tool. It's methods are used by the external scala and java APIs.
@@ -43,16 +44,18 @@ class DocDriver extends Driver {
4344
implicit val (filesToDocument, ctx) = setup(args, initCtx.fresh)
4445
val reporter = doCompile(newCompiler(ctx), filesToDocument)(ctx)
4546
val siteRoot = new java.io.File(ctx.settings.siteRoot.value)
47+
val projectName = ctx.settings.projectName.value
4648

4749
if (!siteRoot.exists || !siteRoot.isDirectory)
4850
ctx.error(s"Site root does not exist: $siteRoot")
4951
else {
50-
Site(siteRoot, ctx.settings.projectName.value, ctx.docbase.packages)
52+
Site(siteRoot, projectName, ctx.docbase.packages)
5153
.generateApiDocs()
5254
.copyStaticFiles()
5355
.generateHtmlFiles()
5456
.generateBlog()
5557

58+
ctx.docbase.printSummary()
5659
System.exit(if (reporter.hasErrors) 1 else 0)
5760
}
5861
}

doc-tool/src/dotty/tools/dottydoc/core/ContextDottydoc.scala

Lines changed: 84 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,12 @@ package dotty.tools
22
package dottydoc
33
package core
44

5-
import dotc.core.Symbols.Symbol
5+
import dotc.core.Symbols._
6+
import dotc.core.Flags._
7+
import dotc.core.Decorators._
68
import dotc.core.Comments.ContextDocstrings
7-
import model.Package
9+
import model.{ Package, Entity }
10+
import model.comment.Comment
811

912
import dotc.core.Contexts.Context
1013
import dotc.printing.Highlighting._
@@ -17,6 +20,12 @@ class ContextDottydoc extends ContextDocstrings {
1720
def packages: Map[String, Package] = _packages.toMap
1821
def packagesMutable: mutable.Map[String, Package] = _packages
1922

23+
private[this] var _statistics: Map[String, Statistics] = Map.empty
24+
def registerStatistics(pkgName: String, stat: Statistics): Unit =
25+
_statistics = _statistics + (pkgName -> stat)
26+
27+
def statistics: Map[String, Statistics] = _statistics
28+
2029
/** Should perhaps factorize this into caches that get flushed */
2130
private var _defs: Map[Symbol, Set[Symbol]] = Map.empty
2231
def defs(sym: Symbol): Set[Symbol] = _defs.get(sym).getOrElse(Set.empty)
@@ -49,4 +58,77 @@ class ContextDottydoc extends ContextDocstrings {
4958
}.toString, pos)
5059

5160
def debug(msg: String)(implicit ctx: Context): Unit = debug(msg, NoSourcePosition)
61+
62+
def printSummary()(implicit ctx: Context): Unit = {
63+
def colored(part: Int, total: Int) =
64+
if (total == 0) "0"
65+
else {
66+
val percentage = (part * 100.0 / total).toInt
67+
val str = s"$part/$total ($percentage%)"
68+
69+
if (percentage > 75) Green(str)
70+
else if (percentage > 50) Yellow(str)
71+
else Red(str)
72+
}
73+
74+
val totalEntities = statistics.totalEntities
75+
76+
val projectName = ctx.settings.projectName.value
77+
val warningsText =
78+
if (ctx.reporter.hasWarnings)
79+
s"total warnings with regards to compilation and documentation: ${ctx.reporter.warningCount}"
80+
else ""
81+
82+
val api = statistics.values.iterator.map(_.api).foldLeft(Counters(0,0,0,0,0,0))(_ merge _)
83+
val internalApi = statistics.values.iterator.map(_.internalApi).foldLeft(Counters(0,0,0,0,0,0))(_ merge _)
84+
85+
val apiSummary = (for {
86+
(pkgName, stat) <- statistics.toList.sortBy(_._1)
87+
} yield {
88+
val pub = colored(stat.api.publicDocstrings, stat.api.publicEntities)
89+
val pro = colored(stat.api.protectedDocstrings, stat.api.protectedEntities)
90+
s"""|package $pkgName
91+
|${Blue("-" * ctx.settings.pageWidth.value)}
92+
|public: $pub \t protected: $pro
93+
|""".stripMargin
94+
}).mkString("\n")
95+
96+
val internalSummary = (for {
97+
(pkgName, stat) <- statistics.toList.sortBy(_._1)
98+
} yield {
99+
val pub = colored(stat.internalApi.publicDocstrings, stat.internalApi.publicEntities)
100+
val pro = colored(stat.internalApi.protectedDocstrings, stat.internalApi.protectedEntities)
101+
val pri = colored(stat.internalApi.privateDocstrings, stat.internalApi.privateEntities)
102+
s"""|package $pkgName
103+
|${Blue("-" * ctx.settings.pageWidth.value)}
104+
|public: $pub \t protected: $pro \t private: $pri
105+
|""".stripMargin
106+
}).mkString("\n")
107+
108+
ctx.echo {
109+
s"""|${Blue("=" * ctx.settings.pageWidth.value)}
110+
|Dottydoc summary report for project `$projectName`
111+
|${Blue("=" * ctx.settings.pageWidth.value)}
112+
|Documented members in public API:
113+
|
114+
|$apiSummary
115+
|
116+
|Summary:
117+
|
118+
|public members with docstrings: ${colored(api.publicDocstrings, api.publicEntities)}
119+
|${hl"${"protected"}"} members with docstrings: ${colored(api.protectedDocstrings, api.protectedEntities)}
120+
|${Blue("=" * ctx.settings.pageWidth.value)}
121+
|
122+
|Documented members in internal API:
123+
|
124+
|$internalSummary
125+
|
126+
|Summary internal API:
127+
|
128+
|public members with docstrings: ${colored(internalApi.publicDocstrings, internalApi.publicEntities)}
129+
|${hl"${"protected"}"} members with docstrings: ${colored(internalApi.protectedDocstrings, internalApi.protectedEntities)}
130+
|${hl"${"private"}"} members with docstrings: ${colored(internalApi.privateDocstrings, internalApi.privateEntities)}
131+
|$warningsText""".stripMargin
132+
}
133+
}
52134
}

doc-tool/src/dotty/tools/dottydoc/core/DocASTPhase.scala

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -226,7 +226,7 @@ class DocASTPhase extends Phase {
226226

227227
override def run(implicit ctx: Context): Unit = {
228228
currentRun += 1
229-
ctx.docbase.echo(s"Compiling ($currentRun/$totalRuns): ${ctx.compilationUnit.source.file.name}")
229+
ctx.echo(s"Compiling ($currentRun/$totalRuns): ${ctx.compilationUnit.source.file.name}")
230230
collect(ctx.compilationUnit.tpdTree) // Will put packages in `packages` var
231231
}
232232

@@ -237,8 +237,7 @@ class DocASTPhase extends Phase {
237237

238238
// (2) Set parents of entities, needed for linking
239239
for {
240-
parentName <- rootPackages(packages)
241-
parent = packages(parentName)
240+
parent <- rootPackages(packages)
242241
child <- parent.members
243242
} setParent(child, to = parent)
244243

doc-tool/src/dotty/tools/dottydoc/core/DocstringPhase.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import util.syntax._
1414

1515
/** Phase to add docstrings to the Dottydoc AST */
1616
class DocstringPhase extends DocMiniPhase with CommentParser with CommentCleaner {
17+
1718
private def getComment(sym: Symbol)(implicit ctx: Context): Option[CompilerComment] =
1819
ctx.docbase.docstring(sym)
1920
.orElse {
Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
package dotty.tools
2+
package dottydoc
3+
package core
4+
5+
import dotc.core.Phases.Phase
6+
import dotc.core.Contexts.Context
7+
import dotc.core.Symbols.Symbol
8+
import dotc.core.Decorators._
9+
import dotc.core.Flags._
10+
import dotc.CompilationUnit
11+
import dottydoc.util.syntax._
12+
import dottydoc.util.traversing._
13+
14+
import model._
15+
16+
object Statistics {
17+
implicit class MapTotals(val map: Map[String, Statistics]) extends AnyVal {
18+
def totalEntities =
19+
map.values.foldLeft(0)(_ + _.totalEntities)
20+
}
21+
}
22+
23+
case class Statistics(pkgName: String, api: Counters, internalApi: Counters) {
24+
def totalEntities =
25+
api.totalEntities + internalApi.totalEntities
26+
27+
def totalDocstrings =
28+
api.totalDocstrings + internalApi.totalDocstrings
29+
}
30+
31+
case class Counters(
32+
publicEntities: Int,
33+
privateEntities: Int,
34+
protectedEntities: Int,
35+
36+
publicDocstrings: Int,
37+
privateDocstrings: Int,
38+
protectedDocstrings: Int
39+
) {
40+
def totalEntities =
41+
publicEntities + privateEntities + protectedEntities
42+
43+
def totalDocstrings =
44+
publicDocstrings + privateDocstrings + protectedDocstrings
45+
46+
def merge(o: Counters): Counters = Counters(
47+
publicEntities + o.publicEntities,
48+
privateEntities + o.privateEntities,
49+
protectedEntities + o.protectedEntities,
50+
publicDocstrings + o.publicDocstrings,
51+
privateDocstrings + o.privateDocstrings,
52+
protectedDocstrings + o.protectedDocstrings
53+
)
54+
}
55+
56+
class StatisticsPhase extends Phase {
57+
58+
def phaseName = "StatisticsPhase"
59+
60+
override def run(implicit ctx: Context): Unit = ()
61+
62+
override def runOn(units: List[CompilationUnit])(implicit ctx: Context): List[CompilationUnit] = {
63+
for {
64+
(pkgName, pack) <- ctx.docbase.packages
65+
externalApi = collectPublicStats(pack)
66+
internalApi = collectInternalStats(pack)
67+
stats = Statistics(pkgName, externalApi, internalApi)
68+
} ctx.docbase.registerStatistics(pkgName, stats)
69+
70+
units
71+
}
72+
73+
def collectPublicStats(pack: Package)(implicit ctx: Context): Counters = {
74+
var publicEntities: Int = 0
75+
var protectedEntities: Int = 0
76+
var publicDocstrings: Int = 0
77+
var protectedDocstrings: Int = 0
78+
79+
if (pack.comment.isDefined) {
80+
publicEntities += 1
81+
publicDocstrings += 1
82+
}
83+
84+
def doCount(sym: Symbol, comment: Int): Unit =
85+
if (!sym.is(Protected)) {
86+
publicEntities += 1
87+
publicDocstrings += comment
88+
}
89+
else {
90+
protectedEntities += 1
91+
protectedDocstrings += comment
92+
}
93+
94+
95+
def recur(e: Entity, reachable: Boolean): Unit = {
96+
val isVisible = !e.symbol.is(Private) && !e.symbol.privateWithin.exists
97+
val shouldCount = isVisible && reachable
98+
e match {
99+
case e: Package => ()
100+
case e: Entity with Members => if (shouldCount) {
101+
doCount(e.symbol, if (e.comment.isDefined) 1 else 0)
102+
e.members.foreach { c =>
103+
if (!(e.symbol.is(Final) && c.symbol.is(Protected))) recur(c, true)
104+
}
105+
}
106+
case e =>
107+
if (shouldCount) doCount(e.symbol, if (e.comment.isDefined) 1 else 0)
108+
}
109+
}
110+
111+
pack.members.foreach(recur(_, true))
112+
Counters(publicEntities, 0, protectedEntities, publicDocstrings, 0, protectedDocstrings)
113+
}
114+
115+
def collectInternalStats(pack: Package)(implicit ctx: Context): Counters = {
116+
var publicEntities: Int = 0
117+
var privateEntities: Int = 0
118+
var protectedEntities: Int = 0
119+
var publicDocstrings: Int = 0
120+
var privateDocstrings: Int = 0
121+
var protectedDocstrings: Int = 0
122+
123+
def doCount(sym: Symbol, comment: Int): Unit =
124+
if (sym.is(Private)) {
125+
privateEntities += 1
126+
privateDocstrings += comment
127+
}
128+
else if (!sym.is(Protected)) {
129+
publicEntities += 1
130+
publicDocstrings += comment
131+
}
132+
else {
133+
protectedEntities += 1
134+
protectedDocstrings += comment
135+
}
136+
137+
138+
def recur(e: Entity, reachable: Boolean): Unit = {
139+
val internal = !reachable || e.symbol.is(Private) || e.symbol.privateWithin.exists
140+
e match {
141+
case _: Package => ()
142+
case e: Entity with Members =>
143+
e.members.foreach { c =>
144+
val childIsInternal = !internal || (e.symbol.is(Final) && c.symbol.is(Protected))
145+
recur(c, childIsInternal)
146+
}
147+
if (internal) doCount(e.symbol, if (e.comment.isDefined) 1 else 0)
148+
case _ =>
149+
if (internal) doCount(e.symbol, if (e.comment.isDefined) 1 else 0)
150+
}
151+
}
152+
153+
pack.members.foreach(recur(_, true))
154+
Counters(publicEntities, privateEntities, protectedEntities, publicDocstrings, privateDocstrings, protectedDocstrings)
155+
}
156+
}

doc-tool/src/dotty/tools/dottydoc/core/MiniPhaseTransform.scala renamed to doc-tool/src/dotty/tools/dottydoc/core/transform.scala

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -45,15 +45,15 @@ object transform {
4545
* -------------------------
4646
* To delete a node in the AST, simply return `NonEntity` from transforming method
4747
*/
48-
abstract class DocMiniTransformations(transformations: List[DocMiniPhase]) extends Phase {
48+
trait DocMiniTransformations extends Phase {
49+
def transformations: List[DocMiniPhase]
4950

5051
override def runOn(units: List[CompilationUnit])(implicit ctx: Context): List[CompilationUnit] = {
5152
for {
52-
rootName <- rootPackages(ctx.docbase.packages)
53-
pack = ctx.docbase.packages(rootName)
53+
pack <- rootPackages(ctx.docbase.packages)
5454
transformed = performPackageTransform(pack)
55-
} yield ctx.docbase.packagesMutable(rootName) = transformed
56-
super.runOn(units)
55+
} yield ctx.docbase.packagesMutable(pack.name) = transformed
56+
units
5757
}
5858

5959
private def performPackageTransform(pack: Package)(implicit ctx: Context): Package = {
@@ -197,8 +197,9 @@ object transform {
197197

198198
object DocMiniTransformations {
199199
private var previousPhase = 0
200-
def apply(transformations: DocMiniPhase*) =
201-
new DocMiniTransformations(transformations.toList) {
200+
def apply(miniPhases: DocMiniPhase*) =
201+
new DocMiniTransformations {
202+
val transformations = miniPhases.toList
202203
val packages = Map.empty[String, Package]
203204

204205
def phaseName = s"MiniTransformation${ previousPhase += 1 }"

0 commit comments

Comments
 (0)