Skip to content

Commit

Permalink
Separate files and add intersperse and block methods
Browse files Browse the repository at this point in the history
  • Loading branch information
keynmol committed Oct 29, 2022
1 parent 15630ce commit af27cdb
Show file tree
Hide file tree
Showing 4 changed files with 104 additions and 20 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,3 @@ object LineBuilder:
lb
end extension
end LineBuilder

opaque type IndentationSize = Int
object IndentationSize extends OpaqueNum[IndentationSize]

opaque type Indentation = Int
object Indentation extends OpaqueNum[Indentation]

import IndentationSize.*
1 change: 0 additions & 1 deletion modules/core/src/main/scala/OpaqueNum.scala
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
package rendition

import Rendering.Config
import IndentationSize.*

private[rendition] trait OpaqueNum[T](using T =:= Int):
inline def apply(i: Int): T = i.asInstanceOf[T]
Expand Down
65 changes: 54 additions & 11 deletions modules/core/src/main/scala/Rendering.scala
Original file line number Diff line number Diff line change
Expand Up @@ -17,29 +17,72 @@
package rendition

import Rendering.Config
import IndentationSize.*

enum Separator:
case Newline(s: String)
case Append(s: String)

case class Rendering(to: LineBuilder, c: Config):
opaque type PrivateC = Config
opaque type Context = Config

inline def indent(using c: PrivateC): String =
inline def indent(using c: Context): String =
(" " * (c.indentSize.value * c.indents.value))

inline def nest(f: PrivateC ?=> Unit)(using config: PrivateC = c) =
f(using config.copy(indents = config.indents.map(_ + 1)))
inline def nest(f: Context ?=> Unit)(using context: Context = c) =
f(using context.copy(indents = context.indents.map(_ + 1)))

inline def deep(count: Int)(f: Context ?=> Unit)(using
context: Context = c
) =
f(using context.copy(indents = context.indents.map(_ + count)))

inline def line(n: String)(using context: Context = c) =
to.appendLine(indent(using context) + n)

inline def emptyLine()(using context: Context = c) =
line("")

inline def deep(count: Int)(f: PrivateC ?=> Unit)(using
config: PrivateC = c
inline def forkRendering(using context: Context = c) = Rendering(to, context)

inline def block(start: String, end: String)(f: Context ?=> Unit)(using
context: Context = c
) =
f(using config.copy(indents = config.indents.map(_ + count)))
line(start)
nest { f }
line(end)

inline def line(n: String)(using config: PrivateC = c) =
to.appendLine(indent(using config) + n)
inline def intersperse(
separator: Separator
)(iterator: Seq[String])(using ctx: Context = c) =
if iterator.size < 2 then iterator.foreach(line(_))
else
var separators = iterator.size - 1
iterator.foreach { str =>
separator match
case Separator.Newline(s) =>
line(str)
if separators > 0 then
line(s)
separators -= 1
case Separator.Append(s) =>
if separators > 0 then
line(str + s)
separators -= 1
else line(str)

inline def forkRendering(using config: PrivateC = c) = Rendering(to, config)
}
end Rendering

object Rendering:
case class Config(indents: Indentation, indentSize: IndentationSize)
object Config:
val default = Config(Indentation(0), IndentationSize(2))

opaque type IndentationSize = Int
object IndentationSize extends OpaqueNum[IndentationSize]

opaque type Indentation = Int
object Indentation extends OpaqueNum[Indentation]

import IndentationSize.*
end Rendering
50 changes: 50 additions & 0 deletions modules/core/src/test/scala/tests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ class Tests extends munit.FunSuite:
line("val x = 25")
}
line("def t = 5")
block("given Test =", "end") {
line("def x = 1")
}

}
}

Expand All @@ -23,11 +27,57 @@ class Tests extends munit.FunSuite:
| def hello =
| val x = 25
| def t = 5
| given Test =
| def x = 1
| end
""".trim.stripMargin

assertEquals(expected, lb.result.trim)
}

test("intersperse") {
val lb = LineBuilder()
lb.render { r =>
import r.*

val definitions = List.tabulate(5)(i => s"val test$i = $i")
val arguments = List.tabulate(5)(i => s"x$i: String")

block("object hello:", "end hello") {
intersperse(Separator.Newline("// test"))(definitions)
}

block("def function(", ") = ???") {
intersperse(Separator.Append(","))(arguments)
}

}

val expected = """
|object hello:
| val test0 = 0
| // test
| val test1 = 1
| // test
| val test2 = 2
| // test
| val test3 = 3
| // test
| val test4 = 4
|end hello
|def function(
| x0: String,
| x1: String,
| x2: String,
| x3: String,
| x4: String
|) = ???
""".stripMargin.trim

assertEquals(lb.result.trim, expected)

}

/** Forking is useful when you want to extract part of the rendering logic
* into a separate function
*/
Expand Down

0 comments on commit af27cdb

Please sign in to comment.