From b470b7b2861016e2bd16e542c2845bbc8257082a Mon Sep 17 00:00:00 2001 From: night0721 Date: Fri, 29 Mar 2024 22:34:26 +0000 Subject: [PATCH] icons and fix goto trash dir and fix preview --- README.md | 4 +- ccc.c | 129 +++++++++++++++++++++++++++++++++-------------------- config.h | 6 ++- file.c | 69 +++++++++++++++-------------- file.h | 3 +- icons.c | 130 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ icons.h | 18 ++++++++ 7 files changed, 275 insertions(+), 84 deletions(-) create mode 100644 icons.c create mode 100644 icons.h diff --git a/README.md b/README.md index 4093a20..e3a6f6b 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,7 @@ Consider this project incomplete and WIP! | Standard movement | X | | | Advanced movement (jumps) | X | | | File details | X | | +| File icons! | X | | | Searching for files | | | | Sorting | | | | Marking and marking operations | | | @@ -32,9 +33,10 @@ Consider this project incomplete and WIP! ### Dependencies - gcc -- ncurses +- ncursesw - make - pkg-config +- Any [Nerd Font](https://www.nerdfonts.com/) for file icons (optional, but turned on by default) ### Building diff --git a/ccc.c b/ccc.c index 09b746a..85f4b8c 100644 --- a/ccc.c +++ b/ccc.c @@ -10,6 +10,8 @@ #include #include #include +#include +#include #include "file.h" #include "util.h" @@ -18,8 +20,9 @@ /* functions' definitions */ void show_help(); void start_ccc(); +char *check_trash_dir(); void change_dir(const char *buf, int selection, int ftype); -int mkdir_p(const char *destdir); +void 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); void add_file_stat(char *filepath, int ftype); @@ -41,6 +44,7 @@ bool show_hidden = SHOW_HIDDEN; bool file_details = SHOW_DETAILS; char *cwd; char *p_cwd; /* previous cwd */ +char *trash_dir; int half_width; ArrayList *files; ArrayList *marked; @@ -71,6 +75,7 @@ int main(int argc, char** argv) /* initialize screen, don't print special chars, * make ctrl + c work, don't show cursor * enable arrow keys */ + setlocale(LC_ALL, ""); initscr(); noecho(); cbreak(); @@ -234,26 +239,10 @@ int main(int argc, char** argv) /* go to the trash dir */ case 't':; - #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 { - if (access(trash_dir, F_OK) != 0) { - /* create the directory with 755 perm if it doesn't exit */ - if (mkdir_p(trash_dir) == -1) { - switch (errno) { - case EACCES: - wpprintw("Parent directory does not allow write permission or one of directories does not allow search access"); - } - } - } + char *trash_dir = check_trash_dir(); + if (trash_dir != NULL) change_dir(trash_dir, 0, 0); - } - break; + break; /* show directories' sizes */ case 'A': @@ -302,7 +291,11 @@ int main(int argc, char** argv) /* delete */ case 'd':; if (marked->length) { - ; + char *trash_dir = check_trash_dir(); + if (trash_dir != NULL) { + ; + /* do your magic here */ + } } break; @@ -374,6 +367,44 @@ void start_ccc() init_windows(); } +/* Checks if trash directory is set and returns it */ +char *check_trash_dir() +{ + char *path = memalloc(PATH_MAX * sizeof(char)); + + #ifdef TRASH_DIR + trash_dir = TRASH_DIR; + #endif + + /* check if there is trash_dir */ + if (trash_dir == NULL) { + wpprintw("No trash directory defined"); + return NULL; + } else { + /* if trash_dir has ~ then make it $HOME */ + /* use path as trash_dir */ + if (trash_dir[0] == '~') { + char *home = getenv("HOME"); + if (home == NULL) { + wpprintw("$HOME is not defined, can't read the trash directory"); + return NULL; + } + /* replace ~ with home */ + snprintf(path, PATH_MAX, "%s%s", home, trash_dir + 1); + } + else { + strcpy(path, trash_dir); + } + + /* if has access to trash_dir */ + if (access(path, F_OK) != 0) { + /* create the directory with 755 perm if it doesn't exit */ + mkdir_p(path); + } + } + return path; +} + /* * Change directory in window with selection */ @@ -399,7 +430,7 @@ void change_dir(const char *buf, int selection, int ftype) * Recursively create directory by creating each subdirectory * like mkdir -p */ -int mkdir_p(const char *destdir) +void mkdir_p(const char *destdir) { char *path = memalloc(PATH_MAX * sizeof(char)); char dir_path[PATH_MAX] = ""; @@ -408,7 +439,7 @@ int mkdir_p(const char *destdir) char *home = getenv("HOME"); if (home == NULL) { wpprintw("$HOME is not defined"); - return -1; + return; } /* replace ~ with home */ snprintf(path, PATH_MAX, "%s%s", home, destdir + 1); @@ -433,15 +464,15 @@ int mkdir_p(const char *destdir) continue; } - perror("ccc"); + wpprintw("mkdir failed: %s\n", strerror(errno)); free(path); - return -1; + return; } token = strtok(NULL, "/"); } free(path); - return 0; + return; } /* @@ -493,7 +524,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, normal marked = 1, marking ALL = 2 + * ftype: normal file = 0, normal marked = 1, marked ALL = 2 */ void add_file_stat(char *filepath, int ftype) { @@ -501,32 +532,35 @@ void add_file_stat(char *filepath, int ftype) if (stat(filepath, &file_stat) == -1) { /* can't be triggered? */ if (errno == EACCES) - arraylist_add(files, filepath, "", "", 8, false, false); + arraylist_add(files, filepath, "", "", "", 8, false, false); } - /* get file type and color, 4 chars for the type */ + /* get file type and color, 4 chars for the type and icon */ char *type = memalloc(4 * sizeof(char)); + wchar_t *icon = memalloc(2 * sizeof(wchar_t)); + wcsncpy(icon, L"", 2); int color; + if (S_ISDIR(file_stat.st_mode)) { - strcpy(type, "DIR"); /* directory type */ + strncpy(type, "DIR", 4); /* directory type */ color = 5; /* blue color */ } else if (S_ISREG(file_stat.st_mode)) { - strcpy(type, "REG"); /* regular file */ + strncpy(type, "REG", 4); /* regular file */ color = 8; /* white color */ } else if (S_ISLNK(file_stat.st_mode)) { - strcpy(type, "LNK"); /* symbolic link */ + strncpy(type, "LNK", 4); /* symbolic link */ color = 3; /* green color */ } else if (S_ISCHR(file_stat.st_mode)) { - strcpy(type, "CHR"); /* character device */ + strncpy(type, "CHR", 4); /* character device */ color = 8; /* white color */ } else if (S_ISSOCK(file_stat.st_mode)) { - strcpy(type, "SOC"); /* socket */ + strncpy(type, "SOC", 4); /* socket */ color = 8; /* white color */ } else if (S_ISBLK(file_stat.st_mode)) { - strcpy(type, "BLK"); /* block device */ + strncpy(type, "BLK", 4); /* block device */ color = 4; /* yellow color */ } else if (S_ISFIFO(file_stat.st_mode)) { - strcpy(type, "FIF"); /* FIFO */ + strncpy(type, "FIF", 4); /* FIFO */ color = 8; /* white color */ } else { color = 8; /* white color */ @@ -536,16 +570,16 @@ void add_file_stat(char *filepath, int ftype) if (ftype == 1 || ftype == 2) { /* force if user is marking all files */ bool force = ftype == 2 ? true : false; - arraylist_add(marked, filepath, NULL, type, 8, true, force); + arraylist_add(marked, filepath, NULL, type, icon, 8, true, force); /* free type and return without allocating more stuff */ free(type); return; } /* get last modified time */ - char *time = memalloc(20 * sizeof(char)); + char *time = memalloc(17 * sizeof(char)); /* format last modified time to a string */ - strftime(time, 20, "%Y-%m-%d %H:%M", localtime(&file_stat.st_mtime)); + strftime(time, 17, "%Y-%m-%d %H:%M", localtime(&file_stat.st_mtime)); /* get file size */ double bytes = file_stat.st_size; @@ -560,7 +594,7 @@ void add_file_stat(char *filepath, int ftype) } } /* max 25 chars due to long, space, suffix and null */ - char *size = memalloc(25 * sizeof(char)); + char *size = memalloc(8 * sizeof(char)); int unit = 0; const char* units[] = {"B", "KiB", "MiB", "GiB", "TiB", "PiB"}; while (bytes > 1024) { @@ -573,17 +607,18 @@ void add_file_stat(char *filepath, int ftype) /* get file mode string */ char *mode_str = get_file_mode(file_stat.st_mode); - char *total_stat = memalloc(56 * sizeof(char)); - snprintf(total_stat, 56, "%s %s %-8s", mode_str, time, size); - total_stat[strlen(total_stat)] = '\0'; + /* 11 + 17 + 8 + 1 for null */ + char *total_stat = memalloc(37 * sizeof(char)); + snprintf(total_stat, 37, "%s %s %-8s", mode_str, time, size); - arraylist_add(files, filepath, total_stat, type, color, false, false); + arraylist_add(files, filepath, total_stat, type, icon, color, false, false); free(time); free(size); free(total_stat); free(type); free(mode_str); + free(icon); } /* @@ -593,7 +628,7 @@ void add_file_stat(char *filepath, int ftype) char *get_file_mode(mode_t mode) { char *mode_str = memalloc(sizeof(char) * 11); - mode_str[0] = S_ISDIR(mode) ? 'd' : '-'; // Check if it's a directory + mode_str[0] = S_ISDIR(mode) ? 'd' : '-'; /* Check if it's a directory */ mode_str[1] = (mode & S_IRUSR) ? 'r' : '-'; mode_str[2] = (mode & S_IWUSR) ? 'w' : '-'; mode_str[3] = (mode & S_IXUSR) ? 'x' : '-'; @@ -603,7 +638,7 @@ char *get_file_mode(mode_t mode) mode_str[7] = (mode & S_IROTH) ? 'r' : '-'; mode_str[8] = (mode & S_IWOTH) ? 'w' : '-'; mode_str[9] = (mode & S_IXOTH) ? 'x' : '-'; - mode_str[10] = '\0'; // Null terminator + mode_str[10] = '\0'; return mode_str; } @@ -694,10 +729,10 @@ void highlight_current_line() #if DRAW_PREVIEW show_file_content(); #endif - wrefresh(preview_content); #if DRAW_BORDERS draw_border_title(preview_border, true); #endif + wrefresh(preview_content); } /* diff --git a/config.h b/config.h index f8abf36..e9b48ac 100644 --- a/config.h +++ b/config.h @@ -9,7 +9,8 @@ #define DRAW_BORDERS true /* Draw borders around windows? */ #define DRAW_PREVIEW true /* Draw file preview? */ #define SHOW_HIDDEN true /* show hidden files/dotfiles in preview */ -#define SHOW_DETAILS true /* show file details */ +#define SHOW_DETAILS true /* show file details */ +#define SHOW_ICONS true /* show file icons */ /* set width offset for windows: +-------------%-------------+ @@ -31,6 +32,9 @@ In COLS: /* File location to write last directory */ #define LAST_D "~/.cache/ccc/.ccc_d" +/* will create this directory if doesn't exist! */ +#define TRASH_DIR "~/.cache/ccc/trash/" + /* Keybindings */ #define CTRLD 0x04 #define ENTER 0xA diff --git a/file.c b/file.c index 6430419..1ab9b61 100644 --- a/file.c +++ b/file.c @@ -2,21 +2,10 @@ #include #include #include +#include #include "util.h" - -typedef struct file { - char *path; - char *stats; - char *type; - int color; -} file; - -typedef struct ArrayList { - size_t length; - size_t capacity; - file *items; -} ArrayList; +#include "file.h" ArrayList *arraylist_init(size_t capacity) { @@ -24,6 +13,7 @@ ArrayList *arraylist_init(size_t capacity) list->length = 0; list->capacity = capacity; list->items = memalloc(capacity * sizeof(file)); + return list; } @@ -36,7 +26,10 @@ void arraylist_free(ArrayList *list) free(list->items[i].path); if (list->items[i].stats != NULL) free(list->items[i].stats); + /*if (list->items[i].icon != NULL) + free(list->items[i].icon);*/ } + free(list->items); list->length = 0; } @@ -48,63 +41,66 @@ bool arraylist_includes(ArrayList *list, char *path) return true; } } + return false; } void arraylist_remove(ArrayList *list, long index) { - if (index >= list->length) { + if (index >= list->length) return; - } free(list->items[index].path); free(list->items[index].stats); free(list->items[index].type); + free(list->items[index].icon); - for (long i = index; i < list->length - 1; i++) { + for (long i = index; i < list->length - 1; i++) list->items[i] = list->items[i + 1]; - } list->length--; } /* - * force will not remove duplicate marked files, instead it just skip adding + * Force will not remove duplicate marked files, instead it just skip adding */ -void arraylist_add(ArrayList *list, char *filepath, char *stats, char *type, int color, bool marked, bool force) +void arraylist_add(ArrayList *list, char *filepath, char *stats, char *type, wchar_t *icon, int color, bool marked, bool force) { char *filepath_cp = NULL; char *stats_cp = NULL; char *type_cp = NULL; + wchar_t *icon_cp = NULL; + if (filepath != NULL) { filepath_cp = strdup(filepath); - if (filepath_cp == NULL) { + if (filepath_cp == NULL) perror("ccc"); - } } if (stats != NULL) { stats_cp = strdup(stats); - if (stats_cp == NULL) { + if (stats_cp == NULL) perror("ccc"); - } } if (type != NULL) { - type_cp = strdup(type); - if (type_cp == NULL) { + type_cp = strdup(type); + if (type_cp == NULL) + perror("ccc"); + } + if (icon != NULL) { + icon_cp = wcsdup(icon); + if (icon_cp == NULL) perror("ccc"); - } } - /* path, stats, type, color */ - file new_file = { filepath_cp, stats_cp, type_cp, color }; + /* path, stats, type, icon, color */ + file new_file = { filepath_cp, stats_cp, type_cp, icon_cp, color }; if (list->capacity != list->length) { if (marked) { for (int i = 0; i < list->length; i++) { if (strcmp(list->items[i].path, new_file.path) == 0) { - if (!force) { + if (!force) arraylist_remove(list, i); - } return; } } @@ -116,9 +112,10 @@ void arraylist_add(ArrayList *list, char *filepath, char *stats, char *type, int file *old_items = list->items; list->capacity = new_cap; list->items = new_items; - for (int i = 0; i < list->length; i++) { + + for (int i = 0; i < list->length; i++) new_items[i] = old_items[i]; - } + free(old_items); list->items[list->length] = new_file; } @@ -132,6 +129,7 @@ char *get_line(ArrayList *list, long index, bool detail) { file file = list->items[index]; char *name = strdup(file.path); + wchar_t *icon = wcsdup(file.icon); char *stats = NULL; size_t length; if (detail) { @@ -148,10 +146,13 @@ char *get_line(ArrayList *list, long index, bool detail) name = basename(name); if (name == NULL) perror("ccc"); + + /*printf("%ls", icon);*/ + if (detail) { - snprintf(line, length, "%s %s", stats, name); + snprintf(line, length, "%s %ls %s", stats, icon, name); } else { - snprintf(line, length, "%s", name); + snprintf(line, length, "%ls %s", icon, name); } return line; diff --git a/file.h b/file.h index e7a0434..49f72fc 100644 --- a/file.h +++ b/file.h @@ -7,6 +7,7 @@ typedef struct file { char *path; char *stats; char *type; + wchar_t *icon; int color; } file; @@ -20,7 +21,7 @@ ArrayList *arraylist_init(size_t capacity); void arraylist_free(ArrayList *list); bool arraylist_includes(ArrayList *list, char *path); void arraylist_remove(ArrayList *list, long index); -void arraylist_add(ArrayList *list, char *filepath, char *stats, char *type, int color, bool marked, bool force); +void arraylist_add(ArrayList *list, char *filepath, char *stats, char *type, wchar_t *icon, int color, bool marked, bool force); char *get_line(ArrayList *list, long index, bool detail); #endif diff --git a/icons.c b/icons.c new file mode 100644 index 0000000..4b995ed --- /dev/null +++ b/icons.c @@ -0,0 +1,130 @@ +#include +#include +#include +#include + +#define MAX_NAME 30 +#define TABLE_SIZE 20 + +typedef struct { + char name[MAX_NAME]; + char *icon; +} icon; + +icon *hash_table[TABLE_SIZE]; + +/* Hashes every name with: name and TABLE_SIZE */ +unsigned int hash(char *name) +{ + int length = strnlen(name, MAX_NAME), i = 0; + unsigned int hash_value = 0; + + for (; i < length; i++) { + hash_value += name[i]; + hash_value = (hash_value * name[i]) % TABLE_SIZE; + } + + return hash_value; +} + +void init_hash_table() +{ + int i = 0; + + for (; i < TABLE_SIZE; i++) + hash_table[i] = NULL; +} + +void print_table() +{ + int i = 0; + + for (; i < TABLE_SIZE; i++) { + if (hash_table[i] == NULL) { + printf("%i. ---\n", i); + } else { + printf("%i. %s %s\n", i, hash_table[i]->name, hash_table[i]->icon); + } + } +} + +/* Gets hashed name and tries to store the icon struct in that place */ +bool add_icon(icon *p) +{ + if (p == NULL) return false; + + int index = hash(p->name); + int i = 0, try; + + try = (i + index) % TABLE_SIZE; + if (hash_table[try] == NULL) { + hash_table[try] = p; + return true; + } + + return false; +} + +/* Rehashes the name and then looks in this spot, if found returns icon */ +icon *icon_search(char *name) +{ + int index = hash(name), i = 0; + + // this handles icons with the same hash values + // or use linked lists in structs + // for (; i < TABLE_SIZE; i++) { + // int try = (index + i) % TABLE_SIZE; + // + // for (; i < TABLE_SIZE; i++) { + // try = (i + index) % TABLE_SIZE; + // + // if (hash_table[try] == NULL) + // return false; + // + // if (strncmp(hash_table[try]->name, name, TABLE_SIZE) == 0) + // return hash_table[try]; + // } + // + // return false; + // } + // + // return NULL; + + if (hash_table[index] == NULL) + return false; + + if (strncmp(hash_table[index]->name, name, MAX_NAME) == 0) + return hash_table[index]; + + return NULL; +} + +int main(void) +{ + init_hash_table(); + + /* name reference name icon */ + icon c = { .name="c", .icon="" }; + icon h = { .name="h", .icon="" }; + icon cpp = { .name="cpp", .icon="" }; + icon hpp = { .name="hpp", .icon="󰰀" }; + icon md = { .name="md", .icon="" }; + + add_icon(&c); + add_icon(&h); + add_icon(&cpp); + add_icon(&hpp); + add_icon(&md); + + print_table(); + + icon *tmp = icon_search("hpp"); + + if (tmp == NULL) + printf("null\n"); + + printf("%s", tmp->icon); + + return 0; +} + diff --git a/icons.h b/icons.h new file mode 100644 index 0000000..2de349f --- /dev/null +++ b/icons.h @@ -0,0 +1,18 @@ +#ifndef FILE_H_ +#define FILE_H_ + +#define MAX_NAME 30 +#define TABLE_SIZE 20 + +typedef struct { + char name[MAX_NAME]; + char icon[4]; +} icon; + +unsigned int hash(char *name); +void init_hash_table(); +void print_table(); +bool add_icon(icon *p); +icon *icon_search(char *name); + +#endif