diff --git a/.clang-tidy b/.clang-tidy index 7539cab..4d00d9a 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,8 @@ Checks: -readability-magic-numbers, -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, diff --git a/.gitignore b/.gitignore index 796b96d..d38229e 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,4 @@ /build +.cache +compile_commands.json +meson.build diff --git a/examples/boxes.cpp b/examples/boxes.cpp index b3285de..cda740d 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; struct AppState { @@ -19,9 +18,8 @@ struct AppState { } state; // make `x` be good for `counter_box` -[[nodiscard]] std::string count(const uint64_t& x) { - unsigned r = 0; + // unsigned r = 0; std::string print; if (x % 100 == 0) { print = std::to_string(x / 100); @@ -61,11 +59,11 @@ 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 = {{{" ", " ", " ", " ", " ", " "}}, @@ -87,7 +85,7 @@ 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) { @@ -162,8 +160,8 @@ void handle_keys(std::vector& boxes, unsigned& cnt_box_ix) { 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 = { diff --git a/examples/hello_world.cpp b/examples/hello_world.cpp index 22277fb..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 @@ -14,11 +13,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(); diff --git a/examples/read_event.cpp b/examples/read_event.cpp index 4852734..ecf2add 100644 --- a/examples/read_event.cpp +++ b/examples/read_event.cpp @@ -1,3 +1,4 @@ +#include "../input.hpp" #include "../tui.hpp" #include #include @@ -5,13 +6,10 @@ #include #include -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'; } diff --git a/examples/read_input.cpp b/examples/read_input.cpp index 6702946..ce7d9ae 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 void clear(int /*sig*/) { diff --git a/examples/screen-filler.cpp b/examples/screen-filler.cpp index 7bc9036..5fcdb56 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; - struct State { Input input; bool quit = false; @@ -47,8 +46,8 @@ 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()); diff --git a/examples/snake.cpp b/examples/snake.cpp index 0481ed2..44c2fa6 100644 --- a/examples/snake.cpp +++ b/examples/snake.cpp @@ -1,16 +1,17 @@ #include "../coords.hpp" +#include "../input.hpp" #include "../tui.hpp" #include #include +#include +#include #include -#include +// #include // needed if MAX_MS is used #include #include #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 @@ -18,12 +19,12 @@ 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; // direction -enum Dir { +enum class Dir : std::uint8_t { Up = 0, Down, Left, @@ -100,16 +101,16 @@ 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; @@ -157,7 +158,7 @@ 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; @@ -259,7 +260,7 @@ 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); } diff --git a/input.hpp b/input.hpp index 175a57d..0c91cae 100644 --- a/input.hpp +++ b/input.hpp @@ -105,9 +105,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 && @@ -138,7 +138,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) { @@ -178,7 +177,7 @@ struct Input { } #else if (byte < 0) { - ignore_byte = get_char(); + get_char(); // ignore } #endif if (byte >= 32 && byte <= 126) { // @@ -218,7 +217,7 @@ struct Input { case SpecKey::Delete: case SpecKey::PageUp: case SpecKey::PageDown: - ignore_byte = get_char(); // ~ + get_char(); // ignore '~' input = Input(static_cast(special)); break; default: diff --git a/tui.hpp b/tui.hpp index 37be957..8cb432b 100644 --- a/tui.hpp +++ b/tui.hpp @@ -12,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 @@ -53,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 @@ -71,25 +74,24 @@ 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 (system("stty raw") != 0) { + err(1, "couldn't set stty raw"); + } + if (system("stty -echo") != 0) { + err(1, "couldn't set stty -echo"); + } + // struct termios term{}; // if (tcgetattr(STDIN_FILENO, &term) == -1) { - // std::cerr << "Error getting terminal attributes." << std::endl; - // exit(1); + // err(1, "error getting terminal attributes"); // } - // 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); + // err(1, "error setting terminal to raw mode"); // } #endif } @@ -101,25 +103,21 @@ 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 (system("stty cooked") != 0) { + err(1, "couldn't set stty cooked"); + } + // struct termios term{}; // if (tcgetattr(STDIN_FILENO, &term) == -1) { - // std::cerr << "Error getting terminal attributes." << std::endl; - // exit(1); + // err(1, "error getting terminal attributes"); // } - // // 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); + // err(1, "error restoring terminal mode"); // } #endif } @@ -225,7 +223,7 @@ namespace tui { return {rows, columns}; #else - struct winsize ws {}; + struct winsize ws{}; int fd = 0; // open the controlling terminal. @@ -249,7 +247,7 @@ namespace tui { namespace text { namespace style { - enum Style { + enum class Style : std::uint8_t { reset = 0, bold = 1, dim = 2, @@ -265,11 +263,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 +302,7 @@ namespace tui { } // namespace style namespace color { - enum Color { + enum class Color : std::uint8_t { black = 0, red, green, @@ -321,22 +321,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 @@ -356,7 +356,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) { @@ -404,11 +404,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(); } @@ -421,7 +419,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); @@ -443,7 +441,4 @@ namespace tui { tui::cursor::visible(true); tui::disable_raw_mode(); } - namespace input { -#include "input.hpp" - } // namespace input } // namespace tui