All Downloads are FREE. Search and download functionalities are using the official Maven repository.

dotty.tools.dottydoc.model.comment.HtmlParsers.scala Maven / Gradle / Ivy

package dotty.tools
package dottydoc
package model
package comment

import dotc.core.Contexts.{Context, ctx}
import dotc.util.Spans._
import dotty.tools.dottydoc.util.syntax._
import util.MemberLookup

import com.vladsch.flexmark.util.ast.{ Node => MarkdownNode}
import com.vladsch.flexmark.html.HtmlRenderer
import com.vladsch.flexmark.parser.Parser
import com.vladsch.flexmark.util.sequence.CharSubSequence

object HtmlParsers {

  implicit class StringToMarkdown(val text: String) extends AnyVal {
    def toMarkdown(origin: Entity)(using Context): MarkdownNode = {
      import com.vladsch.flexmark.ast.Link
      import com.vladsch.flexmark.util.ast.{Visitor, VisitHandler, NodeVisitor }


      val inlineToHtml = InlineToHtml(origin)

      val node = Parser.builder(staticsite.Site.markdownOptions)
        .build.parse(text)

      def isOuter(url: String) =
        url.startsWith("http://") ||
        url.startsWith("https://") ||
        url.startsWith("ftp://") ||
        url.startsWith("ftps://")

      def isRelative(url: String) =
        url.startsWith("../") ||
        url.startsWith("./")

      val linkVisitor = new NodeVisitor(
        new VisitHandler(classOf[Link], new Visitor[Link] with MemberLookup {
          def queryToUrl(title: String, link: String) = makeEntityLink(origin, ctx.docbase.packages, Text(title), link).link match {
            case Tooltip(_) => "#"
            case LinkToExternal(_, url) => url
            case LinkToEntity(t: Entity) => t match {
              case e: Entity with Members => inlineToHtml.relativePath(t)
              case x => x.parent.fold("#") { xpar => inlineToHtml.relativePath(xpar) }
            }
          }

          override def visit(link: Link) = {
            val linkUrl = link.getUrl.toString
            if (!isOuter(linkUrl) && !isRelative(linkUrl))
              link.setUrl(CharSubSequence.of(queryToUrl(link.getTitle.toString, linkUrl)))
          }
        })
      )

      linkVisitor.visit(node)
      node
    }

    def toMarkdownString(origin: Entity)(using Context): String =
      toMarkdown(origin).show
  }

  implicit class MarkdownToHtml(val markdown: MarkdownNode) extends AnyVal {
    def show(using Context): String =
      HtmlRenderer.builder(staticsite.Site.markdownOptions).build().render(markdown)

    def shortenAndShow(using Context): String =
      (new MarkdownShortener).shorten(markdown).show
  }

  implicit class StringToWiki(val text: String) extends AnyVal {
    def toWiki(origin: Entity, packages: Map[String, Package], span: Span): Body =
      new WikiParser(origin, packages, text, span, origin.symbol).document()
  }

  implicit class BodyToHtml(val body: Body) extends AnyVal {
    def show(origin: Entity): String = {
      val inlineToHtml = InlineToHtml(origin)

      def bodyToHtml(body: Body): String =
        (body.blocks map blockToHtml).mkString

      def blockToHtml(block: Block): String = block match {
        case Title(in, 1)  => s"

${inlineToHtml(in)}

" case Title(in, 2) => s"

${inlineToHtml(in)}

" case Title(in, 3) => s"

${inlineToHtml(in)}

" case Title(in, _) => s"

${inlineToHtml(in)}

" case Paragraph(in) => s"

${inlineToHtml(in)}

" case Code(data) => s"""
$data
""" case UnorderedList(items) => s"
    ${listItemsToHtml(items)}
" case OrderedList(items, listStyle) => s"
    ${listItemsToHtml(items)}
" case DefinitionList(items) => s"
${items map { case (t, d) => s"
${inlineToHtml(t)}
${blockToHtml(d)}
" } }
" case HorizontalRule() => "
" } def listItemsToHtml(items: Seq[Block]) = items.foldLeft(""){ (list, item) => item match { case OrderedList(_, _) | UnorderedList(_) => // html requires sub ULs to be put into the last LI list + s"
  • ${blockToHtml(item)}
  • " case Paragraph(inl) => list + s"
  • ${inlineToHtml(inl)}
  • " // LIs are blocks, no need to use Ps case block => list + s"
  • ${blockToHtml(block)}
  • " } } bodyToHtml(body) } } case class InlineToHtml(origin: Entity) { def apply(inl: Inline) = toHtml(inl) def relativePath(target: Entity) = util.traversing.relativePath(origin, target) def toHtml(inl: Inline): String = inl match { case Chain(items) => (items map toHtml).mkString case Italic(in) => s"${toHtml(in)}" case Bold(in) => s"${toHtml(in)}" case Underline(in) => s"${toHtml(in)}" case Superscript(in) => s"${toHtml(in)}" case Subscript(in) => s"${toHtml(in) }" case Link(raw, title) => s"""${toHtml(title)}""" case Monospace(in) => s"${toHtml(in)}" case Text(text) => text case Summary(in) => toHtml(in) case HtmlTag(tag) => tag case EntityLink(target, link) => enityLinkToHtml(target, link) } def enityLinkToHtml(target: Inline, link: LinkTo) = link match { case Tooltip(_) => toHtml(target) case LinkToExternal(n, url) => s"""$n""" case LinkToEntity(t: Entity) => t match { // Entity is a package member case e: Entity with Members => s"""${toHtml(target)}""" // Entity is a Val / Def case x => x.parent.fold(toHtml(target)) { xpar => s"""${toHtml(target)}""" } } } } }




    © 2015 - 2024 Weber Informatics LLC | Privacy Policy