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

japgolly.microlibs.utils.AsciiTable.scala Maven / Gradle / Ivy

The newest version!
package japgolly.microlibs.utils

import japgolly.microlibs.stdlib_ext.StdlibExt._
import scala.annotation.tailrec

/**
 * Taken from
 * https://github.com/dsl-platform/101-dsl-examples/blob/master/001-periodic-table-of-elements/scala/src/main/scala/com/dslplatform/examples/AsciiTable.scala
 */
object AsciiTable {
  // Characters that make up the table.
  private val CrossBorder  = '+'
  private val RowBorder    = '-'
  private val ColumnBorder = '|'
  private val HeaderBorder = '-'
  private val NL           = System.getProperty("line.separator")

  case class Cell(row: Int, col: Int)


  /** An entry (a row) is a list of strings (representing columns). A table is
   *  a list of rows.
   */
  def apply(table: Seq[Seq[String]],
            centre: Cell => Boolean = _ => false,
            separateDataRows: Boolean = false): String = {

    val rowCount = table.size
    val maxColLengths = table.transpose.map(_.map(s => if (s eq null) 4 else s.removeAnsiEscapeCodes.length).max)
    val sb = new StringBuilder

    @tailrec
    def doMake(rowNum: Int): Unit =
      if (rowNum == rowCount)
        addSeparator(true)
      else {
        if (rowNum <= 1)
          addSeparator(true)
        else if (separateDataRows)
          addSeparator(false)
        addRow(rowNum)
        doMake(rowNum + 1)
      }

    def addSeparator(isHeader: Boolean): Unit = {
      val border = if (isHeader) HeaderBorder else RowBorder
      sb.append(CrossBorder)
      maxColLengths foreach { length =>
        sb.append(border.toString * (length + 2))
        sb.append(CrossBorder)
      }
      sb.append(NL)
      ()
    }

    def addRow(rowNo: Int): Unit = {
      val row = table(rowNo)
      sb.append(ColumnBorder)
      for (column <- maxColLengths.indices) {
        val c = Cell(rowNo, column)
        var cell = row(column)
        if (cell eq null)
          cell = "null"
        val ws = maxColLengths(column) - cell.removeAnsiEscapeCodes.length + 2
        if (centre(c)) {
          sb.append(" " * (ws/2))
          sb.append(cell)
          sb.append(" " * (ws/2 + ws%2))
        } else {
          sb.append(' ')
          sb.append(cell)
          sb.append(" " * (ws - 1))
        }
        sb.append(ColumnBorder)
      }
      sb.append(NL)
      ()
    }

    doMake(0)
    sb.dropRight(NL.length).toString()
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy