From b2b682e96cbb1639b7423ab959ad1ab781f52379 Mon Sep 17 00:00:00 2001 From: Piotr Marendowski Date: Sat, 16 Mar 2024 21:37:56 +0100 Subject: [PATCH 01/12] Minor refactoring and changes in config.h --- README.md | 3 -- ccc.c | 94 ++++++++++++++++++++++++++++--------------------------- config.h | 17 ++++++---- 3 files changed, 59 insertions(+), 55 deletions(-) diff --git a/README.md b/README.md index dc3c9fb..42ea80a 100644 --- a/README.md +++ b/README.md @@ -6,9 +6,6 @@ The fact that it is written in C makes it more versatile and rapid, enabling us ## Features -- Vim-like key binding -- File Preview - Consider this project incomplete and WIP! | Feature | Ported | Dropped | Added | diff --git a/ccc.c b/ccc.c index c70da4f..75b6a3c 100644 --- a/ccc.c +++ b/ccc.c @@ -39,7 +39,7 @@ void draw_border_title(WINDOW *window, bool active); /* global variables */ unsigned int focus = 0; long current_selection = 0; -bool dir_mode = BLOCK_SIZE; +bool dirs_size = DIRS_SIZE; char *cwd; int half_width; WIN_STRUCT windows[5]; @@ -153,7 +153,7 @@ int main(int argc, char** argv) break; */ - /* jump up (ctrl u)*/ + /* jump up (ctrl u) */ case CTRLU: if ((current_selection - JUMP_NUM) > 0) current_selection -= JUMP_NUM; @@ -172,7 +172,7 @@ int main(int argc, char** argv) highlight_current_line(); break; - /* jump down (ctrl d)*/ + /* jump down (ctrl d) */ case CTRLD: if ((current_selection + JUMP_NUM) < (files_len() - 1)) current_selection += JUMP_NUM; @@ -241,7 +241,7 @@ int main(int argc, char** argv) /* a to toggle between DISK_USAGE and BLOCK SIZE */ case 'a': - dir_mode = !dir_mode; + dirs_size = !dirs_size; clear_files(); populate_files(cwd); highlight_current_line(); @@ -292,6 +292,9 @@ void change_dir(const char *buf) int mkdir_p(const char *destdir) { char *path = memalloc(PATH_MAX * sizeof(char)); + char *token = strtok(path, "/"); + char dir_path[PATH_MAX] = ""; + strcpy(path, destdir); if (destdir[0] == '~') { char *home = getenv("HOME"); @@ -303,13 +306,9 @@ int mkdir_p(const char *destdir) memmove(path + strlen(home), path + 1, strlen(path)); memcpy(path, home, strlen(home)); } - char *token = strtok(path, "/"); - char dir_path[PATH_MAX] = ""; - - /* fix first / is not appearing in string */ - if (path[0] == '/') { + /* fix first / not appearing in the string */ + if (path[0] == '/') strcat(dir_path, "/"); - } while (token != NULL) { strcat(dir_path, token); @@ -360,7 +359,7 @@ void populate_files(const char *path) filename[0] = '\0'; strcat(filename, cwd); strcat(filename, "/"); - strcat(filename, ep->d_name); /* add file name */ + strcat(filename, ep->d_name); /* add filename */ add_file_stat(filename, 0); } @@ -382,7 +381,7 @@ int get_directory_size(const char *fpath, const struct stat *sb, int typeflag, s /* * Get file's last modified time, size, type * Add that file into list - * ftype: 0->dir files, 0->marked + * ftype: 0 = normal file, 1 = marked */ long add_file_stat(char *filepath, int ftype) { @@ -402,8 +401,8 @@ long add_file_stat(char *filepath, int ftype) /* get file size */ double bytes = file_stat.st_size; - if (!dir_mode) { - /* dir_mode is 0, so disk usage mode, calculate disk usage */ + if (dirs_size) { + /* dirs_size is true, so calculate disk usage */ if (S_ISDIR(file_stat.st_mode)) { /* at most 15 fd opened */ total_dir_size = 0; @@ -426,25 +425,25 @@ long add_file_stat(char *filepath, int ftype) char *type = memalloc(4 * sizeof(char)); /* 4 chars for type */ int color; if (S_ISDIR(file_stat.st_mode)) { - strcpy(type, "DIR"); /* directory type */ + strcpy(type, "DIR"); /* directory type */ color = 5; /* blue color */ } else if (S_ISREG(file_stat.st_mode)) { - strcpy(type, "REG"); /* regular file */ + strcpy(type, "REG"); /* regular file */ color = 8; /* white color */ } else if (S_ISLNK(file_stat.st_mode)) { - strcpy(type, "LNK"); /* symbolic link */ + strcpy(type, "LNK"); /* symbolic link */ color = 3; /* green color */ } else if (S_ISCHR(file_stat.st_mode)) { - strcpy(type, "CHR"); /* character device */ + strcpy(type, "CHR"); /* character device */ color = 8; /* white color */ } else if (S_ISSOCK(file_stat.st_mode)) { - strcpy(type, "SOC"); /* socket */ + strcpy(type, "SOC"); /* socket */ color = 8; /* white color */ } else if (S_ISBLK(file_stat.st_mode)) { - strcpy(type, "BLK"); /* block device */ + strcpy(type, "BLK"); /* block device */ color = 4; /* yellow color */ } else if (S_ISFIFO(file_stat.st_mode)) { - strcpy(type, "FIF"); /* FIFO */ + strcpy(type, "FIF"); /* FIFO */ color = 8; /* white color */ } else { color = 8; /* white color */ @@ -461,8 +460,8 @@ long add_file_stat(char *filepath, int ftype) return index; } /* already marked */ - return -1; /* -1 does nothing, just function required to return something */ + return -1; } char *total_stat = memalloc(45 * sizeof(char)); @@ -501,9 +500,9 @@ void highlight_current_line() } if (range > LINES - 3) { - /* if there is more files than lines available to display*/ - /* shrink range to avaiable lines to display */ - /* with overflow to keep number of iterations to be constant */ + /* if there are more files than lines available to display + * shrink range to avaiable lines to display with + * overflow to keep the number of iterations to be constant */ range = LINES - 3 + overflow; } @@ -516,13 +515,6 @@ void highlight_current_line() /* update the panel */ wclear(panel); - /* showing dir_mode requires 26 characters */ - char *dir_mode_line = memalloc(27 * sizeof(char)); - if (dir_mode) - strncpy(dir_mode_line, "Directory Mode: Block Size", 27); - else - strncpy(dir_mode_line, "Directory Mode: Disk Usage", 27); - /* check for marked files */ long num_marked = marked_len(); if (num_marked > 0) { @@ -531,9 +523,9 @@ void highlight_current_line() char *selected = memalloc((m_len + 1) * sizeof(char)); snprintf(selected, m_len + 1, "(%ld selected)", num_marked); - wprintw(panel, "(%ld/%ld) %s %s %s", current_selection + 1, files_len(), selected, cwd, dir_mode_line); + wprintw(panel, "(%ld/%ld) %s %s", current_selection + 1, files_len(), selected, cwd); } else { - wprintw(panel, "(%ld/%ld) %s %s", current_selection + 1, files_len(), cwd, dir_mode_line); + wprintw(panel, "(%ld/%ld) %s", current_selection + 1, files_len(), cwd); } } /* print the actual filename and stats */ @@ -579,7 +571,10 @@ void show_file_content() { wclear(preview_content); file *current_file = get_file((long) current_selection); - if (strncmp(current_file->type, "DIR", 3) == 0) return; + + if (strncmp(current_file->type, "DIR", 3) == 0) + return; + FILE *file = fopen(current_file->path, "r"); if (file == NULL) { mvwprintw(preview_content, 0, 0, "Unable to read %s", current_file->path); @@ -588,8 +583,8 @@ void show_file_content() draw_border_title(preview_border, true); int c; - /* check binary */ - while ((c=fgetc(file)) != EOF) { + /* check if its binary */ + while ((c = fgetc(file)) != EOF) { if (c == '\0') { mvwprintw(preview_content, 0, 0, "binary"); return; @@ -617,20 +612,27 @@ void show_file_content() */ void edit_file() { - char *editor = getenv("EDITOR"); + #ifdef EDITOR + char *editor = EDITOR; + #else + char *editor = getenv("EDITOR"); + #endif + if (editor == NULL) { wpprintw("Cannot get EDITOR variable, is it defined?"); return; } else { - def_prog_mode(); /* save the tty modes */ - endwin(); /* end curses mode temporarily */ + def_prog_mode(); /* save the tty modes */ + endwin(); /* end curses mode temporarily */ + char *filename = get_filepath(current_selection); - int length = strlen(editor) + strlen(filename) + 2; /* one for space one for nul */ + int length = strlen(editor) + strlen(filename) + 2; /* one for space one for null */ char command[length]; + snprintf(command, length, "%s %s", editor, filename); system(command); - reset_prog_mode(); /* return to previous tty mode */ - refresh(); /* store the screen contents */ + reset_prog_mode(); /* return to previous tty mode */ + refresh(); /* store the screen contents */ free(filename); } } @@ -668,9 +670,9 @@ void init_windows() draw_border_title(preview_border, true); scrollok(directory_content, true); - /* window location y, x */ - windows[0] = (WIN_STRUCT) { directory_border, 0, 0, 0 }; - windows[1] = (WIN_STRUCT) { directory_border, 0, 0, 0 }; + /* window location y, x */ + windows[0] = (WIN_STRUCT) { directory_border, 0, 0, 0 }; + windows[1] = (WIN_STRUCT) { directory_border, 0, 0, 0 }; windows[2] = (WIN_STRUCT) { preview_border, 1, 0, half_width }; windows[3] = (WIN_STRUCT) { preview_content, 1, 0, half_width }; windows[4] = (WIN_STRUCT) { panel, 2, LINES - PH, 0 }; diff --git a/config.h b/config.h index 325b31d..0ead672 100644 --- a/config.h +++ b/config.h @@ -1,3 +1,14 @@ +/* Settings */ +#define PH 1 /* panel height */ +#define JUMP_NUM 14 /* how long ctrl + u/d jump are */ + +/* Calculate directories' sizes upon entering? */ +#define DIRS_SIZE false + +/* Default text editor */ +#define EDITOR "nvim" + +/* Keybindings */ #define CTRLD 0x04 #define ENTER 0xA #define CTRLU 0x15 @@ -9,9 +20,3 @@ #define LEFT 0x104 #define RIGHT 0x105 #define BACKSPACE 0x107 -#define PH 1 /* panel height */ -#define JUMP_NUM 14 /* how long ctrl + u/d jump are */ -#define BLOCK_SIZE true -#define DISK_USAGE false - -static const char *editor = "nvim"; /* default text editor */ From fcab4e35dd79bb7c3219479603d2bf6929ec906f Mon Sep 17 00:00:00 2001 From: Piotr Marendowski Date: Sat, 16 Mar 2024 21:59:49 +0100 Subject: [PATCH 02/12] Minor refactoring + a change in keybindings --- ccc.c | 101 +++++++++++++++++++++++++-------------------------------- file.c | 6 ++++ 2 files changed, 51 insertions(+), 56 deletions(-) diff --git a/ccc.c b/ccc.c index 75b6a3c..0b9c431 100644 --- a/ccc.c +++ b/ccc.c @@ -147,11 +147,6 @@ int main(int argc, char** argv) } } break; - /* - if (focus == 0) focus++; - else if (focus == 1) focus--; - break; - */ /* jump up (ctrl u) */ case CTRLU: @@ -210,7 +205,7 @@ int main(int argc, char** argv) } break; - /* ~ to go home */ + /* go to $HOME */ case TILDE:; char *home = getenv("HOME"); if (home == NULL) { @@ -220,7 +215,7 @@ int main(int argc, char** argv) } break; - /* t to go to trash dir */ + /* go to the trash dir */ case 't':; char *trash_dir = getenv("CCC_TRASH"); if (trash_dir == NULL) { @@ -239,8 +234,8 @@ int main(int argc, char** argv) } break; - /* a to toggle between DISK_USAGE and BLOCK SIZE */ - case 'a': + /* show directories' sizes */ + case 'v': dirs_size = !dirs_size; clear_files(); populate_files(cwd); @@ -258,9 +253,9 @@ int main(int argc, char** argv) break; case KEY_RESIZE: - for (int i = 0; i < 2; i++) { + for (int i = 0; i < 2; i++) delwin(windows[i].window); - } + endwin(); init_windows(); break; @@ -387,9 +382,46 @@ long add_file_stat(char *filepath, int ftype) { struct stat file_stat; if (stat(filepath, &file_stat) == -1) { - /* can't be triggered ? */ - if (errno == EACCES) { + /* can't be triggered? */ + if (errno == EACCES) return add_file(filepath, "", "", 8); + } + + /* get file type and color */ + char *type = memalloc(4 * sizeof(char)); /* 4 chars for type */ + int color; + if (S_ISDIR(file_stat.st_mode)) { + strcpy(type, "DIR"); /* directory type */ + color = 5; /* blue color */ + } else if (S_ISREG(file_stat.st_mode)) { + strcpy(type, "REG"); /* regular file */ + color = 8; /* white color */ + } else if (S_ISLNK(file_stat.st_mode)) { + strcpy(type, "LNK"); /* symbolic link */ + color = 3; /* green color */ + } else if (S_ISCHR(file_stat.st_mode)) { + strcpy(type, "CHR"); /* character device */ + color = 8; /* white color */ + } else if (S_ISSOCK(file_stat.st_mode)) { + strcpy(type, "SOC"); /* socket */ + color = 8; /* white color */ + } else if (S_ISBLK(file_stat.st_mode)) { + strcpy(type, "BLK"); /* block device */ + color = 4; /* yellow color */ + } else if (S_ISFIFO(file_stat.st_mode)) { + strcpy(type, "FIF"); /* FIFO */ + color = 8; /* white color */ + } else { + color = 8; /* white color */ + } + + /* if file is to be marked */ + if (ftype == 1) { + long index = add_marked(filepath, type); + if (index != -1) { + return index; /* just marked */ + } else { + return -1; /* already marked */ } } @@ -420,50 +452,7 @@ long add_file_stat(char *filepath, int ftype) } /* 4 sig fig, limiting characters to have better format */ sprintf(size, "%-6.4g %-3s", bytes, units[unit]); - - /* get file type and color */ - char *type = memalloc(4 * sizeof(char)); /* 4 chars for type */ - int color; - if (S_ISDIR(file_stat.st_mode)) { - strcpy(type, "DIR"); /* directory type */ - color = 5; /* blue color */ - } else if (S_ISREG(file_stat.st_mode)) { - strcpy(type, "REG"); /* regular file */ - color = 8; /* white color */ - } else if (S_ISLNK(file_stat.st_mode)) { - strcpy(type, "LNK"); /* symbolic link */ - color = 3; /* green color */ - } else if (S_ISCHR(file_stat.st_mode)) { - strcpy(type, "CHR"); /* character device */ - color = 8; /* white color */ - } else if (S_ISSOCK(file_stat.st_mode)) { - strcpy(type, "SOC"); /* socket */ - color = 8; /* white color */ - } else if (S_ISBLK(file_stat.st_mode)) { - strcpy(type, "BLK"); /* block device */ - color = 4; /* yellow color */ - } else if (S_ISFIFO(file_stat.st_mode)) { - strcpy(type, "FIF"); /* FIFO */ - color = 8; /* white color */ - } else { - color = 8; /* white color */ - } - /* don't know how to handle socket, block device, character device and FIFO */ - if (ftype == 1) { - long index = add_marked(filepath, type); - free(type); - free(size); - free(time); - if (index != -1) { - /* just marked */ - return index; - } - /* already marked */ - /* -1 does nothing, just function required to return something */ - return -1; - - } char *total_stat = memalloc(45 * sizeof(char)); snprintf(total_stat, 45, "%-18s %-10s", time, size); total_stat[strlen(total_stat)] = '\0'; diff --git a/file.c b/file.c index cfb4976..617e4d0 100644 --- a/file.c +++ b/file.c @@ -265,3 +265,9 @@ char *get_line(long index) return NULL; } } + + +/* + * Get file's type and color + */ +char *get_type(__mode_t st_mode); From b01b5a2279a45583513efed35901f1ffdb18d418 Mon Sep 17 00:00:00 2001 From: Piotr Marendowski Date: Sat, 16 Mar 2024 22:09:47 +0100 Subject: [PATCH 03/12] Add mark all operation --- ccc.c | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/ccc.c b/ccc.c index 0b9c431..35c7e34 100644 --- a/ccc.c +++ b/ccc.c @@ -26,7 +26,7 @@ typedef struct { /* functions' definitions */ void change_dir(const char *buf); int mkdir_p(const char *destdir); -void populate_files(const char *path); +void populate_files(const char *path, int ftype); int get_directory_size(const char *fpath, const struct stat *sb, int typeflag, struct FTW *ftwbuf); long add_file_stat(char *filepath, int ftype); void highlight_current_line(); @@ -95,7 +95,7 @@ int main(int argc, char** argv) cwd = memalloc(PATH_MAX * sizeof(char)); getcwd(cwd, PATH_MAX); - populate_files(cwd); + populate_files(cwd, 0); highlight_current_line(); /* set window name */ @@ -138,7 +138,7 @@ int main(int argc, char** argv) case 'l':; file *file = get_file(current_selection); if (file != NULL) { - /* check if it is directory or regular file */ + /* check if it is directory or a regular file */ if (strncmp(file->type, "DIR", 3) == 0) { /* change cwd to directory */ change_dir(file->path); @@ -238,15 +238,21 @@ int main(int argc, char** argv) case 'v': dirs_size = !dirs_size; clear_files(); - populate_files(cwd); + populate_files(cwd, 0); highlight_current_line(); break; - /* mark files by space */ + /* mark one file */ case SPACE:; add_file_stat(get_filepath(current_selection), 1); highlight_current_line(); break; + + /* mark all files in directory */ + case 'a':; + populate_files(cwd, 1); + change_dir(cwd); /* reload current dir */ + break; /* escape */ case ESC: @@ -276,7 +282,7 @@ void change_dir(const char *buf) { strcpy(cwd, buf); clear_files(); - populate_files(cwd); + populate_files(cwd, 0); current_selection = 0; highlight_current_line(); } @@ -332,7 +338,7 @@ int mkdir_p(const char *destdir) * Read the provided directory and add all files in directory to linked list * ep->d_name -> filename */ -void populate_files(const char *path) +void populate_files(const char *path, int ftype) { DIR *dp; struct dirent *ep; @@ -356,7 +362,7 @@ void populate_files(const char *path) strcat(filename, "/"); strcat(filename, ep->d_name); /* add filename */ - add_file_stat(filename, 0); + add_file_stat(filename, ftype); } free(filename); } @@ -508,10 +514,10 @@ void highlight_current_line() long num_marked = marked_len(); if (num_marked > 0) { /* Determine length of formatted string */ - int m_len = snprintf(NULL, 0, "(%ld selected)", num_marked); + int m_len = snprintf(NULL, 0, "[%ld] selected", num_marked); char *selected = memalloc((m_len + 1) * sizeof(char)); - snprintf(selected, m_len + 1, "(%ld selected)", num_marked); + snprintf(selected, m_len + 1, "[%ld] selected", num_marked); wprintw(panel, "(%ld/%ld) %s %s", current_selection + 1, files_len(), selected, cwd); } else { wprintw(panel, "(%ld/%ld) %s", current_selection + 1, files_len(), cwd); From e80f9ccd7f305ac2e51b60d3cb53725f2eaaab1e Mon Sep 17 00:00:00 2001 From: Piotr Marendowski Date: Sat, 16 Mar 2024 22:46:21 +0100 Subject: [PATCH 04/12] 'Minor refactoring + a change in keybindings'2 --- ccc.c | 39 +++++++++++++++++++++------------------ 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/ccc.c b/ccc.c index 35c7e34..383649e 100644 --- a/ccc.c +++ b/ccc.c @@ -24,7 +24,7 @@ typedef struct { } WIN_STRUCT; /* functions' definitions */ -void change_dir(const char *buf); +void change_dir(const char *buf, int selection); int mkdir_p(const char *destdir); void populate_files(const char *path, int ftype); int get_directory_size(const char *fpath, const struct stat *sb, int typeflag, struct FTW *ftwbuf); @@ -98,9 +98,6 @@ int main(int argc, char** argv) populate_files(cwd, 0); highlight_current_line(); - /* set window name */ - printf("%c]2;ccc: %s%c", ESC, cwd, ESC); - int ch, ch2; while (1) { if (COLS < 80 || LINES < 24) { @@ -117,7 +114,7 @@ int main(int argc, char** argv) /* reload using z */ case 'z': - change_dir(cwd); + change_dir(cwd, 0); break; /* go back by backspace or h or left arrow */ @@ -128,7 +125,7 @@ int main(int argc, char** argv) char *last_slash = strrchr(cwd, '/'); if (last_slash != NULL) { *last_slash = '\0'; - change_dir(cwd); + change_dir(cwd, 0); } break; @@ -141,7 +138,7 @@ int main(int argc, char** argv) /* check if it is directory or a regular file */ if (strncmp(file->type, "DIR", 3) == 0) { /* change cwd to directory */ - change_dir(file->path); + change_dir(file->path, 0); } else if (strncmp(file->type, "REG", 3) == 0) { edit_file(); } @@ -211,13 +208,17 @@ int main(int argc, char** argv) if (home == NULL) { wpprintw("$HOME is not defined"); } else { - change_dir(home); + change_dir(home, 0); } break; /* go to the trash dir */ case 't':; - char *trash_dir = getenv("CCC_TRASH"); + #ifdef TRASH_DIR + char *trash_dir = TRASH_DIR; + #else + char *trash_dir = getenv("CCC_TRASH"); + #endif if (trash_dir == NULL) { wpprintw("$CCC_TRASH is not defined"); } else { @@ -226,16 +227,16 @@ int main(int argc, char** argv) if (mkdir_p(trash_dir) == -1) { switch (errno) { case EACCES: - wpprintw("Parent directory does not allow write permission or one of directory does not allow search access"); + wpprintw("Parent directory does not allow write permission or one of directories does not allow search access"); } } } - change_dir(trash_dir); + change_dir(trash_dir, 0); } break; /* show directories' sizes */ - case 'v': + case 'A': dirs_size = !dirs_size; clear_files(); populate_files(cwd, 0); @@ -250,8 +251,9 @@ int main(int argc, char** argv) /* mark all files in directory */ case 'a':; + int save_current_sel = current_selection; populate_files(cwd, 1); - change_dir(cwd); /* reload current dir */ + change_dir(cwd, save_current_sel); /* reload current dir */ break; /* escape */ @@ -276,14 +278,14 @@ int main(int argc, char** argv) } /* - * Change directory in window + * Change directory in window with selection */ -void change_dir(const char *buf) +void change_dir(const char *buf, int selection) { strcpy(cwd, buf); clear_files(); populate_files(cwd, 0); - current_selection = 0; + current_selection = selection; highlight_current_line(); } @@ -336,6 +338,7 @@ int mkdir_p(const char *destdir) /* * Read the provided directory and add all files in directory to linked list + * ftype: normal files = 0, marked = 1 * ep->d_name -> filename */ void populate_files(const char *path, int ftype) @@ -393,8 +396,8 @@ long add_file_stat(char *filepath, int ftype) return add_file(filepath, "", "", 8); } - /* get file type and color */ - char *type = memalloc(4 * sizeof(char)); /* 4 chars for type */ + /* get file type and color, 4 chars for the type */ + char *type = memalloc(4 * sizeof(char)); int color; if (S_ISDIR(file_stat.st_mode)) { strcpy(type, "DIR"); /* directory type */ From 86e8733e082bffc26ee0f4af4b9ad4efc42a11fe Mon Sep 17 00:00:00 2001 From: Piotr Marendowski Date: Sun, 17 Mar 2024 11:09:22 +0100 Subject: [PATCH 05/12] Revert some stuff --- ccc.c | 21 +++++++++++---------- config.h | 2 +- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/ccc.c b/ccc.c index 383649e..84db03b 100644 --- a/ccc.c +++ b/ccc.c @@ -202,7 +202,7 @@ int main(int argc, char** argv) } break; - /* go to $HOME */ + /* '~' go to $HOME */ case TILDE:; char *home = getenv("HOME"); if (home == NULL) { @@ -385,7 +385,7 @@ int get_directory_size(const char *fpath, const struct stat *sb, int typeflag, s /* * Get file's last modified time, size, type * Add that file into list - * ftype: 0 = normal file, 1 = marked + * ftype: normal file = 0, marked = 1 */ long add_file_stat(char *filepath, int ftype) { @@ -427,6 +427,8 @@ long add_file_stat(char *filepath, int ftype) /* if file is to be marked */ if (ftype == 1) { long index = add_marked(filepath, type); + /* free type and return without allocating more stuff */ + free(type); if (index != -1) { return index; /* just marked */ } else { @@ -454,23 +456,22 @@ long add_file_stat(char *filepath, int ftype) /* max 25 chars due to long, space, suffix and null */ char *size = memalloc(25 * sizeof(char)); int unit = 0; - const char* units[] = {" B", "KiB", "MiB", "GiB", "TiB", "PiB"}; + const char* units[] = {"B", "KB", "MB", "GB", "TB", "PB"}; while (bytes > 1024) { bytes /= 1024; unit++; } - /* 4 sig fig, limiting characters to have better format */ - sprintf(size, "%-6.4g %-3s", bytes, units[unit]); + /* display sizes */ + sprintf(size, "%.3g%s", bytes, units[unit]); char *total_stat = memalloc(45 * sizeof(char)); - snprintf(total_stat, 45, "%-18s %-10s", time, size); + snprintf(total_stat, 45, "%-18s %-8s", time, size); total_stat[strlen(total_stat)] = '\0'; + long index = add_file(filepath, total_stat, type, color); + free(time); free(size); - - long index = add_file(filepath, total_stat, type, color); - free(total_stat); free(type); return index; @@ -636,7 +637,7 @@ void edit_file() } /* - * Print line to panel + * Print line to the panel */ void wpprintw(const char *line) { diff --git a/config.h b/config.h index 0ead672..b3bc9da 100644 --- a/config.h +++ b/config.h @@ -2,7 +2,7 @@ #define PH 1 /* panel height */ #define JUMP_NUM 14 /* how long ctrl + u/d jump are */ -/* Calculate directories' sizes upon entering? */ +/* Calculate directories' sizes RECURSIVELY upon entering? */ #define DIRS_SIZE false /* Default text editor */ From 6d0b2d33210309c55e7a8edc3750d9fec07440d2 Mon Sep 17 00:00:00 2001 From: Piotr Marendowski Date: Sun, 17 Mar 2024 13:28:27 +0100 Subject: [PATCH 06/12] Add more options in config --- ccc.c | 120 +++++++++++++++++++++++++++++++++++++++++++------------ config.h | 17 ++++++++ 2 files changed, 112 insertions(+), 25 deletions(-) diff --git a/ccc.c b/ccc.c index 84db03b..92fd173 100644 --- a/ccc.c +++ b/ccc.c @@ -17,6 +17,7 @@ #include "config.h" typedef struct { + int id; WINDOW *window; int location; int y; @@ -34,7 +35,7 @@ void show_file_content(); void edit_file(); void wpprintw(const char *line); void init_windows(); -void draw_border_title(WINDOW *window, bool active); +void draw_border_title(WINDOW *window, bool active, int id); /* global variables */ unsigned int focus = 0; @@ -255,6 +256,42 @@ int main(int argc, char** argv) populate_files(cwd, 1); change_dir(cwd, save_current_sel); /* reload current dir */ break; + + /* mark actions: */ + /* delete */ + case 'd':; + if (marked_len()) { + ; + } + break; + + /* move */ + case 'm':; + if (marked_len()) { + ; + } + break; + + /* copy */ + case 'c':; + if (marked_len()) { + ; + } + break; + + /* symbolic link */ + case 's':; + if (marked_len()) { + ; + } + break; + + /* bulk rename */ + case 'b':; + if (marked_len()) { + ; + } + break; /* escape */ case ESC: @@ -346,7 +383,9 @@ void populate_files(const char *path, int ftype) DIR *dp; struct dirent *ep; - draw_border_title(directory_border, true); + #if DRAW_BORDERS + draw_border_title(directory_border, true, 0); + #endif if ((dp = opendir(path)) != NULL) { /* clear directory window to ready for printing */ wclear(directory_content); @@ -559,7 +598,9 @@ void highlight_current_line() wrefresh(directory_content); wrefresh(panel); /* show file content every time cursor changes */ - show_file_content(); + #if DRAW_PREVIEW + show_file_content(); + #endif wrefresh(preview_content); } @@ -579,7 +620,9 @@ void show_file_content() mvwprintw(preview_content, 0, 0, "Unable to read %s", current_file->path); return; } - draw_border_title(preview_border, true); + #if DRAW_BORDERS + draw_border_title(preview_border, true, 1); + #endif int c; /* check if its binary */ @@ -648,40 +691,67 @@ void wpprintw(const char *line) void init_windows() { + /* offset for width of the content 1 and 2 */ + int width_left = half_width; + int width_right = half_width; + #ifdef WINDOW_OFFSET + width_left += WINDOW_OFFSET; + width_right -= WINDOW_OFFSET; + #endif + /*------------------------------+ |----border(0)--||--border(2)--|| || || || || content (1) || content (3) || - || || || + || (directory) || (preview) || || || || |---------------||-------------|| +==========panel (4)===========*/ /* lines, cols, y, x */ - directory_border = newwin(LINES - PH, half_width, 0, 0 ); - directory_content = newwin(LINES - PH -2, half_width - 2, 1, 1); - preview_border = newwin(LINES - PH, half_width, 0, half_width ); - preview_content = newwin(LINES - PH - 2, half_width - 2, 1, half_width + 1); panel = newwin(PH, COLS, LINES - PH, 0 ); + /* draw border around windows */ + #if DRAW_BORDERS + directory_border = newwin(LINES - PH, width_left, 0, 0 ); + directory_content = newwin(LINES - PH - 2, width_left - 2, 1, 1 ); + + preview_border = newwin(LINES - PH, width_right, 0, width_left ); + preview_content = newwin(LINES - PH - 2, width_right - 2, 1, width_left + 1); - /* draw border around windows */ - draw_border_title(directory_border, true); - draw_border_title(preview_border, true); + draw_border_title(directory_border, true, 0); + draw_border_title(preview_border, true, 1); + #else + /* if there are no borders, then draw content in their places */ + directory_border = newwin(0, 0, COLS, LINES ); + preview_border = newwin(0, 0, COLS, LINES ); + /* -1 for the one space to the left */ + directory_content = newwin(LINES - PH - 1, width_left, 0, 1 ); + preview_content = newwin(LINES - PH, width_right, 0, width_left ); + #endif scrollok(directory_content, true); - /* window location y, x */ - windows[0] = (WIN_STRUCT) { directory_border, 0, 0, 0 }; - windows[1] = (WIN_STRUCT) { directory_border, 0, 0, 0 }; - windows[2] = (WIN_STRUCT) { preview_border, 1, 0, half_width }; - windows[3] = (WIN_STRUCT) { preview_content, 1, 0, half_width }; - windows[4] = (WIN_STRUCT) { panel, 2, LINES - PH, 0 }; + /* id, window location y, x */ + windows[0] = (WIN_STRUCT) { 1, directory_border, 0, 0, 0 }; + windows[1] = (WIN_STRUCT) { 2, directory_content, 0, 0, 0 }; + windows[2] = (WIN_STRUCT) { 3, preview_border, 1, 0, width_left }; + windows[3] = (WIN_STRUCT) { 4, preview_content, 1, 0, width_left }; + windows[4] = (WIN_STRUCT) { 5, panel, 2, LINES - PH, 0 }; } /* - * Draw the border of the window depending if it's active or not + * Draw the border of the window depending if it's active or not, + * id: directory_border = 0, preview_border = 1 */ -void draw_border_title(WINDOW *window, bool active) +void draw_border_title(WINDOW *window, bool active, int id) { + /* check if the window is directory of preview */ + int width = half_width; + if (id == 0) { /* left */ + width += WINDOW_OFFSET; + } else if (id == 1) { /* right */ + width -= WINDOW_OFFSET; + } + /* turn on color depends on active */ if (active) { wattron(window, COLOR_PAIR(7)); @@ -690,18 +760,18 @@ void draw_border_title(WINDOW *window, bool active) } /* draw top border */ mvwaddch(window, 0, 0, ACS_ULCORNER); /* upper left corner */ - mvwhline(window, 0, 1, ACS_HLINE, half_width - 2); /* top horizontal line */ - mvwaddch(window, 0, half_width - 1, ACS_URCORNER); /* upper right corner */ + mvwhline(window, 0, 1, ACS_HLINE, width - 2); /* top horizontal line */ + mvwaddch(window, 0, width - 1, ACS_URCORNER); /* upper right corner */ /* draw side border */ mvwvline(window, 1, 0, ACS_VLINE, LINES - 2); /* left vertical line */ - mvwvline(window, 1, half_width - 1, ACS_VLINE, LINES - 2); /* right vertical line */ + mvwvline(window, 1, width - 1, ACS_VLINE, LINES - 2); /* right vertical line */ /* draw bottom border * make space for the panel */ mvwaddch(window, LINES - PH - 1, 0, ACS_LLCORNER); /* lower left corner */ - mvwhline(window, LINES - PH - 1, 1, ACS_HLINE, half_width - 2); /* bottom horizontal line */ - mvwaddch(window, LINES - PH - 1, half_width - 1, ACS_LRCORNER); /* lower right corner */ + mvwhline(window, LINES - PH - 1, 1, ACS_HLINE, width - 2); /* bottom horizontal line */ + mvwaddch(window, LINES - PH - 1, width - 1, ACS_LRCORNER); /* lower right corner */ /* turn color off after turning it on */ if (active) { diff --git a/config.h b/config.h index b3bc9da..d596f02 100644 --- a/config.h +++ b/config.h @@ -5,6 +5,23 @@ /* Calculate directories' sizes RECURSIVELY upon entering? */ #define DIRS_SIZE false +#define DRAW_BORDERS true /* Draw borders around windows? */ +#define DRAW_PREVIEW true /* Draw file preview? */ + +/* set width offset for windows: ++-------------%-------------+ +| % | +| files % preview | +| % | ++=============%=============+ +set where the % line between them resides + +In COLS: +0 will make them equal (at the center), +15 will make files bigger +-15 will make preview bigger */ +#define WINDOW_OFFSET 0 + /* Default text editor */ #define EDITOR "nvim" From 0ed3ca858e6c19a8398c0a9840a7b9dde9d38733 Mon Sep 17 00:00:00 2001 From: night0721 Date: Sun, 17 Mar 2024 22:17:46 +0000 Subject: [PATCH 07/12] format issue --- ccc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ccc.c b/ccc.c index 92fd173..c559237 100644 --- a/ccc.c +++ b/ccc.c @@ -747,7 +747,7 @@ void draw_border_title(WINDOW *window, bool active, int id) /* check if the window is directory of preview */ int width = half_width; if (id == 0) { /* left */ - width += WINDOW_OFFSET; + width += WINDOW_OFFSET; } else if (id == 1) { /* right */ width -= WINDOW_OFFSET; } From 82ccba51cb2c5527888c26d61b58ec6070aa8b81 Mon Sep 17 00:00:00 2001 From: night0721 Date: Sun, 17 Mar 2024 22:19:19 +0000 Subject: [PATCH 08/12] revert to use units for 1024 bytes instead for 1000 bytes --- ccc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ccc.c b/ccc.c index c559237..147787b 100644 --- a/ccc.c +++ b/ccc.c @@ -495,7 +495,7 @@ long add_file_stat(char *filepath, int ftype) /* max 25 chars due to long, space, suffix and null */ char *size = memalloc(25 * sizeof(char)); int unit = 0; - const char* units[] = {"B", "KB", "MB", "GB", "TB", "PB"}; + const char* units[] = {"B", "KiB", "MiB", "GiB", "TiB", "PiB"}; while (bytes > 1024) { bytes /= 1024; unit++; From c6c25d2c4596efb8a9e53d2903108ca02f8b3bcd Mon Sep 17 00:00:00 2001 From: night0721 Date: Sun, 17 Mar 2024 22:39:28 +0000 Subject: [PATCH 09/12] remove unnecessary stuff --- file.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/file.c b/file.c index 617e4d0..cfb4976 100644 --- a/file.c +++ b/file.c @@ -265,9 +265,3 @@ char *get_line(long index) return NULL; } } - - -/* - * Get file's type and color - */ -char *get_type(__mode_t st_mode); From 0f52bd265f55ab337ea4a60da801e6abc4a5ce03 Mon Sep 17 00:00:00 2001 From: night0721 Date: Sun, 17 Mar 2024 22:58:31 +0000 Subject: [PATCH 10/12] remove win struct as it is not used --- ccc.c | 62 ++++++++++++++++++++++++----------------------------------- 1 file changed, 25 insertions(+), 37 deletions(-) diff --git a/ccc.c b/ccc.c index 147787b..bbb789b 100644 --- a/ccc.c +++ b/ccc.c @@ -16,14 +16,6 @@ #include "util.h" #include "config.h" -typedef struct { - int id; - WINDOW *window; - int location; - int y; - int x; -} WIN_STRUCT; - /* functions' definitions */ void change_dir(const char *buf, int selection); int mkdir_p(const char *destdir); @@ -35,7 +27,7 @@ void show_file_content(); void edit_file(); void wpprintw(const char *line); void init_windows(); -void draw_border_title(WINDOW *window, bool active, int id); +void draw_border_title(WINDOW *window, bool active); /* global variables */ unsigned int focus = 0; @@ -43,7 +35,6 @@ long current_selection = 0; bool dirs_size = DIRS_SIZE; char *cwd; int half_width; -WIN_STRUCT windows[5]; WINDOW *directory_border; WINDOW *directory_content; WINDOW *preview_border; @@ -298,9 +289,11 @@ int main(int argc, char** argv) break; case KEY_RESIZE: - for (int i = 0; i < 2; i++) - delwin(windows[i].window); - + delwin(directory_border); + delwin(directory_content); + delwin(preview_border); + delwin(preview_content); + delwin(panel); endwin(); init_windows(); break; @@ -384,7 +377,7 @@ void populate_files(const char *path, int ftype) struct dirent *ep; #if DRAW_BORDERS - draw_border_title(directory_border, true, 0); + draw_border_title(directory_border, true); #endif if ((dp = opendir(path)) != NULL) { /* clear directory window to ready for printing */ @@ -532,8 +525,10 @@ void highlight_current_line() long range = files_len(); /* not highlight if no files in directory */ if (range == 0) { - wprintw(preview_content, "empty directory"); - wrefresh(preview_content); + #if DRAW_PREVIEW + wprintw(preview_content, "empty directory"); + wrefresh(preview_content); + #endif return; } @@ -621,7 +616,7 @@ void show_file_content() return; } #if DRAW_BORDERS - draw_border_title(preview_border, true, 1); + draw_border_title(preview_border, true); #endif int c; @@ -708,47 +703,40 @@ void init_windows() |---------------||-------------|| +==========panel (4)===========*/ - /* lines, cols, y, x */ - panel = newwin(PH, COLS, LINES - PH, 0 ); + /* lines, cols, y, x */ + panel = newwin(PH, COLS, LINES - PH, 0 ); /* draw border around windows */ #if DRAW_BORDERS - directory_border = newwin(LINES - PH, width_left, 0, 0 ); - directory_content = newwin(LINES - PH - 2, width_left - 2, 1, 1 ); + directory_border = newwin(LINES - PH, width_left, 0, 0 ); + directory_content = newwin(LINES - PH - 2, width_left - 2, 1, 1 ); preview_border = newwin(LINES - PH, width_right, 0, width_left ); preview_content = newwin(LINES - PH - 2, width_right - 2, 1, width_left + 1); - draw_border_title(directory_border, true, 0); - draw_border_title(preview_border, true, 1); + draw_border_title(directory_border, true); + draw_border_title(preview_border, true); #else /* if there are no borders, then draw content in their places */ - directory_border = newwin(0, 0, COLS, LINES ); - preview_border = newwin(0, 0, COLS, LINES ); + directory_border = newwin(0, 0, COLS, LINES ); + preview_border = newwin(0, 0, COLS, LINES ); /* -1 for the one space to the left */ - directory_content = newwin(LINES - PH - 1, width_left, 0, 1 ); - preview_content = newwin(LINES - PH, width_right, 0, width_left ); + directory_content = newwin(LINES - PH - 1, width_left, 0, 1 ); + preview_content = newwin(LINES - PH, width_right, 0, width_left ); #endif scrollok(directory_content, true); - /* id, window location y, x */ - windows[0] = (WIN_STRUCT) { 1, directory_border, 0, 0, 0 }; - windows[1] = (WIN_STRUCT) { 2, directory_content, 0, 0, 0 }; - windows[2] = (WIN_STRUCT) { 3, preview_border, 1, 0, width_left }; - windows[3] = (WIN_STRUCT) { 4, preview_content, 1, 0, width_left }; - windows[4] = (WIN_STRUCT) { 5, panel, 2, LINES - PH, 0 }; } /* * Draw the border of the window depending if it's active or not, - * id: directory_border = 0, preview_border = 1 */ -void draw_border_title(WINDOW *window, bool active, int id) +void draw_border_title(WINDOW *window, bool active) { /* check if the window is directory of preview */ int width = half_width; - if (id == 0) { /* left */ + if (window == directory_border) { /* left */ width += WINDOW_OFFSET; - } else if (id == 1) { /* right */ + } else if (window == preview_border) { /* right */ width -= WINDOW_OFFSET; } From 255e09c18d5562c85bb98df9bba96719d6824376 Mon Sep 17 00:00:00 2001 From: night0721 Date: Sun, 17 Mar 2024 23:21:58 +0000 Subject: [PATCH 11/12] make mark all work correctly as expected --- ccc.c | 19 ++++++++++--------- file.c | 25 ++++++++++++++++++------- 2 files changed, 28 insertions(+), 16 deletions(-) diff --git a/ccc.c b/ccc.c index bbb789b..5a9a493 100644 --- a/ccc.c +++ b/ccc.c @@ -236,16 +236,15 @@ int main(int argc, char** argv) break; /* mark one file */ - case SPACE:; + case SPACE: add_file_stat(get_filepath(current_selection), 1); highlight_current_line(); break; /* mark all files in directory */ - case 'a':; - int save_current_sel = current_selection; - populate_files(cwd, 1); - change_dir(cwd, save_current_sel); /* reload current dir */ + case 'a': + populate_files(cwd, 2); + change_dir(cwd, current_selection); /* reload current dir */ break; /* mark actions: */ @@ -368,7 +367,7 @@ int mkdir_p(const char *destdir) /* * Read the provided directory and add all files in directory to linked list - * ftype: normal files = 0, marked = 1 + * ftype: normal files = 0, marked = 1, marking ALL = 2 * ep->d_name -> filename */ void populate_files(const char *path, int ftype) @@ -417,7 +416,7 @@ int get_directory_size(const char *fpath, const struct stat *sb, int typeflag, s /* * Get file's last modified time, size, type * Add that file into list - * ftype: normal file = 0, marked = 1 + * ftype: normal file = 0, normal marked = 1, marking ALL = 2 */ long add_file_stat(char *filepath, int ftype) { @@ -457,8 +456,10 @@ long add_file_stat(char *filepath, int ftype) } /* if file is to be marked */ - if (ftype == 1) { - long index = add_marked(filepath, type); + if (ftype == 1 || ftype == 2) { + /* force if user is marking all files */ + bool force = ftype == 2 ? true : false; + long index = add_marked(filepath, type, force); /* free type and return without allocating more stuff */ free(type); if (index != -1) { diff --git a/file.c b/file.c index cfb4976..92179b2 100644 --- a/file.c +++ b/file.c @@ -131,7 +131,10 @@ void remove_marked(file *marked_file) } } -long add_marked(char *filepath, char *type) +/* + * force will not remove duplicate marked files, instead it just skip adding + */ +long add_marked(char *filepath, char *type, bool force) { file *current = marked; file *new_file = memalloc(sizeof(file)); @@ -153,17 +156,25 @@ long add_marked(char *filepath, char *type) long index = 1; while (current->next != NULL) { if (strcmp(current->path, new_file->path) == 0) { - remove_marked(current); - free_file(new_file); - return -1; + if (force) { + return index; + } else { + remove_marked(current); + free_file(new_file); + return -1; + } } current = current->next; index++; } if (strcmp(current->path, new_file->path) == 0){ - remove_marked(current); - free_file(new_file); - return -1; + if (force) { + return 0; + } else { + remove_marked(current); + free_file(new_file); + return -1; + } } current->next = new_file; return index; From 124df59933acebe54740365b0b53ced09e06776a Mon Sep 17 00:00:00 2001 From: Piotr Marendowski Date: Tue, 19 Mar 2024 19:40:32 +0100 Subject: [PATCH 12/12] Add man page and update README --- Makefile | 2 +- README.md | 73 +++++++++++++++++++++++++++++++++++++++++-------------- ccc.1 | 47 +++++++++++++++++++++++++++++++++++ file.h | 2 +- 4 files changed, 104 insertions(+), 20 deletions(-) diff --git a/Makefile b/Makefile index 809ef7f..f36a8b7 100644 --- a/Makefile +++ b/Makefile @@ -12,7 +12,7 @@ MANDIR = $(PREFIX)/share/man/man1 # Flags LDFLAGS = $(shell pkg-config --libs ncurses) -CFLAGS = -march=native -mtune=native -O3 -pipe -s -std=c99 -pedantic $(shell pkg-config --cflags ncurses) -Wall # -Wextra -Werror +CFLAGS = -O3 -pipe -s -std=c99 -pedantic -Wall $(shell pkg-config --cflags ncurses) SRC = ccc.c util.c file.c $(CONF) diff --git a/README.md b/README.md index 42ea80a..e0daa2a 100644 --- a/README.md +++ b/README.md @@ -8,36 +8,73 @@ The fact that it is written in C makes it more versatile and rapid, enabling us Consider this project incomplete and WIP! -| Feature | Ported | Dropped | Added | -|--------------------------------|:------:|:-------:|:-----:| -| Standard movement | X | | | -| Advanced movement (jumps) | X | | | -| Searching | | | | -| File preview | | | X | -| Sorting | | | | -| Marking and marking operations | | | | -| Other operations on files | | | | -| File details | X | | | -| Image previews | | | | -| Help | | | | -| History | | | | -| Bookmarks | | | | -| Bulk rename | | | | -| Workspaces | | | | +| Feature of fff | Ported | Dropped | +|--------------------------------|:------:|:-------:| +| Standard movement | X | | +| Advanced movement (jumps) | X | | +| File details | X | | +| Searching for files | | | +| Sorting | | | +| Marking and marking operations | | | +| Other operations on files | | | +| Image previews | | | +| Help | | | +| History | | | +| Bookmarks | | | +| Bulk rename | | | + +#### Features added that are not in [fff](https://github.com/piotr-marendowski/fff): + +- File preview (without highlighting) + +## Installation ### Dependencies - gcc +- ncurses - make - pkg-config -- ncurses ### Building You will need to run these with elevated privilages. -```sh +``` $ git clone https://github.com/piotr-marendowski/ccc $ make $ sudo make install ``` + +## Usage + +``` +j: scroll down +k: scroll up +h: go to parent dir +l: go to child dir + +down: scroll down +up: scroll up +left: go to parent dir +right: go to child dir + +enter: go to child dir/open file +backspace: go to parent dir + +g: go to top +G: go to bottom + +t: go to trash +~: go to home +z: refresh current dir + +space: mark file +a: mark all files in directory + +q: exit +``` + +## License + +This project has GNU GPL v.3 license. diff --git a/ccc.1 b/ccc.1 index e69de29..02029de 100644 --- a/ccc.1 +++ b/ccc.1 @@ -0,0 +1,47 @@ +. +.TH CCC "1" "March 2024" "ccc" "User Commands" +.SH NAME +ccc \- Fast TUI file manager written in C, using ncurses. +.SH SYNOPSIS +.B ccc +.SH DESCRIPTION +ccc is a rewrite of fff file manager in C aiming for usefulness and speed. The fact that it is written in C makes it more versatile and rapid, enabling us to add features that were previously ruled out due to time complexity. You may call it a soft fork. +.PP +.SH "Usage" +. +.nf + +j: scroll down +k: scroll up +h: go to parent dir +l: go to child dir + +down: scroll down +up: scroll up +left: go to parent dir +right: go to child dir + +enter: go to child dir/open file +backspace: go to parent dir + +g: go to top +G: go to bottom + +t: go to trash +~: go to home +z: refresh current dir + +space: mark file +a: mark all files in directory + +q: exit +. +.fi +. +.SH "Customization" +. +.nf + +Various settings can be changed in config.h file located in the program's directory. +. +.fi diff --git a/file.h b/file.h index b2890cb..57070aa 100644 --- a/file.h +++ b/file.h @@ -16,7 +16,7 @@ void clear_files(); void clear_marked(); long add_file(char *filepath, char *stats, char *type, int color); void remove_marked(file *marked_file); -long add_marked(char *filepath, char *type); +long add_marked(char *filepath, char *type, bool force); file *get_marked(long index); bool in_marked(char *path); file *get_file(long index);