use fmt; use os; use io; use unix::tty; use errors; use bufio; use encoding::utf8; use strings; // A listener on a rune input that returns if the ui needs to terminate or not export type listener = *fn(ui: *ttyui, r: rune) bool; export type ttyui = struct { term: tty::termios, f: io::file, listeners: []listener, }; export fn init() ttyui = { let f = match (tty::open()) { case let f: io::file => yield f; case let e: tty::error => fmt::fatal(tty::strerror(e)); }; if (!tty::isatty(f)) { fmt::fatal("/dev/tty is not a tty"); }; let term = match (tty::termios_query(f)) { case let t: tty::termios => yield t; case let e: errors::error => fmt::fatal(errors::strerror(e)); }; tty::makeraw(&term)!; tty::noecho(&term)!; return ttyui { term = term, f = f, listeners = [], }; }; export fn getwinsize(ui: ttyui) (tty::ttysize | tty::error) = { return tty::winsize(ui.f); }; export fn suspend(ui: *ttyui) void = { tty::termios_restore(&ui.term); }; export fn resume(ui: *ttyui) void = { tty::makeraw(&ui.term)!; }; export fn finish(ui: *ttyui) void = { tty::termios_restore(&ui.term); io::close(ui.f)!; free(ui.listeners); }; export fn scan(ui: ttyui) (rune | utf8::invalid | io::EOF | io::error) = { return bufio::scanrune(ui.f); }; export fn notify(ui: *ttyui, r: rune) bool = { for (let i = 0z; i < len(ui.listeners); i += 1) { if (ui.listeners[i](ui, r)) { return true; }; }; return false; }; fn loop(ui: *ttyui) void = { for (true) { let r = match (bufio::scanrune(ui.f)) { case let r: rune => yield r; case utf8::invalid => fmt::fatal("Invalid utf8 sequence found"); case io::EOF => fmt::fatal("EOF"); case let e: io::error => fmt::fatal(io::strerror(e)); }; for (let i = 0z; i < len(ui.listeners); i += 1) { if (ui.listeners[i](ui, r)) { return; }; }; }; }; export fn addlistener(ui: *ttyui, l: listener) void = { append(ui.listeners, l); }; export fn print(ui: ttyui, arg: (str | rune)) void = { fmt::fprintf(ui.f, "{}\r\n", arg)!; }; export fn clear(ui: ttyui) void = { fmt::fprintf(ui.f, "\x1B[2J\x1B[1;1H\r")!; }; //export @symbol("wcwidth") fn wcwidth(r: rune) int;