diff options
| author | verdant <im@verdant.ee> | 2026-07-23 18:59:22 +0800 |
|---|---|---|
| committer | verdant <im@verdant.ee> | 2026-07-23 18:59:22 +0800 |
| commit | 4fd1111d5b547af4c6db70407df6120db99ea501 (patch) | |
| tree | 5c4ae597c7f898b90bdaee8195e2dd4b4446def8 | |
| parent | 80ac2501501f83f7c64a5591b2075468a5fab6b5 (diff) | |
| download | sf-master.tar.gz sf-master.zip | |
| -rw-r--r-- | fm.c | 211 | ||||
| -rw-r--r-- | fm.h | 6 |
2 files changed, 214 insertions, 3 deletions
@@ -1,7 +1,18 @@ #include "fm.h" +#include <curses.h> +#include <dirent.h> +#include <linux/limits.h> +#include <magic.h> +#include <stddef.h> +#include <stdio.h> +#include <string.h> +#include <sys/types.h> +#include <unistd.h> + #include "display.h" #include "err.h" +#include "log.h" #include "wm.h" static fm_info *fm_w_init(terminal *t) @@ -50,9 +61,207 @@ static fm_info *fm_w_init(terminal *t) f->needs_redraw = 1; return f; } -void fm_getdir(fm_info *f); + +void fm_getcwd(fm_info *f) { getcwd(f->cwd, sizeof(f->cwd)); } + +static void fm_file_items_realloc(file_list *l) +{ + l->cap *= 2; + l->items = realloc(l->items, sizeof(file_item) * l->cap); + if (!l->items) + die("Memory realloc failed"); +} + +void fm_getdir(fm_info *i, file_list *l, const char *path) +{ + log_write(LOG_INFO, "path = %s", path); + DIR *dir = opendir(path); + log_write(LOG_INFO, "OPEN_DIR"); + if (!dir) { + die("Cannot open dir"); + } + + l->count = 0; + + if (l->items && l->cap > 0) { + memset(l->items, 0, l->cap * sizeof(file_item)); + } + + struct dirent *d; + while ((d = readdir(dir)) != NULL) { + if (strcmp(d->d_name, ".") == 0 || strcmp(d->d_name, "..") == 0) + continue; + + if (l->count >= l->cap) + fm_file_items_realloc(l); + + snprintf(l->items[l->count].name, + sizeof(l->items[l->count].name), "%s", d->d_name); + + l->items[l->count].is_dir = (d->d_type == DT_DIR); + + l->count++; + } + + i->got_next_dir = 0; + + snprintf(i->got_dir, sizeof(i->got_dir), "%s", path); + closedir(dir); +} + +static void fm_file_list_init(file_list *l, int cap) +{ + if (!l) + die("File list initialization failed"); + + l->cap = cap; + l->count = 0; + l->items = xmalloc(sizeof(file_item) * cap); + memset(l->items, 0, l->cap * sizeof(file_item)); +} + fm_info *fm_init(terminal *t) { fm_info *f = fm_w_init(t); + f->selected_idx = 0; + f->got_next_dir = 0; + f->cur = xmalloc(sizeof(file_list)); + f->next = xmalloc(sizeof(file_list)); + fm_file_list_init(f->cur, 30); + fm_file_list_init(f->next, 30); return f; } + +static void fm_print_colorful(fm_info *f, file_list *l, int i, int n, window *w) +{ + + int print_width = w->width - 2; + if (i == f->selected_idx && w->win == f->fm_l->win) { + wattron(f->fm_l->win, COLOR_PAIR(COLOR_PAIR_FM_HL)); + mvwprintw(f->fm_l->win, n, 0, "%-*.*s", print_width, + print_width, f->cur->items[i].name); + wattroff(f->fm_l->win, COLOR_PAIR(COLOR_PAIR_FM_HL)); + } else if (l->items[i].is_dir) { + wattron(w->win, COLOR_PAIR(COLOR_PAIR_FM_DIR)); + mvwprintw(w->win, n, 0, "%-*.*s", print_width, print_width, + l->items[i].name); + wattroff(w->win, COLOR_PAIR(COLOR_PAIR_FM_DIR)); + } else { + mvwprintw(w->win, n, 0, "%-*.*s", print_width, print_width, + l->items[i].name); + } +} + +static void get_next_dir(fm_info *f) +{ + if (!f->got_next_dir) { + char next_dir[PATH_MAX] = {0}; + snprintf(next_dir, sizeof(next_dir), "%s/%s", f->cwd, + f->cur->items[f->selected_idx].name); + + if (strcmp(next_dir, f->got_dir) == 0) + return; + + log_write(LOG_INFO, "NEXT_DIR = %s", next_dir); + fm_getdir(f, f->next, next_dir); + f->got_next_dir = 1; + } +} + +static const char *detect_file_type(const char *filepath) +{ + magic_t ctx = magic_open(0); + if (!ctx) + die("Cannot detect file"); + + if (magic_load(ctx, NULL) != 0) + die("Magic file load failed"); + + const char *desc = magic_file(ctx, filepath); + char *result = desc ? strdup(desc) : strdup("unknown"); + magic_close(ctx); + return result; +} +static char *fm_print_preview_content(window *w, const char *path) +{ + char *buf = xmalloc(sizeof(char) * PATH_MAX); + FILE *fp = fopen(path, "r"); + if (!fp) + die("Cannot open file: %s", path); + + int i = 0; + while (fgets(buf, PATH_MAX, fp) != NULL && i < w->height) { + mvwprintw(w->win, i, 0, buf); + i++; + } + return buf; +} +static void *fm_preview_file(fm_info *i) +{ + wclear(i->fm_r->win); + char *path = xmalloc(sizeof(char) * PATH_MAX); + snprintf(path, + sizeof(path) + sizeof(i->cur->items[i->selected_idx].name), + "%s/%s", i->cwd, i->cur->items[i->selected_idx].name); + /* */ + const char *type = xmalloc(sizeof(char) * 4096); + type = detect_file_type(path); + + if (strstr(type, "ASCII text")) { + fm_print_preview_content(i->fm_r, path); + + } else { + mvwprintw(i->fm_r->win, 0, 0, "%s", type); + } + + const char *file_type = detect_file_type(file_type); + free(type); +} + +void fm_draw_entries(fm_info *i, int n, int m) +{ + window *left_window = i->fm_l; + fm_print_colorful(i, i->cur, n, m, left_window); +} + +void fm_draw_right_window(fm_info *i) +{ + window *right_window = i->fm_r; + wclear(right_window->win); + if (!i->got_next_dir && i->cur->items[i->selected_idx].is_dir) { + get_next_dir(i); + for (int j = 0; j < i->next->count; j++) { + fm_print_colorful(i, i->next, j, j, right_window); + } + + i->got_next_dir = 0; + } else { + fm_preview_file(i); + } +} + +void fm_entries_scrool(terminal *t, fm_info *i, int n) +{ + + if ((i->selected_idx + n) == -1 || + (i->selected_idx + n) >= i->cur->count) + return; + + if (n == 1 && (i->bottom - i->selected_idx) <= 4 && + i->cur->count - i->selected_idx > 4) { + i->top++; + i->bottom++; + } else if (n == -1 && (i->selected_idx - i->top) <= 3) { + if (i->top - 1 < 0 || i->bottom - 1 < 1) { + i->selected_idx += n; + i->needs_redraw = 1; + return; + } + + i->top--; + i->bottom--; + } + + i->selected_idx += n; + i->needs_redraw = 1; +} @@ -30,8 +30,10 @@ typedef struct { int needs_redraw; } fm_info; -void fm_getdir(fm_info *f); +void fm_getdir(fm_info *i, file_list *l, const char *path); fm_info *fm_init(terminal *t); void fm_getcwd(fm_info *f); -void fm_draw_entries(fm_info *f); +void fm_draw_entries(fm_info *i, int n, int m); +void fm_entries_scrool(terminal *t, fm_info *i, int n); +void fm_draw_right_window(fm_info *i); #endif /* SF_FM_H */ |
