diff options
Diffstat (limited to 'doc-tool/src/dotty/tools/dottydoc/staticsite/Site.scala')
-rw-r--r-- | doc-tool/src/dotty/tools/dottydoc/staticsite/Site.scala | 116 |
1 files changed, 63 insertions, 53 deletions
diff --git a/doc-tool/src/dotty/tools/dottydoc/staticsite/Site.scala b/doc-tool/src/dotty/tools/dottydoc/staticsite/Site.scala index 05ec113e0..6f1681a0a 100644 --- a/doc-tool/src/dotty/tools/dottydoc/staticsite/Site.scala +++ b/doc-tool/src/dotty/tools/dottydoc/staticsite/Site.scala @@ -4,10 +4,9 @@ package staticsite import java.nio.file.{ Files, FileSystems } import java.nio.file.StandardCopyOption.REPLACE_EXISTING -import java.io.{ File => JFile, OutputStreamWriter, BufferedWriter } +import java.io.{ File => JFile, OutputStreamWriter, BufferedWriter, ByteArrayInputStream } import java.util.{ List => JList, Map => JMap, Arrays } import java.nio.file.Path -import java.io.ByteArrayInputStream import java.nio.charset.StandardCharsets import com.vladsch.flexmark.parser.ParserEmulationProfile @@ -21,13 +20,13 @@ import com.vladsch.flexmark.ext.anchorlink.AnchorLinkExtension import com.vladsch.flexmark.ext.front.matter.YamlFrontMatterExtension import com.vladsch.flexmark.util.options.{ DataHolder, MutableDataSet } -import dotc.config.Printers.dottydoc import dotc.core.Contexts.Context import dotc.util.SourceFile import model.Package import scala.io.{ Codec, Source } import io.{ AbstractFile, VirtualFile, File } import scala.collection.mutable.ArrayBuffer +import util.syntax._ case class Site(val root: JFile, val projectTitle: String, val documentation: Map[String, Package]) extends ResourceFinder { /** Documentation serialized to java maps */ @@ -42,8 +41,8 @@ case class Site(val root: JFile, val projectTitle: String, val documentation: Ma * @note files that are *not* considered static are files ending in a compilable * extension. */ - def staticAssets: Array[JFile] = { - if (_staticAssets eq null) initFiles() + def staticAssets(implicit ctx: Context): Array[JFile] = { + if (_staticAssets eq null) initFiles _staticAssets } @@ -53,8 +52,8 @@ case class Site(val root: JFile, val projectTitle: String, val documentation: Ma * * @note files that are considered compilable end in `.md` or `.html` */ - def compilableFiles: Array[JFile] = { - if (_compilableFiles eq null) initFiles() + def compilableFiles(implicit ctx: Context): Array[JFile] = { + if (_compilableFiles eq null) initFiles _compilableFiles } @@ -66,12 +65,12 @@ case class Site(val root: JFile, val projectTitle: String, val documentation: Ma * * where `ext` is either markdown or html. */ - def blogposts: Array[JFile] = { - if (_blogposts eq null) initFiles() + def blogposts(implicit ctx: Context): Array[JFile] = { + if (_blogposts eq null) initFiles _blogposts } - /** TODO */ + /** Sidebar created from `sidebar.yml` file in site root */ val sidebar: Sidebar = root .listFiles @@ -81,24 +80,32 @@ case class Site(val root: JFile, val projectTitle: String, val documentation: Ma .flatMap(Sidebar.apply) .getOrElse(Sidebar.empty) - protected lazy val blogInfo: Array[BlogPost] = - blogposts - .map { file => - val BlogPost.extract(year, month, day, name, ext) = file.getName - val sourceFile = toSourceFile(file) - val params = defaultParams(file, 2).withUrl(s"/blog/$year/$month/$day/$name.html").toMap - val page = - if (ext == "md") - new MarkdownPage(file.getPath, sourceFile, params, includes, documentation) - else new HtmlPage(file.getPath, sourceFile, params, includes) - BlogPost(file, page) + private[this] var _blogInfo: Array[BlogPost] = _ + protected def blogInfo(implicit ctx: Context): Array[BlogPost] = { + if (_blogInfo eq null) { + _blogInfo = + blogposts + .flatMap { file => + val BlogPost.extract(year, month, day, name, ext) = file.getName + val sourceFile = toSourceFile(file) + val params = defaultParams(file, 2).withUrl(s"/blog/$year/$month/$day/$name.html").toMap + val page = + if (ext == "md") + new MarkdownPage(file.getPath, sourceFile, params, includes, documentation) + else new HtmlPage(file.getPath, sourceFile, params, includes) + BlogPost(file, page) + } + .sortBy(_.date) + .reverse } - .sortBy(_.date) - .reverse + + _blogInfo + } // FileSystem getter private[this] val fs = FileSystems.getDefault + /** Create virtual file from string `sourceCode` */ private def stringToSourceFile(name: String, path: String, sourceCode: String): SourceFile = { val virtualFile = new VirtualFile(name, path) val writer = new BufferedWriter(new OutputStreamWriter(virtualFile.output, "UTF-8")) @@ -108,10 +115,9 @@ case class Site(val root: JFile, val projectTitle: String, val documentation: Ma new SourceFile(virtualFile, Codec.UTF8) } - def copyStaticFiles(outDir: JFile = new JFile(root.getAbsolutePath + "/_site")): this.type = { - if (!outDir.isDirectory) outDir.mkdirs() - if (!outDir.isDirectory) /*dottydoc.*/println(s"couldn't create output folder: $outDir") - else { + /** Copy static files to `outDir` */ + def copyStaticFiles(outDir: JFile = new JFile(root.getAbsolutePath + "/_site"))(implicit ctx: Context): this.type = + createOutput (outDir) { // Copy user-defined static assets staticAssets.foreach { asset => val target = mkdirs(fs.getPath(outDir.getAbsolutePath, stripRoot(asset))) @@ -133,9 +139,8 @@ case class Site(val root: JFile, val projectTitle: String, val documentation: Ma Files.copy(source, target, REPLACE_EXISTING) } } - this - } + /** Generate default params included in each page */ private def defaultParams(pageLocation: JFile, additionalDepth: Int = 0): DefaultParams = { import scala.collection.JavaConverters._ val pathFromRoot = stripRoot(pageLocation) @@ -148,9 +153,10 @@ case class Site(val root: JFile, val projectTitle: String, val documentation: Ma DefaultParams(docs, documentation, PageInfo(pathFromRoot), SiteInfo(baseUrl, projectTitle, Array()), sidebar) } - private def createOutput(outDir: JFile)(op: => Unit): this.type = { + /* Creates output directories if allowed */ + private def createOutput(outDir: JFile)(op: => Unit)(implicit ctx: Context): this.type = { if (!outDir.isDirectory) outDir.mkdirs() - if (!outDir.isDirectory) /*dottydoc.*/println(s"couldn't create output folder: $outDir") + if (!outDir.isDirectory) ctx.docbase.error(s"couldn't create output folder: $outDir") else op this } @@ -159,7 +165,7 @@ case class Site(val root: JFile, val projectTitle: String, val documentation: Ma def generateApiDocs(outDir: JFile = new JFile(root.getAbsolutePath + "/_site"))(implicit ctx: Context): this.type = createOutput(outDir) { def genDoc(e: model.Entity): Unit = { - /*dottydoc.*/println(s"Generating doc page for: ${e.path.mkString(".")}") + ctx.docbase.echo(s"Generating doc page for: ${e.path.mkString(".")}") // Suffix is index.html for packages and therefore the additional depth // is increased by 1 val (suffix, offset) = @@ -170,10 +176,10 @@ case class Site(val root: JFile, val projectTitle: String, val documentation: Ma val params = defaultParams(target.toFile, -1).withPosts(blogInfo).withEntity(e).toMap val page = new HtmlPage("_layouts/api-page.html", layouts("api-page").content, params, includes) - val rendered = render(page) - val source = new ByteArrayInputStream(rendered.getBytes(StandardCharsets.UTF_8)) - - Files.copy(source, target, REPLACE_EXISTING) + render(page).foreach { rendered => + val source = new ByteArrayInputStream(rendered.getBytes(StandardCharsets.UTF_8)) + Files.copy(source, target, REPLACE_EXISTING) + } // Generate docs for nested objects/classes: e.children.foreach(genDoc) @@ -196,14 +202,16 @@ case class Site(val root: JFile, val projectTitle: String, val documentation: Ma if (asset.getName.endsWith(".md")) new MarkdownPage(pathFromRoot, sourceFile, params, includes, documentation) else new HtmlPage(pathFromRoot, sourceFile, params, includes) - val renderedPage = render(page) - val source = new ByteArrayInputStream(renderedPage.getBytes(StandardCharsets.UTF_8)) - val target = pathFromRoot.splitAt(pathFromRoot.lastIndexOf('.'))._1 + ".html" - val htmlTarget = mkdirs(fs.getPath(outDir.getAbsolutePath, target)) - Files.copy(source, htmlTarget, REPLACE_EXISTING) + render(page).foreach { renderedPage => + val source = new ByteArrayInputStream(renderedPage.getBytes(StandardCharsets.UTF_8)) + val target = pathFromRoot.splitAt(pathFromRoot.lastIndexOf('.'))._1 + ".html" + val htmlTarget = mkdirs(fs.getPath(outDir.getAbsolutePath, target)) + Files.copy(source, htmlTarget, REPLACE_EXISTING) + } } } + /** Generate blog from files in `blog/_posts` and output in `outDir` */ def generateBlog(outDir: JFile = new JFile(root.getAbsolutePath + "/_site"))(implicit ctx: Context): this.type = createOutput(outDir) { blogposts.foreach { file => @@ -221,17 +229,19 @@ case class Site(val root: JFile, val projectTitle: String, val documentation: Ma else new HtmlPage(target.toString, sourceFile, params, includes) - - val source = new ByteArrayInputStream(render(page).getBytes(StandardCharsets.UTF_8)) - Files.copy(source, target, REPLACE_EXISTING) + render(page).map { rendered => + val source = new ByteArrayInputStream(rendered.getBytes(StandardCharsets.UTF_8)) + Files.copy(source, target, REPLACE_EXISTING) + } } } - private def mkdirs(path: Path): path.type = { + /** Create directories and issue an error if could not */ + private def mkdirs(path: Path)(implicit ctx: Context): path.type = { val parent = path.getParent.toFile if (!parent.isDirectory && !parent.mkdirs()) - dottydoc.println(s"couldn't create directory: $parent") + ctx.docbase.error(s"couldn't create directory: $parent") path } @@ -254,14 +264,14 @@ case class Site(val root: JFile, val projectTitle: String, val documentation: Ma private[this] var _compilableFiles: Array[JFile] = _ private[this] var _blogposts: Array[JFile] = _ - private[this] def initFiles() = { + private[this] def initFiles(implicit ctx: Context) = { // Split files between compilable and static assets def splitFiles(f: JFile, assets: ArrayBuffer[JFile], comp: ArrayBuffer[JFile]): Unit = { val name = f.getName if (f.isDirectory) { val name = f.getName if (!name.startsWith("_") && name != "api") f.listFiles.foreach(splitFiles(_, assets, comp)) - if (f.getName == "api") dottydoc.println { + if (f.getName == "api") ctx.docbase.warn { "the specified `/api` directory will not be used since it is needed for the api documentation" } } @@ -369,15 +379,15 @@ case class Site(val root: JFile, val projectTitle: String, val documentation: Ma /** Render a page to html, the resulting string is the result of the complete * expansion of the template with all its layouts and includes. */ - def render(page: Page, params: Map[String, AnyRef] = Map.empty)(implicit ctx: Context): String = + def render(page: Page, params: Map[String, AnyRef] = Map.empty)(implicit ctx: Context): Option[String] = page.yaml.get("layout").flatMap(xs => layouts.get(xs.toString)) match { - case None => - page.html - case Some(layout) => + case Some(layout) if page.html.isDefined => import scala.collection.JavaConverters._ - val newParams = page.params ++ params ++ Map("page" -> page.yaml) ++ Map("content" -> page.html) + val newParams = page.params ++ params ++ Map("page" -> page.yaml) ++ Map("content" -> page.html.get) val expandedTemplate = new HtmlPage(layout.path, layout.content, newParams, includes) render(expandedTemplate, params) + case _ => + page.html } } |