Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 31 additions & 6 deletions modules/core/src/main/scala/InteractiveSingleChoice.scala
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ private[cue4s] class InteractiveSingleChoice(
out: Output,
theme: Theme,
windowSize: Int,
width: Int,
symbols: Symbols,
) extends PromptFramework[String](terminal, out):
import InteractiveSingleChoice.*
Expand All @@ -31,6 +32,8 @@ private[cue4s] class InteractiveSingleChoice(

private lazy val altsWithIndex = alts.zipWithIndex
private lazy val altMapping = altsWithIndex.map(_.swap).toMap
private lazy val preSplitMapping =
altMapping.view.mapValues(TextSplitter.split(_, width)).toMap

override def initialState = State(
text = "",
Expand Down Expand Up @@ -75,6 +78,24 @@ private[cue4s] class InteractiveSingleChoice(

import theme.*

def prefixed(lab: (Symbols => String) | String, text: String): String =
lab match
case f: (Symbols => String) => " " + f(symbols) + " " + text
case s: String => " " + s + text

def prefixed(
lab: (Symbols => String) | String,
text: List[String],
): List[String] =
var i = 0
val indent = " " * prefixed(lab, "").length
text.map: l =>
i += 1
if i == 1 then prefixed(lab, l)
else indent + l

end prefixed

override def renderState(
st: State,
status: Status,
Expand Down Expand Up @@ -104,16 +125,20 @@ private[cue4s] class InteractiveSingleChoice(
.zipWithIndex
.foreach:
case (id, idx) =>
val alt = altMapping(id)
lines.addOne(
if id == selected then s" $altCursor $alt".focused
val text = preSplitMapping(id)
lines.addAll(
if id == selected then
prefixed(
_.altCursor,
text,
).map(_.focused)
else if st.display.windowStart > 0 && idx == 0 then
s" $pageUpArrow $alt".option
prefixed(_.pageUpArrow, text).map(_.option)
else if filtered.size > st.display.windowSize &&
idx == st.display.windowSize - 1 &&
filtered.indexOf(id) != filtered.size - 1
then s" $pageDownArrow $alt".option
else s" $alt".option,
then prefixed(_.pageDownArrow, text).map(_.option)
else prefixed(" ", text).map(_.option),
)
end match
case Status.Finished(value) =>
Expand Down
2 changes: 2 additions & 0 deletions modules/core/src/main/scala/Prompt.scala
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,7 @@ object Prompt:
private val lab: String,
private val alts: List[String],
private val windowSize: Int = 10,
private val width: Int = 50,
) extends Prompt[String]:

def withWindowSize(i: Int) = copy(windowSize = i)
Expand All @@ -248,6 +249,7 @@ object Prompt:
out = output,
theme = theme,
windowSize = this.windowSize,
width = this.width,
symbols = symbols,
)
end SingleChoice
Expand Down
36 changes: 36 additions & 0 deletions modules/core/src/main/scala/TextSplitter.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package cue4s

import scala.collection.mutable.ListBuffer

object TextSplitter:

def split(s: String, max: Int): List[String] =

val lines = List.newBuilder[String]
val currentLine = ListBuffer.empty[String]

val words = s.split(" ")

inline def recordLine() =
if currentLine.nonEmpty then
lines += currentLine.mkString(" ")
currentLine.clear()

var curWidth = 0
words.foreach: word =>
if curWidth < max then
currentLine += word
curWidth += word.length + (if currentLine.isEmpty then 0 else 1)
else
recordLine()
currentLine += word
curWidth = word.length
end if

recordLine()

lines.result()

end split

end TextSplitter
1 change: 0 additions & 1 deletion modules/core/src/test/scala/FallbackRenderingTests.scala
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package cue4s

import cue4s.*
import cue4s.Prompt.PasswordInput.Password

import KeyEvent.*

Expand Down
16 changes: 16 additions & 0 deletions modules/core/src/test/scala/TextSplitterTests.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package cue4s

class TextSplitterTests extends munit.FunSuite:
test("splitting") {
val splitter = TextSplitter
val text = "hello world, I say"
val result = splitter.split(text, 5)
assertEquals(result, List("hello", "world,", "I say"))

assertEquals(splitter.split(text, text.length), List(text))

assertEquals(splitter.split("", 0), List(""))
assertEquals(splitter.split("hello", 5), List("hello"))
assertEquals(splitter.split("hello", 3), List("hello"))
}
end TextSplitterTests
2 changes: 1 addition & 1 deletion modules/example/src/main/scala-jvm-native/sync.scala
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ import cue4s.Prompt.PasswordInput.Password
"relaxing",
"stressful",
"exhausting",
"challenging",
"challenging challenging challenging challenging challenging challenging challenging challenging challenging challenging challenging",
"wonderful",
"uneventful",
"interesting",
Expand Down
Loading