Thumbnail

rani/cscroll.git

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

commit 7b1661244d58353d4b6d5a3d27450f5757845f06 Author: rani <clagv.randomgames@gmail.com> Date: Wed Dec 31 20:34:20 2025 +0000 Add: configuration; Add: long mode options and long mode command 'l'; Add: dot file options and dot file command '.'; Add: directory sorting diff --git a/Makefile b/Makefile index 37cbb01..b7d8a73 100644 --- a/Makefile +++ b/Makefile @@ -15 +15 @@  BIN = cscroll -SRC = src/dir.c src/ui.c src/main.c +SRC = src/config.c src/dir.c src/ui.c src/main.c  OBJ = ${SRC:.c=.o}    CC ?= cc diff --git a/include/config.h b/include/config.h new file mode 100644 index 0000000..8c9102a --- /dev/null +++ b/include/config.h @@ -00 +135 @@ +#ifndef CONFIG_H +#define CONFIG_H + +#include <stdbool.h> + +enum dir_sort_dirs { + DIR_SORT_DIRS_FIRST, + DIR_SORT_DIRS_LAST, + DIR_SORT_DIRS_UNSORTED, +}; + +enum dir_sortby { + DIR_SORTBY_NAME, + DIR_SORTBY_TIME, + DIR_SORTBY_SIZE, +}; + +enum dir_sort { + DIR_SORT_INCREASING, + DIR_SORT_DECREASING, + DIR_SORT_UNSORTED, +}; + +typedef struct { + bool longmode; + bool longinline; + bool dots; + enum dir_sort_dirs dir_sort_dirs; + enum dir_sortby dir_sortby; + enum dir_sort dir_sort; +} config_t; + +extern config_t config; + +#endif /* CONFIG_H */ diff --git a/include/dir.h b/include/dir.h index 9551cb0..3d46d07 100644 --- a/include/dir.h +++ b/include/dir.h @@ -526 +528 @@ typedef struct {  typedef struct {   size_t len;   cvector(dirent_t) entries; + size_t nodots_len; + cvector(dirent_t) nodots;     size_t longest_uname;   size_t longest_gname; @@ -666 +689 @@ 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); +size_t dir_len(const dir_t * dir); +cvector(dirent_t) dir_entries(const dir_t * dir); +void dir_sort(const dir_t * dir);    char dirent_crepr(const dirent_t * de); // character representing dir entry  char dirent_creprl(const dirent_t * de); // like above, but for the link diff --git a/include/ui.h b/include/ui.h index a2e07c7..01d3665 100644 --- a/include/ui.h +++ b/include/ui.h @@ -357 +357 @@ void ui_status_info(const char * status);  void ui_status_error(const char * status);  void ui_erase(void);  void ui_refresh(void); -void ui_print_dir(const dir_t * dir, size_t cursor, bool longmode); +void ui_print_dir(const dir_t * dir, size_t cursor);  void ui_print_cursor(size_t cursor, size_t total);  void ui_resize(void);  const char * ui_readline(const char * prompt); diff --git a/src/config.c b/src/config.c new file mode 100644 index 0000000..8353340 --- /dev/null +++ b/src/config.c @@ -00 +113 @@ +#include <stdbool.h> + +#include "config.h" + +config_t config = { + .longmode = true, + .longinline = true, + .dots = true, + + .dir_sortby = DIR_SORTBY_NAME, + .dir_sort = DIR_SORT_INCREASING, + .dir_sort_dirs = DIR_SORT_DIRS_FIRST, +}; diff --git a/src/dir.c b/src/dir.c index a480701..1b7da66 100644 --- a/src/dir.c +++ b/src/dir.c @@ -15 +16 @@  #include <sys/stat.h>  #include <stdbool.h> +#include <strings.h>  #include <dirent.h>  #include <stdlib.h>  #include <string.h> @@ -116 +127 @@  #include <grp.h>    #include "dir.h" +#include "config.h"  #include "cvector.h"    #define CWDSZ (PATH_MAX + 1) @@ -426 +448 @@ int dir_list(const char * path, dir_t * dir) {   dir->len = 0;   dir->entries = NULL;   cvector_init(dir->entries, 1, free_dirent); + dir->nodots_len = 0; + dir->nodots = NULL;   dir->longest_uname = 0;   dir->longest_gname = 0;   dir->longest_size = 0; @@ -626 +6611 @@ int dir_list(const char * path, dir_t * dir) {   cvector_push_back(dir->entries, dirent);   dir->len++;   + if (*de->d_name != '.') { + cvector_push_back(dir->nodots, dirent); + dir->nodots_len++; + } +   size_t uname_len = 0;   size_t gname_len = 0;   size_t size_len = ilen(dirent.size, 10); @@ -1466 +1557 @@ void dir_entry(int dirfd, const char * name, dirent_t * dirent) {    void dir_free(dir_t * dir) {   cvector_free(dir->entries); + cvector_free(dir->nodots);  }    char de_crepr(enum de_type de_type) { @@ -2818 +29111 @@ const char * dir_basename(const char * path) {  }    int dir_search_name(const dir_t * dir, const char * name, size_t * idx) { - for (size_t i = 0; i < dir->len; i++) { - if (!strcmp(dir->entries[i].name, name)) { + size_t dirlen = dir_len(dir); + cvector(dirent_t) entries = dir_entries(dir); + + for (size_t i = 0; i < dirlen; i++) { + if (!strcmp(entries[i].name, name)) {   *idx = i;   return 0;   } @@ -29212 +30515 @@ 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) { + size_t dirlen = dir_len(dir); + cvector(dirent_t) entries = dir_entries(dir); +   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]; + for (size_t i = 0; i < dirlen; i++) { + dirent_t * de = &entries[i];   ret = regexec(&regex, de->name, 0, NULL, 0);   if (!ret) {   *idx = i; @@ -3093 +32548 @@ int dir_search_regex(const dir_t * dir, const char * regexstr, size_t * idx) {   regfree(&regex);   return -REGSEARCH_NOT_FOUND;  } + +size_t dir_len(const dir_t * dir) { + if (config.dots) return dir->len; + else return dir->nodots_len; +} + +cvector(dirent_t) dir_entries(const dir_t * dir) { + if (config.dots) return dir->entries; + else return dir->nodots; +} + +static int dir_sort_cmp(const void * inpa, const void * inpb) { + const dirent_t * a = (const dirent_t*)inpa; + const dirent_t * b = (const dirent_t*)inpb; + + if (config.dir_sort_dirs != DIR_SORT_DIRS_UNSORTED + && ((a->type == DE_DIR) != (b->type == DE_DIR))) { + if (config.dir_sort_dirs == DIR_SORT_DIRS_FIRST) + return (a->type == DE_DIR) ? -1 : 1; + if (config.dir_sort_dirs == DIR_SORT_DIRS_LAST) + return (b->type == DE_DIR) ? -1 : 1; + } + + if (config.dir_sort == DIR_SORT_DECREASING) { + const dirent_t * tmp = a; + a = b; + b = tmp; + } + + switch (config.dir_sortby) { + case DIR_SORTBY_NAME: + return strcasecmp(a->name, b->name); + case DIR_SORTBY_TIME: + return (a->mtime < b->mtime) ? -1 : 1; + case DIR_SORTBY_SIZE: + return (a->size < b->size) ? -1 : 1; + default: return 0; + } +} + +void dir_sort(const dir_t * dir) { + if (config.dir_sort == DIR_SORT_UNSORTED) return; + qsort(dir->entries, dir->len, sizeof(dir->entries[0]), dir_sort_cmp); + qsort(dir->nodots, dir->nodots_len, sizeof(dir->entries[0]), dir_sort_cmp); +} diff --git a/src/main.c b/src/main.c index 58a169a..109b50f 100644 --- a/src/main.c +++ b/src/main.c @@ -512 +515 @@    #include "ui.h"  #include "dir.h" +#include "config.h" +#include "cvector.h"    int main(int argc, char ** argv) {   const char * cwd = dir_get_cwd();     dir_t dir;   dir_list(cwd, &dir); + dir_sort(&dir);     ui_init();   size_t cursor = 0; @@ -1822 +2126 @@ int main(int argc, char ** argv) {   for (;;) {   ui_erase();   + size_t dirlen = dir_len(&dir); + cvector(dirent_t) entries = dir_entries(&dir); +   ui_set_title(cwd); - ui_print_dir(&dir, cursor, true); - ui_print_cursor(cursor, dir.len); + ui_print_dir(&dir, cursor); + ui_print_cursor(cursor, dirlen);     ui_refresh();     dirent_t * cur_de; - if (dir.len == 0) cur_de = NULL; - else cur_de = &dir.entries[cursor]; + if (dirlen == 0) cur_de = NULL; + else cur_de = &entries[cursor]; +   switch (getch()) {   case KEY_UP:   if (cursor > 0) cursor--;   ui_status_info("");   break;   case KEY_DOWN: - if (cursor < dir.len - 1) cursor++; + if (cursor < dirlen - 1) cursor++;   ui_status_info("");   break;   case KEY_LEFT: { @@ -4912 +5613 @@ int main(int argc, char ** argv) {   ret = dir_list(cwd, &dir);   if (ret < 0) {   ui_status_error(strerror(-ret)); - } else if (basename) { - size_t idx; - int i = dir_search_name(&dir, basename, &idx); - if (i >= 0) cursor = idx; - ui_status_info("");   } else { + dir_sort(&dir); + if (basename) { + size_t idx; + int i = dir_search_name(&dir, basename, &idx); + if (i >= 0) cursor = idx; + }   ui_status_info("");   }   } else { @@ -727 +808 @@ int main(int argc, char ** argv) {   cwd = dir_get_cwd();   dir_free(&dir);   dir_list(cwd, &dir); - if (dir.len == 0) ui_status_info("Empty Directory"); + dir_sort(&dir); + if (dirlen == 0) ui_status_info("Empty Directory");   } else {   ui_status_error(strerror(-ret));   } @@ -879 +9627 @@ int main(int argc, char ** argv) {   break;   case KEY_END:   case 'G': - cursor = dir.len - 1; + cursor = dirlen - 1;   ui_status_info("");   break; + case '.': { + config.dots = !config.dots; + size_t idx; + int ret = dir_search_name(&dir, cur_de->name, &idx); + if (ret < 0) cursor = 0; + else cursor = idx; + break; + } + case 'l': + // cycle through long mode options + if (config.longmode) { + if (config.longinline) config.longinline = false; + else config.longmode = false; + } else { + config.longmode = true; + config.longinline = true; + } + break;   case '/': {   const char * input = ui_readline("/");   if (!input) break; diff --git a/src/ui.c b/src/ui.c index 1042da9..ae49f45 100644 --- a/src/ui.c +++ b/src/ui.c @@ -86 +88 @@    #include "ui.h"  #include "dir.h" +#include "config.h" +#include "cvector.h"    #define TITLEWINSTARTY 0  #define TITLEWINLINES 1 @@ -357 +377 @@ 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_print_dirent(const dirent_t * de, size_t pos, bool selected, 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);   @@ -1207 +1227 @@ static void ui_wlpadstr(WINDOW * win, const char * s, size_t len) {   waddstr(win, s);  }   -void ui_print_dirent(const dirent_t * de, size_t pos, bool selected, bool longmode, const dir_t * dir) { +void ui_print_dirent(const dirent_t * de, size_t pos, bool selected, const dir_t * dir) {   static const enum ui_color mode_colors[] = {   ['r'] = RED, ['w'] = MAGENTA, ['x'] = COLOR_EXEC,   ['s'] = YELLOW, ['S'] = YELLOW, ['t'] = RED, @@ -1349 +13619 @@ void ui_print_dirent(const dirent_t * de, size_t pos, bool selected, bool longmo   static char stime[128];   static char isbuf[40]; // should be big enough to hold any integer   - wmove(filewin, pos, 0); + size_t lines, cols; + getmaxyx(filewin, lines, cols); + + size_t dirlen = dir_len(dir); + + if (config.longmode && (config.longinline || (!config.longinline && selected))) { + if (config.longinline) wmove(filewin, pos, 0); + else { + // place the longmode info right on top of the "cursor" info + if (dirlen < lines - 3) wmove(filewin, dirlen + 1, 0); + else wmove(filewin, lines - 2, 0); + }   - if (longmode) {   const char * pmode = dirent_prettymode(de);   for (const char * p = pmode; *p; p++) {   int color = COLOR_PAIR(mode_colors[(unsigned)*p]); @@ -1596 +1719 @@ void ui_print_dirent(const dirent_t * de, size_t pos, bool selected, bool longmo   wprintw(filewin, " %s ", stime);   }   + if (!config.longmode || (config.longmode && !config.longinline)) + wmove(filewin, pos, 0); +   int color = COLOR_PAIR(ui_dirent_color(de));   if (selected) color |= A_REVERSE;   wattron(filewin, color); @@ -21422 +22929 @@ static int ui_link_color(const dirent_t * de) {   }  }   -void ui_print_dir(const dir_t * dir, size_t cursor, bool longmode) { +void ui_print_dir(const dir_t * dir, size_t cursor) {   size_t first;   size_t last; - ui_get_first_last(dir->len, cursor, &first, &last); + size_t len = dir_len(dir); + cvector(dirent_t) entries = dir_entries(dir); + ui_get_first_last(len, cursor, &first, &last);     for (size_t i = first; i < last; i++) {   size_t pos = i - first; - ui_print_dirent(&dir->entries[i], pos, cursor == i, longmode, dir); + ui_print_dirent(&entries[i], pos, cursor == i, dir);   }  }    void ui_print_cursor(size_t cursor, size_t total) {   size_t lines, cols;   getmaxyx(filewin, lines, cols); - if (total < lines - 2) wmove(filewin, total + 1, 0); - else wmove(filewin, lines - 1, 0); + if (config.longmode && !config.longinline) { + if (total < lines - 3) wmove(filewin, total + 2, 0); + else wmove(filewin, lines - 1, 0); + } else { + if (total < lines - 2) wmove(filewin, total + 1, 0); + else wmove(filewin, lines - 1, 0); + }     if (total > 0) {   wprintw(filewin, "%zu/%zu", cursor + 1, total); @@ -2426 +2647 @@ static void ui_get_first_last(size_t dir_len, size_t cursor, size_t * first, siz   size_t lines, cols;   getmaxyx(filewin, lines, cols);   lines -= 2; + if (config.longmode && !config.longinline) lines--;   // try to keep cursor in the middle of the window   if (dir_len < lines) {   *first = 0;