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 | |
| parent | 02a1bdae9780c1f08818d1a5039bdfb055372723 (diff) | |
| parent | b5186a5a724649e9eb71fdfbaf3c2a84b36d7c9c (diff) | |
Merge pull request #1 from seivarya/master
[refactor]: restructure
| -rw-r--r-- | .clang-format | 4 | ||||
| -rw-r--r-- | .gitattributes | 1 | ||||
| -rw-r--r-- | .gitignore | 67 | ||||
| -rwxr-xr-x | FAFR | bin | 51576 -> 0 bytes | |||
| -rw-r--r-- | Main.cpp | 338 | ||||
| -rw-r--r-- | Makefile | 5 | ||||
| -rw-r--r-- | README.md | 9 | ||||
| -rw-r--r-- | include/reader.h | 72 | ||||
| -rw-r--r-- | src/main.cpp | 71 | ||||
| -rw-r--r-- | src/reader.cpp | 140 | ||||
| -rw-r--r-- | testfile (renamed from fuck) | 0 |
11 files changed, 364 insertions, 343 deletions
diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..9fa6cda --- /dev/null +++ b/.clang-format @@ -0,0 +1,4 @@ +BasedOnStyle: LLVM +IndentWidth: 8 +TabWidth: 8 +UseTab: Never diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..6313b56 --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +* text=auto eol=lf diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8a2ec94 --- /dev/null +++ b/.gitignore @@ -0,0 +1,67 @@ +# Prerequisites +*.d + +# clangd files +compile_commands.json + +# misc +.vscode/ + + +# build/ cache files +build +run_tests +.cache + +# Object files +*.o +*.ko +*.obj +*.elf + +# Linker output +*.ilk +*.map +*.exp + +# Precompiled Headers +*.gch +*.pch + +# Libraries +*.lib +*.a +*.la +*.lo + +# Shared objects (inc. Windows DLLs) +*.dll +*.so +*.so.* +*.dylib + +# Executables +*.exe +*.out +*.app +*.i*86 +*.x86_64 +*.hex + +# Debug files +*.dSYM/ +*.su +*.idb +*.pdb + +# Kernel Module Compile Results +*.mod* +*.cmd +.tmp_versions/ +modules.order +Module.symvers +Mkfile.old +dkms.conf + +# debug information files +*.dwo Binary files differdiff --git a/Main.cpp b/Main.cpp deleted file mode 100644 index 53e6cf0..0000000 --- a/Main.cpp +++ /dev/null @@ -1,338 +0,0 @@ -// ==================== -// The purpose of this project is to -// make a reader so that I can read -// novels even faster than my already -// amazing speed.(200k words/day) to (300k words/day) -// -// Rsearch objective: -// Terminal: RSVP (Rapid Serial Visual Presentation) -// -// Project Name: fastAsFKReader(FAFK) -// Author : Aakarsh Kashyap -// [ 2026-06-17 ] -// ==================== - -// Steps -// -// 1. Get to the raw mode -// 2. Get cursor to center of the terminal -// 3. Parse the whole file into the memory and save it into a vector -// of strings. -// 4. Figure out the central letter of the string -// 5. Print that word with the central letter coloured -// 6. We will take a timer args which will make word rendering fast or slow but -// it's fine for now -// 7. The size of the word is smt dependent on user terminal zoomin we will not -// try to render bigger font or anything -// 8. End of the program. - -/* Include */ -#include <asm-generic/ioctls.h> -#include <cerrno> -#include <cstdint> -#include <termios.h> -#include <unistd.h> -#include <cstdlib> -#include <cstdio> -#include <sys/ioctl.h> -#include <cstring> -#include <string> -#include <vector> - -/* Define */ -#define CTRL_KEY(k) ((k) & 0x1f) - - -/** data **/ - -using editorConfig_t = struct editorConfig -{ - int screenrows; - int screencols; - struct termios org_termios{}; - -}; - -editorConfig_t e; - -/** terminal **/ -void Die(const char *s) -{ - write(STDOUT_FILENO, "\x1b[2J", 4); - write(STDOUT_FILENO, "\x1b[H", 3); - - perror(s); - exit(1); -} - -void DisableRawMode() -{ - if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &e.org_termios) == -1) { Die("tcsetattr") ; -} -} - -void EnableRawMode() -{ - if(tcgetattr(STDIN_FILENO, &e.org_termios) == -1) { Die("tcgetattr"); -} - // At exit(program exits) runs the function - atexit(DisableRawMode); - - struct termios raw = e.org_termios; - - - // Iflags are for input flags - // XON is used to control and disable C-s and C-q they are used for software flow control - // CR for carriage return NL for new line - raw.c_iflag &= ~(IXON | ICRNL | BRKINT | INPCK | ISTRIP); - - // turning off the post processing of output - raw.c_oflag &= ~(OPOST); - - raw.c_cflag |= (CS8); - // lflags is for mislaneous things - // ISIG flag disable SIGINT C-c and SIGSTP C-z - // ECHO flag disable return output to screen as we type sudo uses this - // ICANON is used to turn off the canonical/cooked mode so we can process per byte instead of per line - // IEXTEN is used to diable C-v - raw.c_lflag &= ~(ECHO | ICANON | IEXTEN |ISIG); - - - // c_cc is a control character array; - // vmin sets the number of bytes needed before read can return - raw.c_cc[VMIN] = 0; - // Sets max time before read returns - raw.c_cc[VTIME] = 1; - - // TCSAFLUSH is used to flus all the things after thsi func call - if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &raw) == -1) { Die("tcsetattr") ; -} -} - -char EditorReadKey() -{ - int nread; - char c; - while ((nread = read(STDIN_FILENO, &c, 1)) != 1) - { - if(nread == -1 && errno != EAGAIN) { Die("read"); -} - } - return c; -} - -int GetCursorPosition(int *rows, int *cols) -{ - char buf[32]; - unsigned int i = 0; - // n cmd gives the device info 6 as args give us the cursor pos - if (write(STDOUT_FILENO, "\x1b[6n", 4) != 4) { - return -1; -} - while (i < sizeof(buf) - 1) - { - if (read(STDIN_FILENO, &buf[i], 1) != 1) { - break; -} - if (buf[i] == 'R') { - break; -} - i++; - } - buf[i] = '\0'; - - if (buf[0] != '\x1b' || buf[1] != '[') { - return -1; -} - if (sscanf(&buf[2], "%d;%d", rows, cols) != 2) { - return -1; -} - - return 0; -} - - -int GetWindowSize(int *rows, int *cols) -{ - struct winsize ws; - - // TIOCGWINSZ stads for terminal ioctl get window size - // returns -1 on error can even return row and cols as zero so we check both - if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) == -1 || ws.ws_col == 0) - { - if (write(STDOUT_FILENO, "\x1b[999C\x1b[999B", 12) != 12) { - return -1; -} - return GetCursorPosition(rows, cols); - } - - *cols = ws.ws_col; - *rows = ws.ws_row; - return 0; - -} - -/* append buffer */ - -class AppendBuf -{ -private: - char *m_b{nullptr}; - uint32_t m_len{0}; - -public: - AppendBuf() {} - - ~AppendBuf() = default; - - void Append(const char *s, int len) - { - char *num = (char*)realloc(m_b, m_len + len); - - if (num == nullptr) { - return; -} - memcpy(&num[m_len], s, len); - m_b = num; - m_len += len; - } - - static AppendBuf &Instance() - { - static AppendBuf obj; - return obj; - } - void Remove() - { - free(m_b); - m_b = nullptr; - m_len = 0; - } - void WriteOut() - { - write(STDOUT_FILENO, m_b, m_len); - } -}; - -/* output */ - - -void EditorRefreshScreen() -{ - // escape sequence starts with escape character \x1b is 27byte <esc> followed by [ - // is a escape sequence - // Then we specify the command and it's args. args are given before the - // command - // J corresponds to clearning the screen. 2 args means all the screena 1 for - // before the cursor and 0(default) - // for after the cursor to EOS - AppendBuf::Instance().Append("\x1b[2J", 4); - // H for cursor pos control takes two args rowXcol. 12;4H args are seperated by ';' - char tuff[32]; memset(tuff, 0, sizeof(tuff)); - snprintf(tuff, sizeof(tuff), "\x1b[%d;%dH", e.screenrows / 2, e.screencols / 2); - AppendBuf::Instance().Append(tuff, strlen(tuff)); - AppendBuf::Instance().WriteOut(); - AppendBuf::Instance().Remove(); -} - -/* input */ - -void EditorProcessKeyProcess() -{ - char c = EditorReadKey(); - - switch (c) - { - case CTRL_KEY('q'): - write(STDOUT_FILENO, "\x1b[2J", 4); - write(STDOUT_FILENO, "\x1b[H", 3); - exit(0); - break; - } -} - -/* Utils */ -size_t Split(const std::string &txt, std::vector<std::string> &strs, char ch) { - size_t pos = txt.find( ch ); - size_t initaiPos = 0; - // strs.clear(); - - while( pos != std::string::npos) { - strs.push_back(txt.substr(initaiPos, pos - initaiPos)); - initaiPos = pos+1; - - pos = txt.find(ch, initaiPos); - } - strs.push_back( txt.substr(initaiPos)); - - return strs.size(); -} - -/** Init **/ - -void InitEditor() -{ - if (GetWindowSize(&e.screenrows, &e.screencols) == -1) { - Die("getWindowSize"); -} - -} - -int main(int argc, char *argv[]) -{ - EnableRawMode(); - InitEditor(); - if (argc < 2) { - Die("no file provided"); -} - - int speed{250000}; - if (argc == 3) { - speed = std::stoi(argv[2]); -} - FILE *f = fopen(argv[1], "r"); - if (f == nullptr) { Die("fopen"); -} - - fseek(f, 0, SEEK_END); - long size = ftell(f); - rewind(f); - - std::string content(size, '\0'); - fread(content.data(), 1, size, f); - fclose(f); - std::vector<std::string> lund; - Split(content, lund, ' '); - - while (1) - { - for (std::string &k : lund) - { - EditorRefreshScreen(); - 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); - } - EditorProcessKeyProcess(); - } - return 0; -} - -/* CONCLUSION */ -// Experiment have failed. I do not see any particular increase int my -// reading speed, infact it has become difficult to -// keep previous context in mind -// There must be something else going on in that reel -// I will try to ask about it from sei or shashy maybe there is a -// better way -// -// [ 2026-06-17 ] diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..218d1b5 --- /dev/null +++ b/Makefile @@ -0,0 +1,5 @@ +run: + g++ src/reader.cpp src/main.cpp -o run -Isrc -Iinclude + +clean: + rm -rf .cache run @@ -1,4 +1,4 @@ -# FAFR +# reader.cpp Terminal: RSVP (Rapid Serial Visual Presentation) @@ -6,13 +6,12 @@ Terminal: RSVP (Rapid Serial Visual Presentation) How to compile ``` -g++ Main.cpp -o main +make ``` -How to use - +How to use: ``` -main <file_name> <time-interval> +./run <file_name> <time-interval> ``` ## // Licence diff --git a/include/reader.h b/include/reader.h new file mode 100644 index 0000000..27b7a90 --- /dev/null +++ b/include/reader.h @@ -0,0 +1,72 @@ +/* reader.h */ + +#define CTRL_KEY(k) ((k) & 0x1f) + +#include <asm-generic/ioctls.h> +#include <cstdint> +#include <cstdio> +#include <cstdlib> +#include <cstring> +#include <string> +#include <sys/ioctl.h> +#include <termios.h> +#include <unistd.h> +#include <vector> +#include <cstdlib> + + +using editor_cfg = struct editor_cfg { + int screenrows; + int screencols; + termios termios_inst {}; +}; + +class append_buffer { + private: + char *m_b{nullptr}; + uint32_t m_len{0}; + public: + append_buffer() {} + ~append_buffer() = default; + + void append(const char *s, int len) { + char *n = (char *)realloc(m_b, m_len + len); + + if (n == nullptr) + return; + memcpy(&n[m_len], s, len); + m_b = n; + m_len += len; + } + + static append_buffer &instance() { + static append_buffer obj; + return obj; + } + + void remove() { + free(m_b); + m_b = nullptr; + m_len = 0; + } + + void write_output() { + write(STDOUT_FILENO, m_b, m_len); + } +}; + +void init_editor(editor_cfg *cfg); +void die(const char *s); +void disable_raw(editor_cfg *cfg); +void enable_raw(editor_cfg *cfg); +void editor_refresh_scrn(editor_cfg *cfg); + +char editor_readkey(); + +int get_cursor_pos(int *rows, int *cols); +int get_window_size(int *rows, int *cols); +int is_number(char *strnum); + +size_t split(const std::string &txt, std::vector<std::string> &strings, const std::string &delims); + + 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(); +} |
