Skip to content

Instantly share code, notes, and snippets.

@dduan
Last active May 28, 2024 17:29
Show Gist options
  • Save dduan/272d8c20bb6521695bd04e290b489774 to your computer and use it in GitHub Desktop.
Save dduan/272d8c20bb6521695bd04e290b489774 to your computer and use it in GitHub Desktop.
Put terminal in raw mode, clear the screen, run some code. Reset the terminal to original mode when the code finish running.
#if canImport(Darwin)
import Darwin
#else
import Glibc
#endif
enum RawModeError: Error {
case notATerminal
case failedToGetTerminalSetting
case failedToSetTerminalSetting
}
func runInRawMode(_ task: @escaping () throws -> Void) throws {
var originalTermSetting = termios()
guard isatty(STDIN_FILENO) != 0 else {
throw RawModeError.notATerminal
}
guard tcgetattr(STDIN_FILENO, &originalTermSetting) >= 0 else {
throw RawModeError.failedToGetTerminalSetting
}
var raw = originalTermSetting
raw.c_iflag &= ~(UInt(BRKINT) | UInt(ICRNL) | UInt(INPCK) | UInt(ISTRIP) | UInt(IXON))
raw.c_oflag &= ~(UInt(OPOST))
raw.c_cflag |= UInt(CS8)
raw.c_lflag &= ~(UInt(ECHO) | UInt(ICANON) | UInt(IEXTEN) | UInt(ISIG))
raw.c_cc.16 = 0
raw.c_cc.17 = 1
guard tcsetattr(STDIN_FILENO, TCSAFLUSH, &raw) >= 0 else {
throw RawModeError.failedToSetTerminalSetting
}
defer {
tcsetattr(STDIN_FILENO, TCSAFLUSH, &originalTermSetting)
}
print("\u{1b}[2J")
try task()
}
// Example usage: run a loop until 'q' is pressed
let q = Character("q").asciiValue!
try runInRawMode {
while true {
var char: UInt8 = 0
read(STDIN_FILENO, &char, 1)
if char == q {
exit(0)
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment