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

kantan.repl.md.cli.scala Maven / Gradle / Ivy

There is a newer version: 1.2.0
Show newest version
/*
 * Copyright 2021 Nicolas Rinaudo
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package kantan.repl.md.cli

import kantan.repl.md.{cache, markdown, process}
import kantan.repl.md.markdown.{Block, Modifier}
import kantan.repl.md.process.ProcessedBlock
import kantan.repl.Repl
import java.io.File
import scala.io.Source
import scala.util.CommandLineParser as CLP
import scala.util.{Failure, Success, Try}

private def toMarkdown(blocks: List[ProcessedBlock]): List[Block] = {

  def visible(block: ProcessedBlock) = block match
    case ProcessedBlock.Repl(_, Modifier.Invisible | Modifier.Reset, _) => false
    case _                                                              => true

  def scala(content: String) = s"```scala\n$content\n```"

  blocks.filter(visible).map {
    case ProcessedBlock.Other(content)                  => Block.Other(content)
    case ProcessedBlock.Repl(input, Modifier.Silent, _) => Block.Other(scala(input))
    case ProcessedBlock.Repl(input, modifier, output)   => Block.Other(scala(input ++ "\n" ++ output))
  }
}

given CLP.FromString[File] with
  def fromString(s: String) = new File(s)

val rootOptions = List(
  "-classpath",
  "", // Avoid the default "."
  "-usejavacp",
  "-color:never"
)

@main def main(source: File, destination: File, cacheFile: File, scalacOptions: String*) = {

  def readSource =
    Try(markdown.load(Source.fromFile(source)))

  def applyCache(markdown: List[Block]) = for
    cached <- cache.read(cacheFile)
    result <- cache.use(markdown, cached)
  yield Success(result)

  def runRepl(markdown: List[Block]) = {
    val repl = new Repl(rootOptions ++ scalacOptions)
    process.evaluate(repl, source.toString, markdown).map { processed =>
      val cached = cache.extract(processed)

      // We're ignoring errors here because the cache is just an optimisation, not a critical part of what we're
      // doing.
      cache.write(cached, cacheFile).getOrElse(println("Failed to write cache."))
      processed
    }
  }

  def printToDestination(result: List[ProcessedBlock]) =
    Try(markdown.print(toMarkdown(result), destination))

  val outcome = for
    markdown <- readSource
    cached = applyCache(markdown)
    result <- cached.getOrElse(runRepl(markdown))
    _      <- printToDestination(result)
  yield ()

  // Basic error handling.
  outcome match {
    case Failure(error) =>
      System.err.println(error.getMessage)
      System.exit(1)

    case _ =>
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy