use libui; use libui::widget; use libui::widget::list; use libui::layout; use encoding::utf8; use io; use fmt; use os; use strings; use unix::tty; use unix::signal; use bufio; use regex; let u: mainUI = mainUI {...}; let searchterm: str = ""; let searchforward: bool = true; type mainUI = struct { list: *list::listwidget, }; fn globalrunehandler(ui: *libui::ttyui, r: rune) bool = { if (r == 'q') { return true; }; return false; }; fn runehandler(l: *widget::widget, r: rune) bool = { const l = l: *list::listwidget; switch (r) { case 'j' => list::down(l); case 'k' => list::up(l); case 'd' => list::pagedown(l); case 'u' => list::pageup(l); case 'l' => // to print properly suspend the ui, print, then resume libui::suspend(&l.ui); //fmt::println(l.items[l.cursor])!; match (list::selected(*l)) { case let s: str => fmt::println(s)!; case let s: []str => defer free(s); const out = strings::join("\n", s...); defer free(out); fmt::println(out)!; }; libui::resume(&l.ui); return true; case 'g' => list::top(l); case 'G' => list::bottom(l); case 'n' => if (searchforward) { list::search(l, searchterm); } else { list::rsearch(l, searchterm); }; case 'N' => if (searchforward) { list::rsearch(l, searchterm); } else { list::search(l, searchterm); }; case '?' => // TODO add commandline support maybe libui::suspend(&l.ui); fmt::fprint(l.ui.f, '?')!; let line = match (bufio::scanline(l.ui.f)) { case let s: []u8 => yield s; case io::EOF => fmt::fprintln(os::stderr, "EOF")!; return true; case let e: io::error => fmt::fprintln(os::stderr, io::strerror(e))!; return true; }; //defer free(line); searchterm = strings::fromutf8(line); searchforward = false; let c = l.cursor; list::rsearch(l, searchterm); libui::resume(&l.ui); case '/' => // TODO add commandline support maybe libui::suspend(&l.ui); fmt::fprint(l.ui.f, '/')!; let line = match (bufio::scanline(l.ui.f)) { case let s: []u8 => yield s; case io::EOF => fmt::fprintln(os::stderr, "EOF")!; return true; case let e: io::error => fmt::fprintln(os::stderr, io::strerror(e))!; return true; }; //defer free(line); searchterm = strings::fromutf8(line); searchforward = true; let c = l.cursor; list::search(l, searchterm); libui::resume(&l.ui); case 's' => // TODO add commandline support maybe libui::suspend(&l.ui); fmt::fprint(l.ui.f, "s: ")!; let line = match (bufio::scanline(l.ui.f)) { case let s: []u8 => yield s; case io::EOF => fmt::fprintln(os::stderr, "EOF")!; return true; case let e: io::error => fmt::fprintln(os::stderr, io::strerror(e))!; return true; }; defer free(line); list::containsmark(l, strings::fromutf8(line)); libui::resume(&l.ui); case 'S' => // TODO add commandline support maybe libui::suspend(&l.ui); fmt::fprint(l.ui.f, "S: ")!; let line = match (bufio::scanline(l.ui.f)) { case let s: []u8 => yield s; case io::EOF => fmt::fprintln(os::stderr, "EOF")!; return true; case let e: io::error => fmt::fprintln(os::stderr, io::strerror(e))!; return true; }; defer free(line); list::fnmatchmark(l, strings::fromutf8(line)); libui::resume(&l.ui); case 'r' => // TODO add commandline support maybe libui::suspend(&l.ui); fmt::fprint(l.ui.f, "r: ")!; let line = match (bufio::scanline(l.ui.f)) { case let s: []u8 => yield s; case io::EOF => fmt::fprintln(os::stderr, "EOF")!; return true; case let e: io::error => fmt::fprintln(os::stderr, io::strerror(e))!; return true; }; defer free(line); match (regex::compile(strings::fromutf8(line))) { case let re: regex::regex => list::regexmark(l, &re); regex::finish(&re); case let e: regex::error => fmt::fprintln(os::stderr, regex::strerror(e))!; }; libui::resume(&l.ui); case ' ' => list::tmark(l); list::down(l); case 'c' => list::clearmarked(l); case '\n' => // For some reason enter doesn't send r == '\n' fmt::fprintln(os::stderr, "This is not detected")!; yield; case => let us = utf8::encoderune(r); if (len(us) > 0 && us[0] == 13u8) { fmt::fprintln(os::stderr, "newline")!; }; yield; }; libui::clear(l.ui); match (list::print(l)) { case void => yield; case let e: io::error => fmt::fprintln(os::stderr, io::strerror(e))!; return true; case let e: tty::error => fmt::fprintln(os::stderr, tty::strerror(e))!; return true; }; return false; }; fn sighandler(sig: int, info: *signal::siginfo, ucontext: *void) void = { switch (sig) { case signal::SIGWINCH => let sz = libui::getwinsize(u.list.ui)!; let rows: (u16 | size) = if (sz.rows - 2 < len(u.list.items)) { yield sz.rows - 2; } else { yield len(u.list.items); }; u.list.sz.rows = rows: u16; u.list.sz.cols = sz.columns; }; }; export fn main() void = { let in = match (io::drain(os::stdin)) { case let in: []u8 => yield in; case let e: io::error => fmt::fatal(io::strerror(e)); }; defer free(in); let sin = strings::fromutf8(in); sin = strings::trim(sin, '\n'); let items = strings::split(sin, "\n"); let ui = libui::init(); defer libui::finish(&ui); let l = list::newlist(ui, items...); libui::addlistener(&ui, &globalrunehandler); widget::addlistener(&l, &runehandler); let layout = layout::newlayout(&l); defer layout::finishall(&layout); //defer free(searchterm); libui::clear(l.ui); match (layout::print(layout)) { case void => yield; case let e: io::error => fmt::fprintln(os::stderr, io::strerror(e))!; return; case let e: tty::error => fmt::fprintln(os::stderr, tty::strerror(e))!; return; }; //match (list::print(&l)) { //case void => //yield; //case let e: io::error => //fmt::fprintln(os::stderr, io::strerror(e))!; //return; //case let e: tty::error => //fmt::fprintln(os::stderr, tty::strerror(e))!; //return; //}; u = mainUI { list = &l, }; const sigs = signal::handle(signal::SIGWINCH, &sighandler, signal::flag::RESTART); defer signal::restore(signal::SIGWINCH, &sigs); for (true) { let r = match (libui::scan(ui)) { case let r: rune => yield r; case utf8::invalid => fmt::fprintln(os::stderr, "Invalid utf8 sequence")!; break; case io::EOF => fmt::fprintln(os::stderr, "EOF")!; break; case let e: io::error => fmt::fprintln(os::stderr, io::strerror(e))!; break; }; if (libui::notify(&ui, r)) { break; }; if (list::notify(&l, r)) { break; }; }; }; @fini fn finish() void = { free(searchterm); };