icons and fix goto trash dir and fix preview

This commit is contained in:
Night Kaly 2024-03-29 22:34:26 +00:00
parent eab8013601
commit b470b7b286
No known key found for this signature in database
GPG key ID: 8E829D3381CFEBBE
7 changed files with 275 additions and 84 deletions

View file

@ -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

125
ccc.c
View file

@ -10,6 +10,8 @@
#include <ftw.h>
#include <time.h>
#include <ncurses.h>
#include <locale.h>
#include <wchar.h>
#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,25 +239,9 @@ 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;
/* show directories' sizes */
@ -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);
}
/*

View file

@ -10,6 +10,7 @@
#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_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

65
file.c
View file

@ -2,21 +2,10 @@
#include <stdlib.h>
#include <stdbool.h>
#include <libgen.h>
#include <wchar.h>
#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) {
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;

3
file.h
View file

@ -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

130
icons.c Normal file
View file

@ -0,0 +1,130 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#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;
}

18
icons.h Normal file
View file

@ -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