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

mdoc.internal.worksheets.WorksheetProvider.scala Maven / Gradle / Ivy

There is a newer version: 2.2.24
Show newest version
package mdoc.internal.worksheets

import scala.meta._
import mdoc.internal.cli.Context
import scala.collection.JavaConverters._
import mdoc.internal.markdown.SectionInput
import mdoc.internal.markdown.Modifier
import mdoc.internal.markdown.Instrumenter
import mdoc.internal.markdown.MarkdownCompiler
import mdoc.document.Statement
import mdoc.document.RangePosition
import mdoc.internal.cli.Settings
import pprint.TPrintColors
import pprint.PPrinter.BlackWhite
import mdoc.internal.io.StoreReporter
import mdoc.{interfaces => i}
import mdoc.internal.markdown.MdocDialect

class WorksheetProvider(settings: Settings) {

  private val reporter = new StoreReporter()

  // The smallest column width that worksheet values will use for rendering
  // worksheet decorations.
  private val minimumMargin = 20

  def evaluateWorksheet(
      input: Input.VirtualFile,
      ctx: Context
  ): EvaluatedWorksheet = {
    val source = MdocDialect.scala(input).parse[Source].getOrElse(Source(Nil))
    val sectionInput = SectionInput(
      input,
      source,
      Modifier.Default()
    )
    val sectionInputs = List(sectionInput)
    val instrumented = Instrumenter.instrument(sectionInputs)
    val rendered = MarkdownCompiler.buildDocument(
      ctx.compiler,
      reporter,
      sectionInputs,
      instrumented,
      input.path
    )

    val decorations = for {
      section <- rendered.sections.iterator
      statement <- section.section.statements
    } yield renderDecoration(statement)

    EvaluatedWorksheet(
      reporter.diagnostics.map(d => d: i.Diagnostic).toSeq.asJava,
      decorations
        .filterNot(_.summary.isEmpty)
        .map(d => d: i.EvaluatedWorksheetStatement)
        .toList
        .asJava
    )
  }

  private def renderDecoration(statement: Statement): EvaluatedWorksheetStatement = {
    val pos = statement.position
    val range = new RangePosition(
      pos.startLine,
      pos.startColumn,
      pos.endLine,
      pos.endColumn
    )
    val margin = math.max(
      minimumMargin,
      settings.screenWidth - statement.position.endColumn
    )
    val isEmptyValue = isUnitType(statement) || statement.binders.isEmpty
    val renderSummaryResult =
      renderSummary(statement, margin, isEmptyValue)
    val details = renderDetails(statement, isEmptyValue)
    EvaluatedWorksheetStatement(
      range,
      renderSummaryResult.summary,
      details,
      renderSummaryResult.isSummaryComplete
    )
  }

  private def renderDetails(
      statement: Statement,
      isEmptyValue: Boolean
  ): String = {
    val out = new StringBuilder()
    if (!isEmptyValue) {
      statement.binders.iterator.foreach { binder =>
        out
          .append(if (out.nonEmpty) "\n" else "")
          .append(binder.name)
          .append(": ")
          .append(binder.tpe.render(TPrintColors.BlackWhite))
          .append(" = ")
        BlackWhite
          .tokenize(binder.value, width = settings.screenWidth, height = settings.screenHeight)
          .foreach(text => out.appendAll(text.getChars))
      }
    }
    statement.out.linesIterator.foreach { line =>
      out
        .append(if (out.nonEmpty) "\n" else "")
        .append("// ")
        .append(line)
    }
    out.toString()
  }

  private def renderSummary(
      statement: Statement,
      margin: Int,
      isEmptyValue: Boolean
  ): RenderSummaryResult = {
    val out = new StringBuilder()
    val isOverMargin =
      if (isEmptyValue) {
        if (!statement.out.isEmpty()) {
          val lines = statement.out.linesIterator
          out.append(lines.next())
          lines.hasNext || out.length > margin
        } else
          false
      } else {
        val isSingle = statement.binders.lengthCompare(1) == 0
        statement.binders.iterator.foldLeft(false) {
          case (true, _) => true
          case (false, binder) =>
            if (!isSingle) {
              out
                .append(if (out.isEmpty) "" else ", ")
                .append(binder.name)
                .append("=")
            }
            val chunk = BlackWhite
              .tokenize(binder.value, width = margin - out.length)
              .map(_.getChars)
              .filterNot(_.iterator.forall(_.isWhitespace))
              .flatMap(_.iterator)
              .filter {
                case '\n' => false
                case _ => true
              }
            out.appendAll(chunk)
            out.length > margin
        }
      }
    RenderSummaryResult(out.result().take(margin), isSummaryComplete = !isOverMargin)
  }

  private def isUnitType(statement: Statement): Boolean = {
    statement.binders match {
      case head :: Nil => () == head.value
      case _ => false
    }

  }
}

case class RenderSummaryResult(summary: String, isSummaryComplete: Boolean)




© 2015 - 2024 Weber Informatics LLC | Privacy Policy