Thumbnail

rani/cscroll.git

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

commit cd1cdaafbe1a57c6e64fffee8bb208648e1b758c Author: rani <clagv.randomgames@gmail.com> Date: Thu Jan 15 14:34:25 2026 +0000 Add: cutting/pasting marks diff --git a/include/dir.h b/include/dir.h index 7f8d3da..eea10af 100644 --- a/include/dir.h +++ b/include/dir.h @@ -956 +957 @@ cvector(dirent_t) dir_entries(const dir_t * dir);  void dir_sort(dir_t * dir);  const char * dir_get_home(void);  size_t dir_get_total_marked(void); +int dir_paste_marks(const char * cwd, size_t * total_pastes);    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/main.h b/include/main.h new file mode 100644 index 0000000..acb6417 --- /dev/null +++ b/include/main.h @@ -00 +19 @@ +#ifndef MAIN_H +#define MAIN_H + +enum prog_mode { + MODE_NORMAL, + MODE_CUT, +}; + +#endif /* MAIN_H */ diff --git a/include/ui.h b/include/ui.h index 1735fa4..92bcf37 100644 --- a/include/ui.h +++ b/include/ui.h @@ -66 +67 @@  #include <stddef.h>    #include "dir.h" +#include "main.h"    #define CTRL(k) ((k) & 0x1F)   @@ -6210 +6311 @@ 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); -void ui_print_cursor(size_t cursor, size_t total, size_t total_marked); +void ui_print_cursor(size_t cursor, size_t total, enum prog_mode mode, size_t total_marked);  void ui_resize(void);  const char * ui_readline(const char * prompt);  const char * ui_prompt(const char * prompt, prompt_opts_t opts);  bool ui_prompt_deletion(const dirent_t * de); +bool ui_prompt_paste(size_t total_marked);    #endif /* UI_H */ diff --git a/src/dir.c b/src/dir.c index 7dd3748..77c4b1e 100644 --- a/src/dir.c +++ b/src/dir.c @@ -749 +746 @@ static size_t ilen(size_t i, int base) {   }   return r;  } -static void marks_set_destroyer(void * p) { - ; -}  static void marks_destroyer(void * p) {   hashmap_destroy((hashmap*)p);  } @@ -7167 +7137 @@ int dirent_togglemark(dirent_t * de) {   de->marked = true;   hashmap * dirmarks = hashmap_get(marks, cwd);   if (!dirmarks) { - dirmarks = hashmap_new(marks_set_destroyer); + dirmarks = hashmap_new(NULL);   hashmap_insert(marks, cwd, dirmarks);   }   hashmap_insert(dirmarks, de->name, (void*)true); @@ -7613 +75843 @@ int dirent_togglemark(dirent_t * de) {     return 0;  } + +int dir_paste_marks(const char * cwd, size_t * total_pastes) { + *total_pastes = 0; + + DIR * pastedir = opendir(cwd); + if (!pastedir) return -errno; + int pastefd = dirfd(pastedir); + + int retval = 0; + + hashmap_walk_state marksws = {0}; + while (hashmap_walk(marks, &marksws)) { + const char * dirpath = marksws.key; + hashmap * dirmarks = marksws.val; + + DIR * sourcedir = opendir(dirpath); + if (!sourcedir) continue; + int sourcefd = dirfd(sourcedir); + + hashmap_walk_state dirmarksws = {0}; + while (hashmap_walk(dirmarks, &dirmarksws)) { + const char * fname = dirmarksws.key; + // make sure the new file name doesn't already exist + struct stat statbuf; + int ret = fstatat(pastefd, fname, &statbuf, AT_SYMLINK_NOFOLLOW); + if (ret >= 0) continue; + ret = renameat(sourcefd, fname, pastefd, fname); + if (ret < 0) continue; + (*total_pastes)++; + } + + closedir(sourcedir); + } + + closedir(pastedir); + hashmap_destroy(marks); + marks = hashmap_new(marks_destroyer); + n_marks = 0; + return retval; +} diff --git a/src/main.c b/src/main.c index 1bad0ab..1955f4b 100644 --- a/src/main.c +++ b/src/main.c @@ -216 +217 @@ int main(int argc, char ** argv) {   dir_list(cwd, &dir);     ui_init(); + enum prog_mode mode = MODE_NORMAL;   size_t cursor = 0;   ui_status_info("");   for (;;) { @@ -307 +317 @@ int main(int argc, char ** argv) {     ui_set_title(cwd, home);   ui_print_dir(&dir, cursor); - ui_print_cursor(cursor, dirlen, dir_get_total_marked()); + ui_print_cursor(cursor, dirlen, mode, dir_get_total_marked());     ui_refresh();   @@ -1436 +14410 @@ int main(int argc, char ** argv) {   break;   }   case 'd': { + if (mode == MODE_CUT) { + ui_status_info("Cannot Delete While Cutting"); + break; + }   ui_refresh();   bool del = ui_prompt_deletion(cur_de);   if (!del) { @@ -17010 +17514 @@ int main(int argc, char ** argv) {   }   case 'm': {   if (!cur_de) break; + if (mode == MODE_CUT) { + ui_status_info("Cannot Mark While Cutting"); + break; + }   int ret = dirent_togglemark(cur_de);   if (ret < 0) switch (-ret) {   case TOGGLEMARK_PARENT_MARKED: - ui_status_error("Ancestor Already Marked"); + ui_status_info("Ancestor Already Marked");   break;   case TOGGLEMARK_DIRENT_UNKNOWN:   ui_status_error("Cannot Mark Unknown Dirent"); @@ -1846 +19337 @@ int main(int argc, char ** argv) {   }   break;   } + case 'c': + if (mode == MODE_NORMAL && dir_get_total_marked() > 0) mode = MODE_CUT; + else if (mode == MODE_CUT) mode = MODE_NORMAL; + break; + case 'p': { + if (mode != MODE_CUT) { + ui_status_info("Cannot Paste if Not Cutting"); + break; + } + bool paste = ui_prompt_paste(dir_get_total_marked()); + if (!paste) { + ui_status_info("Not Pasting"); + break; + } + mode = MODE_NORMAL; + ui_status_info("Pasting"); + ui_refresh(); + + size_t total_marks, total_pastes; + total_marks = dir_get_total_marked(); + int ret = dir_paste_marks(cwd, &total_pastes); + if (ret < 0) ui_status_error(strerror(-ret)); + else if (total_pastes == 0) + ui_status_error("Nothing Pasted"); + else if (total_marks != total_pastes) + ui_status_error("Not All Marks Pasted"); + else ui_status_info("Pasted"); + dir_free(&dir); + dir_list(cwd, &dir); + break; + }   case 'q':   goto finished;   case KEY_RESIZE: diff --git a/src/ui.c b/src/ui.c index 798f871..5697d26 100644 --- a/src/ui.c +++ b/src/ui.c @@ -116 +117 @@    #include "ui.h"  #include "dir.h" +#include "main.h"  #include "config.h"  #include "cvector.h"   @@ -3637 +3647 @@ void ui_print_dir(const dir_t * dir, size_t cursor) {   }  }   -void ui_print_cursor(size_t cursor, size_t total, size_t total_marked) { +void ui_print_cursor(size_t cursor, size_t total, enum prog_mode mode, size_t total_marked) {   size_t lines, cols;   getmaxyx(filewin, lines, cols);   if (config.longmode && !config.longinline) { @@ -3808 +38114 @@ void ui_print_cursor(size_t cursor, size_t total, size_t total_marked) {   waddstr(filewin, "0/0");   }   - if (total_marked > 0) { - wprintw(filewin, " | %zu Marked", total_marked); + if (total_marked > 0) switch (mode) { + case MODE_NORMAL: + wprintw(filewin, " | %zu Marked", total_marked); + break; + case MODE_CUT: + wprintw(filewin, " | Cutting %zu", total_marked); + break; + default: break;   }  }   @@ -6013 +60818 @@ bool ui_prompt_deletion(const dirent_t * de) {     return true;  } + +bool ui_prompt_paste(size_t total_marked) { + static const char * no = "No"; + static const char * yes = "Yes"; + static const char * fstr = "Paste %zu files into this directory?"; + + size_t len = snprintf(NULL, 0, fstr, total_marked); + char * prompt = malloc(len + 1); + sprintf(prompt, fstr, total_marked); + + const char * ret = ui_prompt(prompt, (prompt_opts_t){no, yes, NULL}); + free(prompt); + if (ret != yes) return false; + return true; +}