Working version of pulling columns into their own file.
This commit is contained in:
parent
8820fda592
commit
78e7a7b59d
2
Makefile
2
Makefile
@ -56,7 +56,7 @@ all: $(NAME)
|
||||
clean:
|
||||
rm -f $(NAME)
|
||||
|
||||
$(NAME): $(NAME).c bterm.h bb.h
|
||||
$(NAME): $(NAME).c bterm.h bb.h columns.h
|
||||
$(CC) $(NAME).c $(CFLAGS) $(CWARN) $(G) $(O) -o $(NAME)
|
||||
|
||||
install: $(NAME)
|
||||
|
111
bb.c
111
bb.c
@ -84,18 +84,6 @@ void cleanup(void)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the color of a file listing, given its mode.
|
||||
*/
|
||||
const char* color_of(mode_t mode)
|
||||
{
|
||||
if (S_ISDIR(mode)) return DIR_COLOR;
|
||||
else if (S_ISLNK(mode)) return LINK_COLOR;
|
||||
else if (mode & (S_IXUSR | S_IXGRP | S_IXOTH))
|
||||
return EXECUTABLE_COLOR;
|
||||
else return NORMAL_COLOR;
|
||||
}
|
||||
|
||||
/*
|
||||
* Used for sorting, this function compares files according to the sorting-related options,
|
||||
* like bb->sort
|
||||
@ -213,7 +201,7 @@ void handle_next_key_binding(bb_t *bb)
|
||||
if (mouse_x != -1 && mouse_y != -1) {
|
||||
// Get bb column:
|
||||
for (int col = 0, x = 0; bb->columns[col]; col++, x++) {
|
||||
x += columns[(int)bb->columns[col]].width;
|
||||
x += (int)strlen(columns[(int)bb->columns[col]].name);
|
||||
if (x >= mouse_x) {
|
||||
bbmousecol[0] = bb->columns[col];
|
||||
break;
|
||||
@ -735,7 +723,7 @@ void run_bbcmd(bb_t *bb, const char *cmd)
|
||||
void render(bb_t *bb)
|
||||
{
|
||||
static int lastcursor = -1, lastscroll = -1;
|
||||
char buf[64];
|
||||
char buf[PATH_MAX * 2];
|
||||
|
||||
if (!dirty) {
|
||||
// Use terminal scrolling:
|
||||
@ -785,7 +773,7 @@ void render(bb_t *bb)
|
||||
move_cursor(tty_out, x, 1);
|
||||
fputs(indicator, tty_out);
|
||||
fputs(title, tty_out);
|
||||
x += columns[(int)bb->columns[col]].width;
|
||||
x += (int)strlen(title) + 1;
|
||||
}
|
||||
fputs(" \033[K\033[0m", tty_out);
|
||||
}
|
||||
@ -819,97 +807,24 @@ void render(bb_t *bb)
|
||||
entry_t *entry = files[i];
|
||||
if (i == bb->cursor) fputs(CURSOR_COLOR, tty_out);
|
||||
|
||||
int use_fullname = strcmp(bb->path, "<selection>") == 0;
|
||||
int x = 0;
|
||||
for (int col = 0; bb->columns[col]; col++) {
|
||||
for (int c = 0; bb->columns[c]; c++) {
|
||||
column_t col = columns[(int)bb->columns[c]];
|
||||
memset(buf, 0, sizeof(buf));
|
||||
col.render(bb, entry, buf, strlen(col.name)+1);
|
||||
|
||||
fprintf(tty_out, "\033[%d;%dH\033[K", y+1, x+1);
|
||||
if (col > 0) {
|
||||
if (col.name == NULL) continue;
|
||||
if (c > 0) {
|
||||
if (i == bb->cursor) fputs("┃", tty_out);
|
||||
else fputs("\033[37;2m┃\033[22m", tty_out);
|
||||
fputs(i == bb->cursor ? CURSOR_COLOR : "\033[0m", tty_out);
|
||||
x += 1;
|
||||
}
|
||||
move_cursor(tty_out, x, y);
|
||||
switch (bb->columns[col]) {
|
||||
case COL_SELECTED:
|
||||
fputs(IS_SELECTED(entry) ? SELECTED_INDICATOR : NOT_SELECTED_INDICATOR, tty_out);
|
||||
fputs(i == bb->cursor ? CURSOR_COLOR : "\033[0m", tty_out);
|
||||
break;
|
||||
|
||||
case COL_RANDOM: {
|
||||
double k = (double)entry->shufflepos/(double)bb->nfiles;
|
||||
int color = (int)(k*232 + (1.-k)*255);
|
||||
fprintf(tty_out, "\033[48;5;%dm \033[0m%s", color,
|
||||
i == bb->cursor ? CURSOR_COLOR : "\033[0m");
|
||||
break;
|
||||
}
|
||||
|
||||
case COL_SIZE: {
|
||||
int j = 0;
|
||||
const char* units = "BKMGTPEZY";
|
||||
double bytes = (double)entry->info.st_size;
|
||||
while (bytes > 1024) {
|
||||
bytes /= 1024;
|
||||
j++;
|
||||
}
|
||||
fprintf(tty_out, " %6.*f%c ", j > 0 ? 1 : 0, bytes, units[j]);
|
||||
break;
|
||||
}
|
||||
|
||||
case COL_MTIME:
|
||||
strftime(buf, sizeof(buf), BB_TIME_FMT, localtime(&(entry->info.st_mtime)));
|
||||
fputs(buf, tty_out);
|
||||
break;
|
||||
|
||||
case COL_CTIME:
|
||||
strftime(buf, sizeof(buf), BB_TIME_FMT, localtime(&(entry->info.st_ctime)));
|
||||
fputs(buf, tty_out);
|
||||
break;
|
||||
|
||||
case COL_ATIME:
|
||||
strftime(buf, sizeof(buf), BB_TIME_FMT, localtime(&(entry->info.st_atime)));
|
||||
fputs(buf, tty_out);
|
||||
break;
|
||||
|
||||
case COL_PERM:
|
||||
fprintf(tty_out, " %03o", entry->info.st_mode & 0777);
|
||||
break;
|
||||
|
||||
case COL_NAME: {
|
||||
char color[128];
|
||||
strcpy(color, color_of(entry->info.st_mode));
|
||||
if (i == bb->cursor) strcat(color, CURSOR_COLOR);
|
||||
fputs(color, tty_out);
|
||||
|
||||
char *name = use_fullname ? entry->fullname : entry->name;
|
||||
if (entry->no_esc) fputs(name, tty_out);
|
||||
else entry->no_esc |= !fputs_escaped(tty_out, name, color);
|
||||
|
||||
if (E_ISDIR(entry)) fputs("/", tty_out);
|
||||
|
||||
if (entry->linkname) {
|
||||
if (i != bb->cursor)
|
||||
fputs("\033[37m", tty_out);
|
||||
fputs("\033[2m -> \033[3m", tty_out);
|
||||
strcpy(color, color_of(entry->linkedmode));
|
||||
if (i == bb->cursor) strcat(color, CURSOR_COLOR);
|
||||
strcat(color, "\033[3;2m");
|
||||
fputs(color, tty_out);
|
||||
if (entry->link_no_esc) fputs(entry->linkname, tty_out);
|
||||
else entry->link_no_esc |= !fputs_escaped(tty_out, entry->linkname, color);
|
||||
|
||||
if (S_ISDIR(entry->linkedmode))
|
||||
fputs("/", tty_out);
|
||||
|
||||
fputs("\033[22;23m", tty_out);
|
||||
}
|
||||
fputs(i == bb->cursor ? CURSOR_COLOR : "\033[0m", tty_out);
|
||||
fputs("\033[K", tty_out);
|
||||
break;
|
||||
}
|
||||
default: break;
|
||||
}
|
||||
x += columns[(int)bb->columns[col]].width;
|
||||
fputs(buf, tty_out);
|
||||
fputs("\033[K", tty_out);
|
||||
x += (int)strlen(col.name) + 1;
|
||||
}
|
||||
fputs(" \033[K\033[0m", tty_out); // Reset color and attributes
|
||||
}
|
||||
|
20
bb.h
20
bb.h
@ -97,11 +97,6 @@ typedef struct {
|
||||
char *description;
|
||||
} binding_t;
|
||||
|
||||
typedef struct {
|
||||
int width;
|
||||
const char *name;
|
||||
} column_t;
|
||||
|
||||
typedef enum {
|
||||
COL_NONE = 0,
|
||||
COL_NAME = 'n',
|
||||
@ -181,24 +176,11 @@ typedef struct proc_s {
|
||||
|
||||
static binding_t bindings[MAX_BINDINGS];
|
||||
|
||||
// Column widths and titles:
|
||||
static const column_t columns[] = {
|
||||
['*'] = {2, "*"},
|
||||
['a'] = {18, " Accessed"},
|
||||
['c'] = {18, " Created"},
|
||||
['m'] = {18, " Modified"},
|
||||
['n'] = {40, "Name"},
|
||||
['p'] = {5, "Permissions"},
|
||||
['r'] = {2, "Random"},
|
||||
['s'] = {9, " Size"},
|
||||
};
|
||||
|
||||
// Functions
|
||||
void bb_browse(bb_t *bb, const char *initial_path);
|
||||
static void check_cmdfile(bb_t *bb);
|
||||
static void cleanup(void);
|
||||
static void cleanup_and_raise(int sig);
|
||||
static const char* color_of(mode_t mode);
|
||||
#ifdef __APPLE__
|
||||
static int compare_files(void *v, const void *v1, const void *v2);
|
||||
#else
|
||||
@ -340,4 +322,6 @@ static const char *runstartup =
|
||||
" fi;\n"
|
||||
"done\n";
|
||||
|
||||
#include "columns.h"
|
||||
|
||||
// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1
|
||||
|
196
columns.h
Normal file
196
columns.h
Normal file
@ -0,0 +1,196 @@
|
||||
/*
|
||||
* This file contains logic for drawing columns.
|
||||
*/
|
||||
|
||||
static void lpad(char *buf, int width)
|
||||
{
|
||||
int len = strlen(buf);
|
||||
if (len < width) {
|
||||
int pad = width - len;
|
||||
memmove(&buf[pad], buf, (size_t)len + 1);
|
||||
while (pad > 0) buf[--pad] = ' ';
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the color of a file listing, given its mode.
|
||||
*/
|
||||
static const char* color_of(mode_t mode)
|
||||
{
|
||||
if (S_ISDIR(mode)) return DIR_COLOR;
|
||||
else if (S_ISLNK(mode)) return LINK_COLOR;
|
||||
else if (mode & (S_IXUSR | S_IXGRP | S_IXOTH))
|
||||
return EXECUTABLE_COLOR;
|
||||
else return NORMAL_COLOR;
|
||||
}
|
||||
|
||||
static char* stpcpy_escaped(char *buf, const char *str, const char *color)
|
||||
{
|
||||
static const char *escapes = " abtnvfr e";
|
||||
for (const char *c = str; *c; ++c) {
|
||||
if (*c > 0 && *c <= '\x1b' && escapes[(int)*c] != ' ') { // "\n", etc.
|
||||
buf += sprintf(buf, "\033[31m\\%c%s", escapes[(int)*c], color);
|
||||
} else if (*c >= 0 && !(' ' <= *c && *c <= '~')) { // "\x02", etc.
|
||||
buf += sprintf(buf, "\033[31m\\x%02X%s", *c, color);
|
||||
} else {
|
||||
*(buf++) = *c;
|
||||
}
|
||||
}
|
||||
*(buf++) = '\0';
|
||||
return buf;
|
||||
}
|
||||
|
||||
static void timeago(char *buf, time_t t)
|
||||
{
|
||||
const int SECOND = 1;
|
||||
const int MINUTE = 60 * SECOND;
|
||||
const int HOUR = 60 * MINUTE;
|
||||
const int DAY = 24 * HOUR;
|
||||
const int MONTH = 30 * DAY;
|
||||
const int YEAR = 365 * DAY;
|
||||
|
||||
time_t now = time(0);
|
||||
double delta = difftime(now, t);
|
||||
|
||||
if (delta < 1.5)
|
||||
sprintf(buf, "a second");
|
||||
else if (delta < 1 * MINUTE)
|
||||
sprintf(buf, "%d seconds", (int)delta);
|
||||
else if (delta < 2 * MINUTE)
|
||||
sprintf(buf, "a minute");
|
||||
else if (delta < 1 * HOUR)
|
||||
sprintf(buf, "%d minutes", (int)delta/MINUTE);
|
||||
else if (delta < 2 * HOUR)
|
||||
sprintf(buf, "an hour");
|
||||
else if (delta < 1 * DAY)
|
||||
sprintf(buf, "%d hours", (int)delta/HOUR);
|
||||
else if (delta < 2 * DAY)
|
||||
sprintf(buf, "yesterday");
|
||||
else if (delta < 1 * MONTH)
|
||||
sprintf(buf, "%d days", (int)delta/DAY);
|
||||
else if (delta < 2 * MONTH)
|
||||
sprintf(buf, "a month");
|
||||
else if (delta < 1 * YEAR)
|
||||
sprintf(buf, "%d months", (int)delta/MONTH);
|
||||
else if (delta < 2 * YEAR)
|
||||
sprintf(buf, "a year");
|
||||
else
|
||||
sprintf(buf, "%d years", (int)delta/YEAR);
|
||||
}
|
||||
|
||||
void col_mreltime(bb_t *bb, entry_t *entry, char *buf, int width) {
|
||||
(void)bb;
|
||||
timeago(buf, entry->info.st_mtime);
|
||||
lpad(buf, width);
|
||||
}
|
||||
|
||||
void col_areltime(bb_t *bb, entry_t *entry, char *buf, int width) {
|
||||
(void)bb;
|
||||
timeago(buf, entry->info.st_atime);
|
||||
lpad(buf, width);
|
||||
}
|
||||
|
||||
void col_creltime(bb_t *bb, entry_t *entry, char *buf, int width) {
|
||||
(void)bb;
|
||||
timeago(buf, entry->info.st_ctime);
|
||||
lpad(buf, width);
|
||||
}
|
||||
|
||||
void col_mtime(bb_t *bb, entry_t *entry, char *buf, int width) {
|
||||
(void)bb;
|
||||
strftime(buf, (size_t)width, BB_TIME_FMT, localtime(&(entry->info.st_mtime)));
|
||||
}
|
||||
|
||||
void col_atime(bb_t *bb, entry_t *entry, char *buf, int width) {
|
||||
(void)bb;
|
||||
strftime(buf, (size_t)width, BB_TIME_FMT, localtime(&(entry->info.st_atime)));
|
||||
}
|
||||
|
||||
void col_ctime(bb_t *bb, entry_t *entry, char *buf, int width) {
|
||||
(void)bb;
|
||||
strftime(buf, (size_t)width, BB_TIME_FMT, localtime(&(entry->info.st_ctime)));
|
||||
}
|
||||
|
||||
void col_selected(bb_t *bb, entry_t *entry, char *buf, int width) {
|
||||
(void)bb; (void)width;
|
||||
strcpy(buf, IS_SELECTED(entry) ? SELECTED_INDICATOR : NOT_SELECTED_INDICATOR);
|
||||
}
|
||||
|
||||
void col_perm(bb_t *bb, entry_t *entry, char *buf, int width) {
|
||||
(void)bb; (void)width;
|
||||
sprintf(buf, " %03o", entry->info.st_mode & 0777);
|
||||
}
|
||||
|
||||
void col_random(bb_t *bb, entry_t *entry, char *buf, int width)
|
||||
{
|
||||
(void)width;
|
||||
double k = (double)entry->shufflepos/(double)bb->nfiles;
|
||||
int color = (int)(k*232 + (1.-k)*255);
|
||||
sprintf(buf, "\033[48;5;%dm \033[0m%s", color,
|
||||
entry == bb->files[bb->cursor] ? CURSOR_COLOR : "\033[0m");
|
||||
}
|
||||
|
||||
void col_size(bb_t *bb, entry_t *entry, char *buf, int width)
|
||||
{
|
||||
(void)bb; (void)width;
|
||||
int j = 0;
|
||||
const char* units = "BKMGTPEZY";
|
||||
double bytes = (double)entry->info.st_size;
|
||||
while (bytes > 1024) {
|
||||
bytes /= 1024;
|
||||
j++;
|
||||
}
|
||||
sprintf(buf, " %6.*f%c ", j > 0 ? 1 : 0, bytes, units[j]);
|
||||
}
|
||||
|
||||
void col_name(bb_t *bb, entry_t *entry, char *buf, int width)
|
||||
{
|
||||
(void)width;
|
||||
char color[128];
|
||||
strcpy(color, color_of(entry->info.st_mode));
|
||||
if (entry == bb->files[bb->cursor]) strcpy(color, CURSOR_COLOR);
|
||||
buf = stpcpy(buf, color);
|
||||
|
||||
int use_fullname = strcmp(bb->path, "<selection>") == 0;
|
||||
char *name = use_fullname ? entry->fullname : entry->name;
|
||||
if (entry->no_esc) buf = stpcpy(buf, name);
|
||||
else buf = stpcpy_escaped(buf, name, color);
|
||||
|
||||
if (E_ISDIR(entry)) buf = stpcpy(buf, "/");
|
||||
|
||||
if (!entry->linkname) return;
|
||||
|
||||
if (entry != bb->files[bb->cursor])
|
||||
buf = stpcpy(buf, "\033[37m");
|
||||
buf = stpcpy(buf, "\033[2m -> \033[3m");
|
||||
strcpy(color, color_of(entry->linkedmode));
|
||||
if (entry == bb->files[bb->cursor]) strcat(color, CURSOR_COLOR);
|
||||
strcat(color, "\033[3;2m");
|
||||
buf = stpcpy(buf, color);
|
||||
if (entry->link_no_esc) buf = stpcpy(buf, entry->linkname);
|
||||
else buf = stpcpy_escaped(buf, entry->linkname, color);
|
||||
|
||||
if (S_ISDIR(entry->linkedmode))
|
||||
buf = stpcpy(buf, "/");
|
||||
|
||||
buf = stpcpy(buf, "\033[22;23m");
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
const char *name;
|
||||
void (*render)(bb_t *, entry_t *, char *, int);
|
||||
} column_t;
|
||||
|
||||
static column_t columns[255] = {
|
||||
['*'] = {.name = "*", .render = col_selected},
|
||||
['n'] = {.name = "Name ", .render = col_name},
|
||||
['s'] = {.name = " Size", .render = col_size},
|
||||
['p'] = {.name = "Perm", .render = col_perm},
|
||||
['m'] = {.name = "Modified", .render = col_mreltime},
|
||||
['M'] = {.name = " Modified ", .render = col_mtime},
|
||||
['a'] = {.name = "Accessed", .render = col_areltime},
|
||||
['A'] = {.name = " Accessed ", .render = col_atime},
|
||||
['c'] = {.name = " Created", .render = col_creltime},
|
||||
['C'] = {.name = " Created ", .render = col_ctime},
|
||||
['r'] = {.name = "R", .render = col_random},
|
||||
};
|
Loading…
Reference in New Issue
Block a user