#include "fm.h" #include #include #include #include #include #include #include #include #include #include "display.h" #include "err.h" #include "log.h" #include "wm.h" static fm_info *fm_w_init(terminal *t) { fm_info *f = xmalloc(sizeof(fm_info)); f->fm_l = xmalloc(sizeof(window)); f->fm_r = xmalloc(sizeof(window)); int i = wm_fd_w_by_name(t, "stat"); if (i == -1) { die("Cannot find window \"stat\""); } int fm_w = t->maxx / 2; int fm_h = t->maxy - t->windows[i]->height - 1; int fm_starty = t->windows[i]->height; int fm_l_startx = 0; int fm_r_startx = t->maxx / 2; window *fm_l = wm_create_new_w(t, "fm_l", fm_h, fm_w, fm_starty, fm_l_startx); window *fm_r = wm_create_new_w(t, "fm_r", fm_h, fm_w, fm_starty, fm_r_startx); if (!fm_l || !fm_r) { die("Cannot create file manager window"); } f->fm_l->height = fm_h; log_write(LOG_INFO, "fm_h = %d", fm_h); log_write(LOG_INFO, "f->fm_l->height = %d", f->fm_l->height); f->fm_l->width = fm_w; f->fm_l->start_y = fm_starty; f->fm_l->start_x = fm_l_startx; f->fm_l->win = fm_l->win; f->fm_r->height = fm_h; f->fm_r->width = fm_w; f->fm_r->start_y = fm_starty; f->fm_r->start_x = fm_r_startx; f->fm_r->win = fm_r->win; f->top = 0; f->bottom = fm_h - 1; log_write(LOG_INFO, "t->windows[i]->height = %d", t->windows[i]->height); f->margin_bottom = 3; f->needs_redraw = 1; return 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; }