Skip to content

[doc] some html enhancements for matsuri #2023

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion doc-tool/resources/_layouts/api-page.html
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ <h1 class="section {% if entity.hasVisibleMembers == false %}empty{% endif %}">
{% for member in entity.members %}
<div id="{{ member.signature }}" class="member {% if member.isPrivate %}private{% elsif member.isProtected %}protected{% endif %}">
<div class="member-title">
<span class="expand-button" onclick="toggleMemberBody(this, '{{ member.signature }}');">[+]</span>
<span class="expand-button {% if member.hasShortenedDocstring == false %}invisible{% endif %}" onclick="toggleMemberBody(this, '{{ member.signature }}');">[+]</span>
<span class="member-annotations">
{% for annot in member.annotations %}@{{ annot | split: '.' | last }} {% endfor %}
</span>
Expand Down
5 changes: 5 additions & 0 deletions doc-tool/resources/css/api-page.css
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,11 @@ div.entity-section > div.member > div.member-title > span.expand-button:hover {
user-select: none;
}

div.entity-section > div.member > div.member-title > span.expand-button.invisible,
div.entity-section > div.member > div.member-title > span.expand-button.invisible:hover {
color: transparent;
}

div.entity-section > div.member > div.member-body {
margin: 5px 0 0 39px;
}
Expand Down
3 changes: 2 additions & 1 deletion doc-tool/src/dotty/tools/dottydoc/DocCompiler.scala
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ class DocCompiler extends Compiler {
new LinkSuperTypes,
new LinkCompanions,
new AlternateConstructors,
new SortMembers))
new SortMembers)),
List(new StatisticsPhase)
)
}
5 changes: 4 additions & 1 deletion doc-tool/src/dotty/tools/dottydoc/DocDriver.scala
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import model.Package
import dotc.config._
import dotc.core.Comments.ContextDoc
import staticsite.Site
import dotc.printing.Highlighting._

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

if (!siteRoot.exists || !siteRoot.isDirectory)
ctx.error(s"Site root does not exist: $siteRoot")
else {
Site(siteRoot, ctx.settings.projectName.value, ctx.docbase.packages)
Site(siteRoot, projectName, ctx.docbase.packages)
.generateApiDocs()
.copyStaticFiles()
.generateHtmlFiles()
.generateBlog()

ctx.docbase.printSummary()
System.exit(if (reporter.hasErrors) 1 else 0)
}
}
Expand Down
86 changes: 84 additions & 2 deletions doc-tool/src/dotty/tools/dottydoc/core/ContextDottydoc.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,12 @@ package dotty.tools
package dottydoc
package core

import dotc.core.Symbols.Symbol
import dotc.core.Symbols._
import dotc.core.Flags._
import dotc.core.Decorators._
import dotc.core.Comments.ContextDocstrings
import model.Package
import model.{ Package, Entity }
import model.comment.Comment

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

private[this] var _statistics: Map[String, Statistics] = Map.empty
def registerStatistics(pkgName: String, stat: Statistics): Unit =
_statistics = _statistics + (pkgName -> stat)

def statistics: Map[String, Statistics] = _statistics

/** Should perhaps factorize this into caches that get flushed */
private var _defs: Map[Symbol, Set[Symbol]] = Map.empty
def defs(sym: Symbol): Set[Symbol] = _defs.get(sym).getOrElse(Set.empty)
Expand Down Expand Up @@ -49,4 +58,77 @@ class ContextDottydoc extends ContextDocstrings {
}.toString, pos)

def debug(msg: String)(implicit ctx: Context): Unit = debug(msg, NoSourcePosition)

def printSummary()(implicit ctx: Context): Unit = {
def colored(part: Int, total: Int) =
if (total == 0) "0"
else {
val percentage = (part * 100.0 / total).toInt
val str = s"$part/$total ($percentage%)"

if (percentage > 75) Green(str)
else if (percentage > 50) Yellow(str)
else Red(str)
}

val totalEntities = statistics.totalEntities

val projectName = ctx.settings.projectName.value
val warningsText =
if (ctx.reporter.hasWarnings)
s"total warnings with regards to compilation and documentation: ${ctx.reporter.warningCount}"
else ""

val api = statistics.values.iterator.map(_.api).foldLeft(Counters(0,0,0,0,0,0))(_ merge _)
val internalApi = statistics.values.iterator.map(_.internalApi).foldLeft(Counters(0,0,0,0,0,0))(_ merge _)

val apiSummary = (for {
(pkgName, stat) <- statistics.toList.sortBy(_._1)
} yield {
val pub = colored(stat.api.publicDocstrings, stat.api.publicEntities)
val pro = colored(stat.api.protectedDocstrings, stat.api.protectedEntities)
s"""|package $pkgName
|${Blue("-" * ctx.settings.pageWidth.value)}
|public: $pub \t protected: $pro
|""".stripMargin
}).mkString("\n")

val internalSummary = (for {
(pkgName, stat) <- statistics.toList.sortBy(_._1)
} yield {
val pub = colored(stat.internalApi.publicDocstrings, stat.internalApi.publicEntities)
val pro = colored(stat.internalApi.protectedDocstrings, stat.internalApi.protectedEntities)
val pri = colored(stat.internalApi.privateDocstrings, stat.internalApi.privateEntities)
s"""|package $pkgName
|${Blue("-" * ctx.settings.pageWidth.value)}
|public: $pub \t protected: $pro \t private: $pri
|""".stripMargin
}).mkString("\n")

ctx.echo {
s"""|${Blue("=" * ctx.settings.pageWidth.value)}
|Dottydoc summary report for project `$projectName`
|${Blue("=" * ctx.settings.pageWidth.value)}
|Documented members in public API:
|
|$apiSummary
|
|Summary:
|
|public members with docstrings: ${colored(api.publicDocstrings, api.publicEntities)}
|${hl"${"protected"}"} members with docstrings: ${colored(api.protectedDocstrings, api.protectedEntities)}
|${Blue("=" * ctx.settings.pageWidth.value)}
|
|Documented members in internal API:
|
|$internalSummary
|
|Summary internal API:
|
|public members with docstrings: ${colored(internalApi.publicDocstrings, internalApi.publicEntities)}
|${hl"${"protected"}"} members with docstrings: ${colored(internalApi.protectedDocstrings, internalApi.protectedEntities)}
|${hl"${"private"}"} members with docstrings: ${colored(internalApi.privateDocstrings, internalApi.privateEntities)}
|$warningsText""".stripMargin
}
}
}
5 changes: 2 additions & 3 deletions doc-tool/src/dotty/tools/dottydoc/core/DocASTPhase.scala
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,7 @@ class DocASTPhase extends Phase {

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

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

// (2) Set parents of entities, needed for linking
for {
parentName <- rootPackages(packages)
parent = packages(parentName)
parent <- rootPackages(packages)
child <- parent.members
} setParent(child, to = parent)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import util.syntax._

/** Phase to add docstrings to the Dottydoc AST */
class DocstringPhase extends DocMiniPhase with CommentParser with CommentCleaner {

private def getComment(sym: Symbol)(implicit ctx: Context): Option[CompilerComment] =
ctx.docbase.docstring(sym)
.orElse {
Expand Down
156 changes: 156 additions & 0 deletions doc-tool/src/dotty/tools/dottydoc/core/StatisticsPhase.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
package dotty.tools
package dottydoc
package core

import dotc.core.Phases.Phase
import dotc.core.Contexts.Context
import dotc.core.Symbols.Symbol
import dotc.core.Decorators._
import dotc.core.Flags._
import dotc.CompilationUnit
import dottydoc.util.syntax._
import dottydoc.util.traversing._

import model._

object Statistics {
implicit class MapTotals(val map: Map[String, Statistics]) extends AnyVal {
def totalEntities =
map.values.foldLeft(0)(_ + _.totalEntities)
}
}

case class Statistics(pkgName: String, api: Counters, internalApi: Counters) {
def totalEntities =
api.totalEntities + internalApi.totalEntities

def totalDocstrings =
api.totalDocstrings + internalApi.totalDocstrings
}

case class Counters(
publicEntities: Int,
privateEntities: Int,
protectedEntities: Int,

publicDocstrings: Int,
privateDocstrings: Int,
protectedDocstrings: Int
) {
def totalEntities =
publicEntities + privateEntities + protectedEntities

def totalDocstrings =
publicDocstrings + privateDocstrings + protectedDocstrings

def merge(o: Counters): Counters = Counters(
publicEntities + o.publicEntities,
privateEntities + o.privateEntities,
protectedEntities + o.protectedEntities,
publicDocstrings + o.publicDocstrings,
privateDocstrings + o.privateDocstrings,
protectedDocstrings + o.protectedDocstrings
)
}

class StatisticsPhase extends Phase {

def phaseName = "StatisticsPhase"

override def run(implicit ctx: Context): Unit = ()

override def runOn(units: List[CompilationUnit])(implicit ctx: Context): List[CompilationUnit] = {
for {
(pkgName, pack) <- ctx.docbase.packages
externalApi = collectPublicStats(pack)
internalApi = collectInternalStats(pack)
stats = Statistics(pkgName, externalApi, internalApi)
} ctx.docbase.registerStatistics(pkgName, stats)

units
}

def collectPublicStats(pack: Package)(implicit ctx: Context): Counters = {
var publicEntities: Int = 0
var protectedEntities: Int = 0
var publicDocstrings: Int = 0
var protectedDocstrings: Int = 0

if (pack.comment.isDefined) {
publicEntities += 1
publicDocstrings += 1
}

def doCount(sym: Symbol, comment: Int): Unit =
if (!sym.is(Protected)) {
publicEntities += 1
publicDocstrings += comment
}
else {
protectedEntities += 1
protectedDocstrings += comment
}


def recur(e: Entity, reachable: Boolean): Unit = {
val isVisible = !e.symbol.is(Private) && !e.symbol.privateWithin.exists
val shouldCount = isVisible && reachable
e match {
case e: Package => ()
case e: Entity with Members => if (shouldCount) {
doCount(e.symbol, if (e.comment.isDefined) 1 else 0)
e.members.foreach { c =>
if (!(e.symbol.is(Final) && c.symbol.is(Protected))) recur(c, true)
}
}
case e =>
if (shouldCount) doCount(e.symbol, if (e.comment.isDefined) 1 else 0)
}
}

pack.members.foreach(recur(_, true))
Counters(publicEntities, 0, protectedEntities, publicDocstrings, 0, protectedDocstrings)
}

def collectInternalStats(pack: Package)(implicit ctx: Context): Counters = {
var publicEntities: Int = 0
var privateEntities: Int = 0
var protectedEntities: Int = 0
var publicDocstrings: Int = 0
var privateDocstrings: Int = 0
var protectedDocstrings: Int = 0

def doCount(sym: Symbol, comment: Int): Unit =
if (sym.is(Private)) {
privateEntities += 1
privateDocstrings += comment
}
else if (!sym.is(Protected)) {
publicEntities += 1
publicDocstrings += comment
}
else {
protectedEntities += 1
protectedDocstrings += comment
}


def recur(e: Entity, reachable: Boolean): Unit = {
val internal = !reachable || e.symbol.is(Private) || e.symbol.privateWithin.exists
e match {
case _: Package => ()
case e: Entity with Members =>
e.members.foreach { c =>
val childIsInternal = !internal || (e.symbol.is(Final) && c.symbol.is(Protected))
recur(c, childIsInternal)
}
if (internal) doCount(e.symbol, if (e.comment.isDefined) 1 else 0)
case _ =>
if (internal) doCount(e.symbol, if (e.comment.isDefined) 1 else 0)
}
}

pack.members.foreach(recur(_, true))
Counters(publicEntities, privateEntities, protectedEntities, publicDocstrings, privateDocstrings, protectedDocstrings)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -45,15 +45,15 @@ object transform {
* -------------------------
* To delete a node in the AST, simply return `NonEntity` from transforming method
*/
abstract class DocMiniTransformations(transformations: List[DocMiniPhase]) extends Phase {
trait DocMiniTransformations extends Phase {
def transformations: List[DocMiniPhase]

override def runOn(units: List[CompilationUnit])(implicit ctx: Context): List[CompilationUnit] = {
for {
rootName <- rootPackages(ctx.docbase.packages)
pack = ctx.docbase.packages(rootName)
pack <- rootPackages(ctx.docbase.packages)
transformed = performPackageTransform(pack)
} yield ctx.docbase.packagesMutable(rootName) = transformed
super.runOn(units)
} yield ctx.docbase.packagesMutable(pack.name) = transformed
units
}

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

object DocMiniTransformations {
private var previousPhase = 0
def apply(transformations: DocMiniPhase*) =
new DocMiniTransformations(transformations.toList) {
def apply(miniPhases: DocMiniPhase*) =
new DocMiniTransformations {
val transformations = miniPhases.toList
val packages = Map.empty[String, Package]

def phaseName = s"MiniTransformation${ previousPhase += 1 }"
Expand Down
Loading