Compare commits
No commits in common. "b1930d91750731a6acb9b0f9935a280a6e6ba389" and "65c06ff53fa94958665b5f0caf68c1879a5c2f0f" have entirely different histories.
b1930d9175
...
65c06ff53f
4 changed files with 48 additions and 99 deletions
|
@ -44,7 +44,7 @@ right: go to child dir
|
||||||
enter: go to child dir/open file
|
enter: go to child dir/open file
|
||||||
backspace: go to parent dir
|
backspace: go to parent dir
|
||||||
|
|
||||||
g: go to top
|
gg: go to top
|
||||||
G: go to bottom
|
G: go to bottom
|
||||||
|
|
||||||
ctrl+u: jump up
|
ctrl+u: jump up
|
||||||
|
@ -60,7 +60,6 @@ u: sort files
|
||||||
.: toggle hidden files
|
.: toggle hidden files
|
||||||
i: toggle file details
|
i: toggle file details
|
||||||
X: toggle executable
|
X: toggle executable
|
||||||
!: open shell in current dir
|
|
||||||
|
|
||||||
A: show directory disk usage/block size
|
A: show directory disk usage/block size
|
||||||
|
|
||||||
|
@ -81,6 +80,7 @@ o: open file with
|
||||||
O: open file with a GUI program detached from file manager
|
O: open file with a GUI program detached from file manager
|
||||||
|
|
||||||
/: search
|
/: search
|
||||||
|
!: open shell in current dir
|
||||||
|
|
||||||
x: view file/dir attributes
|
x: view file/dir attributes
|
||||||
e: show history
|
e: show history
|
||||||
|
|
12
ccc.1
12
ccc.1
|
@ -1,11 +1,11 @@
|
||||||
.
|
.
|
||||||
.TH CCC "1" "March 2024" "ccc" "User Commands"
|
.TH CCC "1" "March 2024" "ccc" "User Commands"
|
||||||
.SH NAME
|
.SH NAME
|
||||||
ccc \- Fast, small, hackable TUI file manager with no dependency
|
ccc \- Fast TUI file manager written in C, using ncurses.
|
||||||
.SH SYNOPSIS
|
.SH SYNOPSIS
|
||||||
.B ccc
|
.B ccc
|
||||||
.SH DESCRIPTION
|
.SH DESCRIPTION
|
||||||
Soft fork of fff in C aiming for size and speed with no dependency, hackable with patches and configurable
|
ccc is a rewrite of fff file manager in C aiming for usefulness and speed. The fact that it is written in C makes it more versatile and rapid, enabling us to add features that were previously ruled out due to time complexity. You may call it a soft fork.
|
||||||
.PP
|
.PP
|
||||||
.SH "Usage"
|
.SH "Usage"
|
||||||
.
|
.
|
||||||
|
@ -24,7 +24,7 @@ right: go to child dir
|
||||||
enter: go to child dir/open file
|
enter: go to child dir/open file
|
||||||
backspace: go to parent dir
|
backspace: go to parent dir
|
||||||
|
|
||||||
g: go to top
|
gg: go to top
|
||||||
G: go to bottom
|
G: go to bottom
|
||||||
|
|
||||||
ctrl+u: jump up
|
ctrl+u: jump up
|
||||||
|
@ -34,19 +34,13 @@ t: go to trash dir
|
||||||
~: go to home dir
|
~: go to home dir
|
||||||
-: go to previous dir
|
-: go to previous dir
|
||||||
z: refresh current dir
|
z: refresh current dir
|
||||||
:: go to a directory by typing
|
|
||||||
u: sort files
|
|
||||||
|
|
||||||
.: toggle hidden files
|
|
||||||
i: toggle file details
|
i: toggle file details
|
||||||
X: toggle executable
|
X: toggle executable
|
||||||
!: open shell in current dir
|
|
||||||
|
|
||||||
A: show directory disk usage/block size
|
A: show directory disk usage/block size
|
||||||
|
|
||||||
f: new file
|
f: new file
|
||||||
n: new dir
|
|
||||||
r: rename
|
|
||||||
|
|
||||||
space: mark file
|
space: mark file
|
||||||
a: mark all files in directory
|
a: mark all files in directory
|
||||||
|
|
120
ccc.c
120
ccc.c
|
@ -35,11 +35,9 @@ enum keys {
|
||||||
PAGE_UP,
|
PAGE_UP,
|
||||||
PAGE_DOWN,
|
PAGE_DOWN,
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
int key;
|
int key;
|
||||||
} key;
|
} key;
|
||||||
|
|
||||||
#define PATH_MAX 4096 /* Max length of path */
|
#define PATH_MAX 4096 /* Max length of path */
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
@ -68,11 +66,9 @@ void goto_dir(void);
|
||||||
void create_dir(void);
|
void create_dir(void);
|
||||||
void create_file(void);
|
void create_file(void);
|
||||||
void delete_files(void);
|
void delete_files(void);
|
||||||
void start_shell(void);
|
|
||||||
void yank_clipboard(void);
|
|
||||||
void wpprintw(const char *fmt, ...);
|
void wpprintw(const char *fmt, ...);
|
||||||
void move_cursor(int row, int col);
|
void move_cursor(int row, int col);
|
||||||
int readch(void);
|
int read_key(void);
|
||||||
int get_window_size(int *row, int *col);
|
int get_window_size(int *row, int *col);
|
||||||
void bprintf(const char *fmt, ...);
|
void bprintf(const char *fmt, ...);
|
||||||
|
|
||||||
|
@ -169,18 +165,19 @@ int main(int argc, char **argv)
|
||||||
|
|
||||||
if (to_open_file) {
|
if (to_open_file) {
|
||||||
sel_file = arraylist_search(files, argv_cp, 1);
|
sel_file = arraylist_search(files, argv_cp, 1);
|
||||||
|
list_files();
|
||||||
}
|
}
|
||||||
|
|
||||||
int ch, run = 1;
|
int ch, ch2;
|
||||||
|
int run = 1;
|
||||||
while (run) {
|
while (run) {
|
||||||
list_files();
|
ch = read_key();
|
||||||
ch = readch();
|
|
||||||
switch (ch) {
|
switch (ch) {
|
||||||
/* quit */
|
/* quit */
|
||||||
case 'q':
|
case 'q':
|
||||||
if (write_last_d() == -1) {
|
if (write_last_d() == -1) {
|
||||||
/* prompt user so error message can be shown to user */
|
/* prompt user so error message can be shown to user */
|
||||||
readch();
|
read_key();
|
||||||
}
|
}
|
||||||
cleanup();
|
cleanup();
|
||||||
run = 0;
|
run = 0;
|
||||||
|
@ -242,6 +239,8 @@ int main(int argc, char **argv)
|
||||||
sel_file -= jump_num;
|
sel_file -= jump_num;
|
||||||
else
|
else
|
||||||
sel_file = 0;
|
sel_file = 0;
|
||||||
|
|
||||||
|
list_files();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* go up */
|
/* go up */
|
||||||
|
@ -249,6 +248,8 @@ int main(int argc, char **argv)
|
||||||
case 'k':
|
case 'k':
|
||||||
if (sel_file > 0)
|
if (sel_file > 0)
|
||||||
sel_file--;
|
sel_file--;
|
||||||
|
|
||||||
|
list_files();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* jump down */
|
/* jump down */
|
||||||
|
@ -257,6 +258,8 @@ int main(int argc, char **argv)
|
||||||
sel_file += jump_num;
|
sel_file += jump_num;
|
||||||
else
|
else
|
||||||
sel_file = (files->length - 1);
|
sel_file = (files->length - 1);
|
||||||
|
|
||||||
|
list_files();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* go down */
|
/* go down */
|
||||||
|
@ -264,16 +267,27 @@ int main(int argc, char **argv)
|
||||||
case 'j':
|
case 'j':
|
||||||
if (sel_file < (files->length - 1))
|
if (sel_file < (files->length - 1))
|
||||||
sel_file++;
|
sel_file++;
|
||||||
|
|
||||||
|
list_files();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* jump to the bottom */
|
/* jump to the bottom */
|
||||||
case 'G':
|
case 'G':
|
||||||
sel_file = (files->length - 1);
|
sel_file = (files->length - 1);
|
||||||
|
list_files();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* jump to the top */
|
/* jump to the top */
|
||||||
|
case 'g':
|
||||||
|
ch2 = read_key();
|
||||||
|
switch (ch2) {
|
||||||
case 'g':
|
case 'g':
|
||||||
sel_file = 0;
|
sel_file = 0;
|
||||||
|
list_files();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* '~' go to $HOME */
|
/* '~' go to $HOME */
|
||||||
|
@ -282,7 +296,6 @@ int main(int argc, char **argv)
|
||||||
if (home == NULL) {
|
if (home == NULL) {
|
||||||
wpprintw("$HOME not defined");
|
wpprintw("$HOME not defined");
|
||||||
} else {
|
} else {
|
||||||
strcpy(p_cwd, cwd);
|
|
||||||
change_dir(home, 0, 0);
|
change_dir(home, 0, 0);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -353,20 +366,12 @@ int main(int argc, char **argv)
|
||||||
|
|
||||||
case 'X':
|
case 'X':
|
||||||
toggle_executable();
|
toggle_executable();
|
||||||
change_dir(cwd, 0, 0);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case '!':
|
|
||||||
start_shell();
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'y':
|
|
||||||
yank_clipboard();
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* mark one file */
|
/* mark one file */
|
||||||
case SPACE:
|
case SPACE:
|
||||||
add_file_stat(files->items[sel_file].name, files->items[sel_file].path, 1);
|
add_file_stat(files->items[sel_file].name, files->items[sel_file].path, 1);
|
||||||
|
list_files();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* mark all files in directory */
|
/* mark all files in directory */
|
||||||
|
@ -458,10 +463,8 @@ void show_help(void)
|
||||||
"r: rename\n\nspace: mark file\na: mark all files in directory\nd: trash"
|
"r: rename\n\nspace: mark file\na: mark all files in directory\nd: trash"
|
||||||
"\n\n?: show help\nq: exit with last dir written to file\n"
|
"\n\n?: show help\nq: exit with last dir written to file\n"
|
||||||
"ctrl+c exit without writing last dir"
|
"ctrl+c exit without writing last dir"
|
||||||
"\nPress any key to continue"
|
|
||||||
);
|
);
|
||||||
wpprintw("Visit https://github.com/night0721/ccc or use 'man ccc' for help");
|
wpprintw("Visit https://github.com/night0721/ccc or use 'man ccc' for help");
|
||||||
readch();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -596,6 +599,8 @@ void populate_files(const char *path, int ftype, ArrayList **list)
|
||||||
free(tmp2);
|
free(tmp2);
|
||||||
}
|
}
|
||||||
closedir(dp);
|
closedir(dp);
|
||||||
|
if (list == &files)
|
||||||
|
list_files();
|
||||||
} else {
|
} else {
|
||||||
wpprintw("stat failed: %s", strerror(errno));
|
wpprintw("stat failed: %s", strerror(errno));
|
||||||
}
|
}
|
||||||
|
@ -999,6 +1004,7 @@ void edit_file(void)
|
||||||
} else if (pid > 0) {
|
} else if (pid > 0) {
|
||||||
/* Parent process */
|
/* Parent process */
|
||||||
waitpid(pid, NULL, 0);
|
waitpid(pid, NULL, 0);
|
||||||
|
list_files();
|
||||||
} else {
|
} else {
|
||||||
/* Fork failed */
|
/* Fork failed */
|
||||||
wpprintw("fork failed: %s", strerror(errno));
|
wpprintw("fork failed: %s", strerror(errno));
|
||||||
|
@ -1041,7 +1047,7 @@ int write_last_d(void)
|
||||||
if (!strcmp(last_d, "")) {
|
if (!strcmp(last_d, "")) {
|
||||||
strcpy(last_d, getenv("CCC_LAST_D"));
|
strcpy(last_d, getenv("CCC_LAST_D"));
|
||||||
if (!strcmp(last_d, "")) {
|
if (!strcmp(last_d, "")) {
|
||||||
wpprintw("$CCC_LAST_D not defined (Press any key to continue)");
|
wpprintw("$CCC_LAST_D not defined (Press enter to continue)");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -1058,7 +1064,7 @@ int write_last_d(void)
|
||||||
mkdir_p(last_ddup);
|
mkdir_p(last_ddup);
|
||||||
FILE *last_d_file = fopen(last_d, "w");
|
FILE *last_d_file = fopen(last_d, "w");
|
||||||
if (last_d_file == NULL) {
|
if (last_d_file == NULL) {
|
||||||
wpprintw("Cannot open last directory file (Press any key to continue)");
|
wpprintw("Cannot open last directory file (Press enter to continue)");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
fwrite(cwd, strlen(cwd), sizeof(char), last_d_file);
|
fwrite(cwd, strlen(cwd), sizeof(char), last_d_file);
|
||||||
|
@ -1075,6 +1081,7 @@ int sort_compare(const void *a, const void *b)
|
||||||
void sort_files(void)
|
void sort_files(void)
|
||||||
{
|
{
|
||||||
qsort(files->items, files->length, sizeof(file), sort_compare);
|
qsort(files->items, files->length, sizeof(file), sort_compare);
|
||||||
|
list_files();
|
||||||
}
|
}
|
||||||
|
|
||||||
char *get_panel_string(char *prompt)
|
char *get_panel_string(char *prompt)
|
||||||
|
@ -1083,10 +1090,9 @@ char *get_panel_string(char *prompt)
|
||||||
char *buf = memalloc(bufsize);
|
char *buf = memalloc(bufsize);
|
||||||
size_t buflen = 0;
|
size_t buflen = 0;
|
||||||
buf[0] = '\0';
|
buf[0] = '\0';
|
||||||
bprintf("\033[?25h");
|
|
||||||
while (1) {
|
while (1) {
|
||||||
wpprintw("%s%s", prompt, buf);
|
wpprintw(prompt);
|
||||||
int c = readch();
|
int c = read_key();
|
||||||
if (c == BACKSPACE) {
|
if (c == BACKSPACE) {
|
||||||
if (buflen != 0) {
|
if (buflen != 0) {
|
||||||
buf[--buflen] = '\0';
|
buf[--buflen] = '\0';
|
||||||
|
@ -1094,12 +1100,10 @@ char *get_panel_string(char *prompt)
|
||||||
} else if (c == '\033') {
|
} else if (c == '\033') {
|
||||||
wpprintw("");
|
wpprintw("");
|
||||||
free(buf);
|
free(buf);
|
||||||
bprintf("\033[?25l");
|
|
||||||
return NULL;
|
return NULL;
|
||||||
} else if (c == '\r') {
|
} else if (c == '\r') {
|
||||||
wpprintw("");
|
wpprintw("");
|
||||||
if (buflen != 0) {
|
if (buflen != 0) {
|
||||||
bprintf("\033[?25l");
|
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
} else if (!iscntrl(c) && c < 128) {
|
} else if (!iscntrl(c) && c < 128) {
|
||||||
|
@ -1115,7 +1119,6 @@ char *get_panel_string(char *prompt)
|
||||||
if (buf[0] == '~')
|
if (buf[0] == '~')
|
||||||
replace_home(buf);
|
replace_home(buf);
|
||||||
|
|
||||||
bprintf("\033[?25l");
|
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1123,9 +1126,6 @@ void rename_file(void)
|
||||||
{
|
{
|
||||||
char *filename = files->items[sel_file].path;
|
char *filename = files->items[sel_file].path;
|
||||||
char *input = get_panel_string("Rename file: ");
|
char *input = get_panel_string("Rename file: ");
|
||||||
if (!input) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
char *newfilename = estrdup(filename);
|
char *newfilename = estrdup(filename);
|
||||||
/* remove basename of newfilename */
|
/* remove basename of newfilename */
|
||||||
char *last_slash = strrchr(newfilename, '/');
|
char *last_slash = strrchr(newfilename, '/');
|
||||||
|
@ -1134,8 +1134,8 @@ void rename_file(void)
|
||||||
strcat(newfilename, "/");
|
strcat(newfilename, "/");
|
||||||
strcat(newfilename, input);
|
strcat(newfilename, input);
|
||||||
if (rename(filename, newfilename)) {
|
if (rename(filename, newfilename)) {
|
||||||
wpprintw("rename failed: %s (Press any key to continue)", strerror(errno));
|
wpprintw("rename failed: %s (Press enter to continue)", strerror(errno));
|
||||||
readch();
|
read_key();
|
||||||
} else {
|
} else {
|
||||||
change_dir(cwd, 0, 0);
|
change_dir(cwd, 0, 0);
|
||||||
wpprintw("Renamed %s to %s", filename, newfilename);
|
wpprintw("Renamed %s to %s", filename, newfilename);
|
||||||
|
@ -1149,13 +1149,13 @@ void goto_dir(void)
|
||||||
char *input = get_panel_string("Goto dir: ");
|
char *input = get_panel_string("Goto dir: ");
|
||||||
struct stat st;
|
struct stat st;
|
||||||
if (lstat(input, &st)) {
|
if (lstat(input, &st)) {
|
||||||
wpprintw("lstat failed: %s (Press any key to continue)", strerror(errno));
|
wpprintw("lstat failed: %s (Press enter to continue)", strerror(errno));
|
||||||
readch();
|
read_key();
|
||||||
}
|
}
|
||||||
/* chdir to directory from argument */
|
/* chdir to directory from argument */
|
||||||
if (S_ISDIR(st.st_mode) && chdir(input)) {
|
if (S_ISDIR(st.st_mode) && chdir(input)) {
|
||||||
wpprintw("chdir failed: %s (Press any key to continue)", strerror(errno));
|
wpprintw("chdir failed: %s (Press enter to continue)", strerror(errno));
|
||||||
readch();
|
read_key();
|
||||||
}
|
}
|
||||||
getcwd(cwd, PATH_MAX);
|
getcwd(cwd, PATH_MAX);
|
||||||
change_dir(cwd, 0, 0);
|
change_dir(cwd, 0, 0);
|
||||||
|
@ -1211,48 +1211,6 @@ void delete_files(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void start_shell(void)
|
|
||||||
{
|
|
||||||
bprintf("\033[2J\033[?25h");
|
|
||||||
move_cursor(1, 1);
|
|
||||||
char shell[PATH_MAX];
|
|
||||||
strcpy(shell, getenv("SHELL"));
|
|
||||||
if (strlen(shell) == 0) {
|
|
||||||
strcpy(shell, "sh");
|
|
||||||
} else {
|
|
||||||
pid_t pid = fork();
|
|
||||||
if (pid == 0) {
|
|
||||||
/* Child process */
|
|
||||||
execlp(shell, shell, NULL);
|
|
||||||
_exit(1); /* Exit if exec fails */
|
|
||||||
} else if (pid > 0) {
|
|
||||||
/* Parent process */
|
|
||||||
waitpid(pid, NULL, 0);
|
|
||||||
bprintf("\033[?25l");
|
|
||||||
} else {
|
|
||||||
/* Fork failed */
|
|
||||||
wpprintw("fork failed: %s", strerror(errno));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void yank_clipboard(void)
|
|
||||||
{
|
|
||||||
pid_t pid = fork();
|
|
||||||
if (pid == 0) {
|
|
||||||
/* Child process */
|
|
||||||
execlp(clipboard, clipboard, files->items[sel_file].name, NULL);
|
|
||||||
_exit(1); /* Exit if exec fails */
|
|
||||||
} else if (pid > 0) {
|
|
||||||
/* Parent process */
|
|
||||||
waitpid(pid, NULL, 0);
|
|
||||||
bprintf("\033[?25l");
|
|
||||||
} else {
|
|
||||||
/* Fork failed */
|
|
||||||
wpprintw("fork failed: %s", strerror(errno));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Print line to the panel
|
* Print line to the panel
|
||||||
*/
|
*/
|
||||||
|
@ -1275,7 +1233,7 @@ void move_cursor(int row, int col)
|
||||||
bprintf("\033[%d;%dH", row, col);
|
bprintf("\033[%d;%dH", row, col);
|
||||||
}
|
}
|
||||||
|
|
||||||
int readch(void)
|
int read_key(void)
|
||||||
{
|
{
|
||||||
int nread;
|
int nread;
|
||||||
char c;
|
char c;
|
||||||
|
|
3
config.h
3
config.h
|
@ -42,9 +42,6 @@ static int dirs_size = 0;
|
||||||
/* Default text editor */
|
/* Default text editor */
|
||||||
static const char *editor = "nvim";
|
static const char *editor = "nvim";
|
||||||
|
|
||||||
/* Default clipboard program */
|
|
||||||
static const char *clipboard = "wl-copy";
|
|
||||||
|
|
||||||
/* File location to write last directory */
|
/* File location to write last directory */
|
||||||
static char last_d[PATH_MAX] = "~/.cache/ccc/.ccc_d";
|
static char last_d[PATH_MAX] = "~/.cache/ccc/.ccc_d";
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue