From 31911d0011155818efbd9edc15e32a6d81b2df3b Mon Sep 17 00:00:00 2001 From: csboo Date: Tue, 18 Mar 2025 23:34:25 +0100 Subject: [PATCH 01/37] git: ingore meson files --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index 796b96d..d38229e 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,4 @@ /build +.cache +compile_commands.json +meson.build From 8e43db254fbe9d2bd36e1f3b4fa4c0c709580d4a Mon Sep 17 00:00:00 2001 From: csboo Date: Tue, 18 Mar 2025 23:42:57 +0100 Subject: [PATCH 02/37] fix: enum -> enum class, with explicit base type --- tui.hpp | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/tui.hpp b/tui.hpp index 37be957..a892c78 100644 --- a/tui.hpp +++ b/tui.hpp @@ -1,6 +1,8 @@ // tui.hpp #pragma once +#include +#include #ifdef _WIN32 // windows #include @@ -249,7 +251,7 @@ namespace tui { namespace text { namespace style { - enum Style { + enum class Style : std::uint8_t { reset = 0, bold = 1, dim = 2, @@ -265,11 +267,13 @@ namespace tui { // generate for cout << STYLE_style(); eg.: cout << bold_style(); #define stylize(STYLE) \ - inline std::string STYLE##_style() { return style(STYLE); } + inline std::string STYLE##_style() { return style(Style::STYLE); } // generate for cout << STYLE_style(text); eg.: cout << bold_style(text); #define stylize_text(STYLE) \ - inline std::string STYLE##_style(const std::string& text) { return concat(style(STYLE), text, reset_style()); } \ - inline std::string STYLE##_style(const char* text) { return concat(style(STYLE), text, reset_style()); } + inline std::string STYLE##_style(const std::string& text) { \ + return concat(style(Style::STYLE), text, reset_style()); \ + } \ + inline std::string STYLE##_style(const char* text) { return concat(style(Style::STYLE), text, reset_style()); } // generate all #define make_stylizer(STYLE) stylize(STYLE) stylize_text(STYLE) @@ -302,7 +306,7 @@ namespace tui { } // namespace style namespace color { - enum Color { + enum class Color : std::uint8_t { black = 0, red, green, @@ -321,22 +325,22 @@ namespace tui { // generate for cout << COLOR_{fg, bg}(); #define colorize(COLOR) \ - inline std::string COLOR##_fg() { return colorizer(COLOR, true); } \ - inline std::string COLOR##_bg() { return colorizer(COLOR, false); } + inline std::string COLOR##_fg() { return colorizer(Color::COLOR, true); } \ + inline std::string COLOR##_bg() { return colorizer(Color::COLOR, false); } // generate for cout << COLOR_{fg, bg}(text); #define colorize_text(COLOR) \ inline std::string COLOR##_fg(const std::string& text) { \ - return concat(colorizer(COLOR, true), text, style::reset_style()); \ + return concat(colorizer(Color::COLOR, true), text, style::reset_style()); \ } \ inline std::string COLOR##_fg(const char* text) { \ - return concat(colorizer(COLOR, true), text, style::reset_style()); \ + return concat(colorizer(Color::COLOR, true), text, style::reset_style()); \ } \ inline std::string COLOR##_bg(const std::string& text) { \ - return concat(colorizer(COLOR, false), text, style::reset_style()); \ + return concat(colorizer(Color::COLOR, false), text, style::reset_style()); \ } \ inline std::string COLOR##_bg(const char* text) { \ - return concat(colorizer(COLOR, false), text, style::reset_style()); \ + return concat(colorizer(Color::COLOR, false), text, style::reset_style()); \ } // generate all From 0e459186c83784b876127c13d00e02ffd5e35c2a Mon Sep 17 00:00:00 2001 From: csboo Date: Tue, 18 Mar 2025 23:43:44 +0100 Subject: [PATCH 03/37] misc: format --- tui.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tui.hpp b/tui.hpp index a892c78..80cf4b6 100644 --- a/tui.hpp +++ b/tui.hpp @@ -227,7 +227,7 @@ namespace tui { return {rows, columns}; #else - struct winsize ws {}; + struct winsize ws{}; int fd = 0; // open the controlling terminal. @@ -425,7 +425,7 @@ namespace tui { // TODO: make it work, or at least try to #else // register the signal handler for SIGWINCH - struct sigaction sa {}; + struct sigaction sa{}; sa.sa_handler = handle_resize; sa.sa_flags = SA_RESTART; // restart functions if interrupted by handler sigaction(SIGWINCH, &sa, nullptr); From 427fc42aa989971e93227295dfeed8bb928bb4fd Mon Sep 17 00:00:00 2001 From: csboo Date: Tue, 18 Mar 2025 23:45:14 +0100 Subject: [PATCH 04/37] fix: an unsigned must be >= 0, assertion not needed --- tui.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tui.hpp b/tui.hpp index 80cf4b6..74f0a52 100644 --- a/tui.hpp +++ b/tui.hpp @@ -360,7 +360,7 @@ namespace tui { // r, g, b values have to be valid: [0;255] inline std::string rgb(unsigned r, unsigned g, unsigned b, bool fg) { - assert(r >= 0 && r <= 255 && g >= 0 && g <= 255 && b >= 0 && b <= 255); + assert(r <= 255 && g <= 255 && b <= 255); return concat(CSI, (fg ? '3' : '4'), "8;2;", r, ';', g, ';', b, 'm'); } inline std::string rgb(unsigned r, unsigned g, unsigned b, bool fg, const std::string& text) { From 5353a7da3f0925d3c1727cc88e52d9f7396b4ceb Mon Sep 17 00:00:00 2001 From: csboo Date: Tue, 18 Mar 2025 23:50:23 +0100 Subject: [PATCH 05/37] fix: enum classes, most value now strictly static cast --- input.hpp | 53 +++++++++++++++++++++++++++-------------------------- 1 file changed, 27 insertions(+), 26 deletions(-) diff --git a/input.hpp b/input.hpp index 175a57d..86328bf 100644 --- a/input.hpp +++ b/input.hpp @@ -1,6 +1,7 @@ #pragma once #include "tui.hpp" +#include #include // Platform-specific includes @@ -23,7 +24,7 @@ #define DEM(X1, X2, X3, X4) _DCEM(X1), _DCEM(X2), _DCEM(X3), _DCEM(X4) // TODO: maybe add keys: F(5-12) NOTE: shall need an own `struct F {num: u8}`, ... -enum SpecKey { +enum class SpecKey : std::uint8_t { CtrlA = 1, DEM(B, C, D, E), DEM(F, G, H, I), @@ -52,7 +53,7 @@ enum SpecKey { #undef DCEM #undef DEM -enum Arrow { +enum class Arrow : std::uint8_t { Up = 65, Down = 66, Right = 67, @@ -71,13 +72,13 @@ inline std::string ctrl_to_str(const unsigned& key) { return tui::concat("Ctrl", inline std::ostream& operator<<(std::ostream& os, const SpecKey& special) { switch (special) { - CRSS(Esc, Tab, Backspace, Enter); - CRSS(F1, F2, F3, F4); - CRSS(Home, End, PageUp, PageDown); - CRSS(ShiftTab, Insert, Delete, None); + CRSS(SpecKey::Esc, SpecKey::Tab, SpecKey::Backspace, SpecKey::Enter); + CRSS(SpecKey::F1, SpecKey::F2, SpecKey::F3, SpecKey::F4); + CRSS(SpecKey::Home, SpecKey::End, SpecKey::PageUp, SpecKey::PageDown); + CRSS(SpecKey::ShiftTab, SpecKey::Insert, SpecKey::Delete, SpecKey::None); default: - if (special >= 1 && special <= 26) { - return os << ctrl_to_str(special); + if (static_cast(special) >= 1 && static_cast(special) <= 26) { + return os << ctrl_to_str(static_cast(special)); } os << "Unknown"; } @@ -86,7 +87,7 @@ inline std::ostream& operator<<(std::ostream& os, const SpecKey& special) { inline std::ostream& operator<<(std::ostream& os, const Arrow& arrow) { switch (arrow) { - CRSS(Up, Down, Right, Left); + CRSS(Arrow::Up, Arrow::Down, Arrow::Right, Arrow::Left); default: os << "Unknown"; } @@ -188,10 +189,10 @@ struct Input { } switch (byte) { - case SpecKey::Backspace: + case 127: input = Input(static_cast(byte)); break; - case SpecKey::Esc: { + case 27: { #ifndef _WIN32 set_non_blocking(true); char next_byte = get_char(); @@ -199,26 +200,26 @@ struct Input { if (next_byte == 79 || next_byte == 91) { char special = get_char(); switch (special) { - case Arrow::Up: - case Arrow::Down: - case Arrow::Right: - case Arrow::Left: + case 65: + case 66: + case 67: + case 68: input = Input(static_cast(special)); break; - case SpecKey::F1: - case SpecKey::F2: - case SpecKey::F3: - case SpecKey::F4: - case SpecKey::End: - case SpecKey::Home: - case SpecKey::ShiftTab: + case 80: + case 81: + case 82: + case 83: + case 72: + case 70: + case 90: input = Input(static_cast(special)); break; - case SpecKey::Insert: - case SpecKey::Delete: - case SpecKey::PageUp: - case SpecKey::PageDown: ignore_byte = get_char(); // ~ + case 50: + case 51: + case 53: + case 54: input = Input(static_cast(special)); break; default: From 0d17058949dacbee143886df20e4fc29ee6d9e9f Mon Sep 17 00:00:00 2001 From: csboo Date: Tue, 18 Mar 2025 23:51:30 +0100 Subject: [PATCH 06/37] fix: removed unused variable --- input.hpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/input.hpp b/input.hpp index 86328bf..0a13636 100644 --- a/input.hpp +++ b/input.hpp @@ -139,7 +139,6 @@ struct Input { static Input read_helper(reader_fn get_char) { char byte = get_char(); - char ignore_byte = 0; auto input = Input(SpecKey::None); #ifdef _WIN32 if (byte == 0 || byte == 224 || byte == -32) { @@ -179,7 +178,7 @@ struct Input { } #else if (byte < 0) { - ignore_byte = get_char(); + get_char(); // ignore } #endif if (byte >= 32 && byte <= 126) { // @@ -215,11 +214,11 @@ struct Input { case 90: input = Input(static_cast(special)); break; - ignore_byte = get_char(); // ~ case 50: case 51: case 53: case 54: + get_char(); // ignore input = Input(static_cast(special)); break; default: From 7ebbfef4f8deb290f53b315ee84709be88112ebc Mon Sep 17 00:00:00 2001 From: csboo Date: Tue, 18 Mar 2025 23:52:26 +0100 Subject: [PATCH 07/37] fix: properly ordered struct member initialization --- input.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/input.hpp b/input.hpp index 0a13636..3be30ec 100644 --- a/input.hpp +++ b/input.hpp @@ -106,9 +106,9 @@ struct Input { SpecKey special = SpecKey::None; Input() = default; - Input(const Arrow& arrow) : arrow(arrow), is_arrow(true) {} - Input(const char& ch) : ch(ch), is_ch(true) {} - Input(const SpecKey& special) : special(special), is_special(true) {} + Input(const Arrow& arrow) : is_arrow(true), arrow(arrow) {} + Input(const char& ch) : is_ch(true), ch(ch) {} + Input(const SpecKey& special) : is_special(true), special(special) {} bool operator==(const Input& other) const { return (this->ch == other.ch && this->is_ch == other.is_ch && this->arrow == other.arrow && From 1268e7aaf24cd0230178206de3259b0bbb47385d Mon Sep 17 00:00:00 2001 From: csboo Date: Tue, 18 Mar 2025 23:54:01 +0100 Subject: [PATCH 08/37] fix: marked function static --- examples/boxes.cpp | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/examples/boxes.cpp b/examples/boxes.cpp index b3285de..8a78b18 100644 --- a/examples/boxes.cpp +++ b/examples/boxes.cpp @@ -11,7 +11,7 @@ using namespace tui::input; using Box = std::pair; -struct AppState { +static struct AppState { Input input; bool quit = false; bool new_input = true; @@ -20,8 +20,9 @@ struct AppState { // make `x` be good for `counter_box` [[nodiscard]] -std::string count(const uint64_t& x) { unsigned r = 0; + +static std::string count(const uint64_t& x) { std::string print; if (x % 100 == 0) { print = std::to_string(x / 100); @@ -36,7 +37,7 @@ std::string count(const uint64_t& x) { return print; } -void counter_box(Coord start, Coord end) { +static void counter_box(Coord start, Coord end) { assert(start.row <= end.row && start.col <= end.col); // do rows @@ -82,7 +83,7 @@ const std::vector> KINDS = {{{" ", " ", " ", " ", " ", // | | // | | // end.row ---------------- end.col -void draw_box(Box box, Kind with) { +static void draw_box(Box box, Kind with) { auto start = box.first; auto end = box.second; assert(start.row <= end.row && start.col <= end.col); @@ -114,7 +115,7 @@ void draw_box(Box box, Kind with) { std::cout << draw[3]; } -void handle_keys(std::vector& boxes, unsigned& cnt_box_ix) { +static void handle_keys(std::vector& boxes, unsigned& cnt_box_ix) { auto* cnt_box = &boxes[cnt_box_ix]; if (state.input == 'n' || state.input == SpecKey::Tab) { if (cnt_box_ix++ == boxes.size() - 1) { @@ -159,7 +160,7 @@ void handle_keys(std::vector& boxes, unsigned& cnt_box_ix) { boxes.erase(boxes.begin() + cnt_box_ix); } } -void run() { +static void run() { const auto msg = tui::string("Szia Csongi!"); auto msg_coord = [msg](bool left) { return Coord{state.size.row / 2 + 1, @@ -218,7 +219,7 @@ void run() { } while (!state.quit); } -void handle_read() { +static void handle_read() { while (state.input != 'q' && state.input != SpecKey::CtrlC) { state.input = Input::read(); state.new_input = true; From 286f0200cff47773b14f1bdb5b8a9271afe73a4a Mon Sep 17 00:00:00 2001 From: csboo Date: Tue, 18 Mar 2025 23:55:07 +0100 Subject: [PATCH 09/37] fix: enum -> enum class : uint8_t --- examples/boxes.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/examples/boxes.cpp b/examples/boxes.cpp index 8a78b18..c321aac 100644 --- a/examples/boxes.cpp +++ b/examples/boxes.cpp @@ -62,11 +62,11 @@ static void counter_box(Coord start, Coord end) { } } -enum Kind { - Empty, - Basic, - Bold, - Rounded, +enum class Kind : std::uint8_t{ + Empty = 0, + Basic = 1, + Bold = 2, + Rounded = 3, }; const std::vector> KINDS = {{{" ", " ", " ", " ", " ", " "}}, From b88bfb60c2b3b92ba5017072882887adf93e9ada Mon Sep 17 00:00:00 2001 From: csboo Date: Tue, 18 Mar 2025 23:57:07 +0100 Subject: [PATCH 10/37] fix: initialize draw type as a ref, with vec.at(), strict type case --- examples/boxes.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/boxes.cpp b/examples/boxes.cpp index c321aac..39c0e1d 100644 --- a/examples/boxes.cpp +++ b/examples/boxes.cpp @@ -88,7 +88,7 @@ static void draw_box(Box box, Kind with) { auto end = box.second; assert(start.row <= end.row && start.col <= end.col); - auto draw = KINDS[with]; + const auto& draw = KINDS.at(static_cast(with)); // do rows for (auto row = start.row + 1; row < end.row; ++row) { From 29a6a6ba2c9a946c872b3c9a79db2a8401cd49dd Mon Sep 17 00:00:00 2001 From: csboo Date: Tue, 18 Mar 2025 23:57:37 +0100 Subject: [PATCH 11/37] fix: unused var --- examples/boxes.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/boxes.cpp b/examples/boxes.cpp index 39c0e1d..99e61cf 100644 --- a/examples/boxes.cpp +++ b/examples/boxes.cpp @@ -20,9 +20,9 @@ static struct AppState { // make `x` be good for `counter_box` [[nodiscard]] - unsigned r = 0; static std::string count(const uint64_t& x) { + // unsigned r = 0; std::string print; if (x % 100 == 0) { print = std::to_string(x / 100); From c7e581410315bd08ba9e66c12d866224409ff48b Mon Sep 17 00:00:00 2001 From: csboo Date: Wed, 19 Mar 2025 00:03:39 +0100 Subject: [PATCH 12/37] misc: use more parentheses for math expressions --- examples/boxes.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/boxes.cpp b/examples/boxes.cpp index 99e61cf..eed2b99 100644 --- a/examples/boxes.cpp +++ b/examples/boxes.cpp @@ -163,8 +163,8 @@ static void handle_keys(std::vector& boxes, unsigned& cnt_box_ix) { static void run() { const auto msg = tui::string("Szia Csongi!"); auto msg_coord = [msg](bool left) { - return Coord{state.size.row / 2 + 1, - static_cast((state.size.col / 2) + (left ? -msg.size() : +msg.size()) / 2)}; + return Coord{(state.size.row / 2) + 1, + static_cast((state.size.col / 2) + ((left ? -msg.size() : +msg.size()) / 2))}; }; std::vector boxes = { From 4eb064d61e38fd6d370bfc9d10f9e82bbecdffc1 Mon Sep 17 00:00:00 2001 From: csboo Date: Wed, 19 Mar 2025 00:04:25 +0100 Subject: [PATCH 13/37] fix: [nodiscard] is a c++17 extension --- examples/boxes.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/examples/boxes.cpp b/examples/boxes.cpp index eed2b99..8c01891 100644 --- a/examples/boxes.cpp +++ b/examples/boxes.cpp @@ -19,7 +19,6 @@ static struct AppState { } state; // make `x` be good for `counter_box` -[[nodiscard]] static std::string count(const uint64_t& x) { // unsigned r = 0; From 81b0cac2a850e99266e7d24c650fcee2935cd3eb Mon Sep 17 00:00:00 2001 From: csboo Date: Wed, 19 Mar 2025 00:04:54 +0100 Subject: [PATCH 14/37] misc: use more parentheses for math expressions --- examples/hello_world.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/hello_world.cpp b/examples/hello_world.cpp index 22277fb..47f5786 100644 --- a/examples/hello_world.cpp +++ b/examples/hello_world.cpp @@ -14,11 +14,11 @@ int main() { while (input != SpecKey::CtrlC && input != 'q') { // main loop // NOTE: use `.size()` before styling, as it'd be completely crazy after applying styles // `msg` will be in the middle of the screen - tui::cursor::set_position(screen_size.first / 2 - 1, screen_size.second / 2 - (msg.size() / 2)); + tui::cursor::set_position((screen_size.first / 2) - 1, (screen_size.second / 2) - (msg.size() / 2)); std::cout << msg.blue().link("https://github.com/csboo/cpptui").bold().underline(); // `msg` will be in the middle of the screen - tui::cursor::set_position(screen_size.first / 2 + 1, screen_size.second / 2 - (note.size() / 2)); + tui::cursor::set_position((screen_size.first / 2) + 1, (screen_size.second / 2) - (note.size() / 2)); std::cout << note.on_rgb(106, 150, 137).rgb(148, 105, 117).italic().dim(); std::cout.flush(); From dbfcd512d85392f57953a99e56335c75160f0958 Mon Sep 17 00:00:00 2001 From: csboo Date: Wed, 19 Mar 2025 00:05:36 +0100 Subject: [PATCH 15/37] fix: marked structs static --- examples/screen-filler.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/screen-filler.cpp b/examples/screen-filler.cpp index 7bc9036..0d95482 100644 --- a/examples/screen-filler.cpp +++ b/examples/screen-filler.cpp @@ -4,7 +4,7 @@ using namespace tui::input; -struct State { +static struct State { Input input; bool quit = false; } state; @@ -12,7 +12,7 @@ struct State { const Coord TOP_LEFT = Coord::origin(); const tui::string CH = tui::string(" "); -void read_char() { +static void read_char() { while (state.input != 'q' && state.input != SpecKey::CtrlC) { state.input = Input::read(); std::this_thread::sleep_for(std::chrono::milliseconds(8)); @@ -20,7 +20,7 @@ void read_char() { state.quit = true; } -void run() { +static void run() { auto screen_size = Coord(); auto prev_screen_size = screen_size; From 962ae574279b812d4e6397cece561e1a850ca4e9 Mon Sep 17 00:00:00 2001 From: csboo Date: Wed, 19 Mar 2025 00:05:43 +0100 Subject: [PATCH 16/37] misc: use more parentheses for math expressions --- examples/screen-filler.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/screen-filler.cpp b/examples/screen-filler.cpp index 0d95482..090efc9 100644 --- a/examples/screen-filler.cpp +++ b/examples/screen-filler.cpp @@ -47,8 +47,8 @@ static void run() { auto mod_mid_ver = screen_size.row % 2; auto even_mid_ver = mod_mid_ver == 0; - auto mid_hor = screen_size.col / 2 + mod_mid_hor; - auto mid_ver = screen_size.row / 2 + mod_mid_ver; + auto mid_hor = (screen_size.col / 2) + mod_mid_hor; + auto mid_ver = (screen_size.row / 2) + mod_mid_ver; auto mid_mid = Coord(mid_ver, mid_hor); TOP_LEFT.print(CH.on_black()); From e00f9dea6f0afaf4eff21ad385335601e9774b47 Mon Sep 17 00:00:00 2001 From: csboo Date: Wed, 19 Mar 2025 00:06:13 +0100 Subject: [PATCH 17/37] fix: marked functions static --- examples/read_event.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/examples/read_event.cpp b/examples/read_event.cpp index 4852734..49cb66a 100644 --- a/examples/read_event.cpp +++ b/examples/read_event.cpp @@ -8,14 +8,14 @@ using tui::input::Input; using tui::input::SpecKey; -std::mutex mtx; -std::condition_variable cv; -Input shared_input; -bool input_available = false; +static std::mutex mtx; +static std::condition_variable cv; +static Input shared_input; +static bool input_available = false; -bool should_quit(const Input& input) { return input == SpecKey::CtrlC || input == 'q'; } +static bool should_quit(const Input& input) { return input == SpecKey::CtrlC || input == 'q'; } -void read_input() { +static void read_input() { while (!should_quit(shared_input)) { shared_input = Input::read(); std::lock_guard lock(mtx); @@ -25,7 +25,7 @@ void read_input() { } } -void main_task() { +static void main_task() { int i = 0; while (true) { std::this_thread::sleep_for(std::chrono::milliseconds(40)); From a80aa83f8b466082ab9e4686cb233dd2d14f4fe4 Mon Sep 17 00:00:00 2001 From: csboo Date: Wed, 19 Mar 2025 00:07:15 +0100 Subject: [PATCH 18/37] fix: marked some function static --- examples/read_input.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/read_input.cpp b/examples/read_input.cpp index 6702946..488649c 100644 --- a/examples/read_input.cpp +++ b/examples/read_input.cpp @@ -3,7 +3,7 @@ using namespace tui::input; // get's called on terminall resize -void clear(int /*sig*/) { +static void clear(int /*sig*/) { tui::screen::clear(); // clears screen tui::cursor::home(); // sets the cursor to the top left corner of the screen // no need to flush `cout`, as `'\n'` does it (well, yeah. don't ask me why though) From 9dbef13dc265bba2f78698a89e421633694f7d07 Mon Sep 17 00:00:00 2001 From: csboo Date: Wed, 19 Mar 2025 00:09:20 +0100 Subject: [PATCH 19/37] fix: comment out unused var --- examples/snake.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/snake.cpp b/examples/snake.cpp index 0481ed2..86a2f1a 100644 --- a/examples/snake.cpp +++ b/examples/snake.cpp @@ -3,7 +3,7 @@ #include #include #include -#include +// #include // needed if MAX_MS is used #include #include #include @@ -18,7 +18,7 @@ const Coord SCORE_COUNT = Coord{2, 4}; // this is the default duration a frame lives for in ms, it's 23.8 fps const std::chrono::milliseconds SLEEP_MS = std::chrono::milliseconds(42); const std::chrono::milliseconds ADD_MS = std::chrono::milliseconds(1); -const std::chrono::milliseconds MAX_MS = std::chrono::milliseconds(std::numeric_limits::infinity()); +// const std::chrono::milliseconds MAX_MS = std::chrono::milliseconds(std::numeric_limits::infinity()); // initial size/lenght of the snake: at the game start const unsigned INIT_LEN = 5; From 3e50201bc054a3d8e7fa8e40694050e3b13b2a43 Mon Sep 17 00:00:00 2001 From: csboo Date: Wed, 19 Mar 2025 00:10:55 +0100 Subject: [PATCH 20/37] fix: marked functions and objects static --- examples/snake.cpp | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/examples/snake.cpp b/examples/snake.cpp index 86a2f1a..3d73538 100644 --- a/examples/snake.cpp +++ b/examples/snake.cpp @@ -2,6 +2,8 @@ #include "../tui.hpp" #include #include +#include +#include #include // #include // needed if MAX_MS is used #include @@ -30,7 +32,7 @@ enum Dir { Right, None, }; -Dir opposite(const Dir& dir) { +static Dir opposite(const Dir& dir) { switch (dir) { case Dir::Up: return Dir::Down; @@ -45,7 +47,7 @@ Dir opposite(const Dir& dir) { } return Dir::None; } -Dir from_input(const Input& input, const Dir& dir = Dir::Right) { +static Dir from_input(const Input& input, const Dir& dir = Dir::Right) { switch (input.ch) { case 'k': case 'w': @@ -77,7 +79,7 @@ Dir from_input(const Input& input, const Dir& dir = Dir::Right) { return dir; } -std::string to_string(const Dir& dir) { +static std::string to_string(const Dir& dir) { switch (dir) { case Dir::Up: return "↑"; // alt: ^ @@ -93,7 +95,7 @@ std::string to_string(const Dir& dir) { return "X"; } -Dir meets_at(const Coord& lhs, const Coord& rhs, const Coord& screen_size) { +static Dir meets_at(const Coord& lhs, const Coord& rhs, const Coord& screen_size) { int row_diff = static_cast(lhs.row) - static_cast(rhs.row); int col_diff = static_cast(lhs.col) - static_cast(rhs.col); @@ -117,7 +119,7 @@ Dir meets_at(const Coord& lhs, const Coord& rhs, const Coord& screen_size) { using Snake = std::vector; -std::string draw(const std::pair& nb) { +static std::string draw(const std::pair& nb) { // rounded: {"╭", "╮", "╰", "╯", "│", "─"} // this is where in Rust we'd use `match` and be happy @@ -146,7 +148,7 @@ std::string draw(const std::pair& nb) { return "X"; } -struct App { +static struct App { Coord screen_size = Coord::screen_size(); Snake snake = App::default_snake(); Coord apple = Coord::random(this->screen_size); @@ -268,7 +270,7 @@ struct App { } app; -void handle_read() { +static void handle_read() { while (!app.quit && app.input != 'q' && app.input != 'Q' && app.input != SpecKey::CtrlC && app.input != SpecKey::CtrlD && app.input != SpecKey::CtrlZ) { app.input = Input::read(); @@ -278,7 +280,7 @@ void handle_read() { std::cout << "reader thread done\n"; } -void run() { +static void run() { app.apple.print(APPLE_TEXT); do { // get direction From 3317a821325de49b2541c15de633367a9d48be56 Mon Sep 17 00:00:00 2001 From: csboo Date: Wed, 19 Mar 2025 00:12:15 +0100 Subject: [PATCH 21/37] fix: static_cast most values --- examples/snake.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/examples/snake.cpp b/examples/snake.cpp index 3d73538..1a7f8b7 100644 --- a/examples/snake.cpp +++ b/examples/snake.cpp @@ -102,16 +102,16 @@ static Dir meets_at(const Coord& lhs, const Coord& rhs, const Coord& screen_size // we set both row and col to x-1 as it's needed :D auto teleport = Coord{screen_size.row - 1, screen_size.col - 1}; - if (row_diff == 1 || teleport.row == -row_diff) { + if (row_diff == 1 || static_cast(teleport.row) == -row_diff) { return Dir::Up; } - if (row_diff == -1 || teleport.row == row_diff) { + if (row_diff == -1 || static_cast(teleport.row) == row_diff) { return Dir::Down; } - if (col_diff == 1 || teleport.col == -col_diff) { + if (col_diff == 1 || static_cast(teleport.col) == -col_diff) { return Dir::Left; } - if (col_diff == -1 || teleport.col == col_diff) { + if (col_diff == -1 || static_cast(teleport.col) == col_diff) { return Dir::Right; } return Dir::None; @@ -159,7 +159,7 @@ static struct App { static Snake default_snake() { auto mid = Coord::screen_size() / 2; Snake snake; - for (auto i = 0; i < INIT_LEN; ++i) { + for (auto i = 0; i < static_cast(INIT_LEN); ++i) { snake.push_back(mid.with_col(mid.col - i)); } return snake; From ce8be9e0dee5975ddfe9e1496c00ce3eac40604b Mon Sep 17 00:00:00 2001 From: csboo Date: Wed, 19 Mar 2025 00:14:56 +0100 Subject: [PATCH 22/37] fix: enum -> enum class : uint8_t --- examples/snake.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/snake.cpp b/examples/snake.cpp index 1a7f8b7..f859b88 100644 --- a/examples/snake.cpp +++ b/examples/snake.cpp @@ -25,7 +25,7 @@ const std::chrono::milliseconds ADD_MS = std::chrono::milliseconds(1); const unsigned INIT_LEN = 5; // direction -enum Dir { +enum class Dir : std::uint8_t { Up = 0, Down, Left, @@ -261,7 +261,7 @@ static struct App { // delete the last one off the screen by overwriting it with a space this->snake.back().print(' '); auto old_snake = this->snake; - for (auto i = 1; i < this->snake.size(); ++i) { + for (size_t i = 1; i < this->snake.size(); ++i) { this->snake.at(i) = old_snake.at(i - 1); } From a1a8a5fa9198bacb44299e5c83449e9a0443515d Mon Sep 17 00:00:00 2001 From: csboo Date: Tue, 18 Mar 2025 23:50:23 +0100 Subject: [PATCH 23/37] fix: enum classes, most value now strictly static cast --- input.hpp | 1 - 1 file changed, 1 deletion(-) diff --git a/input.hpp b/input.hpp index 3be30ec..27fbbb1 100644 --- a/input.hpp +++ b/input.hpp @@ -218,7 +218,6 @@ struct Input { case 51: case 53: case 54: - get_char(); // ignore input = Input(static_cast(special)); break; default: From f0db907b9a0959a6a1599e4ef4fe70354b48a587 Mon Sep 17 00:00:00 2001 From: csboo Date: Tue, 18 Mar 2025 23:51:30 +0100 Subject: [PATCH 24/37] fix: removed unused variable --- input.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/input.hpp b/input.hpp index 27fbbb1..3be30ec 100644 --- a/input.hpp +++ b/input.hpp @@ -218,6 +218,7 @@ struct Input { case 51: case 53: case 54: + get_char(); // ignore input = Input(static_cast(special)); break; default: From e135b0cac56ca31e313372ad9d3a886978416054 Mon Sep 17 00:00:00 2001 From: csboo Date: Tue, 18 Mar 2025 23:54:01 +0100 Subject: [PATCH 25/37] fix: marked function static --- examples/boxes.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/examples/boxes.cpp b/examples/boxes.cpp index 8c01891..4c2f217 100644 --- a/examples/boxes.cpp +++ b/examples/boxes.cpp @@ -19,9 +19,7 @@ static struct AppState { } state; // make `x` be good for `counter_box` - static std::string count(const uint64_t& x) { - // unsigned r = 0; std::string print; if (x % 100 == 0) { print = std::to_string(x / 100); From af6dac41f33dbc529e0cdd14e0c99bf97874c5e0 Mon Sep 17 00:00:00 2001 From: csboo Date: Tue, 18 Mar 2025 23:57:37 +0100 Subject: [PATCH 26/37] fix: unused var --- examples/boxes.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/boxes.cpp b/examples/boxes.cpp index 4c2f217..c8974d9 100644 --- a/examples/boxes.cpp +++ b/examples/boxes.cpp @@ -20,6 +20,7 @@ static struct AppState { // make `x` be good for `counter_box` static std::string count(const uint64_t& x) { + // unsigned r = 0; std::string print; if (x % 100 == 0) { print = std::to_string(x / 100); From da60c63e5672fa70807a9fe1dfebfb5c104f71e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jeromos=20Kov=C3=A1cs?= Date: Wed, 19 Mar 2025 15:03:08 +0100 Subject: [PATCH 27/37] refactor: satisfy `clangd` with many `static`s --- tui.hpp | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/tui.hpp b/tui.hpp index 74f0a52..0c46440 100644 --- a/tui.hpp +++ b/tui.hpp @@ -267,13 +267,15 @@ namespace tui { // generate for cout << STYLE_style(); eg.: cout << bold_style(); #define stylize(STYLE) \ - inline std::string STYLE##_style() { return style(Style::STYLE); } + static inline std::string STYLE##_style() { return style(Style::STYLE); } // generate for cout << STYLE_style(text); eg.: cout << bold_style(text); #define stylize_text(STYLE) \ - inline std::string STYLE##_style(const std::string& text) { \ + static inline std::string STYLE##_style(const std::string& text) { \ return concat(style(Style::STYLE), text, reset_style()); \ } \ - inline std::string STYLE##_style(const char* text) { return concat(style(Style::STYLE), text, reset_style()); } + static inline std::string STYLE##_style(const char* text) { \ + return concat(style(Style::STYLE), text, reset_style()); \ + } // generate all #define make_stylizer(STYLE) stylize(STYLE) stylize_text(STYLE) @@ -325,22 +327,22 @@ namespace tui { // generate for cout << COLOR_{fg, bg}(); #define colorize(COLOR) \ - inline std::string COLOR##_fg() { return colorizer(Color::COLOR, true); } \ - inline std::string COLOR##_bg() { return colorizer(Color::COLOR, false); } + static inline std::string COLOR##_fg() { return colorizer(Color::COLOR, true); } \ + static inline std::string COLOR##_bg() { return colorizer(Color::COLOR, false); } // generate for cout << COLOR_{fg, bg}(text); #define colorize_text(COLOR) \ - inline std::string COLOR##_fg(const std::string& text) { \ - return concat(colorizer(Color::COLOR, true), text, style::reset_style()); \ + static inline std::string COLOR##_fg(const std::string& text) { \ + return concat(colorizer(Color::COLOR, true), text, style::reset_style()); \ } \ - inline std::string COLOR##_fg(const char* text) { \ - return concat(colorizer(Color::COLOR, true), text, style::reset_style()); \ + static inline std::string COLOR##_fg(const char* text) { \ + return concat(colorizer(Color::COLOR, true), text, style::reset_style()); \ } \ - inline std::string COLOR##_bg(const std::string& text) { \ - return concat(colorizer(Color::COLOR, false), text, style::reset_style()); \ + static inline std::string COLOR##_bg(const std::string& text) { \ + return concat(colorizer(Color::COLOR, false), text, style::reset_style()); \ } \ - inline std::string COLOR##_bg(const char* text) { \ - return concat(colorizer(Color::COLOR, false), text, style::reset_style()); \ + static inline std::string COLOR##_bg(const char* text) { \ + return concat(colorizer(Color::COLOR, false), text, style::reset_style()); \ } // generate all @@ -408,11 +410,9 @@ namespace tui { make_color(basic); #undef make_color - inline string link(const char* link) { return text::style::link(link, *this); } - inline string rgb(unsigned r, unsigned g, unsigned b) const { return text::color::rgb(r, g, b, true, *this); } - inline string on_rgb(unsigned r, unsigned g, unsigned b) const { - return text::color::rgb(r, g, b, false, *this); - } + string link(const char* link) { return text::style::link(link, *this); } + string rgb(unsigned r, unsigned g, unsigned b) const { return text::color::rgb(r, g, b, true, *this); } + string on_rgb(unsigned r, unsigned g, unsigned b) const { return text::color::rgb(r, g, b, false, *this); } }; // void handle_resize(int /*sig*/) { screen::clear(); } From 79084c22f6dc908df9e4b72f7bb2ccdcd9219e6e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jeromos=20Kov=C3=A1cs?= Date: Wed, 19 Mar 2025 15:22:13 +0100 Subject: [PATCH 28/37] misc: down with `anonymous-namespace` and `boost` suggestions --- .clang-tidy | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.clang-tidy b/.clang-tidy index 7539cab..68ffd8d 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -2,7 +2,6 @@ Checks: abseil-*, altera-*, android-*, - boost-*, bugprone-*, cert-*, clang-*analyzer-*, @@ -23,6 +22,7 @@ Checks: portability-*, readability-*, zircon-*, + -boost-*, -llvmlibc-*, -altera-unroll-loops, -hicpp-vararg, @@ -47,6 +47,7 @@ Checks: -readability-magic-numbers, -altera-struct-pack-align, -misc-non-private-member-variables-in-classes, + -misc-use-anonymous-namespace, -concurrency-mt-unsafe, -cert-env33-c, -cert-err58-cpp, From b1e3ff3d79c8a41491554b0cb3dee739dc20bccd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jeromos=20Kov=C3=A1cs?= Date: Wed, 19 Mar 2025 15:26:41 +0100 Subject: [PATCH 29/37] refactor(tui)!: don't directly include `input.hpp` --- examples/boxes.cpp | 5 ++--- examples/hello_world.cpp | 3 +-- examples/read_event.cpp | 4 +--- examples/read_input.cpp | 3 +-- examples/screen-filler.cpp | 3 +-- examples/snake.cpp | 3 +-- tui.hpp | 3 --- 7 files changed, 7 insertions(+), 17 deletions(-) diff --git a/examples/boxes.cpp b/examples/boxes.cpp index c8974d9..a3ae221 100644 --- a/examples/boxes.cpp +++ b/examples/boxes.cpp @@ -1,4 +1,5 @@ #include "../coords.hpp" +#include "../input.hpp" #include "../tui.hpp" #include #include @@ -7,8 +8,6 @@ #include #include -using namespace tui::input; - using Box = std::pair; static struct AppState { @@ -60,7 +59,7 @@ static void counter_box(Coord start, Coord end) { } } -enum class Kind : std::uint8_t{ +enum class Kind : std::uint8_t { Empty = 0, Basic = 1, Bold = 2, diff --git a/examples/hello_world.cpp b/examples/hello_world.cpp index 47f5786..7b0d138 100644 --- a/examples/hello_world.cpp +++ b/examples/hello_world.cpp @@ -1,8 +1,7 @@ +#include "../input.hpp" #include "../tui.hpp" #include // for std::pair -using namespace tui::input; - int main() { tui::init(false); // alternate buffer, raw mode, no cursor auto screen_size = tui::screen::size(); // initially set diff --git a/examples/read_event.cpp b/examples/read_event.cpp index 49cb66a..9bd1ac3 100644 --- a/examples/read_event.cpp +++ b/examples/read_event.cpp @@ -1,3 +1,4 @@ +#include "../input.hpp" #include "../tui.hpp" #include #include @@ -5,9 +6,6 @@ #include #include -using tui::input::Input; -using tui::input::SpecKey; - static std::mutex mtx; static std::condition_variable cv; static Input shared_input; diff --git a/examples/read_input.cpp b/examples/read_input.cpp index 488649c..6733a61 100644 --- a/examples/read_input.cpp +++ b/examples/read_input.cpp @@ -1,6 +1,5 @@ #include "../tui.hpp" - -using namespace tui::input; +#include "../input.hpp" // get's called on terminall resize static void clear(int /*sig*/) { diff --git a/examples/screen-filler.cpp b/examples/screen-filler.cpp index 090efc9..08c59b8 100644 --- a/examples/screen-filler.cpp +++ b/examples/screen-filler.cpp @@ -1,9 +1,8 @@ #include "../coords.hpp" +#include "../input.hpp" #include "../tui.hpp" #include -using namespace tui::input; - static struct State { Input input; bool quit = false; diff --git a/examples/snake.cpp b/examples/snake.cpp index f859b88..5ad63a7 100644 --- a/examples/snake.cpp +++ b/examples/snake.cpp @@ -1,4 +1,5 @@ #include "../coords.hpp" +#include "../input.hpp" #include "../tui.hpp" #include #include @@ -11,8 +12,6 @@ #include #include -using namespace tui::input; - // this is how the apple/food will be displayed const tui::string APPLE_TEXT = tui::string('@').red().bold(); // where the score count will be printed diff --git a/tui.hpp b/tui.hpp index 0c46440..4088110 100644 --- a/tui.hpp +++ b/tui.hpp @@ -447,7 +447,4 @@ namespace tui { tui::cursor::visible(true); tui::disable_raw_mode(); } - namespace input { -#include "input.hpp" - } // namespace input } // namespace tui From f9186106e614ef6a5e6b6921d0f3b6e05b8b96f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jeromos=20Kov=C3=A1cs?= Date: Tue, 6 May 2025 16:32:12 +0200 Subject: [PATCH 30/37] misc(clangd): won't suggest adding non-sense (afaik) statics --- .clang-tidy | 1 + 1 file changed, 1 insertion(+) diff --git a/.clang-tidy b/.clang-tidy index 68ffd8d..4d00d9a 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -48,6 +48,7 @@ Checks: -altera-struct-pack-align, -misc-non-private-member-variables-in-classes, -misc-use-anonymous-namespace, + -misc-use-internal-linkage, -concurrency-mt-unsafe, -cert-env33-c, -cert-err58-cpp, From 3e0daa902c46c00901d0c7f73dcca8d4c08b461f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jeromos=20Kov=C3=A1cs?= Date: Tue, 6 May 2025 16:32:54 +0200 Subject: [PATCH 31/37] refactor: remove non-sense `static`s --- examples/boxes.cpp | 14 +++++++------- examples/read_event.cpp | 6 +++--- examples/read_input.cpp | 2 +- examples/screen-filler.cpp | 6 +++--- examples/snake.cpp | 16 ++++++++-------- tui.hpp | 20 +++++++++----------- 6 files changed, 31 insertions(+), 33 deletions(-) diff --git a/examples/boxes.cpp b/examples/boxes.cpp index a3ae221..cda740d 100644 --- a/examples/boxes.cpp +++ b/examples/boxes.cpp @@ -10,7 +10,7 @@ using Box = std::pair; -static struct AppState { +struct AppState { Input input; bool quit = false; bool new_input = true; @@ -18,7 +18,7 @@ static struct AppState { } state; // make `x` be good for `counter_box` -static std::string count(const uint64_t& x) { +std::string count(const uint64_t& x) { // unsigned r = 0; std::string print; if (x % 100 == 0) { @@ -34,7 +34,7 @@ static std::string count(const uint64_t& x) { return print; } -static void counter_box(Coord start, Coord end) { +void counter_box(Coord start, Coord end) { assert(start.row <= end.row && start.col <= end.col); // do rows @@ -80,7 +80,7 @@ const std::vector> KINDS = {{{" ", " ", " ", " ", " ", // | | // | | // end.row ---------------- end.col -static void draw_box(Box box, Kind with) { +void draw_box(Box box, Kind with) { auto start = box.first; auto end = box.second; assert(start.row <= end.row && start.col <= end.col); @@ -112,7 +112,7 @@ static void draw_box(Box box, Kind with) { std::cout << draw[3]; } -static void handle_keys(std::vector& boxes, unsigned& cnt_box_ix) { +void handle_keys(std::vector& boxes, unsigned& cnt_box_ix) { auto* cnt_box = &boxes[cnt_box_ix]; if (state.input == 'n' || state.input == SpecKey::Tab) { if (cnt_box_ix++ == boxes.size() - 1) { @@ -157,7 +157,7 @@ static void handle_keys(std::vector& boxes, unsigned& cnt_box_ix) { boxes.erase(boxes.begin() + cnt_box_ix); } } -static void run() { +void run() { const auto msg = tui::string("Szia Csongi!"); auto msg_coord = [msg](bool left) { return Coord{(state.size.row / 2) + 1, @@ -216,7 +216,7 @@ static void run() { } while (!state.quit); } -static void handle_read() { +void handle_read() { while (state.input != 'q' && state.input != SpecKey::CtrlC) { state.input = Input::read(); state.new_input = true; diff --git a/examples/read_event.cpp b/examples/read_event.cpp index 9bd1ac3..ecf2add 100644 --- a/examples/read_event.cpp +++ b/examples/read_event.cpp @@ -11,9 +11,9 @@ static std::condition_variable cv; static Input shared_input; static bool input_available = false; -static bool should_quit(const Input& input) { return input == SpecKey::CtrlC || input == 'q'; } +bool should_quit(const Input& input) { return input == SpecKey::CtrlC || input == 'q'; } -static void read_input() { +void read_input() { while (!should_quit(shared_input)) { shared_input = Input::read(); std::lock_guard lock(mtx); @@ -23,7 +23,7 @@ static void read_input() { } } -static void main_task() { +void main_task() { int i = 0; while (true) { std::this_thread::sleep_for(std::chrono::milliseconds(40)); diff --git a/examples/read_input.cpp b/examples/read_input.cpp index 6733a61..ce7d9ae 100644 --- a/examples/read_input.cpp +++ b/examples/read_input.cpp @@ -2,7 +2,7 @@ #include "../input.hpp" // get's called on terminall resize -static void clear(int /*sig*/) { +void clear(int /*sig*/) { tui::screen::clear(); // clears screen tui::cursor::home(); // sets the cursor to the top left corner of the screen // no need to flush `cout`, as `'\n'` does it (well, yeah. don't ask me why though) diff --git a/examples/screen-filler.cpp b/examples/screen-filler.cpp index 08c59b8..5fcdb56 100644 --- a/examples/screen-filler.cpp +++ b/examples/screen-filler.cpp @@ -3,7 +3,7 @@ #include "../tui.hpp" #include -static struct State { +struct State { Input input; bool quit = false; } state; @@ -11,7 +11,7 @@ static struct State { const Coord TOP_LEFT = Coord::origin(); const tui::string CH = tui::string(" "); -static void read_char() { +void read_char() { while (state.input != 'q' && state.input != SpecKey::CtrlC) { state.input = Input::read(); std::this_thread::sleep_for(std::chrono::milliseconds(8)); @@ -19,7 +19,7 @@ static void read_char() { state.quit = true; } -static void run() { +void run() { auto screen_size = Coord(); auto prev_screen_size = screen_size; diff --git a/examples/snake.cpp b/examples/snake.cpp index 5ad63a7..44c2fa6 100644 --- a/examples/snake.cpp +++ b/examples/snake.cpp @@ -31,7 +31,7 @@ enum class Dir : std::uint8_t { Right, None, }; -static Dir opposite(const Dir& dir) { +Dir opposite(const Dir& dir) { switch (dir) { case Dir::Up: return Dir::Down; @@ -46,7 +46,7 @@ static Dir opposite(const Dir& dir) { } return Dir::None; } -static Dir from_input(const Input& input, const Dir& dir = Dir::Right) { +Dir from_input(const Input& input, const Dir& dir = Dir::Right) { switch (input.ch) { case 'k': case 'w': @@ -78,7 +78,7 @@ static Dir from_input(const Input& input, const Dir& dir = Dir::Right) { return dir; } -static std::string to_string(const Dir& dir) { +std::string to_string(const Dir& dir) { switch (dir) { case Dir::Up: return "↑"; // alt: ^ @@ -94,7 +94,7 @@ static std::string to_string(const Dir& dir) { return "X"; } -static Dir meets_at(const Coord& lhs, const Coord& rhs, const Coord& screen_size) { +Dir meets_at(const Coord& lhs, const Coord& rhs, const Coord& screen_size) { int row_diff = static_cast(lhs.row) - static_cast(rhs.row); int col_diff = static_cast(lhs.col) - static_cast(rhs.col); @@ -118,7 +118,7 @@ static Dir meets_at(const Coord& lhs, const Coord& rhs, const Coord& screen_size using Snake = std::vector; -static std::string draw(const std::pair& nb) { +std::string draw(const std::pair& nb) { // rounded: {"╭", "╮", "╰", "╯", "│", "─"} // this is where in Rust we'd use `match` and be happy @@ -147,7 +147,7 @@ static std::string draw(const std::pair& nb) { return "X"; } -static struct App { +struct App { Coord screen_size = Coord::screen_size(); Snake snake = App::default_snake(); Coord apple = Coord::random(this->screen_size); @@ -269,7 +269,7 @@ static struct App { } app; -static void handle_read() { +void handle_read() { while (!app.quit && app.input != 'q' && app.input != 'Q' && app.input != SpecKey::CtrlC && app.input != SpecKey::CtrlD && app.input != SpecKey::CtrlZ) { app.input = Input::read(); @@ -279,7 +279,7 @@ static void handle_read() { std::cout << "reader thread done\n"; } -static void run() { +void run() { app.apple.print(APPLE_TEXT); do { // get direction diff --git a/tui.hpp b/tui.hpp index 4088110..7b096af 100644 --- a/tui.hpp +++ b/tui.hpp @@ -267,15 +267,13 @@ namespace tui { // generate for cout << STYLE_style(); eg.: cout << bold_style(); #define stylize(STYLE) \ - static inline std::string STYLE##_style() { return style(Style::STYLE); } + inline std::string STYLE##_style() { return style(Style::STYLE); } // generate for cout << STYLE_style(text); eg.: cout << bold_style(text); #define stylize_text(STYLE) \ - static inline std::string STYLE##_style(const std::string& text) { \ + inline std::string STYLE##_style(const std::string& text) { \ return concat(style(Style::STYLE), text, reset_style()); \ } \ - static inline std::string STYLE##_style(const char* text) { \ - return concat(style(Style::STYLE), text, reset_style()); \ - } + inline std::string STYLE##_style(const char* text) { return concat(style(Style::STYLE), text, reset_style()); } // generate all #define make_stylizer(STYLE) stylize(STYLE) stylize_text(STYLE) @@ -327,21 +325,21 @@ namespace tui { // generate for cout << COLOR_{fg, bg}(); #define colorize(COLOR) \ - static inline std::string COLOR##_fg() { return colorizer(Color::COLOR, true); } \ - static inline std::string COLOR##_bg() { return colorizer(Color::COLOR, false); } + inline std::string COLOR##_fg() { return colorizer(Color::COLOR, true); } \ + inline std::string COLOR##_bg() { return colorizer(Color::COLOR, false); } // generate for cout << COLOR_{fg, bg}(text); #define colorize_text(COLOR) \ - static inline std::string COLOR##_fg(const std::string& text) { \ + inline std::string COLOR##_fg(const std::string& text) { \ return concat(colorizer(Color::COLOR, true), text, style::reset_style()); \ } \ - static inline std::string COLOR##_fg(const char* text) { \ + inline std::string COLOR##_fg(const char* text) { \ return concat(colorizer(Color::COLOR, true), text, style::reset_style()); \ } \ - static inline std::string COLOR##_bg(const std::string& text) { \ + inline std::string COLOR##_bg(const std::string& text) { \ return concat(colorizer(Color::COLOR, false), text, style::reset_style()); \ } \ - static inline std::string COLOR##_bg(const char* text) { \ + inline std::string COLOR##_bg(const char* text) { \ return concat(colorizer(Color::COLOR, false), text, style::reset_style()); \ } From 07f75ddde54bcf95fe8d088c0c58470dcb50fe12 Mon Sep 17 00:00:00 2001 From: Jeromos Kovacs Date: Tue, 6 May 2025 14:18:54 +0200 Subject: [PATCH 32/37] fix: use native raw-mode management instead of `stty`; conventional error msgs; use `err()` where applicable --- tui.hpp | 67 ++++++++++++++++++++++++--------------------------------- 1 file changed, 28 insertions(+), 39 deletions(-) diff --git a/tui.hpp b/tui.hpp index 7b096af..6c4c6c3 100644 --- a/tui.hpp +++ b/tui.hpp @@ -1,8 +1,6 @@ // tui.hpp #pragma once -#include -#include #ifdef _WIN32 // windows #include @@ -14,15 +12,18 @@ #include // err #include // open #include // ioctl, TIOCGWINSZ -#include // close +#include +#include // close #endif #include +#include #include #include #include #include +#include // for std::pair namespace tui { // only the Esc character @@ -55,12 +56,12 @@ namespace tui { #define win_setup() \ HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE); \ if (hStdin == INVALID_HANDLE_VALUE) { \ - std::cerr << "Error getting the standard input handle." << std::endl; \ + std::cerr << "error getting the standard input handle\n"; \ exit(1); \ } \ DWORD mode; \ if (!GetConsoleMode(hStdin, &mode)) { \ - std::cerr << "Error getting the console mode." << std::endl; \ + std::cerr << "error getting the console mode\n"; \ exit(1); \ } #endif @@ -73,26 +74,21 @@ namespace tui { newMode &= ~(ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT | ENABLE_PROCESSED_INPUT); if (!SetConsoleMode(hStdin, newMode)) { - std::cerr << "Error setting the console to raw mode." << std::endl; + std::cerr << "error setting the console to raw mode\n"; exit(1); } #else // not windows - system("stty raw"); - system("stty -echo"); - - // struct termios term {}; - // if (tcgetattr(STDIN_FILENO, &term) == -1) { - // std::cerr << "Error getting terminal attributes." << std::endl; - // exit(1); - // } - - // struct termios raw = term; - // raw.c_lflag &= ~(ICANON | ECHO); - - // if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &raw) == -1) { - // std::cerr << "Error setting terminal to raw mode." << std::endl; - // exit(1); - // } + struct termios term{}; + if (tcgetattr(STDIN_FILENO, &term) == -1) { + err(1, "error getting terminal attributes"); + } + + struct termios raw = term; + raw.c_lflag &= ~(ICANON | ECHO); + + if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &raw) == -1) { + err(1, "error setting terminal to raw mode"); + } #endif } @@ -103,26 +99,19 @@ namespace tui { // Restore original mode mode |= (ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT | ENABLE_PROCESSED_INPUT); if (!SetConsoleMode(hStdin, mode)) { - std::cerr << "Error restoring the console mode." << std::endl; + std::cerr << "error restoring the console mode\n"; exit(1); } #else // not windows - system("stty -raw"); - system("stty echo"); - - // struct termios term {}; - // if (tcgetattr(STDIN_FILENO, &term) == -1) { - // std::cerr << "Error getting terminal attributes." << std::endl; - // exit(1); - // } - - // // Restore original attributes - // term.c_lflag |= (ICANON | ECHO); - - // if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &term) == -1) { - // std::cerr << "Error restoring terminal mode." << std::endl; - // exit(1); - // } + struct termios term{}; + if (tcgetattr(STDIN_FILENO, &term) == -1) { + err(1, "error getting terminal attributes"); + } + // Restore original attributes + term.c_lflag |= (ICANON | ECHO); + if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &term) == -1) { + err(1, "error restoring terminal mode"); + } #endif } From 6cb343f9bb5b5452f3be13b4a5ca223ae923c338 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jeromos=20Kov=C3=A1cs?= Date: Tue, 6 May 2025 16:54:35 +0200 Subject: [PATCH 33/37] refactor: perf < code readability --- input.hpp | 39 +++++++++++++++++++-------------------- 1 file changed, 19 insertions(+), 20 deletions(-) diff --git a/input.hpp b/input.hpp index 3be30ec..ccc8a11 100644 --- a/input.hpp +++ b/input.hpp @@ -1,7 +1,6 @@ #pragma once #include "tui.hpp" -#include #include // Platform-specific includes @@ -24,7 +23,7 @@ #define DEM(X1, X2, X3, X4) _DCEM(X1), _DCEM(X2), _DCEM(X3), _DCEM(X4) // TODO: maybe add keys: F(5-12) NOTE: shall need an own `struct F {num: u8}`, ... -enum class SpecKey : std::uint8_t { +enum SpecKey { CtrlA = 1, DEM(B, C, D, E), DEM(F, G, H, I), @@ -53,7 +52,7 @@ enum class SpecKey : std::uint8_t { #undef DCEM #undef DEM -enum class Arrow : std::uint8_t { +enum Arrow { Up = 65, Down = 66, Right = 67, @@ -188,10 +187,10 @@ struct Input { } switch (byte) { - case 127: + case SpecKey::Backspace: input = Input(static_cast(byte)); break; - case 27: { + case SpecKey::Esc: { #ifndef _WIN32 set_non_blocking(true); char next_byte = get_char(); @@ -199,25 +198,25 @@ struct Input { if (next_byte == 79 || next_byte == 91) { char special = get_char(); switch (special) { - case 65: - case 66: - case 67: - case 68: + case Arrow::Up: + case Arrow::Down: + case Arrow::Right: + case Arrow::Left: input = Input(static_cast(special)); break; - case 80: - case 81: - case 82: - case 83: - case 72: - case 70: - case 90: + case SpecKey::F1: + case SpecKey::F2: + case SpecKey::F3: + case SpecKey::F4: + case SpecKey::End: + case SpecKey::Home: + case SpecKey::ShiftTab: input = Input(static_cast(special)); break; - case 50: - case 51: - case 53: - case 54: + case SpecKey::Insert: + case SpecKey::Delete: + case SpecKey::PageUp: + case SpecKey::PageDown: get_char(); // ignore input = Input(static_cast(special)); break; From 73082cb6d1a2735489c5898fe72122e13c74126a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jeromos=20Kov=C3=A1cs?= Date: Tue, 6 May 2025 17:04:37 +0200 Subject: [PATCH 34/37] fix(input): don't make << ugly --- input.hpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/input.hpp b/input.hpp index ccc8a11..82b3ff1 100644 --- a/input.hpp +++ b/input.hpp @@ -71,10 +71,10 @@ inline std::string ctrl_to_str(const unsigned& key) { return tui::concat("Ctrl", inline std::ostream& operator<<(std::ostream& os, const SpecKey& special) { switch (special) { - CRSS(SpecKey::Esc, SpecKey::Tab, SpecKey::Backspace, SpecKey::Enter); - CRSS(SpecKey::F1, SpecKey::F2, SpecKey::F3, SpecKey::F4); - CRSS(SpecKey::Home, SpecKey::End, SpecKey::PageUp, SpecKey::PageDown); - CRSS(SpecKey::ShiftTab, SpecKey::Insert, SpecKey::Delete, SpecKey::None); + CRSS(Esc, Tab, Backspace, Enter); + CRSS(F1, F2, F3, F4); + CRSS(Home, End, PageUp, PageDown); + CRSS(ShiftTab, Insert, Delete, None); default: if (static_cast(special) >= 1 && static_cast(special) <= 26) { return os << ctrl_to_str(static_cast(special)); @@ -86,7 +86,7 @@ inline std::ostream& operator<<(std::ostream& os, const SpecKey& special) { inline std::ostream& operator<<(std::ostream& os, const Arrow& arrow) { switch (arrow) { - CRSS(Arrow::Up, Arrow::Down, Arrow::Right, Arrow::Left); + CRSS(Up, Down, Right, Left); default: os << "Unknown"; } From 211c4d2cf3f2d43e0e2a05754fd7e544ad8efe67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jeromos=20Kov=C3=A1cs?= Date: Tue, 6 May 2025 17:05:41 +0200 Subject: [PATCH 35/37] docs(input): a comment of what were ignoring --- input.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/input.hpp b/input.hpp index 82b3ff1..6ed6e32 100644 --- a/input.hpp +++ b/input.hpp @@ -217,7 +217,7 @@ struct Input { case SpecKey::Delete: case SpecKey::PageUp: case SpecKey::PageDown: - get_char(); // ignore + get_char(); // ignore '~' input = Input(static_cast(special)); break; default: From b772597abd596df27bf916c8a68d51a43cd6521a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jeromos=20Kov=C3=A1cs?= Date: Tue, 6 May 2025 17:15:21 +0200 Subject: [PATCH 36/37] fix(input): unnecessary cast ruins stuff --- input.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/input.hpp b/input.hpp index 6ed6e32..0c91cae 100644 --- a/input.hpp +++ b/input.hpp @@ -76,8 +76,8 @@ inline std::ostream& operator<<(std::ostream& os, const SpecKey& special) { CRSS(Home, End, PageUp, PageDown); CRSS(ShiftTab, Insert, Delete, None); default: - if (static_cast(special) >= 1 && static_cast(special) <= 26) { - return os << ctrl_to_str(static_cast(special)); + if (special >= 1 && special <= 26) { + return os << ctrl_to_str(special); } os << "Unknown"; } From a1cdb629ad98fdf439e06c90e21e9c48c1c8412c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jeromos=20Kov=C3=A1cs?= Date: Tue, 6 May 2025 17:54:36 +0200 Subject: [PATCH 37/37] fix(unix-raw-mode): use `stty` as it's somehow more universal --- tui.hpp | 41 ++++++++++++++++++++++++----------------- 1 file changed, 24 insertions(+), 17 deletions(-) diff --git a/tui.hpp b/tui.hpp index 6c4c6c3..8cb432b 100644 --- a/tui.hpp +++ b/tui.hpp @@ -78,17 +78,21 @@ namespace tui { exit(1); } #else // not windows - struct termios term{}; - if (tcgetattr(STDIN_FILENO, &term) == -1) { - err(1, "error getting terminal attributes"); + if (system("stty raw") != 0) { + err(1, "couldn't set stty raw"); } - - struct termios raw = term; - raw.c_lflag &= ~(ICANON | ECHO); - - if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &raw) == -1) { - err(1, "error setting terminal to raw mode"); + if (system("stty -echo") != 0) { + err(1, "couldn't set stty -echo"); } + // struct termios term{}; + // if (tcgetattr(STDIN_FILENO, &term) == -1) { + // err(1, "error getting terminal attributes"); + // } + // struct termios raw = term; + // raw.c_lflag &= ~(ICANON | ECHO); + // if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &raw) == -1) { + // err(1, "error setting terminal to raw mode"); + // } #endif } @@ -103,15 +107,18 @@ namespace tui { exit(1); } #else // not windows - struct termios term{}; - if (tcgetattr(STDIN_FILENO, &term) == -1) { - err(1, "error getting terminal attributes"); - } - // Restore original attributes - term.c_lflag |= (ICANON | ECHO); - if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &term) == -1) { - err(1, "error restoring terminal mode"); + if (system("stty cooked") != 0) { + err(1, "couldn't set stty cooked"); } + // struct termios term{}; + // if (tcgetattr(STDIN_FILENO, &term) == -1) { + // err(1, "error getting terminal attributes"); + // } + // // Restore original attributes + // term.c_lflag |= (ICANON | ECHO); + // if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &term) == -1) { + // err(1, "error restoring terminal mode"); + // } #endif }