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

ammonite.repl.Highlighter.scala Maven / Gradle / Ivy

The newest version!
package ammonite.repl


import ammonite.interp.Parsers

import fastparse.all._

import scalaparse.Scala._
import scalaparse.syntax.Identifiers._
object Highlighter {

  object BackTicked{
    private[this] val regex = "`([^`]+)`".r
    def unapplySeq(s: Any): Option[List[String]] = {
      regex.unapplySeq(s.toString)
    }
  }


  def flattenIndices(boundedIndices: Seq[(Int, fansi.Attrs)],
                     buffer: Vector[Char]) = {

    boundedIndices
      .sliding(2)
      .map{case Seq((s, c1), (e, c2)) =>
        assert(e >= s, s"s: $s e: $e")
        c1(fansi.Str(buffer.slice(s, e), errorMode = fansi.ErrorMode.Sanitize))
      }.reduce(_ ++ _).render.toVector
  }

  def defaultHighlight(buffer: Vector[Char],
                       comment: fansi.Attrs,
                       `type`: fansi.Attrs,
                       literal: fansi.Attrs,
                       keyword: fansi.Attrs,
                       reset: fansi.Attrs) = {
    defaultHighlight0(Parsers.Splitter, buffer, comment, `type`, literal, keyword, reset)
  }

  def defaultHighlight0(parser: P[_],
                        buffer: Vector[Char],
                        comment: fansi.Attrs,
                        `type`: fansi.Attrs,
                        literal: fansi.Attrs,
                        keyword: fansi.Attrs,
                        reset: fansi.Attrs) = {
    val boundedIndices =
      defaultHighlightIndices0(parser, buffer, comment, `type`, literal, keyword, reset)

    flattenIndices(boundedIndices, buffer)
  }
  def defaultHighlightIndices(buffer: Vector[Char],
                              comment: fansi.Attrs,
                              `type`: fansi.Attrs,
                              literal: fansi.Attrs,
                              keyword: fansi.Attrs,
                              reset: fansi.Attrs) = Highlighter.defaultHighlightIndices0(
    Parsers.Splitter, buffer, comment, `type`, literal, keyword, reset
  )
  def defaultHighlightIndices0(parser: P[_],
                               buffer: Vector[Char],
                               comment: fansi.Attrs,
                               `type`: fansi.Attrs,
                               literal: fansi.Attrs,
                               keyword: fansi.Attrs,
                               reset: fansi.Attrs) = Highlighter.highlightIndices(
    parser,
    buffer,
    {
      case Literals.Expr.Interp | Literals.Pat.Interp => reset
      case Literals.Comment => comment
      case ExprLiteral => literal
      case TypeId => `type`
      case BackTicked(body)
        if alphaKeywords.contains(body) => keyword
    },
    reset
  )
  def highlightIndices[T](parser: Parser[_],
                          buffer: Vector[Char],
                          ruleColors: PartialFunction[Parser[_], T],
                          endColor: T): Seq[(Int, T)] = {
    val indices = {
      var indices = collection.mutable.Buffer((0, endColor))
      var done = false
      val input = buffer.mkString
      parser.parse(input, instrument = (rule, idx, res) => {
        for(color <- ruleColors.lift(rule)){
          val closeColor = indices.last._2
          val startIndex = indices.length
          indices += ((idx, color))

          res() match {
            case s: Parsed.Success[_] =>
              val prev = indices(startIndex - 1)._1

              if (idx < prev && s.index <= prev){
                indices.remove(startIndex, indices.length - startIndex)

              }
              while (idx < indices.last._1 && s.index <= indices.last._1) {
                indices.remove(indices.length - 1)
              }
              indices += ((s.index, closeColor))
              if (s.index == buffer.length) done = true
            case f: Parsed.Failure
              if f.index == buffer.length
              && (WL ~ End).parse(input, idx).isInstanceOf[Parsed.Failure] =>
              // EOF, stop all further parsing
              done = true
            case _ =>  // hard failure, or parsed nothing. Discard all progress
              indices.remove(startIndex, indices.length - startIndex)
          }
        }
      })
      indices
    }
    // Make sure there's an index right at the start and right at the end! This
    // resets the colors at the snippet's end so they don't bleed into later output
    indices ++ Seq((999999999, endColor))
  }
  def highlight(parser: Parser[_],
                buffer: Vector[Char],
                ruleColors: PartialFunction[Parser[_], fansi.Attrs],
                endColor: fansi.Attrs) = {
    val boundedIndices = highlightIndices(parser, buffer, ruleColors, endColor)
    flattenIndices(boundedIndices, buffer)
  }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy