diff options
| author | Julian Hurst <julian.hurst92@gmail.com> | 2022-05-05 23:10:04 +0200 |
|---|---|---|
| committer | Julian Hurst <julian.hurst92@gmail.com> | 2022-05-05 23:10:04 +0200 |
| commit | 1aece8326ee62e242f308c3dbeb5f2bb5e2d53b9 (patch) | |
| tree | fa650c989ddc4e3c7dd7d1d0343d183369fdd14e | |
| parent | 6aa1de7118b0b813cdbff631a22e04d8944dc951 (diff) | |
| download | ilhare-1aece8326ee62e242f308c3dbeb5f2bb5e2d53b9.tar.gz | |
Improve docs and search (forwards/backwards search)
| -rw-r--r-- | libui/libui.ha | 17 | ||||
| -rw-r--r-- | libui/list/list.ha | 31 | ||||
| -rw-r--r-- | main.ha | 65 |
3 files changed, 98 insertions, 15 deletions
diff --git a/libui/libui.ha b/libui/libui.ha index 0546d24..6ad33d1 100644 --- a/libui/libui.ha +++ b/libui/libui.ha @@ -17,6 +17,7 @@ export type ttyui = struct { listeners: []listener, }; +// Initializes the UI and returns a ttyui. export fn init() ttyui = { let f = match (tty::open()) { case let f: io::file => @@ -43,28 +44,36 @@ export fn init() ttyui = { }; }; +// Returns the window size for the given ttyui. export fn getwinsize(ui: ttyui) (tty::ttysize | tty::error) = { return tty::winsize(ui.f); }; +// Suspend the UI. To restore it, use [[resume]]. export fn suspend(ui: *ttyui) void = { tty::termios_restore(&ui.term); }; +// Resumes the UI after a [[suspend]]. export fn resume(ui: *ttyui) void = { tty::makeraw(&ui.term)!; + tty::noecho(&ui.term)!; }; +// Restores the UI state and closes and frees the resources associated with the +// given ttyui. export fn finish(ui: *ttyui) void = { tty::termios_restore(&ui.term); io::close(ui.f)!; free(ui.listeners); }; +// Scans a rune. A convenience function for [[bufio::scanrune]]. export fn scan(ui: ttyui) (rune | utf8::invalid | io::EOF | io::error) = { return bufio::scanrune(ui.f); }; +// Notify (call) the ttyui's listeners with the ttyui and r as a parameter. export fn notify(ui: *ttyui, r: rune) bool = { for (let i = 0z; i < len(ui.listeners); i += 1) { if (ui.listeners[i](ui, r)) { @@ -94,17 +103,17 @@ fn loop(ui: *ttyui) void = { }; }; +// Add a listener to the given ttyui. export fn addlistener(ui: *ttyui, l: listener) void = { append(ui.listeners, l); }; - +// Print a string or rune to the ttyui. export fn print(ui: ttyui, arg: (str | rune)) void = { - fmt::fprintf(ui.f, "{}\r\n", arg)!; + fmt::fprintf(ui.f, "{}\r", arg)!; }; +// Clear the ttyui. export fn clear(ui: ttyui) void = { fmt::fprintf(ui.f, "\x1B[2J\x1B[1;1H\r")!; }; - -//export @symbol("wcwidth") fn wcwidth(r: rune) int; diff --git a/libui/list/list.ha b/libui/list/list.ha index 6cbafd7..16e2ecc 100644 --- a/libui/list/list.ha +++ b/libui/list/list.ha @@ -29,6 +29,7 @@ export type ttysize = struct { export type listener = *fn(l: *listwidget, r: rune) bool; +// Create a new list with the given items. export fn newlist(ui: libui::ttyui, items: str...) listwidget = { let sz = libui::getwinsize(ui)!; let rows: (u16 | size) = if (sz.rows - 2 < len(items)) { @@ -53,10 +54,13 @@ export fn newlist(ui: libui::ttyui, items: str...) listwidget = { return w; }; +// Add a listener to the given list. export fn addlistener(list: *listwidget, l: listener) void = { append(list.listeners, l); }; +// Print the list's items while truncating the items to not be wider than the +// list.sz.cols. export fn print(list: *listwidget) (void | io::error | tty::error) = { //let sz = libui::getwinsize(list.ui)?; //let rows: (u16 | size) = if (sz.rows - 2 < len(list.items)) { @@ -90,6 +94,8 @@ export fn print(list: *listwidget) (void | io::error | tty::error) = { libui::print(list.ui, s); }; +// Notify (call) the listwidget's listeners with the listwidget and r as a +// parameter. export fn notify(l: *listwidget, r: rune) bool = { for (let i = 0z; i < len(l.listeners); i += 1) { if (l.listeners[i](l, r)) { @@ -99,6 +105,7 @@ export fn notify(l: *listwidget, r: rune) bool = { return false; }; +// Move the list's cursor down one item. Returns the new cursor. export fn down(l: *listwidget) size = { if (l.cursor < len(l.items) - 1) { l.cursor += 1; @@ -107,6 +114,7 @@ export fn down(l: *listwidget) size = { return l.cursor; }; +// Move the list's cursor up one item. Returns the new cursor. export fn up(l: *listwidget) size = { if (l.cursor > 0) { l.cursor -= 1; @@ -115,6 +123,8 @@ export fn up(l: *listwidget) size = { return l.cursor; }; +// Reset the list's frame based on the cursor. Returns whether the frame was +// updated. fn reframe(l: *listwidget) bool = { let reframed: bool = false; if (l.cursor < l.frame.start) { @@ -130,6 +140,7 @@ fn reframe(l: *listwidget) bool = { return reframed; }; +// Move the list's cursor to the top (first item). Returns the new cursor. export fn top(l: *listwidget) size = { l.cursor = 0; l.frame.start = 0; @@ -137,6 +148,7 @@ export fn top(l: *listwidget) size = { return l.cursor; }; +// Move the list's cursor to the bottom (last item). Returns the new cursor. export fn bottom(l: *listwidget) size = { l.cursor = len(l.items) - 1; l.frame.end = len(l.items): u16; @@ -144,11 +156,28 @@ export fn bottom(l: *listwidget) size = { return l.cursor; }; +// Forward search through the list's items for an item containing s. Returns the +// new cursor. export fn search(l: *listwidget, s: str) size = { - for (let i = 0z; i < len(l.items); i += 1) { + for (let i = l.cursor + 1; i < len(l.items); i += 1) { if (strings::contains(l.items[i], s)) { l.cursor = i; reframe(l); + return l.cursor; + }; + }; + return l.cursor; +}; + +// Backwards search through the list's items for an item containing s. Returns +// the new cursor. +export fn rsearch(l: *listwidget, s: str) size = { + // size wraps to max value for size when < 0 + for (let i = l.cursor: int - 1; i >= 0; i -= 1) { + if (strings::contains(l.items[i], s)) { + l.cursor = i: size; + reframe(l); + return l.cursor; }; }; return l.cursor; @@ -7,10 +7,13 @@ use os; use strings; use unix::tty; use unix::signal; +use bufio; -//let l: list::listwidget = list::listwidget {...}; let u: mainUI = mainUI {...}; +let searchterm: str = ""; +let searchforward: bool = true; + type mainUI = struct { list: *list::listwidget, }; @@ -24,8 +27,6 @@ fn globalrunehandler(ui: *libui::ttyui, r: rune) bool = { fn runehandler(l: *list::listwidget, r: rune) bool = { switch (r) { - case 'f' => - fmt::fprintln(os::stderr, "f in chat")!; case 'j' => list::down(l); case 'k' => @@ -38,17 +39,60 @@ fn runehandler(l: *list::listwidget, r: rune) bool = { return true; case 'g' => list::top(l); - //l.cursor = 0; case 'G' => list::bottom(l); - //l.cursor = len(l.items) - 1; - case '/' => - // TODO add commandline support - fmt::fprintln(os::stderr, "searching")!; + 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; - if (list::search(l, "workspace") != c) { - fmt::fprintln(os::stderr, "changed")!; + 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 '\n' => // For some reason enter doesn't send r == '\n' fmt::fprintln(os::stderr, "This is not detected")!; @@ -107,6 +151,7 @@ export fn main() void = { let l = list::newlist(ui, items...); libui::addlistener(&ui, &globalrunehandler); list::addlistener(&l, &runehandler); + defer free(searchterm); libui::clear(l.ui); match (list::print(&l)) { case void => |
