Skip to content

Commit a7ba826

Browse files
committed
WIP
1 parent 807d775 commit a7ba826

16 files changed

+325
-226
lines changed

scala3doc/resources/dotty_res/scripts/ux.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,16 @@ window.addEventListener("DOMContentLoaded", () => {
55
document.getElementById("leftColumn").classList.toggle("open");
66
};
77
}
8+
9+
var elements = document.getElementsByClassName("documentableElement")
10+
if (elements) {
11+
for (i = 0; i < elements.length; i++) {
12+
elements[i].onclick = function(){
13+
this.classList.toggle("expand")
14+
}
15+
}
16+
}
17+
818
var logo = document.getElementById("logo");
919
if (logo) {
1020
logo.onclick = function() {

scala3doc/resources/dotty_res/styles/scalastyle.css

Lines changed: 74 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@
1212
--inactive-fg: #777;
1313
--title-fg: #00485E;
1414

15+
--link-sig-fd: #7c99a5;
16+
--link-sig-hover-fd: #7c99a5;
17+
1518
--leftbar-bg: #003048;
1619
--leftbar-fg: #fff;
1720
--leftbar-current-bg: #0090BB;
@@ -364,7 +367,7 @@ dl.attributes > dt.implicit {
364367
}
365368
dl.attributes > dd {
366369
display: block;
367-
padding-left: 10em;
370+
padding-left: 5em;
368371
margin-bottom: 5px;
369372
min-height: 15px;
370373
}
@@ -437,11 +440,43 @@ footer .pull-right {
437440
margin-left: auto;
438441
}
439442

443+
440444
.modifiers {
441-
width: 12em;
442445
display: table-cell;
443-
text-align: right;
444446
padding-right: 0.5em;
447+
min-width: 10em;
448+
max-width: 10em;
449+
overflow: hidden;
450+
direction: rtl;
451+
white-space: nowrap;
452+
text-indent: 0em;
453+
}
454+
455+
.modifiers .other-modifiers {
456+
color: gray;
457+
}
458+
459+
.other-modifiers a, .other-modifiers a:visited, .other-modifiers span[data-unresolved-link] {
460+
color: var(--link-sig-fd);
461+
}
462+
463+
.expand .modifiers {
464+
display: inline-table;
465+
min-width: 4em;
466+
}
467+
468+
.signature {
469+
color: gray;
470+
display: table-cell;
471+
padding-left: 0.5em;
472+
}
473+
474+
.signature a, .signature a:visited, .signature span[data-unresolved-link] {
475+
color: var(--link-sig-fd);
476+
}
477+
478+
.expand .signature {
479+
display: inline;
445480
}
446481

447482
.documentableElement {
@@ -454,15 +489,50 @@ footer .pull-right {
454489
font-weight: 500;
455490
font-size: 12px;
456491
background: var(--code-bg);
492+
border: 0.25em solid white;
457493
}
458494

459495
.documentableElement>div {
460496
display: table;
461497
}
462498

499+
.expand.documentableElement>div {
500+
display: block;
501+
padding-left: 3em;
502+
}
503+
504+
.expand.documentableElement>div.header {
505+
display: block;
506+
padding-left: 7.5em;
507+
text-indent: -4.5em;
508+
}
509+
510+
.documentableElement>div .cover {
511+
display: none;
512+
}
513+
514+
.documentableElement.expand>div .cover {
515+
display: block;
516+
}
517+
518+
.expand .doc {
519+
margin-left: 6.5em;
520+
}
521+
522+
.documentableElement:hover {
523+
cursor: pointer;
524+
border-left: 0.25em solid var(--leftbar-bg);
525+
}
526+
463527
.annotations {
464-
margin-left: 9em;
528+
color: gray;
529+
display: none;
465530
}
531+
532+
.expand .annotations {
533+
display: inline-block;
534+
}
535+
466536
.documentableAnchor {
467537
position: absolute;
468538
width: 24px;

scala3doc/src/dotty/dokka/SourceLinks.scala

Lines changed: 37 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,30 @@ import liqp.Template
66
import dotty.dokka.model.api._
77
import dotty.tools.dotc.core.Contexts.Context
88

9-
case class SourceLink(val path: Option[Path], val urlTemplate: Template)
9+
trait SourceLink:
10+
val path: Option[Path] = None
11+
def render(path: String, operation: String, line: Option[Int]): String
12+
13+
case class PrefixedSourceLink(val myPath: Path, nested: SourceLink) extends SourceLink:
14+
export nested.render
15+
override val path = Some(myPath)
16+
17+
case class TemplateSourceLink(val urlTemplate: Template) extends SourceLink:
18+
override val path: Option[Path] = None
19+
override def render(path: String, operation: String, line: Option[Int]): String =
20+
val config = java.util.HashMap[String, Object]()
21+
config.put("path", path)
22+
line.foreach(l => config.put("line", l.toString))
23+
config.put("operation", operation)
24+
25+
urlTemplate.render(config)
26+
27+
case class WebBasedSourceLink(prefix: String, revision: String) extends SourceLink:
28+
override val path: Option[Path] = None
29+
override def render(path: String, operation: String, line: Option[Int]): String =
30+
val action = if operation == "view" then "blob" else operation
31+
val linePart = line.fold("")(l => s"#L$l")
32+
s"$prefix/$action/$revision/$path$linePart"
1033

1134
object SourceLink:
1235
val SubPath = "([^=]+)=(.+)".r
@@ -18,41 +41,39 @@ object SourceLink:
1841
"€{FILE_LINE}" -> "{{ line }}"
1942
)
2043

21-
def githubTemplate(organization: String, repo: String)(revision: String) =
22-
s"""https://github.com/$organization/$repo/{{ operation | replace: "view", "blob" }}/$revision/{{ path }}#L{{ line }}""".stripMargin
44+
def githubPrefix(org: String, repo: String) = s"https://github.com/$org/$repo"
2345

24-
def gitlabTemplate(organization: String, repo: String)(revision: String) =
25-
s"""https://gitlab.com/$organization/$repo/-/{{ operation | replace: "view", "blob" }}/$revision/{{ path }}#L{{ line }}"""
46+
def gitlabPrefix(org: String, repo: String) = s"https://gitlab.com/$org/$repo/-"
2647

2748

2849
private def parseLinkDefinition(s: String): Option[SourceLink] = ???
2950

3051
def parse(string: String, revision: Option[String]): Either[String, SourceLink] =
3152
def asTemplate(template: String) =
32-
try Right(SourceLink(None,Template.parse(template))) catch
53+
try Right(TemplateSourceLink(Template.parse(template))) catch
3354
case e: RuntimeException =>
3455
Left(s"Failed to parse template: ${e.getMessage}")
3556

3657
string match
3758
case KnownProvider(name, organization, repo) =>
38-
def withRevision(template: String => String) =
39-
revision.fold(Left(s"No revision provided"))(rev => Right(SourceLink(None, Template.parse(template(rev)))))
59+
def withRevision(template: String => SourceLink) =
60+
revision.fold(Left(s"No revision provided"))(r => Right(template(r)))
4061

4162
name match
4263
case "github" =>
43-
withRevision(githubTemplate(organization, repo))
64+
withRevision(rev => WebBasedSourceLink(githubPrefix(organization, repo), rev))
4465
case "gitlab" =>
45-
withRevision(gitlabTemplate(organization, repo))
66+
withRevision(rev => WebBasedSourceLink(gitlabPrefix(organization, repo), rev))
4667
case other =>
4768
Left(s"'$other' is not a known provider, please provide full source path template.")
4869

4970
case SubPath(prefix, config) =>
5071
parse(config, revision) match
5172
case l: Left[String, _] => l
52-
case Right(SourceLink(Some(prefix), _)) =>
73+
case Right(_:PrefixedSourceLink) =>
5374
Left(s"Source path $string has duplicated subpath setting (scm template can not contains '=')")
54-
case Right(SourceLink(None, template)) =>
55-
Right(SourceLink(Some(Paths.get(prefix)), template))
75+
case Right(nested) =>
76+
Right(PrefixedSourceLink(Paths.get(prefix), nested))
5677
case BrokenKnownProvider("gitlab" | "github") =>
5778
Left(s"Does not match known provider syntax: `<name>://organization/repository`")
5879
case scaladocSetting if ScalaDocPatten.findFirstIn(scaladocSetting).nonEmpty =>
@@ -70,15 +91,9 @@ type Operation = "view" | "edit"
7091
case class SourceLinks(links: Seq[SourceLink], projectRoot: Path):
7192
def pathTo(rawPath: Path, line: Option[Int] = None, operation: Operation = "view"): Option[String] =
7293
def resolveRelativePath(path: Path) =
73-
links.find(_.path.forall(p => path.startsWith(p))).map { link =>
74-
val config = java.util.HashMap[String, Object]()
75-
val pathString = path.toString.replace('\\', '/')
76-
config.put("path", pathString)
77-
line.foreach(l => config.put("line", l.toString))
78-
config.put("operation", operation)
79-
80-
link.urlTemplate.render(config)
81-
}
94+
links
95+
.find(_.path.forall(p => path.startsWith(p)))
96+
.map(_.render(path.toString.replace('\\', '/'), operation, line))
8297

8398
if rawPath.isAbsolute then
8499
if rawPath.startsWith(projectRoot) then resolveRelativePath(projectRoot.relativize(rawPath))

scala3doc/src/dotty/dokka/model/api/api.scala

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import collection.JavaConverters._
88
import org.jetbrains.dokka.model.doc._
99
import org.jetbrains.dokka.model.properties._
1010
import org.jetbrains.dokka.pages._
11+
import dotty.dokka.tasty.comments.Comment
1112

1213
enum Visibility(val name: String):
1314
case Unrestricted extends Visibility("")
@@ -156,6 +157,7 @@ extension[T] (member: Member):
156157
def origin: Origin = memberExt.fold(Origin.DefinedWithin)(_.origin)
157158
def annotations: List[Annotation] = memberExt.fold(Nil)(_.annotations)
158159
def sources: Option[TastyDocumentableSource] = memberExt.fold(None)(_.sources)
160+
def docs: Option[Comment] = memberExt.fold(None)(_.rawDoc)
159161
def name = member.getName
160162
def dri = member.getDri
161163

@@ -173,3 +175,5 @@ extension (module: DModule):
173175
def driMap: Map[DRI, Member] = ModuleExtension.getFrom(module).fold(Map.empty)(_.driMap)
174176

175177
case class TastyDocumentableSource(val path: String, val lineNumber: Int)
178+
179+
type DocPart = DocTag

scala3doc/src/dotty/dokka/model/api/internalExtensions.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import org.jetbrains.dokka.model.DModule
1919
import collection.JavaConverters._
2020
import org.jetbrains.dokka.model.doc.DocumentationNode
2121
import org.jetbrains.dokka.model.properties._
22+
import dotty.dokka.tasty.comments.Comment
2223

2324
case class MemberExtension(
2425
visibility: Visibility,
@@ -29,6 +30,7 @@ case class MemberExtension(
2930
sources: Option[TastyDocumentableSource] = None,
3031
origin: Origin = Origin.DefinedWithin,
3132
graph: HierarchyGraph = HierarchyGraph.empty,
33+
rawDoc: Option[Comment] = None
3234
) extends ExtraProperty[Documentable]:
3335
override def getKey = MemberExtension
3436

scala3doc/src/dotty/dokka/model/scalaModel.scala

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import org.jetbrains.dokka.model.properties._
88
import org.jetbrains.dokka.pages._
99
import dotty.dokka.model.api.Signature
1010
import dotty.dokka.model.api.HierarchyGraph
11+
import dotty.dokka.model.api.Member
1112

1213
enum TableStyle extends org.jetbrains.dokka.pages.Style:
1314
case Borderless
@@ -30,15 +31,15 @@ case class HtmlContentNode(
3031
override def getExtra = extra
3132
override def withNewExtras(p: PropertyContainer[ContentNode]) = copy(extra = p)
3233

33-
class ScalaTagWrapper(root: DocTag) extends TagWrapper(null):
34+
class ScalaTagWrapper(root: DocTag, val name: String) extends TagWrapper(null):
3435
override def getRoot = root
3536

3637
object ScalaTagWrapper {
3738

38-
case class See(root: DocTag) extends ScalaTagWrapper(root)
39-
case class Todo(root: DocTag) extends ScalaTagWrapper(root)
40-
case class Note(root: DocTag) extends ScalaTagWrapper(root)
41-
case class Example(root: DocTag) extends ScalaTagWrapper(root)
39+
case class See(root: DocTag) extends ScalaTagWrapper(root, "See")
40+
case class Todo(root: DocTag) extends ScalaTagWrapper(root, "Todo")
41+
case class Note(root: DocTag) extends ScalaTagWrapper(root, "Note")
42+
case class Example(root: DocTag) extends ScalaTagWrapper(root, "Example")
4243
case class NestedNamedTag(
4344
name: String,
4445
subname: String,
@@ -101,7 +102,8 @@ case class DocumentableElement(
101102
brief: Seq[ContentNode],
102103
originInfo: Signature,
103104
attributes: Map[String, String],
104-
params: ContentNodeParams
105+
params: ContentNodeParams,
106+
member: Member
105107
) extends ScalaContentNode(params):
106108
override def newInstance(params: ContentNodeParams) = copy(params = params)
107109

@@ -125,3 +127,7 @@ case class DocumentableList(
125127

126128
case class DocumentableFilter(params: ContentNodeParams) extends ScalaContentNode(params):
127129
override def newInstance(params: ContentNodeParams) = copy(params = params)
130+
131+
case class MemberInfo(member: Member, params: ContentNodeParams)
132+
extends ScalaContentNode(params):
133+
override def newInstance(params: ContentNodeParams) = copy(params = params)

scala3doc/src/dotty/dokka/tasty/BasicSupport.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ trait BasicSupport:
4141
case None =>
4242
Map.empty
4343

44+
def documentation2 = sym.docstring.map(preparseComment(_, sym.tree))
45+
4446
def source =
4547
val path = Some(sym.pos.get.sourceFile.jpath).filter(_ != null).map(_.toAbsolutePath).map(_.toString)
4648
path.map(TastyDocumentableSource(_, sym.pos.get.startLine))

scala3doc/src/dotty/dokka/tasty/ClassLikeSupport.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -442,10 +442,10 @@ trait ClassLikeSupport:
442442
null,
443443
JNil,
444444
emptyJMap,
445-
symbol.documentation.asJava,
445+
emptyJMap,
446446
null,
447447
placeholderModifier,
448448
ctx.sourceSet.toSet,
449449
/*isExpectActual =*/ false,
450-
PropertyContainer.Companion.empty().plus(member).plus(compositeExt)
450+
PropertyContainer.Companion.empty().plus(member.copy(rawDoc = symbol.documentation2)).plus(compositeExt)
451451
)

scala3doc/src/dotty/dokka/tasty/ScalaDocSupport.scala

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,50 @@ import org.jetbrains.dokka.model.{doc => dkkd}
77
import dotty.dokka.Scala3doc.CommentSyntax
88
import dotty.dokka.ScalaTagWrapper
99
import comments.{kt, dkk}
10+
import dotty.dokka.tasty.comments.Comment
1011

1112
trait ScaladocSupport { self: TastyParser =>
1213
import qctx.reflect._
1314

15+
def preparseComment(
16+
docstring: String,
17+
tree: Tree
18+
): Comment =
19+
val commentString: String =
20+
if tree.symbol.isClassDef || tree.symbol.owner.isClassDef then
21+
import dotty.tools.dotc
22+
given ctx: dotc.core.Contexts.Context = qctx.asInstanceOf[scala.quoted.runtime.impl.QuotesImpl].ctx
23+
24+
val sym = tree.symbol.asInstanceOf[dotc.core.Symbols.Symbol]
25+
26+
comments.CommentExpander.cookComment(sym)(using ctx)
27+
.get.expanded.get
28+
else
29+
docstring
30+
31+
val preparsed =
32+
comments.Preparser.preparse(comments.Cleaner.clean(commentString))
33+
34+
val commentSyntax =
35+
preparsed.syntax.headOption match {
36+
case Some(commentSetting) =>
37+
CommentSyntax.parse(commentSetting).getOrElse {
38+
val msg = s"not a valid comment syntax: $commentSetting, defaulting to Markdown syntax."
39+
// we should update pos with span from documentation
40+
report.warning(msg, tree.pos)
41+
CommentSyntax.default
42+
}
43+
case None => ctx.args.defaultSyntax
44+
}
45+
46+
val parser = commentSyntax match {
47+
case CommentSyntax.Wiki =>
48+
comments.WikiCommentParser(comments.Repr(qctx)(tree.symbol))
49+
case CommentSyntax.Markdown =>
50+
comments.MarkdownCommentParser(comments.Repr(qctx)(tree.symbol))
51+
}
52+
parser.parse(preparsed)
53+
1454
def parseComment(
1555
docstring: String,
1656
tree: Tree

0 commit comments

Comments
 (0)