diff --git a/README.md b/README.md index dee03fa..62b935d 100644 --- a/README.md +++ b/README.md @@ -2,29 +2,106 @@ # ASCII Table -This is a small library to display tables using ascii art. +This is a small library to render tables using ascii art. The column widths are calculated automatically by sampling the +first 50 rows (configurable) to fit the table in desired screen width. + +### Multi-line mode + +When used in multi-line mode, cells overflowing the column width are rendered using several lines, for example: ```scala AsciiTable() - .header("first column", "2") - .row("1", "second value") - .row("", "") + .width(40) // screen width to fit table in + .multiline(true) // render rows across multiple lines + .columnMinWidth(7) // column width will be 7 characters or more + .rowMaxHeight(3) // clip cells at 3 lines + .header("N", "column", "column with long values") + .row("1", "value 1", "Lorem ipsum dolor sit amet, consectetur") + .row("2", "value 2", "Lorem ipsum dolor sit amet, consectetur" * 3) + .row("3", "foo", "bar") .write() ``` -will render +produces: + +```text +<------------ 40 characters -----------> +╔═╤═══════╤════════════════════════════╗ +║N│column │column with long values ║ +╠═╪═══════╪════════════════════════════╣ +║1│value 1│Lorem ipsum dolor sit amet, ║ +║ │ │consectetur ║ +╟─┼───────┼────────────────────────────╢ ↑ +║2│value 2│Lorem ipsum dolor sit amet, ║ | +║ │ │consecteturLorem ipsum dolor║ 3 lines max +║ │ │ sit amet, consecteturLorem…║ | +╟─┼───────┼────────────────────────────╢ ↓ +║3│foo │bar ║ +╚═╧═══════╧════════════════════════════╝ + <- 7 -> +``` + +### One-line mode + +In one-line mode cells are clipped at column width: + +```scala +AsciiTable() + .width(40) // screen width to fit table in + .multiline(false) // one line per row + .columnMinWidth(7) // column width is be 7 characters or more + .header("N", "column", "column with long values") + .row("1", "value 1", "Lorem ipsum dolor sit amet, consectetur") + .row("2", "value 2", "Lorem ipsum dolor sit amet, consectetur" * 3) + .row("3", "foo", "bar") +``` + +```text +<------------ 40 characters -----------> +╔═╤═══════╤════════════════════════════╗ +║N│column │column with long values ║ +╠═╪═══════╪════════════════════════════╣ +║1│value 1│Lorem ipsum dolor sit amet,…║ +║2│value 2│Lorem ipsum dolor sit amet,…║ +║3│foo │bar ║ +╚═╧═══════╧════════════════════════════╝ +``` + +### ASCII-only mode + +Previous sections used [box drawing characters](https://en.wikipedia.org/wiki/Box-drawing_character), which contain +unicode symbols. If ASCII-only set is required, it is possible to switch to legacy mode: +```scala +AsciiTable() + .useAscii(true) // use ASCII-only characters + .width(40) + .multiline(true) + .columnMinWidth(7) + .rowMaxHeight(3) + .header("N", "column", "column with long values") + .row("1", "value 1", "Lorem ipsum dolor sit amet, consectetur") + .row("2", "value 2", "Lorem ipsum dolor sit amet, consectetur" * 3) + .row("3", "foo", "bar") + .write() ``` -┌────────────┬────────────┐ -│first column│2 │ -├────────────┼────────────┤ -│1 │second value│ -├────────────┼────────────┤ -│ │ │ -└────────────┴────────────┘ + +```text ++-+-------+----------------------------+ +|N|column |column with long values | ++-+-------+----------------------------+ +|1|value 1|Lorem ipsum dolor sit amet, | +| | |consectetur | ++-+-------+----------------------------+ +|2|value 2|Lorem ipsum dolor sit amet, | +| | |consecteturLorem ipsum dolor| +| | | sit amet, consecteturLorem_| ++-+-------+----------------------------+ +|3|foo |bar | ++-+-------+----------------------------+ ``` -## Usage +## Installation ### Gradle ``` @@ -36,7 +113,7 @@ allprojects { } dependencies { - compile 'com.github.ivanfrolovmd:asciitable:0.0.6' + compile 'com.github.ivanfrolovmd:asciitable:0.0.7' } ``` @@ -52,12 +129,12 @@ dependencies { com.github.ivanfrolovmd asciitable - 0.0.6 + 0.0.7 ``` ### SBT ``` resolvers += "jitpack" at "https://jitpack.io" -libraryDependencies += "com.github.ivanfrolovmd" % "asciitable" % "0.0.6" +libraryDependencies += "com.github.ivanfrolovmd" % "asciitable" % "0.0.7" ``` diff --git a/src/main/scala/io/github/asciitable/AsciiTable.scala b/src/main/scala/io/github/asciitable/AsciiTable.scala index f6c0b76..6c445f3 100644 --- a/src/main/scala/io/github/asciitable/AsciiTable.scala +++ b/src/main/scala/io/github/asciitable/AsciiTable.scala @@ -8,7 +8,45 @@ import io.github.asciitable.Maths._ import scala.collection.immutable.Stream.StreamBuilder import scala.language.postfixOps -class AsciiTable { +/** + *

AsciiTable should be used as a builder by chaining building instructions and calling terminal toString() + * or write() functions in the end. + * + *

Usage example: + * + *

+  * AsciiTable()
+  *   .width(40) // screen width to fit table in
+  *   .multiline(true) // render rows across multiple lines
+  *   .columnMinWidth(7) // column width will be 7 characters or more
+  *   .rowMaxHeight(3) // clip cells at 3 lines
+  *   .header("N", "column", "column with long values")
+  *   .row("1", "value 1", "Lorem ipsum dolor sit amet, consectetur")
+  *   .row("2", "value 2", "Lorem ipsum dolor sit amet, consectetur" * 3)
+  *   .row("3", "foo", "bar")
+  *   .write()
+  * 
+ * + *

renders: + * + *

+  * <------------ 40 characters ----------->
+  * ╔═╤═══════╤════════════════════════════╗
+  * ║N│column │column with long values     ║
+  * ╠═╪═══════╪════════════════════════════╣
+  * ║1│value 1│Lorem ipsum dolor sit amet, ║
+  * ║ │       │consectetur                 ║
+  * ╟─┼───────┼────────────────────────────╢ ↑
+  * ║2│value 2│Lorem ipsum dolor sit amet, ║ |
+  * ║ │       │consecteturLorem ipsum dolor║ 3 lines max
+  * ║ │       │ sit amet, consecteturLorem…║ |
+  * ╟─┼───────┼────────────────────────────╢ ↓
+  * ║3│foo    │bar                         ║
+  * ╚═╧═══════╧════════════════════════════╝
+  *    <- 7 ->
+  * 
+ */ +final class AsciiTable { private var header: Option[Seq[String]] = None private val streamBuilder = new StreamBuilder[Seq[String]] private var width: Option[Int] = None @@ -16,23 +54,24 @@ class AsciiTable { private var emptyMessage = DefaultEmptyMessage private var rowMaxHeight = DefaultRowMaxHeight private var columnMinWidth = DefaultColumnMinWidth - private var columnMaxWidth = DefaultColumnMaxWidth private var sampleRows = DefaultSampleRows private var chars: CharacterSet = Unicode + // data builders def header(columnNames: String*): AsciiTable = { header = Some(columnNames); this } def header(columnNames: TraversableOnce[String]): AsciiTable = { header = Some(columnNames.toSeq); this } def row(values: String*): AsciiTable = { streamBuilder += values; this } def row(values: TraversableOnce[String]): AsciiTable = { streamBuilder += values.toSeq; this } def rows(rows: TraversableOnce[TraversableOnce[String]]): AsciiTable = { streamBuilder ++= rows.map(_.toSeq); this } - def width(value: Int): AsciiTable = { width = Some(value); this } - def multiline(value: Boolean): AsciiTable = { multiline = value; this } - def emptyMessage(value: String): AsciiTable = { emptyMessage = value; this } - def rowMaxHeight(value: Int): AsciiTable = { rowMaxHeight = value; this } - def columnMinWidth(value: Int): AsciiTable = { columnMinWidth = value; this } - def columnMaxWidth(value: Int): AsciiTable = { columnMaxWidth = value; this } - def sampleAtMostRows(value: Int): AsciiTable = { sampleRows = value; this } - def useAscii(value: Boolean): AsciiTable = { chars = if (value) Ascii else Unicode; this } + + // configuration + def width(value: Int): AsciiTable = { width = Some(value); this } + def multiline(value: Boolean): AsciiTable = { multiline = value; this } + def emptyMessage(value: String): AsciiTable = { emptyMessage = value; this } + def rowMaxHeight(value: Int): AsciiTable = { rowMaxHeight = value; this } + def columnMinWidth(value: Int): AsciiTable = { columnMinWidth = value; this } + def sampleAtMostRows(value: Int): AsciiTable = { sampleRows = value; this } + def useAscii(value: Boolean): AsciiTable = { chars = if (value) Ascii else Unicode; this } private lazy val rows = streamBuilder.result() @@ -229,7 +268,6 @@ object AsciiTable { private val DefaultWidth = 80 private val DefaultRowMaxHeight = 7 private val DefaultColumnMinWidth = 1 - private val DefaultColumnMaxWidth = 5 private val DefaultWidthPercentile = .75 private val DefaultEmptyMessage = "" private val DefaultSampleRows = 50