From 5bd1d9280df62b9fd75e0c7fa0308472bbd75e49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filip=20Zyba=C5=82a?= Date: Tue, 15 Dec 2020 14:25:44 +0100 Subject: [PATCH 1/2] Remove liquid templates from source links generation. Add support for some scaladoc euro-sign parameters --- project/Build.scala | 2 +- scala3doc/src/dotty/dokka/SourceLinks.scala | 65 ++++++++++--------- .../test/dotty/dokka/SourceLinksTests.scala | 20 +++--- 3 files changed, 44 insertions(+), 43 deletions(-) diff --git a/project/Build.scala b/project/Build.scala index f6699568ce51..61ab0a73715d 100644 --- a/project/Build.scala +++ b/project/Build.scala @@ -1532,7 +1532,7 @@ object Build { val projectRoot = (ThisBuild/baseDirectory).value.toPath val stdLibRoot = projectRoot.relativize(managedSources.toPath.normalize()) val scalaSourceLink = - s"$stdLibRoot=github://scala/scala/v${stdlibVersion(Bootstrapped)}#src/library" + s"$stdLibRoot=https://github.com/scala/scala/blob/v${stdlibVersion(Bootstrapped)}/src/library€{FILE_PATH}#L€{FILE_LINE}" val sourcesAndRevision = s"-source-links $scalaSourceLink,github://lampepfl/dotty -revision $ref -project-version $projectVersion" val cmd = s""" -d $outDir -project "$name" $sourcesAndRevision $params $targets""" run.in(Compile).toTask(cmd) diff --git a/scala3doc/src/dotty/dokka/SourceLinks.scala b/scala3doc/src/dotty/dokka/SourceLinks.scala index 470b22deddf4..6fbb5be551f0 100644 --- a/scala3doc/src/dotty/dokka/SourceLinks.scala +++ b/scala3doc/src/dotty/dokka/SourceLinks.scala @@ -2,36 +2,45 @@ package dotty.dokka import java.nio.file.Path import java.nio.file.Paths -import liqp.Template import dotty.dokka.model.api._ import dotty.tools.dotc.core.Contexts.Context +import scala.util.matching.Regex -def pathToString(p: Path) = p.toString.replace('\\', '/') +def pathToString(p: Path) = "/" + p.toString.replace('\\', '/') trait SourceLink: val path: Option[Path] = None - def render(path: Path, operation: String, line: Option[Int]): String + def render(memberName: String, path: Path, operation: String, line: Option[Int]): String case class PrefixedSourceLink(val myPath: Path, nested: SourceLink) extends SourceLink: val myPrefix = pathToString(myPath) override val path = Some(myPath) - override def render(path: Path, operation: String, line: Option[Int]): String = - nested.render(myPath.relativize(path), operation, line) + override def render(memberName: String, path: Path, operation: String, line: Option[Int]): String = + nested.render(memberName, myPath.relativize(path), operation, line) -case class TemplateSourceLink(val urlTemplate: Template) extends SourceLink: +case class TemplateSourceLink(val urlTemplate: String) extends SourceLink: override val path: Option[Path] = None - override def render(path: Path, operation: String, line: Option[Int]): String = - val config = java.util.HashMap[String, Object]() - config.put("path", pathToString(path)) - line.foreach(l => config.put("line", l.toString)) - config.put("operation", operation) + override def render(memberName: String, path: Path, operation: String, line: Option[Int]): String = + val mapping = Map( + "\\{\\{ path \\}\\}".r -> pathToString(path), + "\\{\\{ line \\}\\}".r -> line.fold("")(_.toString), + "\\{\\{ ext \\}\\}".r -> Some( + pathToString(path)).filter(_.lastIndexOf(".") == -1).fold("")(p => p.substring(p.lastIndexOf(".")) + ), + "\\{\\{ path_no_ext \\}\\}".r -> Some( + pathToString(path)).filter(_.lastIndexOf(".") == -1).fold(pathToString(path))(p => p.substring(0, p.lastIndexOf(".")) + ), + "\\{\\{ name \\}\\}".r -> memberName + ) + mapping.foldLeft(urlTemplate) { + case (sourceLink, (regex, value)) => regex.replaceAllIn(sourceLink, Regex.quoteReplacement(value)) + } - urlTemplate.render(config) case class WebBasedSourceLink(prefix: String, revision: String, subPath: String) extends SourceLink: override val path: Option[Path] = None - override def render(path: Path, operation: String, line: Option[Int]): String = + override def render(memberName: String, path: Path, operation: String, line: Option[Int]): String = val action = if operation == "view" then "blob" else operation val linePart = line.fold("")(l => s"#L$l") s"$prefix/$action/$revision$subPath/$path$linePart" @@ -40,10 +49,13 @@ object SourceLink: val SubPath = "([^=]+)=(.+)".r val KnownProvider = raw"(\w+):\/\/([^\/#]+)\/([^\/#]+)(\/[^\/#]+)?(#.+)?".r val BrokenKnownProvider = raw"(\w+):\/\/.+".r - val ScalaDocPatten = raw"€\{(TPL_NAME|TPL_NAME|FILE_PATH|FILE_EXT|FILE_LINE|FILE_PATH_EXT)\}".r + val ScalaDocPatten = raw"€\{(TPL_NAME|TPL_OWNER|FILE_PATH|FILE_EXT|FILE_LINE|FILE_PATH_EXT)\}".r val SupportedScalaDocPatternReplacements = Map( "€{FILE_PATH_EXT}" -> "{{ path }}", - "€{FILE_LINE}" -> "{{ line }}" + "€{FILE_LINE}" -> "{{ line }}", + "€{TPL_NAME}" -> "{{ name }}", + "€{FILE_EXT}" -> "{{ ext }}", + "€{FILE_PATH}" -> "{{ path_no_ext }}" ) def githubPrefix(org: String, repo: String) = s"https://github.com/$org/$repo" @@ -54,10 +66,6 @@ object SourceLink: private def parseLinkDefinition(s: String): Option[SourceLink] = ??? def parse(string: String, revision: Option[String]): Either[String, SourceLink] = - def asTemplate(template: String) = - try Right(TemplateSourceLink(Template.parse(template))) catch - case e: RuntimeException => - Left(s"Failed to parse template: ${e.getMessage}") string match case KnownProvider(name, organization, repo, rawRevision, rawSubPath) => @@ -90,20 +98,20 @@ object SourceLink: val all = ScalaDocPatten.findAllIn(scaladocSetting) val (supported, unsupported) = all.partition(SupportedScalaDocPatternReplacements.contains) if unsupported.nonEmpty then Left(s"Unsupported patterns from scaladoc format are used: ${unsupported.mkString(" ")}") - else asTemplate(supported.foldLeft(string)((template, pattern) => - template.replace(pattern, SupportedScalaDocPatternReplacements(pattern)))) - - case template => asTemplate(template) + else Right(TemplateSourceLink(supported.foldLeft(string)((template, pattern) => + template.replace(pattern, SupportedScalaDocPatternReplacements(pattern))))) + case other => + Right(TemplateSourceLink("")) type Operation = "view" | "edit" case class SourceLinks(links: Seq[SourceLink], projectRoot: Path): - def pathTo(rawPath: Path, line: Option[Int] = None, operation: Operation = "view"): Option[String] = + def pathTo(rawPath: Path, memberName: String = "", line: Option[Int] = None, operation: Operation = "view"): Option[String] = def resolveRelativePath(path: Path) = links .find(_.path.forall(p => path.startsWith(p))) - .map(_.render(path, operation, line)) + .map(_.render(memberName, path, operation, line)) if rawPath.isAbsolute then if rawPath.startsWith(projectRoot) then resolveRelativePath(projectRoot.relativize(rawPath)) @@ -111,7 +119,7 @@ case class SourceLinks(links: Seq[SourceLink], projectRoot: Path): else resolveRelativePath(rawPath) def pathTo(member: Member): Option[String] = - member.sources.flatMap(s => pathTo(Paths.get(s.path), Option(s.lineNumber).map(_ + 1))) + member.sources.flatMap(s => pathTo(Paths.get(s.path), member.name, Option(s.lineNumber).map(_ + 1))) object SourceLinks: @@ -130,15 +138,10 @@ object SourceLinks: | will match https://gitlab.com/$organization/$repository/-/[blob|edit]/$revision[/$subpath]/$filePath[$lineNumber] | when revision is not provided then requires revision to be specified as argument for scala3doc | - - | -