diff options
| author | Aakarsh Kashyap <[email protected]> | 2026-06-20 18:57:14 +0530 |
|---|---|---|
| committer | GitHub <[email protected]> | 2026-06-20 18:57:14 +0530 |
| commit | 19df8e77977f634064aed3c0332d1b0fc56e158b (patch) | |
| tree | ac664730e758ef50f8472831fada93c6e8f7c5d7 /src | |
| parent | 02a1bdae9780c1f08818d1a5039bdfb055372723 (diff) | |
| parent | b5186a5a724649e9eb71fdfbaf3c2a84b36d7c9c (diff) | |
Merge pull request #1 from seivarya/master
[refactor]: restructure
Diffstat (limited to 'src')
| -rw-r--r-- | src/main.cpp | 71 | ||||
| -rw-r--r-- | src/reader.cpp | 140 |
2 files changed, 211 insertions, 0 deletions
diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..10c3df6 --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,71 @@ +#include "reader.h" + +int main(int argc, char *argv[]) { + try { + editor_cfg *cfg = (editor_cfg *)malloc(sizeof(editor_cfg)); + if (cfg == nullptr) { + die("[err]: malloc failed\n"); + } + + enable_raw(cfg); + init_editor(cfg); + + int speed { 250000 }; + + if (argc < 2) + die("[err]: no file provided!\n"); + + if (argc > 3) + die("[err]: too many arguments!\n"); + + if (argc == 3) { + if (!is_number(argv[2])) + die("[err]: invalid speed interval provided!\n"); + speed = std::stoi(argv[2]); + } + + FILE *fp = fopen(argv[1], "r"); + + if (fp == nullptr) + die("[err]: fopen failed\n"); + + fseek(fp, 0, SEEK_END); + long size = ftell(fp); + rewind(fp); + + std::string content(size, '\0'); + fread(content.data(), 1, size, fp); + + fclose(fp); + + std::vector<std::string> data; + split(content, data, " \t\r\n,;:!?"); + + while(1) { + for (std::string &k: data) { + if (k.empty()) continue; + editor_refresh_scrn(cfg); + int mid = k.size() / 2; + + write(STDOUT_FILENO, k.substr(0, mid).c_str(), mid); + write(STDOUT_FILENO, "\x1b[31m", 5); + write(STDOUT_FILENO, k.substr(mid, 1).c_str(), 1); + write(STDOUT_FILENO, "\x1b[m", 3); + + int remaining = k.size() - mid - 1; + + write(STDOUT_FILENO, k.substr(mid + 1, remaining).c_str(), remaining); + usleep(speed); + } + } + + free(cfg); + + } catch (const std::exception &e) { + die(e.what()); + } catch (...) { + die("[err]: Unknown exception occurred\n"); + } + + return 0; +} /* main.cpp */ diff --git a/src/reader.cpp b/src/reader.cpp new file mode 100644 index 0000000..508205d --- /dev/null +++ b/src/reader.cpp @@ -0,0 +1,140 @@ +#include "reader.h" +#include <csignal> + +void die(const char *s) { + write(STDOUT_FILENO, "\x1b[2J", 4); + write(STDOUT_FILENO, "\x1b[H", 3); + + perror(s); + fprintf(stderr, "[exit]: die(s) invoked, exiting..\n"); + exit(1); +} + +static editor_cfg *g_cfg = nullptr; + +void disable_raw_atexit() { + if (g_cfg) { + tcsetattr(STDIN_FILENO, TCSAFLUSH, &(g_cfg->termios_inst)); + } +} + +void handle_signal(int sig) { + disable_raw_atexit(); + _exit(128 + sig); +} + +void disable_raw(editor_cfg *cfg) { + if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &(cfg->termios_inst))) + die("tcsetattr"); +} + +void enable_raw(editor_cfg *cfg) { + if (tcgetattr(STDIN_FILENO, &(cfg->termios_inst)) == -1) + die("tcgetattr"); + + g_cfg = cfg; + + std::atexit(disable_raw_atexit); + + std::signal(SIGINT, handle_signal); + std::signal(SIGTERM, handle_signal); + std::signal(SIGQUIT, handle_signal); + + struct termios raw = cfg->termios_inst; + raw.c_iflag &= ~(IXON | ICRNL | BRKINT | INPCK | ISTRIP); + raw.c_oflag &= ~(OPOST); + raw.c_lflag &= + ~(ECHO | ICANON | IEXTEN); // disables several keybinds in terminal + + raw.c_cc[VMIN] = 0; + raw.c_cc[VTIME] = 1; + + if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &raw) == -1) + die("tcsetattr"); +} + +char editor_readkey() { + int nread; + char c; + + while ((nread = read(STDIN_FILENO, &c, 1)) != 1) { + if (nread == -1 && errno != EAGAIN) + die("read"); + } + return c; +} + +int get_cursor_pos(int *rows, int *cols) { + char buff[32]; + unsigned int i = 0; + + if (write(STDOUT_FILENO, "\x1b[6n", 4) != 4) { + return -1; + } + while (i < sizeof(buff) - 1) { + if (read(STDIN_FILENO, &buff[i], 1) != 1) + break; + if (buff[i] == 'R') + break; + i++; + } + buff[i] = '\0'; + + if (buff[0] != '\x1b' || buff[1] != '[') + return -1; + if (sscanf(&buff[2], "%d;%d", rows, cols) != 2) + return -1; + return 0; +} + +int get_window_size(int *rows, int *cols) { + struct winsize w_size; + + if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &w_size) == -1 || + w_size.ws_col == 0) { + if (write(STDOUT_FILENO, "\x1b[999C\x1b[999B", 12) != 12) + return -1; + return get_cursor_pos(rows, cols); + } + + *rows = w_size.ws_row; + *cols = w_size.ws_col; + + return 0; +} + +void editor_refresh_scrn(editor_cfg *cfg) { + append_buffer::instance().append("\x1b[2J", 4); + char buff[32]; + memset(buff, 0, sizeof(buff)); + + snprintf(buff, sizeof(buff), "\x1b[%d;%dH", cfg->screenrows / 2, cfg->screencols / 2); + + append_buffer::instance().append(buff, strlen(buff)); + append_buffer::instance().write_output(); + append_buffer::instance().remove(); +} + +size_t split(const std::string &txt, std::vector<std::string> &strings, const std::string &delims) { + size_t initial_pos = txt.find_first_not_of(delims, 0); + size_t pos = txt.find_first_of(delims, initial_pos); + + while (initial_pos != std::string::npos) { + strings.push_back(txt.substr(initial_pos, pos - initial_pos)); + initial_pos = txt.find_first_not_of(delims, pos); + pos = txt.find_first_of(delims, initial_pos); + } + return strings.size(); +} + +void init_editor(editor_cfg *cfg) { + if (get_window_size(&(cfg->screenrows), &(cfg->screencols)) == -1) + die("get_window_size"); +} + +int is_number(char *strnum) { + std::string str = strnum; + std::string::const_iterator it = str.begin(); + while (it != str.end() && std::isdigit(*it)) ++it; + return !str.empty() && it == str.end(); +} |
