@@ -2,48 +2,61 @@ package dotty.dokka
22
33import java .nio .file .Path
44import java .nio .file .Paths
5- import liqp .Template
65import dotty .dokka .model .api ._
76import dotty .tools .dotc .core .Contexts .Context
7+ import scala .util .matching .Regex
88
99def pathToString (p : Path ) = p.toString.replace('\\ ' , '/' )
1010
1111trait SourceLink :
1212 val path : Option [Path ] = None
13- def render (path : Path , operation : String , line : Option [Int ]): String
13+ def render (memberName : String , path : Path , operation : String , line : Option [Int ]): String
1414
1515case class PrefixedSourceLink (val myPath : Path , nested : SourceLink ) extends SourceLink :
1616 val myPrefix = pathToString(myPath)
1717 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)
18+ override def render (memberName : String , path : Path , operation : String , line : Option [Int ]): String =
19+ nested.render(memberName, myPath.relativize(path), operation, line)
2020
2121
22- case class TemplateSourceLink (val urlTemplate : Template ) extends SourceLink :
22+ case class TemplateSourceLink (val urlTemplate : String ) extends SourceLink :
2323 override val path : Option [Path ] = None
24- override def render (path : Path , operation : String , line : Option [Int ]): String =
25- val config = java.util.HashMap [String , Object ]()
26- config.put(" path" , pathToString(path))
27- line.foreach(l => config.put(" line" , l.toString))
28- config.put(" operation" , operation)
24+ override def render (memberName : String , path : Path , operation : String , line : Option [Int ]): String =
25+ val pathString = " /" + pathToString(path)
26+ val mapping = Map (
27+ " \\ {\\ { path \\ }\\ }" .r -> pathString,
28+ " \\ {\\ { line \\ }\\ }" .r -> line.fold(" " )(_.toString),
29+ " \\ {\\ { ext \\ }\\ }" .r -> Some (
30+ pathString).filter(_.lastIndexOf(" ." ) == - 1 ).fold(" " )(p => p.substring(p.lastIndexOf(" ." ))
31+ ),
32+ " \\ {\\ { path_no_ext \\ }\\ }" .r -> Some (
33+ pathString).filter(_.lastIndexOf(" ." ) == - 1 ).fold(pathString)(p => p.substring(0 , p.lastIndexOf(" ." ))
34+ ),
35+ " \\ {\\ { name \\ }\\ }" .r -> memberName
36+ )
37+ mapping.foldLeft(urlTemplate) {
38+ case (sourceLink, (regex, value)) => regex.replaceAllIn(sourceLink, Regex .quoteReplacement(value))
39+ }
2940
30- urlTemplate.render(config)
3141
3242case class WebBasedSourceLink (prefix : String , revision : String , subPath : String ) extends SourceLink :
3343 override val path : Option [Path ] = None
34- override def render (path : Path , operation : String , line : Option [Int ]): String =
44+ override def render (memberName : String , path : Path , operation : String , line : Option [Int ]): String =
3545 val action = if operation == " view" then " blob" else operation
3646 val linePart = line.fold(" " )(l => s " #L $l" )
37- s " $prefix/ $action/ $revision$subPath/ $path$linePart"
47+ s " $prefix/ $action/ $revision$subPath/ ${pathToString( path)} $linePart"
3848
3949object SourceLink :
4050 val SubPath = " ([^=]+)=(.+)" .r
4151 val KnownProvider = raw " (\w+):\/\/([^\/#]+)\/([^\/#]+)(\/[^\/#]+)?(#.+)? " .r
4252 val BrokenKnownProvider = raw " (\w+):\/\/.+ " .r
43- val ScalaDocPatten = raw " €\{(TPL_NAME|TPL_NAME |FILE_PATH|FILE_EXT|FILE_LINE|FILE_PATH_EXT)\} " .r
53+ val ScalaDocPatten = raw " €\{(TPL_NAME|TPL_OWNER |FILE_PATH|FILE_EXT|FILE_LINE|FILE_PATH_EXT)\} " .r
4454 val SupportedScalaDocPatternReplacements = Map (
4555 " €{FILE_PATH_EXT}" -> " {{ path }}" ,
46- " €{FILE_LINE}" -> " {{ line }}"
56+ " €{FILE_LINE}" -> " {{ line }}" ,
57+ " €{TPL_NAME}" -> " {{ name }}" ,
58+ " €{FILE_EXT}" -> " {{ ext }}" ,
59+ " €{FILE_PATH}" -> " {{ path_no_ext }}"
4760 )
4861
4962 def githubPrefix (org : String , repo : String ) = s " https://github.com/ $org/ $repo"
@@ -54,10 +67,6 @@ object SourceLink:
5467 private def parseLinkDefinition (s : String ): Option [SourceLink ] = ???
5568
5669 def parse (string : String , revision : Option [String ]): Either [String , SourceLink ] =
57- def asTemplate (template : String ) =
58- try Right (TemplateSourceLink (Template .parse(template))) catch
59- case e : RuntimeException =>
60- Left (s " Failed to parse template: ${e.getMessage}" )
6170
6271 string match
6372 case KnownProvider (name, organization, repo, rawRevision, rawSubPath) =>
@@ -90,28 +99,28 @@ object SourceLink:
9099 val all = ScalaDocPatten .findAllIn(scaladocSetting)
91100 val (supported, unsupported) = all.partition(SupportedScalaDocPatternReplacements .contains)
92101 if unsupported.nonEmpty then Left (s " Unsupported patterns from scaladoc format are used: ${unsupported.mkString(" " )}" )
93- else asTemplate (supported.foldLeft(string)((template, pattern) =>
94- template.replace(pattern, SupportedScalaDocPatternReplacements (pattern))))
95-
96- case template => asTemplate(template )
102+ else Right ( TemplateSourceLink (supported.foldLeft(string)((template, pattern) =>
103+ template.replace(pattern, SupportedScalaDocPatternReplacements (pattern)))))
104+ case other =>
105+ Right ( TemplateSourceLink ( " " ) )
97106
98107
99108type Operation = " view" | " edit"
100109
101110case class SourceLinks (links : Seq [SourceLink ], projectRoot : Path ):
102- def pathTo (rawPath : Path , line : Option [Int ] = None , operation : Operation = " view" ): Option [String ] =
111+ def pathTo (rawPath : Path , memberName : String = " " , line : Option [Int ] = None , operation : Operation = " view" ): Option [String ] =
103112 def resolveRelativePath (path : Path ) =
104113 links
105114 .find(_.path.forall(p => path.startsWith(p)))
106- .map(_.render(path, operation, line))
115+ .map(_.render(memberName, path, operation, line))
107116
108117 if rawPath.isAbsolute then
109118 if rawPath.startsWith(projectRoot) then resolveRelativePath(projectRoot.relativize(rawPath))
110119 else None
111120 else resolveRelativePath(rawPath)
112121
113122 def pathTo (member : Member ): Option [String ] =
114- member.sources.flatMap(s => pathTo(Paths .get(s.path), Option (s.lineNumber).map(_ + 1 )))
123+ member.sources.flatMap(s => pathTo(Paths .get(s.path), member.name, Option (s.lineNumber).map(_ + 1 )))
115124
116125object SourceLinks :
117126
@@ -130,15 +139,10 @@ object SourceLinks:
130139 | will match https://gitlab.com/$organization/$repository/-/[blob|edit]/$revision[/$subpath]/$filePath[$lineNumber]
131140 | when revision is not provided then requires revision to be specified as argument for scala3doc
132141 | - <scaladoc-template>
133- | - <template>
134142 |
135143 |<scaladoc-template> is a format for `doc-source-url` parameter scaladoc.
136144 |NOTE: We only supports `€{FILE_PATH_EXT}` and €{FILE_LINE} patterns
137145 |
138- |<template> is a liqid template string that can accepts follwoing arguments:
139- | - `operation`: either "view" or "edit"
140- | - `path`: relative path of file to provide link to
141- | - `line`: optional parameter that specify line number within a file
142146 |
143147 |
144148 |Template can defined only by subset of sources defined by path prefix represented by `<sub-path>`.
0 commit comments