Skip to content
Draft
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
33 changes: 12 additions & 21 deletions core/jvm/src/main/scala/terminus/JLineTerminal.scala
Original file line number Diff line number Diff line change
Expand Up @@ -55,14 +55,9 @@ class JLineTerminal(terminal: JTerminal) extends Terminal, TerminalKeyReader {

def write(string: String): Unit = writer.write(string)

def raw[A](f: Terminal ?=> A): A = {
private[terminus] def setRawMode(): () => Unit = {
val attrs = terminal.enterRawMode()
try {
val result = f(using this)
result
} finally {
terminal.setAttributes(attrs)
}
() => terminal.setAttributes(attrs)
}

def getDimensions: effect.TerminalDimensions = {
Expand All @@ -73,23 +68,19 @@ class JLineTerminal(terminal: JTerminal) extends Terminal, TerminalKeyReader {
def setDimensions(dimensions: TerminalDimensions): Unit =
terminal.setSize(Size(dimensions.columns, dimensions.rows))

def application[A](f: Terminal ?=> A): A = {
try {
terminal.puts(Capability.keypad_xmit)
val result = f(using this)
result
} finally {
val _ = terminal.puts(Capability.keypad_local)
private[terminus] def setApplicationMode(): () => Unit = {
terminal.puts(Capability.keypad_xmit)
() => {
terminal.puts(Capability.keypad_local)
()
}
}

def alternateScreen[A](f: Terminal ?=> A): A = {
try {
terminal.puts(Capability.enter_ca_mode)
val result = f(using this)
result
} finally {
val _ = terminal.puts(Capability.exit_ca_mode)
private[terminus] def setAlternateScreenMode(): () => Unit = {
terminal.puts(Capability.enter_ca_mode)
() => {
terminal.puts(Capability.exit_ca_mode)
()
}
}

Expand Down
36 changes: 18 additions & 18 deletions core/native/src/main/scala/terminus/NativeTerminal.scala
Original file line number Diff line number Diff line change
Expand Up @@ -111,26 +111,26 @@ object NativeTerminal
}
}

def application[A](f: (terminus.Terminal) ?=> A): A = {
withEffect(AnsiCodes.mode.application.on, AnsiCodes.mode.application.off)(f)
private[terminus] def setRawMode(): () => Unit = {
implicit val z: Zone = Zone.open()
val origAttrs = termios.getAttributes()
termios.setRawMode()

() => {
termios.setAttributes(origAttrs)
z.close()
}
}

def alternateScreen[A](f: (terminus.Terminal) ?=> A): A = {
withEffect(
private[terminus] def setApplicationMode(): () => Unit =
effectDeferRollback(
AnsiCodes.mode.application.on,
AnsiCodes.mode.application.off
)

private[terminus] def setAlternateScreenMode(): () => Unit =
effectDeferRollback(
AnsiCodes.mode.alternateScreen.on,
AnsiCodes.mode.alternateScreen.off
)(f)
}

def raw[A](f: Terminal ?=> A): A = {
Zone {
val origAttrs = termios.getAttributes()
try {
termios.setRawMode()
f(using this)
} finally {
termios.setAttributes(origAttrs)
}
}
}
)
}
10 changes: 9 additions & 1 deletion core/shared/src/main/scala/terminus/AlternateScreenMode.scala
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,13 @@ trait AlternateScreenMode {
def alternateScreen[F <: effect.Effect, A](
f: F ?=> A
): (F & effect.AlternateScreenMode[F]) ?=> A =
effect ?=> effect.alternateScreen(f)
effect ?=> {
val finalizer = effect.setAlternateScreenMode()

try {
f(using effect)
} finally {
finalizer()
}
}
}
9 changes: 8 additions & 1 deletion core/shared/src/main/scala/terminus/ApplicationMode.scala
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,12 @@ trait ApplicationMode {
def application[F <: effect.Effect, A](
f: F ?=> A
): (F & effect.ApplicationMode[F]) ?=> A =
effect ?=> effect.application(f)
effect ?=>
val finalizer = effect.setApplicationMode()

try {
f(using effect)
} finally {
finalizer()
}
}
10 changes: 9 additions & 1 deletion core/shared/src/main/scala/terminus/RawMode.scala
Original file line number Diff line number Diff line change
Expand Up @@ -23,5 +23,13 @@ trait RawMode {
* which is the default, user input is only available a line at a time.
*/
def raw[F <: effect.Effect, A](f: F ?=> A): (F & effect.RawMode[F]) ?=> A =
effect ?=> effect.raw(f)
effect ?=> {
val finalizer = effect.setRawMode()

try {
f(using effect)
} finally {
finalizer()
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ trait AlternateScreenMode[+F <: Effect] { self: F =>
/** Run the given terminal program `f` in alternate screen mode, which means
* that whatever is displayed by `f` will not been shown when the program
* exits, and similarly key presses will not be saved in the history buffer.
*
* This is a low level method that is slightly dangerous. Care must be taken
* to ensure raw mode is closed and as such, this method is package private
* to avoid exposure.
*/
def alternateScreen[A](f: F ?=> A): A
private[terminus] def setAlternateScreenMode(): () => Unit
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,10 @@ trait ApplicationMode[+F <: Effect] { self: F =>
/** Run the given terminal program `f` in application mode, which changes the
* input sent to the program when arrow keys are pressed. See
* https://invisible-island.net/xterm/xterm.faq.html#xterm_arrows
*
* This is a low level method that is slightly dangerous. Care must be taken
* to ensure raw mode is closed and as such, this method is package private
* to avoid exposure.
*/
def application[A](f: F ?=> A): A

private[terminus] def setApplicationMode(): () => Unit
}
12 changes: 8 additions & 4 deletions core/shared/src/main/scala/terminus/effect/RawMode.scala
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,13 @@ package terminus.effect

trait RawMode[+F <: Effect] { self: F =>

/** Run the given terminal program `f` in raw mode, which means that the
* program can read user input a character at a time. In canonical mode,
* which is the default, user input is only available a line at a time.
/** Sets the terminal to raw mode and returns thunk that rolls back the
* terminal mode to its original state. This returned thunk should not be
* called more than once.
*
* This is a low level method that is slightly dangerous. Care must be taken
* to ensure raw mode is closed and as such, this method is package private
* to avoid exposure.
*/
def raw[A](f: F ?=> A): A
private[terminus] def setRawMode(): () => Unit
}
5 changes: 5 additions & 0 deletions core/shared/src/main/scala/terminus/effect/WithEffect.scala
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,9 @@ trait WithEffect[+F <: Writer] { self: F =>
write(on)
f(using this)
}

protected def effectDeferRollback(on: String, off: String): () => Unit = {
write(on)
() => write(off)
}
}
Loading