Thumbnail

rani/cscroll.git

Clone URL: https://git.buni.party/rani/cscroll.git

commit e760413675670103c599e9b6ba31368fadacd2b6 Author: rani <clagv.randomgames@gmail.com> Date: Wed Dec 31 16:16:57 2025 +0000 Add: terminal resizing support; Add: file searching; Add: show link resolutions diff --git a/include/dir.h b/include/dir.h index 10c6d38..9551cb0 100644 --- a/include/dir.h +++ b/include/dir.h @@ -216 +219 @@  #define M_OTHW S_IWOTH  #define M_OTHX S_IXOTH   +#define REGSEARCH_BAD_REGEX 1 +#define REGSEARCH_NOT_FOUND 2 +  enum de_type {   DE_FILE,   DE_DIR, @@ -617 +649 @@ const char * dir_get_cwd(void);  int dir_cd_back(const char * cwd);  int dir_cd(const char * cwd, const char * next);  int dir_search_name(const dir_t * dir, const char * name, size_t * idx); +int dir_search_regex(const dir_t * dir, const char * regexstr, size_t * idx);  const char * dir_basename(const char * path); +  char dirent_crepr(const dirent_t * de); // character representing dir entry  char dirent_creprl(const dirent_t * de); // like above, but for the link  char dirent_longcrepr(const dirent_t * de); // like above, but for long mode diff --git a/include/ui.h b/include/ui.h index facf0a5..a2e07c7 100644 --- a/include/ui.h +++ b/include/ui.h @@ -76 +79 @@    #include "dir.h"   +#define KEY_DEL 127 +#define KEY_ESC 27 +  enum ui_color {   COLOR_FILE = 1,   COLOR_DIR, @@ -345 +377 @@ void ui_erase(void);  void ui_refresh(void);  void ui_print_dir(const dir_t * dir, size_t cursor, bool longmode);  void ui_print_cursor(size_t cursor, size_t total); +void ui_resize(void); +const char * ui_readline(const char * prompt);    #endif /* UI_H */ diff --git a/src/dir.c b/src/dir.c index 8a63343..a480701 100644 --- a/src/dir.c +++ b/src/dir.c @@ -46 +47 @@  #include <stdlib.h>  #include <string.h>  #include <unistd.h> +#include <regex.h>  #include <errno.h>  #include <fcntl.h>  #include <pwd.h> @@ -2893 +29022 @@ int dir_search_name(const dir_t * dir, const char * name, size_t * idx) {     return -1;  } + +int dir_search_regex(const dir_t * dir, const char * regexstr, size_t * idx) { + regex_t regex; + int ret = regcomp(&regex, regexstr, REG_EXTENDED); + if (!!ret) return -REGSEARCH_BAD_REGEX; + + for (size_t i = 0; i < dir->len; i++) { + dirent_t * de = &dir->entries[i]; + ret = regexec(&regex, de->name, 0, NULL, 0); + if (!ret) { + *idx = i; + regfree(&regex); + return 0; + } + } + + regfree(&regex); + return -REGSEARCH_NOT_FOUND; +} diff --git a/src/main.c b/src/main.c index 017c67d..58a169a 100644 --- a/src/main.c +++ b/src/main.c @@ -627 +628 @@ int main(int argc, char ** argv) {   }   free(basename);   break; - } case KEY_RIGHT: + } + case KEY_RIGHT:   if (cur_de && (cur_de->type == DE_DIR || (cur_de->type == DE_LINK   && cur_de->linktype == DE_DIR))) {   int ret = dir_cd(cwd, cur_de->name); @@ -898 +9032 @@ int main(int argc, char ** argv) {   cursor = dir.len - 1;   ui_status_info("");   break; + case '/': { + const char * input = ui_readline("/"); + if (!input) break; + size_t idx; + int i = dir_search_regex(&dir, input, &idx); + if (i >= 0) { + cursor = idx; + ui_status_info(""); + } else switch (-i) { + case REGSEARCH_BAD_REGEX: + ui_status_error("Bad RegEx"); + break; + case REGSEARCH_NOT_FOUND: + ui_status_info("No Matches Found"); + break; + default: + ui_status_error("Unhandled Case"); + break; + } + break; + }   case 'q':   goto finished; + case KEY_RESIZE: + ui_resize(); + break;   default: break;   }   } diff --git a/src/ui.c b/src/ui.c index ef060a5..1042da9 100644 --- a/src/ui.c +++ b/src/ui.c @@ -317 +338 @@  #include <stddef.h>  #include <string.h>  #include <locale.h> +#include <ctype.h>  #include <time.h>    #include "ui.h"  #include "dir.h"   -static WINDOW * titlewin = NULL; +#define TITLEWINSTARTY 0 +#define TITLEWINLINES 1 +#define TITLEWINCOLS COLS + +#define STATUSWINSTARTY 1 +#define STATUSWINLINES 1 +#define STATUSWINCOLS COLS + +#define FILEWINSTARTY 2 +#define FILEWINLINES (LINES - 3) +#define FILEWINCOLS COLS + +#define INPUTWINSTARTY (LINES - 1) +#define INPUTWINLINES 1 +#define INPUTWINCOLS COLS + +#define INPUTBUFSZ 2048 + +static WINDOW * titlewin = NULL;  static WINDOW * statuswin = NULL; -static WINDOW * filewin = NULL; +static WINDOW * filewin = NULL; +static WINDOW * inputwin = NULL;    static void win_set(WINDOW * win, const char * str, int attrs);  static int ui_dirent_color(const dirent_t * de); +static int ui_link_color(const dirent_t * de);  static void ui_print_dirent(const dirent_t * de, size_t pos, bool selected, bool longmode, const dir_t * dir);  static void ui_wlpadstr(WINDOW * win, const char * s, size_t len);  static void ui_get_first_last(size_t n_dirents, size_t cursor, size_t * first, size_t * last); @@ -269 +4710 @@ void ui_init(void) {   curs_set(0);   noecho();   - titlewin = newwin(1, COLS, 0, 0); - statuswin = newwin(1, COLS, 1, 0); - filewin = newwin(LINES - 2, COLS, 2, 0); + titlewin = newwin(TITLEWINLINES, TITLEWINCOLS, TITLEWINSTARTY, 0); + statuswin = newwin(STATUSWINLINES, STATUSWINCOLS, STATUSWINSTARTY, 0); + filewin = newwin(FILEWINLINES, FILEWINCOLS, FILEWINSTARTY, 0); + inputwin = newwin(INPUTWINLINES, INPUTWINCOLS, INPUTWINSTARTY, 0);     clear();   refresh(); @@ -7219 +9419 @@ void ui_status_info(const char * status) {  }    void ui_status_error(const char * status) { - wattron(statuswin, COLOR_PAIR(RED)); - win_set(statuswin, status, 0); - wattroff(statuswin, COLOR_PAIR(RED)); + win_set(statuswin, status, COLOR_PAIR(RED));  }    void ui_erase(void) {   werase(filewin); + werase(inputwin);  }    void ui_refresh(void) {   wnoutrefresh(titlewin);   wnoutrefresh(statuswin);   wnoutrefresh(filewin); + wnoutrefresh(inputwin);   doupdate();  }   @@ -1446 +16617 @@ void ui_print_dirent(const dirent_t * de, size_t pos, bool selected, bool longmo   wattroff(filewin, color);   char c = dirent_crepr(de);   if (c) waddch(filewin, c); + + if (de->type == DE_LINK) { + waddstr(filewin, " -> "); + color = COLOR_PAIR(ui_link_color(de)); + if (selected) color |= A_REVERSE; + wattron(filewin, color); + waddstr(filewin, de->linkname); + wattroff(filewin, color); + char c = dirent_creprl(de); + if (c) waddch(filewin, c); + }  }    static int ui_dirent_color(const dirent_t * de) { @@ -1676 +20020 @@ static int ui_dirent_color(const dirent_t * de) {   return color;  }   +static int ui_link_color(const dirent_t * de) { + switch (de->linktype) { + case DE_FILE: return COLOR_FILE; + case DE_DIR: return COLOR_DIR; + case DE_FIFO: return COLOR_FIFO; + case DE_LINK: return COLOR_LINK; + case DE_BLOCK: return COLOR_BLOCK; + case DE_CHAR: return COLOR_CHAR; + case DE_SOCKET: return COLOR_SOCKET; + case DE_UNKNOWN: return COLOR_UNKNOWN; + default: return WHITE; + } +} +  void ui_print_dir(const dir_t * dir, size_t cursor, bool longmode) {   size_t first;   size_t last; @@ -20015 +24775 @@ static void ui_get_first_last(size_t dir_len, size_t cursor, size_t * first, siz   *first = 0;   *last = dir_len;   } else { - size_t off = lines / 2; - if (cursor < off) { + size_t off_lo = lines / 2; + size_t off_hi = lines - off_lo; + if (cursor < off_lo) {   *first = 0;   if (dir_len > lines) *last = lines;   else *last = dir_len;   } else { - *first = cursor - off; - if (dir_len > cursor + off) *last = cursor + off; + *first = cursor - off_lo; + if (dir_len > cursor + off_hi) *last = cursor + off_hi;   else *last = dir_len;   }   }  } + +void ui_resize(void) { + // unless a WINCH handler is specified, ncurses resizes the terminal + // automatically, so this function just resizes the windows + wresize(titlewin, TITLEWINLINES, TITLEWINCOLS); + wresize(statuswin, STATUSWINLINES, STATUSWINCOLS); + wresize(filewin, FILEWINLINES, FILEWINCOLS); + wresize(inputwin, INPUTWINLINES, INPUTWINCOLS); + + mvwin(titlewin, TITLEWINSTARTY, 0); + mvwin(statuswin, STATUSWINSTARTY, 0); + mvwin(filewin, FILEWINSTARTY, 0); + mvwin(inputwin, INPUTWINSTARTY, 0); + + ui_refresh(); +} + +const char * ui_readline(const char * prompt) { + static char inputbuf[INPUTBUFSZ]; + + char * p = inputbuf; + *p = 0; + + werase(inputwin); + waddstr(inputwin, prompt); + wattron(inputwin, A_REVERSE); + waddch(inputwin, ' '); + wattroff(inputwin, A_REVERSE); + wrefresh(inputwin); + + int c; + while ((c = wgetch(inputwin)) != '\n') { + if (c == KEY_ESC) { + curs_set(0); + return NULL; + } + + if (c == KEY_DEL || c == KEY_BACKSPACE) { + if (p != inputbuf) *--p = 0; + else return NULL; + } else if (isprint(c)) { + if (p - inputbuf < INPUTBUFSZ - 1) { + *p++ = (char)c; + *p = 0; + } + } + + werase(inputwin); + waddstr(inputwin, prompt); + waddstr(inputwin, inputbuf); + wattron(inputwin, A_REVERSE); + waddch(inputwin, ' '); + wattroff(inputwin, A_REVERSE); + wrefresh(inputwin); + } + + if (p == inputbuf) return NULL; + return inputbuf; +}