From fe423ed2794273445ad51332d08b19155bcbc3e8 Mon Sep 17 00:00:00 2001 From: verdant Date: Tue, 28 Jul 2026 14:46:43 +0800 Subject: Implement open with editor Fork a child process to run the text editor. If the "EDITOR" envrionment variable is not set, fallback to "vi". --- fm.c | 45 +++++++++++++++++++++++++++++++++++++++++++++ fm.h | 12 ++++++++++++ keys.c | 24 ++++++++++++++++++++++++ 3 files changed, 81 insertions(+) diff --git a/fm.c b/fm.c index 17d0b7f..1d1302c 100644 --- a/fm.c +++ b/fm.c @@ -6,6 +6,7 @@ #include "wm.h" #include #include +#include #include #include #include @@ -14,9 +15,12 @@ #include #include #include +#include #include static magic_t g_magic_ctx = NULL; +static char *const utils[] = {"vi", "xdg-open"}; +static char *const envs[] = {"SHELL", "EDITOR", "SF"}; bool need_redraw = true; /* Function forward declarations */ @@ -24,6 +28,9 @@ 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 char *detect_file_type(const char *filepath); +static void fm_getenv(void); +static char *xgetenv(const char *const name, char *fallback); +int open_with_editor(char **argv); bool fm_preview_file(window *w, const char *path); /* Functions */ @@ -119,6 +126,7 @@ static void fm_file_list_init(file_list *l, int cap) l->items = xmalloc(sizeof(file_item) * cap); l->items->is_dir = 0; memset(l->items, 0, l->cap * sizeof(file_item)); + fm_getenv(); } fm_info *fm_init(terminal *t) @@ -334,3 +342,40 @@ void magic_cleanup(void) if (g_magic_ctx) magic_close(g_magic_ctx); } +static char *xgetenv(const char *const name, char *fallback) +{ + char *value = getenv(name); + + return value && value[0] ? value : fallback; +} + +static void fm_getenv(void) +{ + enveditor = xgetenv(envs[ENV_EDITOR], utils[UTIL_VI]); +} + +int open_with_editor(char **argv) +{ + pid_t pid; + def_prog_mode(); + endwin(); + + if (!argv[0] || *argv[0] == '\0') { + argv[0] = utils[UTIL_VI]; + } + + if ((pid = fork()) < 0) { + log_write(LOG_ERR, "fork error"); + return -1; + } else if (pid == 0) { + if (execvp(argv[0], argv) < 0) { + log_write(LOG_ERR, "execvp error"); + return -1; + } + } else { + wait(NULL); + need_redraw = true; + } + + return 0; +} diff --git a/fm.h b/fm.h index 4acf2d6..e515d5a 100644 --- a/fm.h +++ b/fm.h @@ -35,6 +35,17 @@ typedef struct { int top, bottom; } fm_info; +extern bool need_redraw; + +#define UTIL_VI 0 +#define UTIL_XDG_OPEN 1 + +#define ENV_SHELL 0 +#define ENV_EDITOR 1 +#define ENV_SF 2 + +static char *enveditor; + file_list *fm_getdir(file_list *list, const char *path); fm_info *fm_init(terminal *t); void fm_getcwd(fm_info *info); @@ -47,6 +58,7 @@ void fm_draw_file_stream(window *w, FILE *fp); void fm_cd_up(fm_info *i); void fm_cd_down(fm_info *i); bool fm_preview_file(window *w, const char *path); +int open_with_editor(char **argv); void magic_init(void); void magic_cleanup(void); #endif /* SF_FM_H */ diff --git a/keys.c b/keys.c index a954794..8fa11c6 100644 --- a/keys.c +++ b/keys.c @@ -1,11 +1,15 @@ #include "keys.h" +#include #include +#include #include #include "display.h" +#include "err.h" #include "fm.h" #include "log.h" +#include "mem.h" #include "wm.h" void handling_keys(int ch, fm_info *i) @@ -34,7 +38,27 @@ void handling_keys(int ch, fm_info *i) case 'l': fm_cd_down(i); break; + case 'o': + case '\n': + case '\r': + case KEY_ENTER: + log_write(LOG_INFO, "Open file"); + if (!(i->cur->items[i->cursor].is_dir)) { + char filepath[PATH_MAX]; + size_t len = + snprintf(filepath, PATH_MAX, "%s/%s", i->cwd, + i->cur->items[i->cursor].name); + if (len >= PATH_MAX) { + die("snprintf failed"); + } + char *argv[] = {enveditor, filepath, NULL}; + open_with_editor(argv); + break; + } else { + return; + } + break; default: return; } -- cgit v1.2.3