aboutsummaryrefslogtreecommitdiff
path: root/bb.c
diff options
context:
space:
mode:
authorBruce Hill <bruce@bruce-hill.com>2019-05-26 16:01:56 -0700
committerBruce Hill <bruce@bruce-hill.com>2019-05-26 16:01:56 -0700
commit75c2f4e1692335b9432abcc66c0d3004743a0ed1 (patch)
treef380660d848fc1d31dab399c515199e8b73d5162 /bb.c
parentb20b1786cb2cfaf2613279bf890e8f272c5e78ce (diff)
Fixed a bunch of alignment issues with unicode names and stuff, fixed
and issue with linked list removal, and added a bunch of error checks for commands with no value.
Diffstat (limited to 'bb.c')
-rw-r--r--bb.c109
1 files changed, 75 insertions, 34 deletions
diff --git a/bb.c b/bb.c
index e7ff464..f1b32bf 100644
--- a/bb.c
+++ b/bb.c
@@ -27,6 +27,8 @@
#define BB_VERSION "0.9.0"
#define KEY_DELAY 50
#define SCROLLOFF MIN(5, (termheight-4)/2)
+#define SORT_INDICATOR "▼"
+#define RSORT_INDICATOR "▲"
#define CMDFILE_FORMAT "/tmp/bb.XXXXXX"
#ifndef PATH_MAX
@@ -38,7 +40,9 @@
#define writez(fd, str) write(fd, str, strlen(str))
#define IS_SELECTED(p) (((p)->atme) != NULL)
#define LLREMOVE(e) do { \
- (e)->next->atme = (e)->atme; \
+ if ((e)->next) { \
+ (e)->next->atme = (e)->atme; \
+ } \
*((e)->atme) = (e)->next; \
(e)->next = NULL; \
(e)->atme = NULL; \
@@ -55,8 +59,7 @@
close_term(); \
} \
fprintf(stderr, __VA_ARGS__); \
- if (errno) \
- fprintf(stderr, "\n%s", strerror(errno)); \
+ if (errno) fprintf(stderr, "\n%s", strerror(errno)); \
fprintf(stderr, "\n"); \
cleanup_and_exit(1); \
} while (0)
@@ -123,7 +126,7 @@ static void* memcheck(void *p);
static int unprintables(char *s);
static int run_cmd_on_selection(bb_state_t *s, const char *cmd);
static void term_move(int x, int y);
-static size_t bwrite_escaped(int fd, const char *str, const char *reset_color);
+static void bwrite_escaped(int fd, const char *str, const char *reset_color);
static void render(bb_state_t *s, int lazy);
static int compare_files(void *r, const void *v1, const void *v2);
static int find_file(bb_state_t *s, const char *name);
@@ -308,25 +311,35 @@ static void bmove(int fd, int x, int y)
if (len > 0)
bwrite(fd, buf, (size_t)len);
}
-static size_t bwrite_escaped(int fd, const char *str, const char *color)
+static void bwrite_escaped(int fd, const char *str, const char *color)
{
static const char *escapes = " abtnvfr e";
- size_t wrote = 0, maxcharlen = (size_t)strlen(color) + 10;
+ size_t maxcharlen = (size_t)strlen(color) + 10;
for (const char *c = str; *c; ++c) {
if (SCREENBUF_SIZE - screenbufpos < maxcharlen)
bflush(fd);
- if (*c <= '\x1b' && escapes[(int)*c] != ' ') { // "\n", etc.
+ if ((*c & 0xE0) == 0xC0 && (c[1] & 0xC0) == 0x80) { // UTF8 2-byte
+ screenbuf[screenbufpos++] = *(c++);
+ screenbuf[screenbufpos++] = *c;
+ } else if ((*c & 0xF0) == 0xE0 && (c[1] & 0xC0) == 0x80
+ && (c[2] & 0xC0) == 0x80) { // UTF8 3-byte
+ screenbuf[screenbufpos++] = *(c++);
+ screenbuf[screenbufpos++] = *(c++);
+ screenbuf[screenbufpos++] = *c;
+ } else if ((*c & 0xF8) == 0xF0 && (c[1] & 0xC0) == 0x80
+ && (c[2] & 0xC0) == 0x80 && (c[3] & 0xC0) == 0x80 ) { // UTF8 4-byte
+ screenbuf[screenbufpos++] = *(c++);
+ screenbuf[screenbufpos++] = *(c++);
+ screenbuf[screenbufpos++] = *(c++);
+ screenbuf[screenbufpos++] = *c;
+ } else if (*c > 0 && *c <= '\x1b' && escapes[(int)*c] != ' ') { // "\n", etc.
screenbufpos += (size_t)sprintf(&screenbuf[screenbufpos], "\033[31m\\%c%s", escapes[(int)*c], color);
- wrote += 2;
} else if (!(' ' <= *c && *c <= '~')) { // "\x02", etc.
screenbufpos += (size_t)sprintf(&screenbuf[screenbufpos], "\033[31m\\x%02X%s", *c, color);
- wrote += 4;
} else {
screenbuf[screenbufpos++] = *c;
- wrote += 1;
}
}
- return wrote;
}
@@ -349,19 +362,22 @@ void render(bb_state_t *s, int lazy)
}
}
colnamew = termwidth - 1;
+ int namecols = 0;
for (char *col = s->columns; *col; ++col) {
switch (*col) {
- case 's':
- colnamew -= colsizew + 3;
- break;
+ case 's': colnamew -= colsizew;
+ break;
case 'm': case 'c': case 'a':
- colnamew -= coldatew + 3;
- break;
- case 'p':
- colnamew -= colpermw + 3;
- break;
+ colnamew -= coldatew;
+ break;
+ case 'p': colnamew -= colpermw;
+ break;
+ case 'n': namecols++;
+ break;
}
}
+ colnamew -= 3*strlen(s->columns);
+ colnamew /= namecols;
if (!lazy) {
// Path
@@ -372,7 +388,7 @@ void render(bb_state_t *s, int lazy)
// Columns
bmove(termfd,0,1);
- bwritez(termfd, " \033[0;44;30m");
+ bwritez(termfd, "\033[41m \033[0;44;30m");
for (char *col = s->columns; *col; ++col) {
const char *colname;
int colwidth = 0;
@@ -399,11 +415,13 @@ void render(bb_state_t *s, int lazy)
continue;
}
if (col != s->columns) bwritez(termfd, " │ ");
- bwritez(termfd, DESCENDING(s->sort) == *col ? (IS_REVERSED(s->sort) ? "▲" : "▼") : " ");
+ if (DESCENDING(s->sort) != *col) bwritez(termfd, " ");
+ else if (IS_REVERSED(s->sort)) bwritez(termfd, RSORT_INDICATOR);
+ else bwritez(termfd, SORT_INDICATOR);
for (ssize_t i = bwritez(termfd, colname); i < colwidth-1; i++)
bwrite(termfd, " ", 1);
}
- bwritez(termfd, "\033[0m");
+ bwritez(termfd, " \033[K\033[0m");
}
entry_t **files = s->files;
@@ -451,8 +469,23 @@ void render(bb_state_t *s, int lazy)
color = NORMAL_COLOR;
bwritez(termfd, color);
+ int x = 1;
for (char *col = s->columns; *col; ++col) {
- if (col != s->columns) bwritez(termfd, " │ ");
+ char posbuf[32];
+ if (col != s->columns) {
+ sprintf(posbuf, "\033[%d;%dH\033[K", y+1, x+2);
+ bwritez(termfd, posbuf);
+ if (color == CURSOR_COLOR)
+ bwritez(termfd, "│ ");
+ else {
+ bwritez(termfd, "\033[0;2m│\033[22m ");
+ bwritez(termfd, color);
+ }
+ x += 3;
+ } else {
+ sprintf(posbuf, "\033[%d;%dH\033[K", y+1, x+1);
+ bwritez(termfd, posbuf);
+ }
switch (*col) {
case 's': {
int j = 0;
@@ -464,22 +497,26 @@ void render(bb_state_t *s, int lazy)
}
sprintf(buf, "%6.*f%c", j > 0 ? 1 : 0, bytes, units[j]);
bwritez(termfd, buf);
+ x += colsizew;
break;
}
case 'm':
strftime(buf, sizeof(buf), "%l:%M%p %b %e %Y", localtime(&(entry->info.st_mtime)));
bwritez(termfd, buf);
+ x += coldatew;
break;
case 'c':
strftime(buf, sizeof(buf), "%l:%M%p %b %e %Y", localtime(&(entry->info.st_ctime)));
bwritez(termfd, buf);
+ x += coldatew;
break;
case 'a':
strftime(buf, sizeof(buf), "%l:%M%p %b %e %Y", localtime(&(entry->info.st_atime)));
bwritez(termfd, buf);
+ x += coldatew;
break;
case 'p':
@@ -488,38 +525,35 @@ void render(bb_state_t *s, int lazy)
buf[2] = '0' + ((entry->info.st_mode >> 3) & 7);
buf[3] = '0' + ((entry->info.st_mode >> 0) & 7);
bwrite(termfd, buf, 4);
+ x += colpermw;
break;
case 'n': {
- ssize_t wrote = bwrite(termfd, " ", 1);
if (entry->d_escname)
- wrote += bwrite_escaped(termfd, entry->d_name, color);
+ bwrite_escaped(termfd, entry->d_name, color);
else
- wrote += bwritez(termfd, entry->d_name);
+ bwritez(termfd, entry->d_name);
if (entry->d_isdir) {
bwritez(termfd, "/");
- ++wrote;
}
if (entry->d_linkname) {
bwritez(termfd, "\033[2m -> ");
- wrote += 4;
if (entry->d_esclink)
- wrote += bwrite_escaped(termfd, entry->d_linkname, color);
+ bwrite_escaped(termfd, entry->d_linkname, color);
else
- wrote += bwritez(termfd, entry->d_linkname);
+ bwritez(termfd, entry->d_linkname);
if (entry->d_isdir) {
bwritez(termfd, "/");
- ++wrote;
}
+ bwritez(termfd, "\033[22m");
}
- while (wrote++ < colnamew - 1)
- bwrite(termfd, " ", 1);
+ x += colnamew;
break;
}
}
}
- bwritez(termfd, " \033[0m\033[K"); // Reset color and attributes
+ bwritez(termfd, " \033[K\033[0m"); // Reset color and attributes
}
static const char *help = "Press '?' to see key bindings ";
@@ -859,6 +893,7 @@ execute_cmd(bb_state_t *state, const char *cmd)
case 's': // sort:, select:, scroll:, spread:
switch (cmd[1]) {
case 'o': // sort:
+ if (!value) return BB_INVALID;
switch (*value) {
case 'n': case 'N': case 's': case 'S':
case 'p': case 'P': case 'm': case 'M':
@@ -870,6 +905,7 @@ execute_cmd(bb_state_t *state, const char *cmd)
}
return BB_INVALID;
case 'c': { // scroll:
+ if (!value) return BB_INVALID;
// TODO: figure out the best version of this
int isdelta = value[0] == '+' || value[0] == '-';
int n = (int)strtol(value, &value, 10);
@@ -886,6 +922,7 @@ execute_cmd(bb_state_t *state, const char *cmd)
goto move;
case '\0': case 'e': // select:
+ if (!value) value = state->files[state->cursor]->d_name;
if (strcmp(value, "*") == 0) {
for (int i = 0; i < state->nfiles; i++)
select_file(state->files[i]);
@@ -900,6 +937,7 @@ execute_cmd(bb_state_t *state, const char *cmd)
case 'd': { // cd:
char pbuf[PATH_MAX];
cd:
+ if (!value) return BB_INVALID;
if (value[0] == '~') {
char *home;
if (!(home = getenv("HOME")))
@@ -937,6 +975,7 @@ execute_cmd(bb_state_t *state, const char *cmd)
return BB_REFRESH;
}
case 't': { // toggle:
+ if (!value) value = state->files[state->cursor]->d_name;
int f = find_file(state, value);
if (f < 0) return BB_INVALID;
entry_t *e = state->files[f];
@@ -953,6 +992,7 @@ execute_cmd(bb_state_t *state, const char *cmd)
populate_files(state, state->path);
return BB_REFRESH;
} else if (value) { // deselect:
+ if (!value) value = state->files[state->cursor]->d_name;
if (strcmp(value, "*") == 0) {
clear_selection();
return BB_DIRTY;
@@ -1004,6 +1044,7 @@ execute_cmd(bb_state_t *state, const char *cmd)
default: { // move:
int oldcur, isdelta, n;
move:
+ if (!value) return BB_INVALID;
oldcur = state->cursor;
isdelta = value[0] == '-' || value[0] == '+';
n = (int)strtol(value, &value, 10);