diff options
| author | verdant <im@verdant.ee> | 2026-07-27 09:26:02 +0800 |
|---|---|---|
| committer | verdant <im@verdant.ee> | 2026-07-27 09:26:02 +0800 |
| commit | 48ca0d55b562230644e5f71597979c8d813b80e2 (patch) | |
| tree | f1309624a546c76c9a638500456cbeb82b1d12a5 | |
| parent | a988bc1eb3c0dbc0ce3ccd0f3422a459a9e61295 (diff) | |
| download | sf-48ca0d55b562230644e5f71597979c8d813b80e2.tar.gz sf-48ca0d55b562230644e5f71597979c8d813b80e2.zip | |
Refactor fm
| -rw-r--r-- | fm.c | 410 | ||||
| -rw-r--r-- | fm.h | 37 |
2 files changed, 269 insertions, 178 deletions
@@ -1,90 +1,107 @@ +#define _GNU_SOURCE #include "fm.h" - +#include "display.h" +#include "err.h" +#include "log.h" +#include "mem.h" +#include "wm.h" #include <curses.h> #include <dirent.h> +#include <libgen.h> #include <linux/limits.h> #include <magic.h> #include <stddef.h> #include <stdio.h> +#include <stdlib.h> #include <string.h> #include <sys/types.h> #include <unistd.h> -#include "display.h" -#include "err.h" -#include "log.h" -#include "wm.h" +static magic_t g_magic_ctx = NULL; -static fm_info *fm_w_init(terminal *t) +void magic_init(void) { - 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\""); + if (!g_magic_ctx) { + g_magic_ctx = magic_open(MAGIC_MIME_TYPE | MAGIC_SYMLINK); + if (!g_magic_ctx) + die("Cannot initialize magic"); + if (magic_load(g_magic_ctx, NULL) != 0) + die("Magic load failed: %s", magic_error(g_magic_ctx)); } +} - int fm_w = t->maxx / 2; - int fm_h = t->maxy - t->windows[i]->height - 1; - int fm_starty = t->windows[i]->height; +void magic_cleanup(void) +{ + if (g_magic_ctx) + magic_close(g_magic_ctx); +} - int fm_l_startx = 0; - int fm_r_startx = t->maxx / 2; +/* Function forward declarations */ +static fm_info *fm_w_init(terminal *term); +static void fm_file_list_init(file_list *l, int cap); +static void fm_file_items_realloc(file_list *l); +/* static void get_next_dir(fm_info *f); */ +static char *detect_file_type(const char *filepath); +bool fm_preview_file(window *w, const char *path); +/* static void fm_print_preview_content(window *w, const char *path); */ +/* static void fm_calc_scroll(int maxy, int entries_count, ) */ - 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; +/* Functions */ + +static fm_info *fm_w_init(terminal *term) + +{ + int maxx = term->maxx; + int maxy = term->maxy; + + fm_info *info = xmalloc(sizeof(fm_info)); + info->windows[PANE_LEFT] = xmalloc(sizeof(window)); + info->windows[PANE_RIGHT] = xmalloc(sizeof(window)); + + int pane_width = maxx / 2; + int pane_height = maxy - 1; + int pane_starty = 0; + + int pane_left_startx = 0; + int pane_right_startx = maxx / 2; + + info->windows[PANE_LEFT] = + wm_create_new_w(term, "pane_left", pane_height, pane_width, + pane_starty, pane_left_startx); + info->windows[PANE_RIGHT] = + wm_create_new_w(term, "pane_right", pane_height, pane_width, + pane_starty, pane_right_startx); + + info->top = 0; + info->bottom = pane_height - 1; + + info->need_redraw = true; + return info; } -void fm_getcwd(fm_info *f) { getcwd(f->cwd, sizeof(f->cwd)); } +void fm_getcwd(fm_info *info) { getcwd(info->cwd, sizeof(info->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"); + l->items = xrealloc(l->items, sizeof(file_item) * l->cap); } -void fm_getdir(fm_info *i, file_list *l, const char *path) +file_list *fm_getdir(file_list *list, 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; + file_list *new_list = list; + LOG_WRITE_INFO("list->cap = %zu", list->cap); - if (l->items && l->cap > 0) { - memset(l->items, 0, l->cap * sizeof(file_item)); + if (new_list->items && new_list->cap > 0) { + LOG_WRITE_INFO("Initialize list"); + memset(new_list->items, 0, new_list->cap * sizeof(file_item)); } struct dirent *d; @@ -92,21 +109,24 @@ void fm_getdir(fm_info *i, file_list *l, const char *path) if (strcmp(d->d_name, ".") == 0 || strcmp(d->d_name, "..") == 0) continue; - if (l->count >= l->cap) - fm_file_items_realloc(l); + if (new_list->count >= new_list->cap) + fm_file_items_realloc(new_list); - snprintf(l->items[l->count].name, - sizeof(l->items[l->count].name), "%s", d->d_name); + snprintf(new_list->items[new_list->count].name, + sizeof(new_list->items[new_list->count].name), "%s", + d->d_name); - l->items[l->count].is_dir = (d->d_type == DT_DIR); + if (d->d_type == DT_DIR) { + new_list->items[new_list->count].is_dir = true; + } else { + new_list->items[new_list->count].is_dir = false; + } - l->count++; + new_list->count++; } - i->got_next_dir = 0; - - snprintf(i->got_dir, sizeof(i->got_dir), "%s", path); closedir(dir); + return new_list; } static void fm_file_list_init(file_list *l, int cap) @@ -117,154 +137,212 @@ static void fm_file_list_init(file_list *l, int cap) l->cap = cap; l->count = 0; l->items = xmalloc(sizeof(file_item) * cap); + l->items->is_dir = 0; 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; + fm_info *info = fm_w_init(t); + info->cursor = 0; + info->cur = xmalloc(sizeof(file_list)); + info->next = xmalloc(sizeof(file_list)); + fm_file_list_init(info->cur, 30); + fm_file_list_init(info->next, 30); + return info; } -static void fm_print_colorful(fm_info *f, file_list *l, int i, int n, window *w) +static char *detect_file_type(const char *filepath) { + if (!g_magic_ctx) + magic_init(); - 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); - } + const char *desc = magic_file(g_magic_ctx, filepath); + return desc ? strdup(desc) : strdup("unknown"); } -static void get_next_dir(fm_info *f) +void fm_draw_file_stream(window *w, FILE *fp) { - 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; + char line_buf[512]; + int line_num = 0; - log_write(LOG_INFO, "NEXT_DIR = %s", next_dir); - fm_getdir(f, f->next, next_dir); - f->got_next_dir = 1; + while (line_num < w->height && + fgets(line_buf, sizeof(line_buf), fp) != NULL) { + mvwprintw(w->win, line_num, 0, "%.*s", w->width, line_buf); + line_num++; } } -static const char *detect_file_type(const char *filepath) +bool fm_preview_file(window *w, const char *path) { - magic_t ctx = magic_open(0); - if (!ctx) - die("Cannot detect file"); + wclear(w->win); + if (!w || !path) + return false; - if (magic_load(ctx, NULL) != 0) - die("Magic file load failed"); + char *file_type = detect_file_type(path); + + if (strstr(file_type, "text") == NULL) { + mvwprintw(w->win, 0, 0, "%s", file_type); + return false; + } - 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) { - free(buf); - die("Cannot open file: %s", path); + mvwprintw(w->win, 0, 0, "<Cannot open file>"); + return false; } - int i = 0; - while (fgets(buf, PATH_MAX, fp) != NULL && i < w->height) { - mvwprintw(w->win, i, 0, "%s", buf); - i++; - } + fm_draw_file_stream(w, fp); - free(buf); + fclose(fp); + free(file_type); + return true; } -static void fm_preview_file(fm_info *i) + +static void fm_print(window *win, const char *name, int y, int print_width, + int color_pair) { - 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); - } + wattron(win->win, COLOR_PAIR(color_pair)); + mvwprintw(win->win, y, 0, "%-*.*s", print_width, print_width, name); + wattroff(win->win, COLOR_PAIR(color_pair)); +} + +void fm_draw_entries(window *window, file_list *list, size_t cursor, int top, + int bottom) +{ + if (!window || !list) + return; - free(path); - free(type); + wclear(window->win); + + for (int i = top; i < bottom && i < list->count; i++) { + int y = i - top; + + int color = 0; + if (i == cursor) + color = COLOR_PAIR_FM_HL; + else if (list->items[i].is_dir) + color = COLOR_PAIR_FM_DIR; + + if (color != 0) { + wattron(window->win, COLOR_PAIR(color)); + } + + mvwprintw(window->win, y, 0, "%s", list->items[i].name); + + if (color != 0) { + wattroff(window->win, COLOR_PAIR(color)); + } + } } -void fm_draw_entries(fm_info *i, int n, int m) +void fm_entries_scroll(fm_info *info, int n) { - window *left_window = i->fm_l; - fm_print_colorful(i, i->cur, n, m, left_window); + if (!info) + return; + + info->cursor += n; + + if (info->cursor < 0) + info->cursor = 0; + if (info->cursor >= info->cur->count) + info->cursor = info->cur->count - 1; + + int win_height = info->bottom - info->top; + + if (info->cursor >= info->bottom) { + info->bottom = info->cursor + 1; + info->top = info->bottom - win_height; + } + if (info->cursor < info->top) { + info->top = info->cursor; + info->bottom = info->top + win_height; + } + + info->need_redraw = true; } -void fm_draw_right_window(fm_info *i) +static void fm_reset_windows_data(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); - } + if (!i) + return; - i->got_next_dir = 0; - } else { - fm_preview_file(i); + i->top = 0; + i->bottom = i->windows[FM_PANE_LEFT]->height - 1; +} +void fm_cd_up(fm_info *info) +{ + if (strcmp(info->cwd, "/") == 0) + return; + + fm_reset_windows_data(info); + + char *cp_cwd = strdup(info->cwd); + if (!cp_cwd) + die("strdup failed"); + + char *parent_dir = dirname(cp_cwd); + + if (chdir(parent_dir) != 0) { + free(cp_cwd); + return; } + + snprintf(info->cwd, sizeof(info->cwd), "%s", parent_dir); + free(cp_cwd); + + info->cur->cap = 30; + info->cur->count = 0; + + file_list *new_list = fm_getdir(info->cur, info->cwd); + if (new_list) { + info->cur = new_list; + LOG_WRITE_INFO("11: %s", info->cwd); + } + + info->cursor = 0; + info->top = 0; + info->bottom = info->windows[FM_PANE_LEFT]->height; + info->need_redraw = true; } -void fm_entries_scrool(terminal *t, fm_info *i, int n) +void fm_cd_down(fm_info *info) { + if (!info->cur || info->cur->count == 0) + return; - if ((i->selected_idx + n) == -1 || - (i->selected_idx + n) >= i->cur->count) + if (!info->cur->items[info->cursor].is_dir) 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; + fm_reset_windows_data(info); + + size_t buf_size = strlen(info->cwd) + 1 + + strlen(info->cur->items[info->cursor].name) + 1; + char *next_dir = xmalloc(buf_size); + + if (strcmp(info->cwd, "/") == 0) { + snprintf(next_dir, buf_size, "/%s", + info->cur->items[info->cursor].name); + } else { + snprintf(next_dir, buf_size, "%s/%s", info->cwd, + info->cur->items[info->cursor].name); + } + + if (chdir(next_dir) == 0) { + snprintf(info->cwd, sizeof(info->cwd), "%s", next_dir); + + info->cur->cap = 30; + info->cur->count = 0; + file_list *new_list = fm_getdir(info->cur, info->cwd); + if (new_list) { + info->cur = new_list; } - i->top--; - i->bottom--; + info->cursor = 0; + info->top = 0; + info->need_redraw = true; } - i->selected_idx += n; - i->needs_redraw = 1; + free(next_dir); } @@ -4,9 +4,15 @@ #include <limits.h> #include <linux/limits.h> #include <ncurses.h> +#include <stdbool.h> #include "wm.h" +#define PANE_LEFT 0 +#define PANE_RIGHT 1 + +#define MARGIN 3 + typedef struct { char name[256]; int is_dir; @@ -14,26 +20,33 @@ typedef struct { typedef struct { file_item *items; - int count; - int cap; + size_t count; + size_t cap; } file_list; typedef struct { file_list *cur; file_list *next; - int selected_idx; - window *fm_l, *fm_r; - int got_next_dir; + int cursor; + window *windows[2]; + /* int got_next_dir; */ char got_dir[PATH_MAX]; char cwd[PATH_MAX]; - int top, bottom, margin_bottom; - int needs_redraw; + int top, bottom; + bool need_redraw; } fm_info; -void fm_getdir(fm_info *i, file_list *l, const char *path); +file_list *fm_getdir(file_list *list, const char *path); fm_info *fm_init(terminal *t); -void fm_getcwd(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); +void fm_getcwd(fm_info *info); +void fm_draw_entries(window *window, file_list *list, size_t cursor, int top, + int bottom); +void fm_entries_scroll(fm_info *info, int n); +/* void fm_draw_right_window(fm_info *i); */ + +void fm_cd_up(fm_info *i); +void fm_cd_down(fm_info *i); +bool fm_preview_file(window *w, const char *path); +void magic_init(void); +void magic_cleanup(void); #endif /* SF_FM_H */ |
