aboutsummaryrefslogtreecommitdiffstats
path: root/fm.c
diff options
context:
space:
mode:
authorverdant <im@verdant.ee>2026-07-27 09:26:02 +0800
committerverdant <im@verdant.ee>2026-07-27 09:26:02 +0800
commit48ca0d55b562230644e5f71597979c8d813b80e2 (patch)
treef1309624a546c76c9a638500456cbeb82b1d12a5 /fm.c
parenta988bc1eb3c0dbc0ce3ccd0f3422a459a9e61295 (diff)
downloadsf-48ca0d55b562230644e5f71597979c8d813b80e2.tar.gz
sf-48ca0d55b562230644e5f71597979c8d813b80e2.zip
Refactor fm
Diffstat (limited to 'fm.c')
-rw-r--r--fm.c410
1 files changed, 244 insertions, 166 deletions
diff --git a/fm.c b/fm.c
index f6a7bfd..e03ac57 100644
--- a/fm.c
+++ b/fm.c
@@ -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);
}