<commit_before>/*
 * Copyright 2012-2020 the original author or authors.
 *
 * 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 laika.rst

import cats.data.NonEmptyChain
import laika.ast._
import laika.bundle.{BlockParser, BlockParserBuilder}
import laika.collection.Stack
import laika.collection.TransitionalCollectionOps.Zip3Iterator
import laika.parse.builders._
import laika.parse.implicits._
import laika.parse._
import laika.parse.markup.RecursiveParsers

import scala.collection.mutable
import scala.collection.mutable.ListBuffer

/** Provides parsers for the two table types supported by reStructuredText.
 * 
 * @author <NAME>
 */
object TableParsers {

  private abstract class TableElement
  
  private abstract class TableDecoration extends TableElement
  private case object Intersection extends TableDecoration {
    override def toString = "+"
  }
  private case object RowSeparator extends TableDecoration
  private case object TableBoundary extends TableDecoration
  private case class CellSeparator (decoration: String) extends TableDecoration {
    override def toString = decoration
  }
  private case class CellElement (text: LineSource) extends TableElement {
    override def toString = text.input
  }
      
  class CellBuilder (recParser: RecursiveParsers) {
    
    private val seps = new ListBuffer[TableElement]
    private val previousLines = new ListBuffer[LineSource]
    private var currentLine: Option[LineSource] = None
    private def allLines: mutable.Buffer[LineSource] = previousLines ++ currentLine.toBuffer
    
    var rowSpan = 1
    var colSpan = 1
    
    var removed: Boolean = false
    
    def nextLine (sep: TableElement, line: LineSource, nextRow: Boolean): Unit = { 
      seps += sep
      currentLine.foreach(previousLines += _)
      currentLine = Some(line)
      if (nextRow) rowSpan += 1
    }
    def currentLine (sep: TableElement, line: LineSource): Unit = {
      currentLine.foreach { current =>
        currentLine = Some(LineSource(current.input + sep.toString + line.input, current.parent))
      }
    }
    def merge (rightBuilder: CellBuilder): Unit = if (currentLine.isDefined) {
      val newLines = Zip3Iterator(allLines, rightBuilder.seps, rightBuilder.allLines).map {
        case (left, sep, right) => 
          LineSource(left.input + sep.toString + right.input, left.parent)
      }.toSeq
      previousLines.clear()
      previousLines ++= newLines.tail
      currentLine = newLines.headOption
      colSpan += 1
    }
    
    def trimmedCellContent: Option[BlockSource] = {
      NonEmptyChain.fromSeq(allLines).map { nonEmptyLines =>
        val minIndent = nonEmptyLines.map { line =>
          if (line.input.trim.isEmpty) Int.MaxValue
          else line.input.prefixLength(_ == ' ')
        }.iterator.min
        val trimmedLines = nonEmptyLines.map { line =>
          if (line.input.trim.isEmpty) LineSource("", line.parent) else {
            val padding = " " * (line.input.prefixLength(_ == ' ') - minIndent)
            LineSource(padding + line.input.trim, line.parent.consume(minIndent))
          }
        }
        BlockSource(trimmedLines)
      }
    }
    
    def parsedCellContent: Seq[Block] = trimmedCellContent.fold[Seq[Block]](Nil)(src => recParser.recursiveBlocks.parse(src).getOrElse(Nil))<commit_msg>fix compilation error on 2.13.x<commit_after>/*
 * Copyright 2012-2020 the original author or authors.
 *
 * 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 laika.rst

import cats.data.NonEmptyChain
import laika.ast._
import laika.bundle.{BlockParser, BlockParserBuilder}
import laika.collection.Stack
import laika.collection.TransitionalCollectionOps.Zip3Iterator
import laika.parse.builders._
import laika.parse.implicits._
import laika.parse._
import laika.parse.markup.RecursiveParsers

import scala.collection.mutable
import scala.collection.mutable.ListBuffer

/** Provides parsers for the two table types supported by reStructuredText.
 * 
 * @author <NAME>
 */
object TableParsers {

  private abstract class TableElement
  
  private abstract class TableDecoration extends TableElement
  private case object Intersection extends TableDecoration {
    override def toString = "+"
  }
  private case object RowSeparator extends TableDecoration
  private case object TableBoundary extends TableDecoration
  private case class CellSeparator (decoration: String) extends TableDecoration {
    override def toString = decoration
  }
  private case class CellElement (text: LineSource) extends TableElement {
    override def toString = text.input
  }
      
  class CellBuilder (recParser: RecursiveParsers) {
    
    private val seps = new ListBuffer[TableElement]
    private val previousLines = new ListBuffer[LineSource]
    private var currentLine: Option[LineSource] = None
    private def allLines: mutable.Buffer[LineSource] = previousLines ++ currentLine.toBuffer
    
    var rowSpan = 1
    var colSpan = 1
    
    var removed: Boolean = false
    
    def nextLine (sep: TableElement, line: LineSource, nextRow: Boolean): Unit = { 
      seps += sep
      currentLine.foreach(previousLines += _)
      currentLine = Some(line)
      if (nextRow) rowSpan += 1
    }
    def currentLine (sep: TableElement, line: LineSource): Unit = {
      currentLine.foreach { current =>
        currentLine = Some(LineSource(current.input + sep.toString + line.input, current.parent))
      }
    }
    def merge (rightBuilder: CellBuilder): Unit = if (currentLine.isDefined) {
      val newLines = Zip3Iterator(allLines, rightBuilder.seps, rightBuilder.allLines).map {
        case (left, sep, right) => 
          LineSource(left.input + sep.toString + right.input, left.parent)
      }.toSeq
      previousLines.clear()
      previousLines ++= newLines.tail
      currentLine = newLines.headOption
      colSpan += 1
    }
    
    def trimmedCellContent: Option[BlockSource] = {
      NonEmptyChain.fromSeq(allLines.toSeq).map { nonEmptyLines =>
        val minIndent = nonEmptyLines.map { line =>
          if (line.input.trim.isEmpty) Int.MaxValue
          else line.input.prefixLength(_ == ' ')
        }.iterator.min
        val trimmedLines = nonEmptyLines.map { line =>
          if (line.input.trim.isEmpty) LineSource("", line.parent) else {
            val padding = " " * (line.input.prefixLength(_ == ' ') - minIndent)
            LineSource(padding + line.input.trim, line.parent.consume(minIndent))
          }
        }
        BlockSource(trimmedLines)
      }
    }
    
    def parsedCellContent: Seq[Block] = trimmedCellContent.fold[Seq[Block]](Nil)(src => recParser.recursiveBlocks.parse(src).getOrElse(Nil))
{'fraction_non_alphanumeric': 0.087890625, 'fraction_numerical': 0.005078125, 'mean_word_length': 3.329763246899662, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 17, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2271595', 'n_tokens_mistral': 2142, 'n_tokens_neox': 2095, 'n_words': 627}