@@ -14,13 +14,6 @@ trait SourceLink:
1414 val path : Option [Path ] = None
1515 def render (memberName : String , path : Path , operation : String , line : Option [Int ]): String
1616
17- case class PrefixedSourceLink (val myPath : Path , nested : SourceLink ) extends SourceLink :
18- val myPrefix = pathToString(myPath)
19- override val path = Some (myPath)
20- override def render (memberName : String , path : Path , operation : String , line : Option [Int ]): String =
21- nested.render(memberName, myPath.relativize(path), operation, line)
22-
23-
2417case class TemplateSourceLink (val urlTemplate : String ) extends SourceLink :
2518 override val path : Option [Path ] = None
2619 override def render (memberName : String , path : Path , operation : String , line : Option [Int ]): String =
@@ -48,8 +41,7 @@ case class WebBasedSourceLink(prefix: String, revision: String, subPath: String)
4841 val linePart = line.fold(" " )(l => s " #L $l" )
4942 s " $prefix/ $action/ $revision$subPath/ ${pathToString(path)}$linePart"
5043
51- object SourceLink :
52- val SubPath = " ([^=]+)=(.+)" .r
44+ class SourceLinkParser (revision : Option [String ]) extends ArgParser [SourceLink ]:
5345 val KnownProvider = raw " (\w+):\/\/([^\/#]+)\/([^\/#]+)(\/[^\/#]+)?(#.+)? " .r
5446 val BrokenKnownProvider = raw " (\w+):\/\/.+ " .r
5547 val ScalaDocPatten = raw " €\{(TPL_NAME|TPL_OWNER|FILE_PATH|FILE_EXT|FILE_LINE|FILE_PATH_EXT)\} " .r
@@ -68,9 +60,8 @@ object SourceLink:
6860
6961 private def parseLinkDefinition (s : String ): Option [SourceLink ] = ???
7062
71- def parse (string : String , revision : Option [String ]): Either [String , SourceLink ] =
72-
73- string match
63+ def parse (string : String ): Either [String , SourceLink ] =
64+ val res = string match
7465 case KnownProvider (name, organization, repo, rawRevision, rawSubPath) =>
7566 val subPath = Option (rawSubPath).fold(" " )(" /" + _.drop(1 ))
7667 val pathRev = Option (rawRevision).map(_.drop(1 )).orElse(revision)
@@ -87,14 +78,6 @@ object SourceLink:
8778 WebBasedSourceLink (gitlabPrefix(organization, repo), rev, subPath))
8879 case other =>
8980 Left (s " ' $other' is not a known provider, please provide full source path template. " )
90-
91- case SubPath (prefix, config) =>
92- parse(config, revision) match
93- case l : Left [String , _] => l
94- case Right (_:PrefixedSourceLink ) =>
95- Left (s " Source path $string has duplicated subpath setting (scm template can not contains '=') " )
96- case Right (nested) =>
97- Right (PrefixedSourceLink (Paths .get(prefix), nested))
9881 case BrokenKnownProvider (" gitlab" | " github" ) =>
9982 Left (s " Does not match known provider syntax: `<name>://organization/repository` " )
10083 case scaladocSetting if ScalaDocPatten .findFirstIn(scaladocSetting).nonEmpty =>
@@ -104,28 +87,23 @@ object SourceLink:
10487 else Right (TemplateSourceLink (supported.foldLeft(string)((template, pattern) =>
10588 template.replace(pattern, SupportedScalaDocPatternReplacements (pattern)))))
10689 case other =>
107- Right (TemplateSourceLink (" " ))
90+ Left (" Does not match any implemented source link syntax" )
91+ res match {
92+ case Left (error) => Left (s " ' $string': $error" )
93+ case other => other
94+ }
10895
10996
11097type Operation = " view" | " edit"
11198
112- case class SourceLinks (links : Seq [SourceLink ], projectRoot : Path ):
99+ class SourceLinks (val sourceLinks : PathBased [SourceLink ]):
113100 def pathTo (rawPath : Path , memberName : String = " " , line : Option [Int ] = None , operation : Operation = " view" ): Option [String ] =
114- def resolveRelativePath (path : Path ) =
115- links
116- .find(_.path.forall(p => path.startsWith(p)))
117- .map(_.render(memberName, path, operation, line))
118-
119- if rawPath.isAbsolute then
120- if rawPath.startsWith(projectRoot) then resolveRelativePath(projectRoot.relativize(rawPath))
121- else None
122- else resolveRelativePath(rawPath)
101+ sourceLinks.get(rawPath).map(res => res.elem.render(memberName, res.path, operation, line))
123102
124103 def pathTo (member : Member ): Option [String ] =
125104 member.sources.flatMap(s => pathTo(s.path, member.name, Option (s.lineNumber).map(_ + 1 )))
126105
127106object SourceLinks :
128-
129107 val usage =
130108 """ Source links provide a mapping between file in documentation and code repository.
131109 |
@@ -150,32 +128,16 @@ object SourceLinks:
150128 |Template can defined only by subset of sources defined by path prefix represented by `<sub-path>`.
151129 |In such case paths used in templates will be relativized against `<sub-path>`""" .stripMargin
152130
153- def load (
154- configs : Seq [String ],
155- revision : Option [String ],
156- projectRoot : Path )(
157- using Context ): SourceLinks =
158- val mappings = configs.map(str => str -> SourceLink .parse(str, revision))
159-
160- val errors = mappings.collect {
161- case (template, Left (message)) =>
162- s " ' $template': $message"
163- }.mkString(" \n " )
164-
165- if errors.nonEmpty then report.warning(
166- s """ Following templates has invalid format:
167- | $errors
168- |
169- | $usage
170- | """ .stripMargin
171- )
172-
173- SourceLinks (mappings.collect {case (_, Right (link)) => link}, projectRoot)
174-
175- def load (using ctx : DocContext ): SourceLinks =
176- load(
177- ctx.args.sourceLinks,
178- ctx.args.revision,
179- // TODO (https://github.com/lampepfl/scaladoc/issues/240): configure source root
180- Paths .get(" " ).toAbsolutePath
181- )
131+ def load (config : Seq [String ], revision : Option [String ], projectRoot : Path = Paths .get(" " ).toAbsolutePath)(using CompilerContext ): SourceLinks =
132+ PathBased .parse(config, projectRoot)(using SourceLinkParser (revision)) match {
133+ case PathBased .ParsingResult (errors, sourceLinks) =>
134+ if errors.nonEmpty then report.warning(
135+ s """ Following templates has invalid format:
136+ | $errors
137+ |
138+ | ${SourceLinks .usage}
139+ | """ .stripMargin
140+ )
141+ SourceLinks (sourceLinks)
142+ }
143+
0 commit comments