From e074c936bb99ccfce311445f4dbf42ba964b44a4 Mon Sep 17 00:00:00 2001 From: Julian Hurst Date: Wed, 12 Mar 2025 22:36:13 +0100 Subject: Implement global state and clear scheduling --- cmd/list.ha | 6 +++--- cmd/list_nostyle.ha | 6 +++--- cmd/list_strictsz.ha | 6 +++--- cmd/text.ha | 20 +++++++++++++++++--- tui/tui.ha | 25 +++++++++++++++++++++---- tui/widget/list/list.ha | 7 ++++--- tui/widget/text/text.ha | 5 +++-- tui/widget/widget.ha | 32 +++++++++++++++++++------------- 8 files changed, 73 insertions(+), 34 deletions(-) diff --git a/cmd/list.ha b/cmd/list.ha index 0148adb..1db46b4 100644 --- a/cmd/list.ha +++ b/cmd/list.ha @@ -8,9 +8,9 @@ use fmt; use time; export fn main() void = { - const out = tui::init()!; - defer io::close(out)!; - let li = list::newlist(out, (1, 1), void, &widget::style { + const state = tui::init()!; + defer tui::finish(&state); + let li = list::newlist(&state, (1, 1), void, &widget::style { border = true, colorfg = widget::color::REDFG, colorbg = widget::color::REDBG, diff --git a/cmd/list_nostyle.ha b/cmd/list_nostyle.ha index 4e77955..4454220 100644 --- a/cmd/list_nostyle.ha +++ b/cmd/list_nostyle.ha @@ -8,9 +8,9 @@ use fmt; use time; export fn main() void = { - const out = tui::init()!; - defer io::close(out)!; - let li = list::newlist(out, (1, 1), void, void,"hello", "world", "bye", "world")!; + const state = tui::init()!; + defer tui::finish(&state); + let li = list::newlist(&state, (1, 1), void, void,"hello", "world", "bye", "world")!; let l = layout::newvlayout(&li); l.layout.print(&l); }; diff --git a/cmd/list_strictsz.ha b/cmd/list_strictsz.ha index 13c2808..e0a371d 100644 --- a/cmd/list_strictsz.ha +++ b/cmd/list_strictsz.ha @@ -8,9 +8,9 @@ use fmt; use time; export fn main() void = { - const out = tui::init()!; - defer io::close(out)!; - let li = list::newlist(out, (1, 1), tty::ttysize { + const state = tui::init()!; + defer tui::finish(&state); + let li = list::newlist(&state, (1, 1), tty::ttysize { rows = 3, columns = 4, }, &widget::style { diff --git a/cmd/text.ha b/cmd/text.ha index 3ec0f2a..f7ce1fc 100644 --- a/cmd/text.ha +++ b/cmd/text.ha @@ -7,9 +7,9 @@ use fmt; use time; export fn main() void = { - const out = tui::init()!; - defer io::close(out)!; - let txt = text::newtext(out, "hello world", (50, 20), &widget::style { + const state = tui::init()!; + defer tui::finish(&state); + let txt = text::newtext(&state, "hello world", (50, 20), &widget::style { border = true, colorfg = widget::color::REDFG, colorbg = widget::color::REDBG, @@ -17,32 +17,46 @@ export fn main() void = { let l = layout::newvlayout(&txt); l.layout.print(&l); + tui::clear(&state); + time::sleep(1 * time::SECOND); let st = txt.widget.style as *widget::style; st.colorfg = widget::color::GREENFG; text::settext(&txt, "bye world"); l.layout.print(&l); + tui::clear(&state); + time::sleep(1 * time::SECOND); st.colorfg = widget::color::BROWNFG; l.layout.print(&l); + tui::clear(&state); + time::sleep(1 * time::SECOND); st.colorfg = widget::color::BLUEFG; l.layout.print(&l); + tui::clear(&state); + time::sleep(1 * time::SECOND); st.colorfg = widget::color::MAGENTAFG; l.layout.print(&l); + tui::clear(&state); + time::sleep(1 * time::SECOND); st.colorfg = widget::color::CYANFG; l.layout.print(&l); + tui::clear(&state); + time::sleep(1 * time::SECOND); st.colorfg = widget::color::WHITEFG; l.layout.print(&l); + tui::clear(&state); + time::sleep(1 * time::SECOND); st.colorfg = widget::color::DEFAULTFG; l.layout.print(&l); diff --git a/tui/tui.ha b/tui/tui.ha index 871f847..4f6c1d5 100644 --- a/tui/tui.ha +++ b/tui/tui.ha @@ -2,13 +2,30 @@ use fmt; use io; use unix::tty; -export fn init() (io::file | tty::error) = { +export type tui = struct { + out: io::file, + clear: bool, +}; + +export fn init() (tui | tty::error) = { const f = tty::open()?; - clear(f); - return f; + doclear(f); + return tui { + out = f, + clear = false, + }; }; -export fn clear(out: io::file) void = { +fn doclear(out: io::file) void = { fmt::fprint(out, "\x1B[2J\x1B[1;1H")!; }; + +export fn clear(state: *tui) void = { + state.clear = true; + //fmt::fprint(out, "\x1B[2J\x1B[1;1H")!; +}; + +export fn finish(state: *tui) void = { + io::close(state.out)!; +}; diff --git a/tui/widget/list/list.ha b/tui/widget/list/list.ha index 50fb8df..ca7571b 100644 --- a/tui/widget/list/list.ha +++ b/tui/widget/list/list.ha @@ -1,3 +1,4 @@ +use tui; use tui::widget; use io; use unix::tty; @@ -18,9 +19,9 @@ export type list = struct { // Return an instance of list. out is the tty file, pos the starting position, // sz is the size of the widget (if void is used, the maximum possible // size is used), items is the slice of items of the list. -export fn newlist(out: io::file, pos: widget::coords, sz: widget::widgetsize, +export fn newlist(state: *tui::tui, pos: widget::coords, sz: widget::widgetsize, style: (*widget::style | void), items: str...) (list | tty::error) = { - const tsz = tty::winsize(out)?; + const tsz = tty::winsize(state.out)?; let end = match (sz) { case let sz: tty::ttysize => @@ -35,7 +36,7 @@ style: (*widget::style | void), items: str...) (list | tty::error) = { return list { widget = widget::widget { - out = out, + state = state, print = &printlist, resize = &resizelist, pos = pos, diff --git a/tui/widget/text/text.ha b/tui/widget/text/text.ha index ecb5c2c..d849661 100644 --- a/tui/widget/text/text.ha +++ b/tui/widget/text/text.ha @@ -1,5 +1,6 @@ use io; use unix::tty; +use tui; use tui::widget; use strings; @@ -8,10 +9,10 @@ export type text = struct { txt: str, }; -export fn newtext(out: io::file, txt: str, pos: widget::coords, style: (*widget::style | void)) text = { +export fn newtext(state: *tui::tui, txt: str, pos: widget::coords, style: (*widget::style | void)) text = { return text { widget = widget::widget { - out = out, + state = state, print = &printtext, resize = &resizetext, pos = pos, diff --git a/tui/widget/widget.ha b/tui/widget/widget.ha index f2510c6..a56203a 100644 --- a/tui/widget/widget.ha +++ b/tui/widget/widget.ha @@ -1,3 +1,4 @@ +use tui; use fmt; use unix::tty; use io; @@ -13,6 +14,16 @@ export type resizefn = fn(w: *widget, ttysize: tty::ttysize) void; export type widgetsize = (tty::ttysize | void); +export type widget = struct { + state: *tui::tui, + print: *printfn, + resize: *resizefn, + buf: str, + pos: coords, + sz: widgetsize, + style: (*style | void), +}; + export type color = enum uint { BLACKFG = 30, REDFG = 31, @@ -47,16 +58,6 @@ export def DEFAULT_STYLE: style = style { colorbg = color::DEFAULTBG, }; -export type widget = struct { - out: io::file, - print: *printfn, - resize: *resizefn, - buf: str, - pos: coords, - sz: widgetsize, - style: (*style | void), -}; - def gotoroot: str = "\x1B[1;1H"; def UNDERLINE: str = "\x1B[4m"; @@ -97,7 +98,6 @@ fn minrows(out: io::file, x: u16, y: widgetsize) (u16 | tty::error) = { fn color_to_str(color: color) str = fmt::asprintf("\x1B[{}m", strconv::utos(color)); export fn print(w: *widget) void = { - fmt::fprintf(w.out, "\x1B[{};{}H", w.pos.0, w.pos.1)!; let s = truncate_to_size(w); defer free(s); @@ -105,7 +105,13 @@ export fn print(w: *widget) void = { let sstyle = applystyles(w.style, s); defer free(sstyle); - fmt::fprint(w.out, sstyle)!; + const clear = if (w.state.clear) "\x1B[2J" else ""; + let seekpos = fmt::asprintf("{}\x1B[{};{}H", clear, w.pos.0, w.pos.1); + defer free(seekpos); + const sout = strings::concat(seekpos, sstyle); + defer free(sout); + + fmt::fprint(w.state.out, sout)!; }; // Applies styling (style) to the given string @@ -134,7 +140,7 @@ fn truncate_to_size(w: *widget) str = { let spl = strings::split(w.buf, "\n"); const st = memio::dynamic(); defer io::close(&st)!; - for (let i = 0z; i < minrows(w.out, len(spl): u16, w.sz)!; i += 1) { + for (let i = 0z; i < minrows(w.state.out, len(spl): u16, w.sz)!; i += 1) { const line = spl[i]; let item = match (w.sz) { case let sz: tty::ttysize => -- cgit v1.2.3