aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libui/libui.ha17
-rw-r--r--libui/list/list.ha31
-rw-r--r--main.ha65
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;
diff --git a/main.ha b/main.ha
index f1bd20e..4809a18 100644
--- a/main.ha
+++ b/main.ha
@@ -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 =>