diff --git a/help/src/main/scala/flatgraph/help/Table.scala b/help/src/main/scala/flatgraph/help/Table.scala index 95520532..14a43e32 100644 --- a/help/src/main/scala/flatgraph/help/Table.scala +++ b/help/src/main/scala/flatgraph/help/Table.scala @@ -8,16 +8,27 @@ case class Table(columnNames: Seq[String], rows: Seq[Row]) { if (columnNames.isEmpty && rows.isEmpty) { "" } else { - val renderingWidth = math.max(availableWidthProvider.apply(), 60) - val minWidth = 5 - val maxWidth = renderingWidth - minWidth - val allRows = columnNames +: rows - val numCols = columnNames.size + val minWidth = 1 + val allRows = columnNames +: rows + val numCols = columnNames.size + val separatorWidth = numCols + 1 // │ around and between each column + val minRenderingWidth = math.max(60, numCols * minWidth + separatorWidth) + val renderingWidth = math.max(availableWidthProvider.apply(), minRenderingWidth) + val availableForContent = renderingWidth - separatorWidth - // calculate column widths: longest content per column, clamped to [minWidth, maxWidth] - val colWidths = (0 until numCols).map { col => + // calculate natural column widths: longest content per column, clamped to minWidth + val widths = (0 until numCols).map { col => val longest = allRows.map(row => if (col < row.size) row(col).length else 0).max - math.min(math.max(longest, minWidth), maxWidth) + math.max(longest, minWidth) + }.toArray + + // shrink widest columns until total fits within available space + val colWidths = { + while (widths.sum > availableForContent) { + val maxIdx = widths.zipWithIndex.maxBy(_._1)._2 + widths(maxIdx) = math.max(widths(maxIdx) - 1, minWidth) + } + widths.toIndexedSeq } val sb = new StringBuilder() diff --git a/help/src/test/scala/flatgraph/help/TableTests.scala b/help/src/test/scala/flatgraph/help/TableTests.scala index 74b9df29..101b5039 100644 --- a/help/src/test/scala/flatgraph/help/TableTests.scala +++ b/help/src/test/scala/flatgraph/help/TableTests.scala @@ -35,26 +35,28 @@ class TableTests extends AnyWordSpec { implicit val availableWidthProvider: AvailableWidthProvider = () => currentTerminalWidth table.render.trim shouldBe - """┌───────────────────────────────────────────────────────┐ - |│lorem ipsum │ - |├───────────────────────────────────────────────────────┤ - |│Lorem ipsum dolor sit amet, consectetur adipiscing │ - |│elit, sed do eiusmod tempor incididunt ut labore et │ - |│dolore magna aliqua. Ut enim ad minim veniam, quis │ - |│nostrud exercitation ullamco laboris nisi ut aliquip │ - |└───────────────────────────────────────────────────────┘ + """┌──────────────────────────────────────────────────────────┐ + |│lorem ipsum │ + |├──────────────────────────────────────────────────────────┤ + |│Lorem ipsum dolor sit amet, consectetur adipiscing elit, │ + |│sed do eiusmod tempor incididunt ut labore et dolore magna│ + |│aliqua. Ut enim ad minim veniam, quis nostrud exercitation│ + |│ullamco laboris nisi ut aliquip │ + |└──────────────────────────────────────────────────────────┘ |""".stripMargin.trim + table.render.trim.linesIterator.foreach(_.length shouldBe 60) // 60 is min rendering width currentTerminalWidth = 100 // emulating: terminal size has changed table.render.trim shouldBe - """┌───────────────────────────────────────────────────────────────────────────────────────────────┐ - |│lorem ipsum │ - |├───────────────────────────────────────────────────────────────────────────────────────────────┤ - |│Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut │ - |│labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco │ - |│laboris nisi ut aliquip │ - |└───────────────────────────────────────────────────────────────────────────────────────────────┘ + """┌──────────────────────────────────────────────────────────────────────────────────────────────────┐ + |│lorem ipsum │ + |├──────────────────────────────────────────────────────────────────────────────────────────────────┤ + |│Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut │ + |│labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris │ + |│nisi ut aliquip │ + |└──────────────────────────────────────────────────────────────────────────────────────────────────┘ |""".stripMargin.trim + table.render.trim.linesIterator.foreach(_.length shouldBe currentTerminalWidth) } } diff --git a/tests/src/test/scala/flatgraph/traversal/TraversalTests.scala b/tests/src/test/scala/flatgraph/traversal/TraversalTests.scala index bd22ade7..a62c68ae 100644 --- a/tests/src/test/scala/flatgraph/traversal/TraversalTests.scala +++ b/tests/src/test/scala/flatgraph/traversal/TraversalTests.scala @@ -165,7 +165,9 @@ class TraversalTests extends AnyWordSpec { // thingTraversalHelpVerbose should include("simple.SimpleDomainTravers") thingTraversalHelpVerbose should include("node label") thingTraversalHelpVerbose should include("flatgraph.traversal.NodeSteps") - thingTraversalHelpVerbose should include("result to a list") + thingTraversalHelpVerbose should include( + "│.l │Execute the traversal and convert the result to a │flatgraph.traversal.GenericSteps│ │" + ) thingTraversalHelpVerbose should include("flatgraph.traversal.GenericSt") } }