Skip to content

Commit 675eeaa

Browse files
authored
allow to provide terminal width dynamically via implicit (#416)
1 parent ad8bec6 commit 675eeaa

File tree

7 files changed

+104
-26
lines changed

7 files changed

+104
-26
lines changed

traversal-tests/src/test/scala/overflowdb/traversal/TraversalTests.scala

Lines changed: 2 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ import overflowdb.traversal.testdomains.gratefuldead._
99
import overflowdb.{Node, toPropertyKeyOps}
1010

1111
import scala.collection.mutable
12-
import overflowdb.traversal._
1312
import overflowdb.traversal.help.Table
13+
import overflowdb.traversal.help.Table.AvailableWidthProvider
1414

1515
import scala.jdk.CollectionConverters.IteratorHasAsScala
1616

@@ -179,6 +179,7 @@ class TraversalTests extends AnyWordSpec with ExampleGraphSetup {
179179

180180
".help step" should {
181181
import SimpleDomain._ // for domain specific `DocSearchPackages`
182+
implicit val availableWidthProvider: AvailableWidthProvider = new Table.ConstantWidth(100)
182183

183184
"give a domain overview" in {
184185
val helpText = simpleDomain.help
@@ -237,17 +238,3 @@ class TraversalTests extends AnyWordSpec with ExampleGraphSetup {
237238
}
238239

239240
}
240-
241-
object TableStyleTester {
242-
def main(args: Array[String]): Unit = {
243-
println(
244-
Table(
245-
Seq("column a", "column b"),
246-
Seq(
247-
Seq("abc 1", "bde 1"),
248-
Seq("abc 2", "bde 2")
249-
)
250-
).render()
251-
)
252-
}
253-
}
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
package overflowdb.traversal.help
2+
3+
import org.scalatest.matchers.should.Matchers._
4+
import org.scalatest.wordspec.AnyWordSpec
5+
import overflowdb.traversal.help.Table.AvailableWidthProvider
6+
7+
class TableTests extends AnyWordSpec {
8+
9+
"render a nice generic table" in {
10+
val table = Table(
11+
Seq("column a", "column b"),
12+
Seq(
13+
Seq("abc 1", "bde 1"),
14+
Seq("abc 2", "bde 2")
15+
)
16+
)
17+
18+
implicit val availableWidthProvider: AvailableWidthProvider = new Table.ConstantWidth(100)
19+
table.render.trim shouldBe
20+
"""┌─────────────────────────────────────────────────┬────────────────────────────────────────────────┐
21+
|│column a │column b │
22+
|├─────────────────────────────────────────────────┼────────────────────────────────────────────────┤
23+
|│abc 1 │bde 1 │
24+
|│abc 2 │bde 2 │
25+
|└─────────────────────────────────────────────────┴────────────────────────────────────────────────┘
26+
|""".stripMargin.trim
27+
}
28+
29+
"adapt to dynamically changing terminal width" in {
30+
val table = Table(
31+
Seq("lorem ipsum"),
32+
Seq(
33+
Seq(
34+
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et" +
35+
" dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip " +
36+
"ex ea commodo consequat."
37+
)
38+
)
39+
)
40+
41+
var currentTerminalWidth = 80 // think "looking up current value from an actual terminal"
42+
implicit val availableWidthProvider: AvailableWidthProvider = () => currentTerminalWidth
43+
44+
table.render.trim shouldBe
45+
"""┌──────────────────────────────────────────────────────────────────────────────┐
46+
|│lorem ipsum │
47+
|├──────────────────────────────────────────────────────────────────────────────┤
48+
|│Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor│
49+
|│incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis │
50+
|│nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. │
51+
|└──────────────────────────────────────────────────────────────────────────────┘
52+
|""".stripMargin.trim
53+
54+
currentTerminalWidth = 100 // emulating: terminal size has changed
55+
table.render.trim shouldBe
56+
"""┌──────────────────────────────────────────────────────────────────────────────────────────────────┐
57+
|│lorem ipsum │
58+
|├──────────────────────────────────────────────────────────────────────────────────────────────────┤
59+
|│Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut │
60+
|│labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris │
61+
|│nisi ut aliquip ex ea commodo consequat. │
62+
|└──────────────────────────────────────────────────────────────────────────────────────────────────┘
63+
|""".stripMargin.trim
64+
}
65+
66+
}

traversal-tests/src/test/scala/overflowdb/traversal/testdomains/hierarchical/HierarchicalDomain.scala

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package overflowdb.traversal.testdomains.hierarchical
33
import overflowdb.traversal.{TraversalSource, help}
44
import overflowdb.{Config, Graph}
55
import overflowdb.traversal._
6+
import overflowdb.traversal.help.Table.AvailableWidthProvider
67

78
import java.util
89
import overflowdb.traversal.help.{Doc, DocSearchPackages, TraversalHelp}
@@ -37,5 +38,6 @@ class HierarchicalDomainTraversalSource(graph: Graph) extends TraversalSource(gr
3738
@Doc(info = "all animals")
3839
def animal: Traversal[Animal] = all.collect { case node: Animal => node }
3940

40-
lazy val help: String = HierarchicalDomain.help.forTraversalSources
41+
def help(implicit availableWidthProvider: AvailableWidthProvider): String =
42+
HierarchicalDomain.help.forTraversalSources
4143
}

traversal-tests/src/test/scala/overflowdb/traversal/testdomains/simple/SimpleDomain.scala

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package overflowdb.traversal.testdomains.simple
22

3+
import overflowdb.traversal.help.Table.AvailableWidthProvider
34
import overflowdb.traversal.{TraversalSource, help}
45
import overflowdb.{Config, Graph}
56

@@ -29,5 +30,6 @@ class SimpleDomainTraversalSource(graph: Graph) extends TraversalSource(graph) {
2930
@Doc(info = "all things")
3031
def things: Traversal[Thing] = label(Thing.Label).cast[Thing]
3132

32-
lazy val help: String = SimpleDomain.help.forTraversalSources
33+
def help(implicit availableWidthProvider: AvailableWidthProvider): String =
34+
SimpleDomain.help.forTraversalSources
3335
}

traversal/src/main/scala/overflowdb/traversal/Traversal.scala

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package overflowdb.traversal
22

33
import org.slf4j.LoggerFactory
4+
import overflowdb.traversal.help.Table.AvailableWidthProvider
45
import overflowdb.traversal.help.{Doc, DocSearchPackages, TraversalHelp}
56

67
import scala.collection.{
@@ -115,11 +116,19 @@ class TraversalSugarExt[A](val iter: Iterator[A]) extends AnyVal {
115116
* will simply list all documented steps in the classpath
116117
*/
117118
@Doc(info = "print help/documentation based on the current elementType `A`.")
118-
def help[B >: A](implicit elementType: ClassTag[B], searchPackages: DocSearchPackages): String =
119+
def help[B >: A](implicit
120+
elementType: ClassTag[B],
121+
searchPackages: DocSearchPackages,
122+
availableWidthProvider: AvailableWidthProvider
123+
): String =
119124
new TraversalHelp(searchPackages).forElementSpecificSteps(elementType.runtimeClass, verbose = false)
120125

121126
@Doc(info = "print verbose help/documentation based on the current elementType `A`.")
122-
def helpVerbose[B >: A](implicit elementType: ClassTag[B], searchPackages: DocSearchPackages): String =
127+
def helpVerbose[B >: A](implicit
128+
elementType: ClassTag[B],
129+
searchPackages: DocSearchPackages,
130+
availableWidthProvider: AvailableWidthProvider
131+
): String =
123132
new TraversalHelp(searchPackages).forElementSpecificSteps(elementType.runtimeClass, verbose = true)
124133
}
125134
class TraversalFilterExt[A](val iterator: Iterator[A]) extends AnyVal {

traversal/src/main/scala/overflowdb/traversal/help/Table.scala

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,13 @@ package overflowdb.traversal.help
33
import de.vandermeer.asciitable.AsciiTable
44
import de.vandermeer.asciithemes.TA_GridThemes
55
import de.vandermeer.skb.interfaces.transformers.textformat.TextAlignment
6+
import overflowdb.traversal.help.Table._
67

78
import scala.jdk.CollectionConverters.SeqHasAsJava
89

910
case class Table(columnNames: Seq[String], rows: Seq[Seq[String]]) {
1011

11-
def render(width: Int = 120): String = {
12+
def render(implicit availableWidthProvider: AvailableWidthProvider): String = {
1213
if (columnNames.isEmpty && rows.isEmpty) {
1314
""
1415
} else {
@@ -22,8 +23,17 @@ case class Table(columnNames: Seq[String], rows: Seq[Seq[String]]) {
2223
table.addRule()
2324
table.getContext.setGridTheme(TA_GridThemes.FULL)
2425
table.setTextAlignment(TextAlignment.LEFT)
25-
table.render(width)
26+
table.render(availableWidthProvider.apply())
2627
}
2728
}
2829

2930
}
31+
32+
object Table {
33+
trait AvailableWidthProvider extends (() => Int)
34+
35+
class ConstantWidth(width: Int) extends AvailableWidthProvider {
36+
override def apply() = width
37+
}
38+
39+
}

traversal/src/main/scala/overflowdb/traversal/help/TraversalHelp.scala

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,10 @@ import org.reflections8.Reflections
44
import overflowdb.traversal.help.DocFinder.StepDoc
55
import overflowdb.traversal.{ElementTraversal, NodeTraversal, help}
66
import overflowdb.traversal
7+
import overflowdb.traversal.help.Table.AvailableWidthProvider
78
import overflowdb.{NodeDb, NodeRef}
89

910
import java.lang.annotation.{Annotation => JAnnotation}
10-
import scala.collection.mutable
1111
import scala.jdk.CollectionConverters._
1212

1313
/** Searches classpath for @Traversal|@TraversalSource and @Doc annotations (via reflection). Used for `.help` step.
@@ -24,7 +24,9 @@ import scala.jdk.CollectionConverters._
2424
class TraversalHelp(searchPackages: DocSearchPackages) {
2525
import TraversalHelp._
2626

27-
def forElementSpecificSteps(elementClass: Class[_], verbose: Boolean): String = {
27+
def forElementSpecificSteps(elementClass: Class[_], verbose: Boolean)(implicit
28+
availableWidthProvider: AvailableWidthProvider
29+
): String = {
2830
val isNode = classOf[NodeDb].isAssignableFrom(elementClass)
2931
val isNodeRef = classOf[NodeRef[_]].isAssignableFrom(elementClass)
3032

@@ -54,11 +56,11 @@ class TraversalHelp(searchPackages: DocSearchPackages) {
5456
)
5557

5658
s"""Available steps for ${elementClass.getSimpleName}:
57-
|${table.render()}
59+
|${table.render}
5860
|""".stripMargin
5961
}
6062

61-
lazy val forTraversalSources: String = {
63+
def forTraversalSources(implicit availableWidthProvider: AvailableWidthProvider): String = {
6264
val stepDocs = for {
6365
packageName <- packageNamesToSearch
6466
traversal <- findClassesAnnotatedWith(packageName, classOf[help.TraversalSource])
@@ -73,7 +75,7 @@ class TraversalHelp(searchPackages: DocSearchPackages) {
7375
)
7476

7577
s"""Available starter steps:
76-
|${table.render()}
78+
|${table.render}
7779
|""".stripMargin
7880
}
7981

0 commit comments

Comments
 (0)