Skip to content

Commit 5ee1c7e

Browse files
committed
Properly link to source files from stdlib
Expand semantic of prefixed source link as well as add option to provide revision and subpach to web-based ones.
1 parent ad9eb17 commit 5ee1c7e

File tree

3 files changed

+73
-24
lines changed

3 files changed

+73
-24
lines changed

project/Build.scala

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1527,7 +1527,13 @@ object Build {
15271527
def generateDocumentation(targets: String, name: String, outDir: String, ref: String, params: String = "") = Def.taskDyn {
15281528
val projectVersion = version.value
15291529
IO.createDirectory(file(outDir))
1530-
val sourcesAndRevision = s"-source-links github://lampepfl/dotty -revision $ref -project-version $projectVersion"
1530+
val managedSources =
1531+
(`stdlib-bootstrapped`/Compile/sourceManaged).value / "scala-library-src"
1532+
val projectRoot = (ThisBuild/baseDirectory).value.toPath
1533+
val stdLibRoot = projectRoot.relativize(managedSources.toPath.normalize())
1534+
val scalaSourceLink =
1535+
s"$stdLibRoot=github://scala/scala/v${stdlibVersion(Bootstrapped)}#src/library"
1536+
val sourcesAndRevision = s"-source-links $scalaSourceLink,github://lampepfl/dotty -revision $ref -project-version $projectVersion"
15311537
val cmd = s""" -d $outDir -project "$name" $sourcesAndRevision $params $targets"""
15321538
run.in(Compile).toTask(cmd)
15331539
}

scala3doc/src/dotty/dokka/SourceLinks.scala

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

9+
def pathToString(p: Path) = p.toString.replace('\\', '/')
10+
911
trait SourceLink:
1012
val path: Option[Path] = None
11-
def render(path: String, operation: String, line: Option[Int]): String
13+
def render(path: Path, operation: String, line: Option[Int]): String
1214

1315
case class PrefixedSourceLink(val myPath: Path, nested: SourceLink) extends SourceLink:
14-
export nested.render
16+
val myPrefix = pathToString(myPath)
1517
override val path = Some(myPath)
18+
override def render(path: Path, operation: String, line: Option[Int]): String =
19+
nested.render(myPath.relativize(path), operation, line)
20+
1621

1722
case class TemplateSourceLink(val urlTemplate: Template) extends SourceLink:
1823
override val path: Option[Path] = None
19-
override def render(path: String, operation: String, line: Option[Int]): String =
24+
override def render(path: Path, operation: String, line: Option[Int]): String =
2025
val config = java.util.HashMap[String, Object]()
21-
config.put("path", path)
26+
config.put("path", pathToString(path))
2227
line.foreach(l => config.put("line", l.toString))
2328
config.put("operation", operation)
2429

2530
urlTemplate.render(config)
2631

27-
case class WebBasedSourceLink(prefix: String, revision: String) extends SourceLink:
32+
case class WebBasedSourceLink(prefix: String, revision: String, subPath: String) extends SourceLink:
2833
override val path: Option[Path] = None
29-
override def render(path: String, operation: String, line: Option[Int]): String =
34+
override def render(path: Path, operation: String, line: Option[Int]): String =
3035
val action = if operation == "view" then "blob" else operation
3136
val linePart = line.fold("")(l => s"#L$l")
32-
s"$prefix/$action/$revision/$path$linePart"
37+
s"$prefix/$action/$revision$subPath/$path$linePart"
3338

3439
object SourceLink:
3540
val SubPath = "([^=]+)=(.+)".r
36-
val KnownProvider = raw"(\w+):\/\/([^\/]+)\/([^\/]+)".r
41+
val KnownProvider = raw"(\w+):\/\/([^\/#]+)\/([^\/#]+)(\/[^\/#]+)?(#.+)?".r
3742
val BrokenKnownProvider = raw"(\w+):\/\/.+".r
3843
val ScalaDocPatten = raw"€\{(TPL_NAME|TPL_NAME|FILE_PATH|FILE_EXT|FILE_LINE|FILE_PATH_EXT)\}".r
3944
val SupportedScalaDocPatternReplacements = Map(
@@ -55,15 +60,20 @@ object SourceLink:
5560
Left(s"Failed to parse template: ${e.getMessage}")
5661

5762
string match
58-
case KnownProvider(name, organization, repo) =>
63+
case KnownProvider(name, organization, repo, rawRevision, rawSubPath) =>
64+
val subPath = Option(rawSubPath).fold("")("/" + _.drop(1))
65+
val pathRev = Option(rawRevision).map(_.drop(1)).orElse(revision)
66+
5967
def withRevision(template: String => SourceLink) =
60-
revision.fold(Left(s"No revision provided"))(r => Right(template(r)))
68+
pathRev.fold(Left(s"No revision provided"))(r => Right(template(r)))
6169

6270
name match
6371
case "github" =>
64-
withRevision(rev => WebBasedSourceLink(githubPrefix(organization, repo), rev))
72+
withRevision(rev =>
73+
WebBasedSourceLink(githubPrefix(organization, repo), rev, subPath))
6574
case "gitlab" =>
66-
withRevision(rev => WebBasedSourceLink(gitlabPrefix(organization, repo), rev))
75+
withRevision(rev =>
76+
WebBasedSourceLink(gitlabPrefix(organization, repo), rev, subPath))
6777
case other =>
6878
Left(s"'$other' is not a known provider, please provide full source path template.")
6979

@@ -93,7 +103,7 @@ case class SourceLinks(links: Seq[SourceLink], projectRoot: Path):
93103
def resolveRelativePath(path: Path) =
94104
links
95105
.find(_.path.forall(p => path.startsWith(p)))
96-
.map(_.render(path.toString.replace('\\', '/'), operation, line))
106+
.map(_.render(path, operation, line))
97107

98108
if rawPath.isAbsolute then
99109
if rawPath.startsWith(projectRoot) then resolveRelativePath(projectRoot.relativize(rawPath))
@@ -113,8 +123,12 @@ object SourceLinks:
113123
|<source-link>
114124
|
115125
|where <source-link> is one of following:
116-
| - `github://<organization>/<repository>` (requires revision to be specified as argument for scala3doc)
117-
| - `gitlab://<organization>/<repository>` (requires revision to be specified as argument for scala3doc)
126+
| - `github://<organization>/<repository>[/revision][#subpath]`
127+
| will match https://github.com/$organization/$repository/[blob|edit]/$revision[/$subpath]/$filePath[$lineNumber]
128+
| when revision is not provided then requires revision to be specified as argument for scala3doc
129+
| - `gitlab://<organization>/<repository>`
130+
| will match https://gitlab.com/$organization/$repository/-/[blob|edit]/$revision[/$subpath]/$filePath[$lineNumber]
131+
| when revision is not provided then requires revision to be specified as argument for scala3doc
118132
| - <scaladoc-template>
119133
| - <template>
120134
|
@@ -127,7 +141,8 @@ object SourceLinks:
127141
| - `line`: optional parameter that specify line number within a file
128142
|
129143
|
130-
|Template can defined only by subset of sources defined by path prefix represented by `<sub-path>`""".stripMargin
144+
|Template can defined only by subset of sources defined by path prefix represented by `<sub-path>`.
145+
|In such case paths used in templates will be relativized against `<sub-path>`""".stripMargin
131146

132147
def load(
133148
configs: Seq[String],

scala3doc/test/dotty/dokka/SourceLinksTests.scala

Lines changed: 35 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ class SourceLinkTest:
4848
val res = SourceLink.parse(template, None)
4949
assertTrue(s"Expected failure containing missing revision: $res", res.left.exists(_.contains("revision")))
5050

51-
Seq(s"$provider://ala/ma/", s"$provider://ala", s"$provider://ala/ma/develop").foreach { template =>
51+
Seq(s"$provider://ala/ma/", s"$provider://ala", s"$provider://ala/ma/develop/on/master").foreach { template =>
5252
val res = SourceLink.parse(template, Some("develop"))
5353
assertTrue(s"Expected failure syntax info: $res", res.left.exists(_.contains("syntax")))
5454
}
@@ -89,6 +89,34 @@ class SourceLinksTest:
8989
("project/Build.scala", 54, edit) -> "https://github.com/lampepfl/dotty/edit/develop/project/Build.scala#L54",
9090
)
9191

92+
testLink(Seq("github://lampepfl/dotty/dev"), Some("develop"))(
93+
"project/Build.scala" -> "https://github.com/lampepfl/dotty/blob/dev/project/Build.scala",
94+
("project/Build.scala", 54) -> "https://github.com/lampepfl/dotty/blob/dev/project/Build.scala#L54",
95+
("project/Build.scala", edit) -> "https://github.com/lampepfl/dotty/edit/dev/project/Build.scala",
96+
("project/Build.scala", 54, edit) -> "https://github.com/lampepfl/dotty/edit/dev/project/Build.scala#L54",
97+
)
98+
99+
testLink(Seq("github://lampepfl/dotty/dev#src/lib"), None)(
100+
"project/Build.scala" -> "https://github.com/lampepfl/dotty/blob/dev/src/lib/project/Build.scala",
101+
("project/Build.scala", 54) -> "https://github.com/lampepfl/dotty/blob/dev/src/lib/project/Build.scala#L54",
102+
("project/Build.scala", edit) -> "https://github.com/lampepfl/dotty/edit/dev/src/lib/project/Build.scala",
103+
("project/Build.scala", 54, edit) -> "https://github.com/lampepfl/dotty/edit/dev/src/lib/project/Build.scala#L54",
104+
)
105+
106+
testLink(Seq("github://lampepfl/dotty/dev#src/lib"), Some("develop"))(
107+
"project/Build.scala" -> "https://github.com/lampepfl/dotty/blob/dev/src/lib/project/Build.scala",
108+
("project/Build.scala", 54) -> "https://github.com/lampepfl/dotty/blob/dev/src/lib/project/Build.scala#L54",
109+
("project/Build.scala", edit) -> "https://github.com/lampepfl/dotty/edit/dev/src/lib/project/Build.scala",
110+
("project/Build.scala", 54, edit) -> "https://github.com/lampepfl/dotty/edit/dev/src/lib/project/Build.scala#L54",
111+
)
112+
113+
testLink(Seq("github://lampepfl/dotty#src/lib"), Some("develop"))(
114+
"project/Build.scala" -> "https://github.com/lampepfl/dotty/blob/develop/src/lib/project/Build.scala",
115+
("project/Build.scala", 54) -> "https://github.com/lampepfl/dotty/blob/develop/src/lib/project/Build.scala#L54",
116+
("project/Build.scala", edit) -> "https://github.com/lampepfl/dotty/edit/develop/src/lib/project/Build.scala",
117+
("project/Build.scala", 54, edit) -> "https://github.com/lampepfl/dotty/edit/develop/src/lib/project/Build.scala#L54",
118+
)
119+
92120
testLink(Seq("gitlab://lampepfl/dotty"), Some("develop"))(
93121
"project/Build.scala" -> "https://gitlab.com/lampepfl/dotty/-/blob/develop/project/Build.scala",
94122
("project/Build.scala", 54) -> "https://gitlab.com/lampepfl/dotty/-/blob/develop/project/Build.scala#L54",
@@ -113,9 +141,9 @@ class SourceLinksTest:
113141
@Test
114142
def testBasicPrefixedPaths =
115143
testLink(Seq("src=gitlab://lampepfl/dotty"), Some("develop"))(
116-
"src/lib/core.scala" -> "https://gitlab.com/lampepfl/dotty/-/blob/develop/src/lib/core.scala",
117-
("src/lib/core.scala", 33, edit) -> "https://gitlab.com/lampepfl/dotty/-/edit/develop/src/lib/core.scala#L33",
118-
("src/lib/core.scala", 33, edit) -> "https://gitlab.com/lampepfl/dotty/-/edit/develop/src/lib/core.scala#L33",
144+
"src/lib/core.scala" -> "https://gitlab.com/lampepfl/dotty/-/blob/develop/lib/core.scala",
145+
("src/lib/core.scala", 33, edit) -> "https://gitlab.com/lampepfl/dotty/-/edit/develop/lib/core.scala#L33",
146+
("src/lib/core.scala", 33, edit) -> "https://gitlab.com/lampepfl/dotty/-/edit/develop/lib/core.scala#L33",
119147
"build.sbt" -> None
120148
)
121149

@@ -128,7 +156,7 @@ class SourceLinksTest:
128156
"github://lampepfl/dotty"
129157
), Some("develop"))(
130158
("project/Build.scala", 54, edit) -> "https://github.com/lampepfl/dotty/edit/develop/project/Build.scala#L54",
131-
("src/lib/core.scala", 33, edit) -> "https://gitlab.com/lampepfl/dotty/-/edit/develop/src/lib/core.scala#L33",
132-
("src/generated.scala", 33, edit) -> "https://gitlab.com/lampepfl/dotty/-/edit/develop/src/generated.scala#L33",
133-
("src/generated/template.scala", 1, edit) -> "/edit/src/generated/template.scala#1"
159+
("src/lib/core.scala", 33, edit) -> "https://gitlab.com/lampepfl/dotty/-/edit/develop/lib/core.scala#L33",
160+
("src/generated.scala", 33, edit) -> "https://gitlab.com/lampepfl/dotty/-/edit/develop/generated.scala#L33",
161+
("src/generated/template.scala", 1, edit) -> "/edit/template.scala#1"
134162
)

0 commit comments

Comments
 (0)