summaryrefslogtreecommitdiff
path: root/main.c
diff options
context:
space:
mode:
authorWormHeamer2026-01-02 03:00:29 -0500
committerWormHeamer2026-01-02 03:00:29 -0500
commit07b3782804272abce9ada300e96fa141e359b359 (patch)
tree018d1cb14ea771ff9d7858bea5c91f5ac50c9c4d /main.c
parent52d4c6e59f5a5034988ddcf6f4cf2800df6ea7c8 (diff)
convert non-utf-8 files to a readonly hex dump
Diffstat (limited to 'main.c')
-rw-r--r--main.c91
1 files changed, 57 insertions, 34 deletions
diff --git a/main.c b/main.c
index 9325a11..f9cf22e 100644
--- a/main.c
+++ b/main.c
@@ -30,7 +30,8 @@
typedef enum {
ED_BUF_SCRATCH,
- ED_BUF_FILE
+ ED_BUF_FILE,
+ ED_BUF_BIN_FILE
} EditBufType;
typedef struct {
@@ -56,7 +57,7 @@ static const char *mode_key_str[] = {
};
typedef struct {
- Arena scratch;
+ Arena perm, scratch;
EditBuf buf[ED_BUF_MAX];
u32 bufn, bufi;
Txt *txt_free;
@@ -84,6 +85,8 @@ typedef struct {
Editor e = { 0 };
+int ed_buf_shell_replace(Editor *e, u32 bufi, TxtLoc start, TxtLoc end, const char *cmd);
+
static Str normalize_path(Str s);
int ed_buf_open(Editor *e, const char *path) {
Str paths = { 0 };
@@ -95,26 +98,32 @@ int ed_buf_open(Editor *e, const char *path) {
}
if (e->bufn == ED_BUF_MAX) return -1;
- EditBuf b = { 0 };
- b.arena = arena_init(1L << 30);
- b.txt = FREELIST_NEW(&e->txt_free, &b.arena);
+ EditBuf *b = &e->buf[e->bufn];
+ memset(b, 0, sizeof(EditBuf));
+ b->arena = arena_init(1L << 30);
+ b->txt = FREELIST_NEW(&e->txt_free, &e->perm);
if (path) {
- b.path = str_dup(paths, &b.arena);
- b.type = ED_BUF_FILE;
- txt_load(b.txt, path);
+ b->path = str_dup(paths, &b->arena);
+ b->type = ED_BUF_FILE;
+ txt_load(b->txt, path);
+ if (!utf8_validate(b->txt->buf[TXT_SRC].s, b->txt->buf[TXT_SRC].n)) {
+ ed_buf_shell_replace(e, e->bufn, txt_start(b->txt), txt_end(b->txt), "xxd");
+ b->txt->readonly = 1;
+ b->type = ED_BUF_BIN_FILE;
+ }
} else {
- b.path = S("*scratch*");
- b.type = ED_BUF_SCRATCH;
- txt_load_empty(b.txt);
+ b->path = S("*scratch*");
+ b->type = ED_BUF_SCRATCH;
+ txt_load_empty(b->txt);
}
- b.cur = txt_end(b.txt);
- txt_hist_push(b.txt, b.cur);
- e->buf[e->bufn] = b;
+ b->cur = txt_end(b->txt);
+ b->txt->ptbl.dirty = 0;
+ txt_hist_push(b->txt, b->cur);
return e->bufn++;
}
-void ed_buf_free(EditBuf *b) {
- txt_free(b->txt);
+void ed_buf_free(Editor *e, EditBuf *b) {
+ FREELIST_FREE(&e->txt_free, b->txt);
arena_free(&b->arena);
}
@@ -127,6 +136,7 @@ void ed_buf_change_path(Editor *e, u32 i, Str s) {
void ed_init(Editor *e) {
memset(e, 0, sizeof(Editor));
e->scratch = arena_init(1L << 30);
+ e->perm = arena_init(1L << 30);
e->bufi = ed_buf_open(e, NULL);
Str s = S("(Scratch buffer, type whatever)");
e->buf[e->bufi].cur = txt_insert(e->buf[e->bufi].cur, s.s, s.n);
@@ -135,14 +145,14 @@ void ed_init(Editor *e) {
void ed_fini(Editor *e) {
for (u32 i = 0; i < e->bufn; i++) {
- ed_buf_free(&e->buf[i]);
+ ed_buf_free(e, &e->buf[i]);
}
if (e->search.s) free(e->search.s);
if (e->yank.s) free(e->yank.s);
}
u32 ed_buf_close(Editor *e, u32 i) {
- ed_buf_free(&e->buf[i]);
+ ed_buf_free(e, &e->buf[i]);
if (i + 1 < e->bufn) {
MOVE(&e->buf[i], &e->buf[i+1], e->bufn - (i + 1));
}
@@ -150,15 +160,6 @@ u32 ed_buf_close(Editor *e, u32 i) {
return i > 0 ? i - 1 : 0;
}
-int ed_buf_save(Editor *e, u32 i) {
- EditBuf *b = &e->buf[i];
- if (b->type == ED_BUF_FILE) {
- return txt_save(b->txt, str_to_cstr(b->path, &e->scratch));
- } else {
- return 0;
- }
-}
-
Str str_printf(Arena *a, const char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
@@ -171,6 +172,17 @@ Str str_printf(Arena *a, const char *fmt, ...) {
return (Str) { buf, n };
}
+int ed_buf_save(Editor *e, u32 i) {
+ EditBuf *b = &e->buf[i];
+ if (b->type == ED_BUF_FILE || b->type == ED_BUF_BIN_FILE) {
+ e->msg = str_printf(&e->scratch, "%.02fk written", b->txt->len / 1024.0);
+ return txt_save(b->txt, str_to_cstr(b->path, &e->scratch));
+ } else {
+ e->msg = S("unwriteable file type");
+ return 0;
+ }
+}
+
static inline int is_space(u32 c) {
return c <= 0x20 && c != 0;
}
@@ -362,7 +374,7 @@ int popen2(const char *cmd, int *in, int *out) {
return p;
}
-int shell_replace(TxtLoc start, TxtLoc end, const char *cmd) {
+int ed_buf_shell_replace(Editor *e, u32 bufi, TxtLoc start, TxtLoc end, const char *cmd) {
if (txt_before(end, start)) {
TxtLoc t = start;
start = end;
@@ -377,7 +389,7 @@ int shell_replace(TxtLoc start, TxtLoc end, const char *cmd) {
{ .fd = in, .events = POLLOUT },
{ .fd = out, .events = POLLIN }
};
- Str wrs = txt_collect_range(start, end, &e.scratch);
+ Str wrs = txt_collect_range(start, end, &e->scratch);
DYNARR(char) rds = { 0 };
u32 wr_i = 0;
while ((pfds[0].fd >= 0 || pfds[1].fd >= 0) && poll(pfds, 2, 200) >= 0) {
@@ -397,7 +409,7 @@ int shell_replace(TxtLoc start, TxtLoc end, const char *cmd) {
pfds[0].fd = -1;
}
if (pfds[1].revents & POLLIN) {
- DA_AFIT(&rds, &e.scratch, rds.n + (-rds.n & (chunksz-1)) + chunksz);
+ DA_AFIT(&rds, &e->scratch, rds.n + (-rds.n & (chunksz-1)) + chunksz);
isize r = read(out, &rds.v[rds.n], chunksz);
if (r > 0) {
rds.n += r;
@@ -419,7 +431,7 @@ int shell_replace(TxtLoc start, TxtLoc end, const char *cmd) {
* final one until it matches or gets too small.
*/
if (!txt_range_equal(start, end, (Str){rds.v,rds.n})) {
- EditBuf *eb = &e.buf[e.bufi];
+ EditBuf *eb = &e->buf[bufi];
u32 b = txt_ofs(eb->cur);
start = txt_delete_range(start, end);
end = txt_insert(start, rds.v, rds.n);
@@ -428,6 +440,10 @@ int shell_replace(TxtLoc start, TxtLoc end, const char *cmd) {
return 0;
}
+int shell_replace(TxtLoc start, TxtLoc end, const char *cmd) {
+ return ed_buf_shell_replace(&e, e.bufi, start, end, cmd);
+}
+
#define ANY_KEY_PROMPT "[Press any key to resume editing]"
static void press_any_key(void) {
@@ -524,7 +540,7 @@ void draw_buf(EditBuf *eb) {
VuiAttr a = i == e.bufi ? sel : norm;
Str p = basename(b->path);
x += vui_aprintf(x, y, a, " %.*s", (int)p.n, p.s);
- if (b->type == ED_BUF_FILE && b->txt->ptbl.dirty) {
+ if (b->type != ED_BUF_SCRATCH && b->txt->ptbl.dirty) {
x += vui_putsa(x, y, "* ", a);
} else {
vui_chra(x++, y, ' ', a);
@@ -554,7 +570,7 @@ void draw_buf(EditBuf *eb) {
if (c == '\n') {
x = lmarg;
y++;
- } else if (is_space(c)) {
+ } else if (c == '\n' || c == '\t' || c == ' ') {
VuiAttr a = txt_chr(start) == '\n' ? trailsp : txt;
if (c == '\t') {
u32 n = 1 + (-(x+1) & 7);
@@ -562,8 +578,14 @@ void draw_buf(EditBuf *eb) {
} else {
vui_chra(x++, y, ' ', a);
}
+ } else if (c < 0x20) {
+ x += vui_aprintf(x, y, FG_CYAN, "<%02>", c);
} else if (c) {
vui_chra(x++, y, c, txt);
+ } else if (x >= COLS) {
+ start = next_line_start(start);
+ x = lmarg;
+ y++;
}
}
@@ -1373,7 +1395,6 @@ void mode_key_normal(Editor *e, u32 c) {
case 'Z':
case 0x13 /* ^S */:
ed_buf_save(e, e->bufi);
- e->msg = str_printf(&e->scratch, "%.02fk written", eb->txt->len / 1024.0);
if (c == 'Z') e->bufi = ed_buf_close(e, e->bufi);
break;
case 'i':
@@ -1677,6 +1698,8 @@ int main(int argc, const char **argv) {
vui_redraw_ctx(&e);
while (e.bufn > 0) {
+ ASSERT(e.bufi < e.bufn);
+ ASSERT(e.buf[e.bufi].cur.t == e.buf[e.bufi].txt);
draw(NULL);
arena_reset(&e.scratch); /* must happen after draw, so e.msg can persist */
vui_blit();