From 236f39995401ae628bd1f5416626429ab2279b88 Mon Sep 17 00:00:00 2001 From: Florian3k Date: Fri, 3 May 2024 12:30:47 +0200 Subject: [PATCH] fix scaladoc crash on windows - illegal path characters --- .../tools/scaladoc/renderers/SiteRenderer.scala | 10 ++++++++-- .../tools/scaladoc/site/StaticSiteContext.scala | 14 ++++++++------ .../src/dotty/tools/scaladoc/util/escape.scala | 17 +++++++++++++++++ 3 files changed, 33 insertions(+), 8 deletions(-) diff --git a/scaladoc/src/dotty/tools/scaladoc/renderers/SiteRenderer.scala b/scaladoc/src/dotty/tools/scaladoc/renderers/SiteRenderer.scala index 7f64ce92ffc8..71b0a1b572ac 100644 --- a/scaladoc/src/dotty/tools/scaladoc/renderers/SiteRenderer.scala +++ b/scaladoc/src/dotty/tools/scaladoc/renderers/SiteRenderer.scala @@ -13,6 +13,7 @@ import java.nio.file.Path import java.nio.file.Files import java.io.File import scala.util.chaining._ +import dotty.tools.scaladoc.util.Escape.escapeFilename case class ResolvedTemplate(template: LoadedTemplate, ctx: StaticSiteContext): val resolved = template.resolveToHtml(ctx) @@ -55,11 +56,16 @@ trait SiteRenderer(using DocContext) extends Locations: val staticSiteRootPath = content.ctx.root.toPath.toAbsolutePath def asValidURL: Option[String] = Try(URI(str).toURL).toOption.map(_ => str) def asAsset: Option[String] = Option.when( - Files.exists(staticSiteRootPath.resolve("_assets").resolve(str.stripPrefix("/"))) + Try( + Files.exists(staticSiteRootPath.resolve("_assets").resolve(str.stripPrefix("/"))) + ).getOrElse(false) )( resolveLink(pageDri, str.stripPrefix("/")) ) - def asStaticSite: Option[String] = tryAsDriPlain(str).orElse(tryAsDri(str)) + def asStaticSite: Option[String] = + tryAsDriPlain(str) + .orElse(tryAsDri(str)) + .orElse(tryAsDriPlain(escapeFilename(str))) /* Link resolving checks performs multiple strategies with following priority: 1. We check if the link is a valid URL e.g. http://dotty.epfl.ch diff --git a/scaladoc/src/dotty/tools/scaladoc/site/StaticSiteContext.scala b/scaladoc/src/dotty/tools/scaladoc/site/StaticSiteContext.scala index 7a90a462cba0..a610e41f12f0 100644 --- a/scaladoc/src/dotty/tools/scaladoc/site/StaticSiteContext.scala +++ b/scaladoc/src/dotty/tools/scaladoc/site/StaticSiteContext.scala @@ -7,9 +7,8 @@ import java.nio.file.FileVisitOption import java.nio.file.Path import java.nio.file.Paths -import scala.util.Try import scala.jdk.CollectionConverters._ -import scala.annotation.static +import scala.util.control.NonFatal class StaticSiteContext( val root: File, @@ -75,10 +74,13 @@ class StaticSiteContext( val templateSourceLocation = staticSiteRoot.reverseSiteMappings.get(templateDestLocation) // Check if link is relative or absolute - if link.startsWith("/") - then Seq(root.toPath.resolve(link.drop(1))) - else Seq(templateDestLocation.getParent.resolve(link).normalize) ++ - templateSourceLocation.map(_.getParent.resolve(link).normalize) + try + if link.startsWith("/") + then Seq(root.toPath.resolve(link.drop(1))) + else Seq(templateDestLocation.getParent.resolve(link).normalize) ++ + templateSourceLocation.map(_.getParent.resolve(link).normalize) + catch + case NonFatal(_) => Seq.empty // Try to strip site extension and create all possible file paths val fileNames = if siteExtensions.exists(link.endsWith(_)) diff --git a/scaladoc/src/dotty/tools/scaladoc/util/escape.scala b/scaladoc/src/dotty/tools/scaladoc/util/escape.scala index 686d384337c1..5d4bf02e8b38 100644 --- a/scaladoc/src/dotty/tools/scaladoc/util/escape.scala +++ b/scaladoc/src/dotty/tools/scaladoc/util/escape.scala @@ -5,7 +5,24 @@ object Escape: .replace("#","%23") def escapeFilename(filename: String) = + // from compiler/src/dotty/tools/dotc/util/NameTransformer.scala val escaped = filename + .replace("~", "$tilde") + .replace("=", "$eq") + .replace("<", "$less") + .replace(">", "$greater") + .replace("!", "$bang") + .replace("#", "$hash") + .replace("%", "$percent") + .replace("^", "$up") + .replace("&", "$amp") + .replace("|", "$bar") + .replace("*", "$times") .replace("/", "$div") + .replace("+", "$plus") + .replace("-", "$minus") + .replace(":", "$colon") .replace("\\", "$bslash") + .replace("?", "$qmark") + .replace("@", "$at") if escaped != filename then escaped + "$" else escaped