aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fm.c211
-rw-r--r--fm.h6
2 files changed, 214 insertions, 3 deletions
diff --git a/fm.c b/fm.c
index 66e588f..fba24f8 100644
--- a/fm.c
+++ b/fm.c
@@ -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;
+}
diff --git a/fm.h b/fm.h
index 06de931..b50dabe 100644
--- a/fm.h
+++ b/fm.h
@@ -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 */