@@ -6,34 +6,39 @@ import liqp.Template
66import dotty .dokka .model .api ._
77import dotty .tools .dotc .core .Contexts .Context
88
9+ def pathToString (p : Path ) = p.toString.replace('\\ ' , '/' )
10+
911trait 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
1315case 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
1722case 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
3439object 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 ],
0 commit comments