sfm

simple file manager
git clone git://git.afify.dev/sfm
Log | Files | Refs | README | LICENSE

commit a9537187196cd2fc97430522f01196f0a9eb9fcf
parent bfd368b6d2278d4ec79b84f9d1ab0d467e1378ff
Author: afify <hassan@afify.dev>
Date:   Mon, 13 Sep 2021 20:28:46 +0300

[feat] add change owner and group

Diffstat:
MREADME.md | 6+++++-
Mconfig.def.h | 27++++++++++++++++++++-------
Msfm.1 | 14+++++++++++++-
Msfm.c | 66++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
4 files changed, 102 insertions(+), 11 deletions(-)

diff --git a/README.md b/README.md @@ -70,11 +70,15 @@ $ man sfm | `p` | paste | | `P` | move | | `c` | rename | +| `cw` | rename | +| `co` | owner and group | +| `cc` | exit change | +| `cq` | exit change | | `.` | toggle dotfiles | | `v` | start visual mode | | `/` | start filter | | `ENTER` | find filter | -| `ESC` | exit filter | +| `ESC` | exit filter|change | | `SPACE` | switch pane | **visual mode** diff --git a/config.def.h b/config.def.h @@ -25,13 +25,15 @@ static const Cpair cstatus = { 243, 0 }; /* commands */ static const char *rm_cmd[] = { "rm", "-rf" }; /* delete */ static const char *cp_cmd[] = { "cp", "-r" }; /* copy */ +static const char *chown_cmd[] = { "chown", "-R" }; /* change file owner and group */ static const char *mv_cmd[] = { "mv" }; /* move */ static const char delconf[] = "yes"; -static const size_t rm_cmd_len = LEN(rm_cmd); -static const size_t cp_cmd_len = LEN(cp_cmd); -static const size_t mv_cmd_len = LEN(mv_cmd); -static const size_t delconf_len = LEN(delconf); +static const size_t rm_cmd_len = LEN(rm_cmd); +static const size_t cp_cmd_len = LEN(cp_cmd); +static const size_t chown_cmd_len = LEN(chown_cmd); +static const size_t mv_cmd_len = LEN(mv_cmd); +static const size_t delconf_len = LEN(delconf); /* bookmarks */ static const char root[] = "/"; @@ -47,7 +49,6 @@ static const char *r2[] = { "r2", "-c", "vv" }; /* extensions*/ static const char *images[] = { "bmp", "jpg", "jpeg", "png", "gif", "xpm" }; -static const char *web[] = { "htm", "html" }; static const char *pdf[] = { "epub", "pdf" }; static const char *arts[] = { "xcf" }; static const char *obj[] = { "o", "a", "so" }; @@ -60,7 +61,6 @@ static const char *documents[] = { "odt", "doc", "docx", "xls", "xlsx", "odp", static Rule rules[] = { {videos, LEN(videos), mpv, LEN(mpv) }, {images, LEN(images), sxiv, LEN(sxiv) }, - {web, LEN(web), surf, LEN(surf) }, {pdf, LEN(pdf), mupdf, LEN(mupdf) }, {documents, LEN(documents), libreoffice, LEN(libreoffice) }, {arts, LEN(arts), gimp, LEN(gimp) }, @@ -93,12 +93,24 @@ static Key nkeys[] = { { {.ch = 'y'}, yank, {0} }, { {.ch = 'p'}, paste, {0} }, { {.ch = 'P'}, selmv, {0} }, - { {.ch = 'c'}, rname, {0} }, + { {.ch = 'c'}, start_change, {0} }, { {.key = TB_KEY_SPACE}, switch_pane, {0} }, { {.ch = '\\'}, bkmrk, {.v = root} }, { {.ch = '.'}, toggle_df, {0} }, }; +/* change keys */ +static Key ckeys[] = { + /* keyval function arg */ + { {.ch = 'w'}, rname, {0} }, + { {.ch = 'o'}, chngo, {0} }, +// { {.ch = 'p'}, chngp, {0} }, +// { {.ch = 'a'}, chngq, {0} }, + { {.ch = 'q'}, exit_change, {0} }, + { {.ch = 'c'}, exit_change, {0} }, + { {.key = TB_KEY_ESC}, exit_change, {0} }, +}; + /* visual keys */ static Key vkeys[] = { /* keyval function arg */ @@ -116,6 +128,7 @@ static Key vkeys[] = { static const size_t nkeyslen = LEN(nkeys); static const size_t vkeyslen = LEN(vkeys); +static const size_t ckeyslen = LEN(ckeys); /* permissions */ static const mode_t ndir_perm = S_IRWXU; diff --git a/sfm.1 b/sfm.1 @@ -64,8 +64,20 @@ paste move .TP .B c +start change +.TP +.B cw rename .TP +.B co +owner and group +.TP +.B cc +exit change +.TP +.B cq +exit change +.TP .B . toggle dotfiles .TP @@ -101,7 +113,7 @@ exit visual mode exit visual mode .TP .B ESC -exit visual mode +exit visual mode | change .SH CUSTOMIZATION sfm is customized by creating a custom .IR config.h diff --git a/sfm.c b/sfm.c @@ -154,6 +154,8 @@ static void toggle_df(const Arg *arg); static void start_filter(const Arg *arg); static void start_vmode(const Arg *arg); static void exit_vmode(const Arg *arg); +static void start_change(const Arg *arg); +static void exit_change(const Arg *arg); static void selup(const Arg *arg); static void seldwn(const Arg *arg); static void selall(const Arg *arg); @@ -167,6 +169,7 @@ static void init_files(void); static void free_files(void); static void yank(const Arg *arg); static void rname(const Arg *arg); +static void chngo(const Arg *arg); static void dupl(const Arg *arg); static void switch_pane(const Arg *arg); static void quit(const Arg *arg); @@ -193,6 +196,7 @@ static int *sel_indexes; static size_t sel_len = 0; static char **sel_files; static int cont_vmode = 0; +static int cont_change = 0; static pid_t fork_pid = 0, main_pid; #if defined(_SYS_INOTIFY_H) #define READEVSZ 16 @@ -1077,7 +1081,8 @@ addwatch(Pane *pane) #if defined(_SYS_INOTIFY_H) return pane->inotify_wd = inotify_add_watch(inotify_fd, pane->dirn, IN_MODIFY | IN_MOVED_FROM | IN_MOVED_TO | IN_CREATE | - IN_DELETE | IN_DELETE_SELF | IN_MOVE_SELF); + IN_ATTRIB | IN_DELETE | IN_DELETE_SELF | + IN_MOVE_SELF); #elif defined(_SYS_EVENT_H_) pane->event_fd = open(pane->dirn, O_RDONLY); if (pane->event_fd < 0) @@ -1085,7 +1090,7 @@ addwatch(Pane *pane) EV_SET(&evlist[pane->pane_id], pane->event_fd, EVFILT_VNODE, EV_ADD | EV_CLEAR, NOTE_DELETE | NOTE_EXTEND | NOTE_LINK | NOTE_RENAME | - NOTE_REVOKE | NOTE_WRITE, + NOTE_ATTRIB | NOTE_REVOKE | NOTE_WRITE, 0, NULL); return 0; #endif @@ -1216,6 +1221,35 @@ exit_vmode(const Arg *arg) } static void +start_change(const Arg *arg) +{ + if (cpane->dirc < 1) + return; + struct tb_event fev; + + cont_change = 0; + print_prompt("c [wopa]"); + tb_present(); + while (tb_poll_event(&fev) != 0) { + switch (fev.type) { + case TB_EVENT_KEY: + grabkeys(&fev, ckeys, ckeyslen); + if (cont_change == -1) + return; + tb_present(); + break; + } + } +} + +static void +exit_change(const Arg *arg) +{ + cont_change = -1; + print_info(cpane, NULL); +} + +static void selup(const Arg *arg) { mv_ver(arg); @@ -1415,6 +1449,34 @@ rname(const Arg *arg) PERROR(spawn(rename_cmd, 3, NULL, 0, NULL, DontWait) < 0); free(input_name); + exit_change(0); +} + +static void +chngo(const Arg *arg) +{ + if (cpane->dirc < 1) + return; + char *input_og; + char *tmp[1]; + + input_og = ecalloc(MAX_N, sizeof(char)); + + if (get_usrinput(input_og, MAX_N, "OWNER:GROUP %s", + basename(CURSOR(cpane).name)) < 0) { + free(input_og); + return; + } + + tmp[0] = input_og; + if (spawn(chown_cmd, chown_cmd_len, tmp, 1, CURSOR(cpane).name, + DontWait) < 0) { + print_error(strerror(errno)); + return; + } + + free(input_og); + exit_change(0); } static void