diff --git a/abuf.h b/abuf.h index eb926bd..90d87f3 100644 --- a/abuf.h +++ b/abuf.h @@ -1,8 +1,8 @@ /* * abuf.h - append/prepend buffer utilities */ -#ifndef ABUF_H -#define ABUF_H +#ifndef KE_ABUF_H +#define KE_ABUF_H #include diff --git a/buffer.c b/buffer.c index 9908412..7f17f14 100644 --- a/buffer.c +++ b/buffer.c @@ -35,12 +35,13 @@ static int buffer_find_exact_by_name(const char *name) { buffer *b = NULL; + size_t i = 0; if (name == NULL) { return -1; } - for (int i = 0; i < editor.bufcount; i++) { + for (i = 0; i < editor.bufcount; i++) { b = editor.buffers[i]; const char *full = b->filename; const char *base = buf_basename(full); @@ -66,11 +67,12 @@ static int buffer_collect_prefix_matches(const char *prefix, int *out_idx, const int max_out) { buffer *b = NULL; - int count = 0; - int matched = 0; + int count = 0; + int matched = 0; + size_t i = 0; size_t plen = (prefix ? strlen(prefix) : 0); - for (int i = 0; i < editor.bufcount; i++) { + for (i = 0; i < editor.bufcount; i++) { matched = 0; b = editor.buffers[i]; @@ -206,49 +208,6 @@ buffer_switch_prompt_cb(char *buf, const int16_t key) } -static void -buffer_bind_to_editor(const buffer *b) -{ - if (b == NULL) { - return; - } - - editor.curx = b->curx; - editor.cury = b->cury; - editor.rx = b->rx; - editor.nrows = b->nrows; - editor.rowoffs = b->rowoffs; - editor.coloffs = b->coloffs; - editor.row = b->row; - editor.filename = b->filename; - editor.dirty = b->dirty; - editor.mark_set = b->mark_set; - editor.mark_curx = b->mark_curx; - editor.mark_cury = b->mark_cury; -} - - -static void -buffer_extract_from_editor(buffer *b) -{ - if (b == NULL) { - return; - } - - b->curx = editor.curx; - b->cury = editor.cury; - b->rx = editor.rx; - b->nrows = editor.nrows; - b->rowoffs = editor.rowoffs; - b->coloffs = editor.coloffs; - b->row = editor.row; - b->filename = editor.filename; - b->dirty = editor.dirty; - b->mark_set = editor.mark_set; - b->mark_curx = editor.mark_curx; - b->mark_cury = editor.mark_cury; -} - const char * buffer_name(buffer *b) { @@ -263,12 +222,12 @@ buffer_name(buffer *b) void buffers_init(void) { - int idx = 0; + int idx = 0; - editor.buffers = NULL; - editor.bufcount = 0; - editor.curbuf = -1; - editor.bufcap = 0; + editor.buffers = NULL; + editor.bufcount = 0; + editor.curbuf = 0; + editor.bufcap = 0; idx = buffer_add_empty(); buffer_switch(idx); @@ -278,28 +237,28 @@ buffers_init(void) static void buffer_list_resize(void) { - buffer **newlist = NULL; + buffer **newlist = NULL; - if (editor.bufcount == (int)editor.bufcap) { - editor.bufcap = cap_growth((int)editor.bufcap, editor.bufcount + 1); + if (editor.bufcount == editor.bufcap) { + editor.bufcap = (size_t)cap_growth((int)editor.bufcap, (int)editor.bufcount + 1); - newlist = realloc(editor.buffers, sizeof(buffer *) * editor.bufcap); - assert(newlist != NULL); - editor.buffers = newlist; - } + newlist = realloc(editor.buffers, sizeof(buffer *) * editor.bufcap); + assert(newlist != NULL); + editor.buffers = newlist; + } } int buffer_add_empty(void) { - buffer *buf = NULL; - int idx = 0; + buffer *buf = NULL; + int idx = 0; - buffer_list_resize(); + buffer_list_resize(); - buf = calloc(1, sizeof(buffer)); - assert(buf != NULL); + buf = calloc(1, sizeof(buffer)); + assert(buf != NULL); buf->curx = 0; buf->cury = 0; @@ -314,34 +273,28 @@ buffer_add_empty(void) buf->mark_curx = 0; buf->mark_cury = 0; - editor.buffers[editor.bufcount] = buf; - idx = editor.bufcount; - editor.bufcount++; - return idx; + editor.buffers[editor.bufcount] = buf; + idx = (int)editor.bufcount; + editor.bufcount++; + return idx; } void buffer_save_current(void) { - buffer *b = NULL; - - if (editor.curbuf < 0 || editor.curbuf >= editor.bufcount) { - return; - } - - b = editor.buffers[editor.curbuf]; - buffer_extract_from_editor(b); + /* No-op: editor no longer mirrors per-buffer fields */ + (void)editor; } buffer * buffer_current(void) { - if (editor.curbuf < 0 || editor.curbuf >= editor.bufcount) { - return NULL; - } - return editor.buffers[editor.curbuf]; + if (editor.bufcount == 0 || editor.curbuf >= editor.bufcount) { + return NULL; + } + return editor.buffers[editor.curbuf]; } @@ -375,75 +328,69 @@ buffer_is_unnamed_and_empty(const buffer *b) void buffer_switch(const int idx) { - buffer *b = NULL; + buffer *b = NULL; - if (idx < 0 || idx >= editor.bufcount) { - return; - } + if (idx < 0 || (size_t)idx >= editor.bufcount) { + return; + } - if (editor.curbuf == idx) { - return; - } + if (editor.curbuf == (size_t)idx) { + return; + } - if (editor.curbuf >= 0) { - buffer_save_current(); - } - - b = editor.buffers[idx]; - buffer_bind_to_editor(b); - editor.curbuf = idx; - editor.dirtyex = 1; - editor_set_status("Switched to buffer %d: %s", editor.curbuf, buffer_name(b)); + b = editor.buffers[idx]; + editor.curbuf = (size_t)idx; + editor.dirtyex = 1; + editor_set_status("Switched to buffer %d: %s", editor.curbuf, buffer_name(b)); } void buffer_next(void) { - int idx = 0; + size_t idx = 0; - if (editor.bufcount <= 1) { - return; - } + if (editor.bufcount <= 1) { + return; + } - idx = (editor.curbuf + 1) % editor.bufcount; - buffer_switch(idx); + idx = (editor.curbuf + 1) % editor.bufcount; + buffer_switch((int)idx); } void buffer_prev(void) { - int idx = 0; + size_t idx = 0; - if (editor.bufcount <= 1) { - return; - } + if (editor.bufcount <= 1) { + return; + } - idx = (editor.curbuf - 1 + editor.bufcount) % editor.bufcount; - buffer_switch(idx); + idx = (editor.curbuf == 0) ? (editor.bufcount - 1) : (editor.curbuf - 1); + buffer_switch((int)idx); } void buffer_close_current(void) { - buffer *b = NULL; - int closing = 0; - int target = 0; - int nb = 0; + buffer *b = NULL; + size_t closing = 0; + int target = 0; + int nb = 0; /* sanity check */ - if (editor.curbuf < 0 || editor.curbuf >= editor.bufcount) { + if (editor.bufcount == 0 || editor.curbuf >= editor.bufcount) { editor_set_status("No buffer to close."); return; } closing = editor.curbuf; - target = -1; if (editor.bufcount > 1) { - target = (closing - 1 >= 0) ? (closing - 1) : (closing + 1); + target = (closing > 0) ? (int) (closing - 1) : (int) (closing + 1); buffer_switch(target); } else { nb = buffer_add_empty(); @@ -453,7 +400,7 @@ buffer_close_current(void) b = editor.buffers[closing]; if (b) { if (b->row) { - for (int i = 0; i < b->nrows; i++) { + for (size_t i = 0; i < b->nrows; i++) { ab_free(&b->row[i]); } free(b->row); @@ -466,11 +413,11 @@ buffer_close_current(void) } memmove(&editor.buffers[closing], &editor.buffers[closing + 1], - sizeof(buffer *) * (editor.bufcount - closing - 1)); + sizeof(buffer *) * (editor.bufcount - closing - 1)); editor.bufcount--; if (editor.bufcount == 0) { - editor.curbuf = -1; + editor.curbuf = 0; } else { if (editor.curbuf > closing) { editor.curbuf--; @@ -479,7 +426,7 @@ buffer_close_current(void) editor.dirtyex = 1; editor_set_status("Closed buffer. Now on %s", - buffer_name(editor.buffers[editor.curbuf])); + buffer_name(editor.buffers[editor.curbuf])); } @@ -512,7 +459,7 @@ buffer_switch_by_name(void) if (idx >= 0) { buffer_switch(idx); } else { - editor_set_status("No such buffer: %s", name); + editor_set_status("No open buffer: %s", name); } free(name); diff --git a/buffer.h b/buffer.h index 970392b..1289801 100644 --- a/buffer.h +++ b/buffer.h @@ -1,19 +1,19 @@ -#ifndef BUFFER_H -#define BUFFER_H +#ifndef KE_BUFFER_H +#define KE_BUFFER_H #include "abuf.h" typedef struct buffer { - int curx, cury; - int rx; - int nrows; - int rowoffs, coloffs; + size_t curx, cury; + size_t rx; + size_t nrows; + size_t rowoffs, coloffs; abuf *row; char *filename; int dirty; int mark_set; - int mark_curx, mark_cury; + size_t mark_curx, mark_cury; } buffer; /* Access current buffer and convenient aliases for file-specific fields */ diff --git a/core.c b/core.c index e31c0b6..a7f89b3 100644 --- a/core.c +++ b/core.c @@ -35,19 +35,8 @@ strnstr(const char *s, const char *find, size_t slen) #endif -char -nibble_to_hex(char c) -{ - c &= 0xf; - if (c < 10) { - return (char)('0' + c); - } - return (char)('A' + (c - 10)); -} - - void -swap_int(int *first, int *second) +swap_size_t(size_t *first, size_t *second) { *first ^= *second; *second ^= *first; diff --git a/core.h b/core.h index 85bb786..f2d0c3b 100644 --- a/core.h +++ b/core.h @@ -4,7 +4,6 @@ #include -#define calloc1(sz) calloc(1, sz) #define INITIAL_CAPACITY 8 @@ -29,10 +28,9 @@ char *strnstr(const char *s, const char *find, size_t slen); #define INCLUDE_STRNSTR #endif -char nibble_to_hex(char c); -void swap_int(int *first, int *second); -int next_power_of_2(int n); -int cap_growth(int cap, int sz); +void swap_size_t(size_t *first, size_t *second); +int next_power_of_2(int n); +int cap_growth(int cap, int sz); size_t kstrnlen(const char *buf, size_t max); void kwrite(int fd, const char *buf, int len); void die(const char *s); diff --git a/editor.c b/editor.c index 401d44e..1083e54 100644 --- a/editor.c +++ b/editor.c @@ -16,31 +16,20 @@ * Global editor instance */ struct editor editor = { - .cols = 0, - .rows = 0, - .curx = 0, - .cury = 0, - .rx = 0, - .mode = 0, - .nrows = 0, - .rowoffs = 0, - .coloffs = 0, - .row = NULL, + .cols = 0, + .rows = 0, + .mode = 0, .killring = NULL, - .kill = 0, - .no_kill = 0, - .filename = NULL, - .dirty = 0, - .dirtyex = 0, - .mark_set = 0, - .mark_curx = 0, - .mark_cury = 0, - .uarg = 0, - .ucount = 0, - .msgtm = 0, - .buffers = NULL, + .kill = 0, + .no_kill = 0, + .dirtyex = 0, + .uarg = 0, + .ucount = 0, + .msgtm = 0, + .buffers = NULL, .bufcount = 0, - .curbuf = -1, + .curbuf = 0, + .bufcap = 0, }; @@ -69,26 +58,15 @@ init_editor(void) editor.rows--; /* status bar */ editor.rows--; /* message line */ - editor.curx = editor.cury = 0; - editor.rx = 0; - - editor.nrows = 0; - editor.rowoffs = editor.coloffs = 0; - editor.row = NULL; - /* don't clear out the kill ring: * killing / yanking across files is helpful, and killring * is initialized to NULL at program start. */ - editor.kill = 0; + editor.kill = 0; editor.no_kill = 0; editor.msg[0] = '\0'; - editor.msgtm = 0; - - editor.dirty = 0; - editor.mark_set = 0; - editor.mark_cury = editor.mark_curx = 0; + editor.msgtm = 0; /* initialize buffer system on first init */ if (editor.buffers == NULL && editor.bufcount == 0) { @@ -101,25 +79,31 @@ init_editor(void) void reset_editor(void) { - /* Clear current working set. Notably, does not reset terminal - * or buffers list. */ - for (int i = 0; i < editor.nrows; i++) { - ab_free(&editor.row[i]); - } - free(editor.row); - - editor.row = NULL; - editor.nrows = 0; - editor.rowoffs = editor.coloffs = 0; - editor.curx = editor.cury = 0; - editor.rx = 0; - - if (editor.filename != NULL) { - free(editor.filename); - editor.filename = NULL; + /* Reset the current buffer's contents/state. */ + buffer *b = buffer_current(); + if (b == NULL) { + return; } - editor.dirty = 0; - editor.mark_set = 0; - editor.mark_cury = editor.mark_curx = 0; + if (b->row) { + for (size_t i = 0; i < b->nrows; i++) { + ab_free(&b->row[i]); + } + free(b->row); + } + b->row = NULL; + b->nrows = 0; + b->rowoffs = 0; + b->coloffs = 0; + b->rx = 0; + b->curx = 0; + b->cury = 0; + if (b->filename) { + free(b->filename); + b->filename = NULL; + } + b->dirty = 0; + b->mark_set = 0; + b->mark_curx = 0; + b->mark_cury = 0; } diff --git a/editor.h b/editor.h index 8d24969..c148cfd 100644 --- a/editor.h +++ b/editor.h @@ -1,5 +1,5 @@ -#ifndef EDITOR_H -#define EDITOR_H +#ifndef KE_EDITOR_H +#define KE_EDITOR_H #include #include @@ -9,32 +9,19 @@ #include "buffer.h" -/* TODO(kyle): remove the "per-buffer" fields completely from the editor. */ - struct editor { - int rows, cols; - int curx, cury; /* per-buffer */ - int rx; /* per-buffer */ + size_t rows, cols; int mode; - int nrows; /* per-buffer */ - int rowoffs, coloffs; /* per-buffer */ - abuf *row; /* per-buffer */ abuf *killring; int kill; /* KILL CHAIN (\m/) */ int no_kill; /* don't kill in delete_row */ - char *filename; /* per-buffer */ - int dirty; /* per-buffer */ int dirtyex; char msg[80]; - int mark_set; /* per-buffer */ - int mark_curx, mark_cury; /* per-buffer */ int uarg, ucount; /* C-u support */ time_t msgtm; - - /* Multi-buffer support */ struct buffer **buffers; /* array of buffers */ - int bufcount; /* number of buffers */ - int curbuf; /* current buffer index */ + size_t bufcount; /* number of buffers */ + size_t curbuf; /* current buffer index */ size_t bufcap; /* current buffer capacity */ }; @@ -45,4 +32,4 @@ void init_editor(void); void reset_editor(void); -#endif /* EDITOR_H */ +#endif /* KE_EDITOR_H */ diff --git a/main.c b/main.c index b8e4d34..f101cf1 100644 --- a/main.c +++ b/main.c @@ -83,49 +83,49 @@ void killring_start_with_char(unsigned char ch); void killring_append_char(unsigned char ch); void killring_prepend_char(unsigned char ch); void toggle_markset(void); -int cursor_after_mark(void); -int count_chars_from_cursor_to_mark(void); +int cursor_after_mark(void); +int count_chars_from_cursor_to_mark(void); void kill_region(void); void indent_region(void); void delete_region(void); /* miscellaneous */ -void jump_to_position(int col, int row); +void jump_to_position(size_t col, size_t row); void goto_line(void); -int cursor_at_eol(void); -int iswordchar(unsigned char c); +int cursor_at_eol(void); +int iswordchar(unsigned char c); void find_next_word(void); void delete_next_word(void); void find_prev_word(void); void delete_prev_word(void); -void delete_row(int at); +void delete_row(const size_t at); void row_insert_ch(abuf *row, int at, int16_t c); void row_delete_ch(abuf *row, int at); void insertch(int16_t c); void deletech(uint8_t op); void open_file(const char *filename); char *rows_to_buffer(int *buflen); -int save_file(void); +int save_file(void); uint16_t is_arrow_key(int16_t c); int16_t get_keypress(void); void editor_find_callback(char *query, int16_t c); void editor_find(void); char *editor_prompt(const char*, void (*cb)(char*, int16_t)); void editor_openfile(void); -int first_nonwhitespace(abuf *row); +int first_nonwhitespace(abuf *row); void move_cursor_once(int16_t c, int interactive); void move_cursor(int16_t c, int interactive); void uarg_start(void); void uarg_digit(int d); void uarg_clear(void); -int uarg_get(void); +int uarg_get(void); void newline(void); void process_kcommand(int16_t c); void process_normal(int16_t c); void process_escape(int16_t c); -int process_keypress(void); +int process_keypress(void); char *get_cloc_code_lines(const char *filename); -int dump_pidfile(void); +int dump_pidfile(void); void draw_rows(abuf *ab); char status_mode_char(void); void draw_status_bar(abuf *ab); @@ -483,19 +483,19 @@ erow_init(abuf *row, int len) void erow_insert(int at, char *s, int len) { - abuf *row = realloc(EROW, sizeof(abuf) * (ENROWS + 1)); + abuf *row = realloc(EROW, sizeof(abuf) * (ENROWS + 1)); assert(row != NULL); EROW = row; - if (at < ENROWS) { + if ((size_t) at < ENROWS) { memmove(&EROW[at + 1], &EROW[at], - sizeof(abuf) * (ENROWS - at)); + sizeof(abuf) * (ENROWS - (size_t) at)); } ab_init(&EROW[at]); - ab_append(&EROW[at], s, len); - ENROWS++; + ab_append(&EROW[at], s, (size_t) len); + ENROWS++; } @@ -630,16 +630,15 @@ cursor_after_mark(void) int count_chars_from_cursor_to_mark(void) { - int count = 0; - int curx = ECURX; - int cury = ECURY; - - int markx = EMARK_CURX; - int marky = EMARK_CURY; + size_t count = 0; + size_t curx = ECURX; + size_t cury = ECURY; + size_t markx = EMARK_CURX; + size_t marky = EMARK_CURY; if (!cursor_after_mark()) { - swap_int(&curx, &markx); - swap_int(&curx, &marky); + swap_size_t(&curx, &markx); + swap_size_t(&curx, &marky); } ECURX = markx; @@ -667,10 +666,10 @@ count_chars_from_cursor_to_mark(void) void kill_region(void) { - int curx = ECURX; - int cury = ECURY; - int markx = EMARK_CURX; - int marky = EMARK_CURY; + size_t curx = ECURX; + size_t cury = ECURY; + size_t markx = EMARK_CURX; + size_t marky = EMARK_CURY; if (!EMARK_SET) { return; @@ -680,8 +679,8 @@ kill_region(void) killring_flush(); if (!cursor_after_mark()) { - swap_int(&curx, &markx); - swap_int(&cury, &marky); + swap_size_t(&curx, &markx); + swap_size_t(&cury, &marky); } ECURX = markx; @@ -703,16 +702,16 @@ kill_region(void) editor_set_status("Region killed."); /* clearing the mark needs to be done outside this function; * - * when deleting the region, the mark needs to be set too. */ + * when deleting the region, the mark needs to be set too. */ } void indent_region(void) { - int start_row = 0; - int end_row = 0; - int i = 0; + size_t start_row = 0; + size_t end_row = 0; + size_t i = 0; if (!EMARK_SET) { return; @@ -729,15 +728,11 @@ indent_region(void) } /* Ensure bounds are valid */ - if (start_row < 0) { - start_row = 0; - } - if (end_row >= ENROWS) { end_row = ENROWS - 1; } - if (start_row >= ENROWS || end_row < 0) { + if (start_row >= ENROWS) { return; } @@ -753,10 +748,10 @@ indent_region(void) void unindent_region(void) { - int start_row = 0; - int end_row = 0; - int i = 0; - int del = 0; + size_t start_row = 0; + size_t end_row = 0; + size_t i = 0; + size_t del = 0; abuf *row = NULL; if (!EMARK_SET) { @@ -777,13 +772,12 @@ unindent_region(void) return; } - if (end_row >= editor.nrows) { - end_row = editor.nrows - 1; + if (end_row >= ENROWS) { + end_row = ENROWS - 1; } - /* actually unindent every line in the region */ for (i = start_row; i <= end_row; i++) { - row = &editor.row[i]; + row = &EROW[i]; if (row->size == 0) { continue; @@ -794,45 +788,45 @@ unindent_region(void) } else if (row->b[0] == ' ') { del = 0; - while (del < TAB_STOP && del < (int) row->size && + while (del < TAB_STOP && del < row->size && row->b[del] == ' ') { del++; } if (del > 0) { - memmove(row->b, row->b + del, row->size - del + 1); /* +1 for NUL */ + /* +1 for NUL */ + memmove(row->b, row->b + del, + row->size - del + 1); row->size -= del; } } } - editor.curx = 0; - editor.cury = start_row; + ECURX = 0; + ECURY = start_row; - editor.dirty++; + EDIRTY++; editor_set_status("Region unindented"); } -/* call after kill_region */ void delete_region(void) { - int count = count_chars_from_cursor_to_mark(); - int killed = 0; - int curx = editor.curx; - int cury = editor.cury; - int markx = editor.mark_curx; - int marky = editor.mark_cury; + size_t count = count_chars_from_cursor_to_mark(); + size_t killed = 0; + size_t curx = ECURX; + size_t cury = ECURY; + size_t markx = EMARK_CURX; + size_t marky = EMARK_CURY; - - if (!editor.mark_set) { + if (!EMARK_SET) { return; } if (!cursor_after_mark()) { - swap_int(&curx, &markx); - swap_int(&cury, &marky); + swap_size_t(&curx, &markx); + swap_size_t(&cury, &marky); } jump_to_position(markx, marky); @@ -843,7 +837,7 @@ delete_region(void) killed++; } - while (editor.curx != markx && editor.cury != marky) { + while (ECURX != markx && ECURY != marky) { deletech(KILLRING_NO_OP); } @@ -853,37 +847,26 @@ delete_region(void) void -jump_to_position(int col, int row) +jump_to_position(size_t col, size_t row) { if (ENROWS <= 0) { ECURX = 0; ECURY = 0; - - editor.curx = ECURX; - editor.cury = ECURY; - display_refresh(); return; } - if (row < 0) { - row = 0; - } else if (row >= ENROWS) { + if (row >= ENROWS) { row = ENROWS - 1; } - if (col < 0) { - col = 0; - } else if (col > (int) EROW[row].size) { - col = (int) EROW[row].size; + if (col > EROW[row].size) { + col = EROW[row].size; } ECURX = col; ECURY = row; - editor.curx = ECURX; - editor.cury = ECURY; - display_refresh(); } @@ -891,14 +874,14 @@ jump_to_position(int col, int row) void goto_line(void) { - int lineno = 0; + size_t lineno = 0; char *query = editor_prompt("Line: %s", NULL); if (query == NULL) { return; } - lineno = atoi(query); + lineno = strtoul(query, NULL, 10); if (lineno < 1 || lineno > ENROWS) { editor_set_status("Line number must be between 1 and %d.", ENROWS); @@ -914,12 +897,10 @@ goto_line(void) int cursor_at_eol(void) { - assert(ECURX >= 0); - assert(ECURY >= 0); assert(ECURY <= ENROWS); - assert(ECURX <= (int)EROW[ECURY].size); + assert(ECURX <= EROW[ECURY].size); - return ECURX == (int)EROW[ECURY].size; + return ECURX == EROW[ECURY].size; } @@ -988,23 +969,21 @@ delete_next_word(void) void find_prev_word(void) { - if (editor.cury == 0 && editor.curx == 0) { + if (ECURY == 0 && ECURX == 0) { return; } move_cursor(ARROW_LEFT, 1); - while (cursor_at_eol() || isspace( - editor.row[editor.cury].b[editor.curx])) { - if (editor.cury == 0 && editor.curx == 0) { + while (cursor_at_eol() || isspace(EROW[ECURY].b[ECURX])) { + if (ECURY == 0 && ECURX == 0) { return; } move_cursor(ARROW_LEFT, 1); } - while (editor.curx > 0 && !isspace( - editor.row[editor.cury].b[editor.curx - 1])) { + while (ECURX > 0 && !isspace(EROW[ECURY].b[ECURX - 1])) { move_cursor(ARROW_LEFT, 1); } } @@ -1013,27 +992,27 @@ find_prev_word(void) void delete_prev_word(void) { - if (editor.cury == 0 && editor.curx == 0) { + if (ECURY == 0 && ECURX == 0) { return; } deletech(KILLRING_PREPEND); - while (editor.cury > 0 || editor.curx > 0) { - if (editor.curx == 0) { + while (ECURY > 0 || ECURX > 0) { + if (ECURX == 0) { deletech(KILLRING_PREPEND); continue; } - if (!isspace(editor.row[editor.cury].b[editor.curx - 1])) { + if (!isspace(EROW[ECURY].b[ECURX - 1])) { break; } deletech(KILLRING_PREPEND); } - while (editor.curx > 0) { - if (isspace(editor.row[editor.cury].b[editor.curx - 1])) { + while (ECURX > 0) { + if (isspace(EROW[ECURY].b[ECURX - 1])) { break; } deletech(KILLRING_PREPEND); @@ -1042,13 +1021,13 @@ delete_prev_word(void) void -delete_row(const int at) +delete_row(const size_t at) { - abuf *row = NULL; + abuf *row = NULL; - if (at < 0 || at >= editor.nrows) { - return; - } + if (at >= ENROWS) { + return; + } /* * Update killring with the deleted row's contents followed by a newline @@ -1057,21 +1036,19 @@ delete_row(const int at) * newline itself and we must NOT also push the entire row here. */ if (!editor.no_kill) { - row = &editor.row[at]; - /* Start or continue the kill sequence based on editor.killing */ + row = &EROW[at]; if (row->size > 0) { - /* push raw bytes of the line */ if (!editor.kill) { killring_start_with_char( - (unsigned char)row->b[0]); - for (int i = 1; i < (int)row->size; i++) { + (unsigned char) row->b[0]); + for (int i = 1; i < (int) row->size; i++) { killring_append_char( - (unsigned char)row->b[i]); + (unsigned char) row->b[i]); } } else { - for (int i = 0; i < (int)row->size; i++) { + for (int i = 0; i < (int) row->size; i++) { killring_append_char( - (unsigned char)row->b[i]); + (unsigned char) row->b[i]); } } killring_append_char('\n'); @@ -1086,12 +1063,12 @@ delete_row(const int at) } } - ab_free(&editor.row[at]); - memmove(&editor.row[at], - &editor.row[at + 1], - sizeof(abuf) * (editor.nrows - at - 1)); - editor.nrows--; - editor.dirty++; + ab_free(&EROW[at]); + memmove(&EROW[at], + &EROW[at + 1], + sizeof(abuf) * (ENROWS - at - 1)); + ENROWS--; + EDIRTY++; } @@ -1099,7 +1076,7 @@ void row_append_row(abuf *row, const char *s, const int len) { ab_append(row, s, len); - editor.dirty++; + EDIRTY++; } @@ -1125,14 +1102,14 @@ row_insert_ch(abuf *row, int at, const int16_t c) void row_delete_ch(abuf *row, const int at) { - if (at < 0 || at >= (int)row->size) { + if (at < 0 || at >= (int) row->size) { return; } memmove(&row->b[at], &row->b[at + 1], row->size - at); row->size--; row->b[row->size] = 0; - editor.dirty++; + EDIRTY++; } @@ -1144,59 +1121,59 @@ insertch(const int16_t c) * a row; it can just figure out where the cursor is * at and what to do. */ - if (ECURY == ENROWS) { - erow_insert(ENROWS, "", 0); - } + if (ECURY == ENROWS) { + erow_insert(ENROWS, "", 0); + } /* Inserting ends kill ring chaining. */ editor.kill = 0; - row_insert_ch(&EROW[ECURY], - ECURX, - (int16_t)(c & 0xff)); - ECURX++; - EDIRTY++; + row_insert_ch(&EROW[ECURY], + ECURX, + (int16_t) (c & 0xff)); + ECURX++; + EDIRTY++; } void deletech(uint8_t op) { - abuf *row = NULL; + abuf *row = NULL; unsigned char dch = 0; int prev = 0; - if (ECURY >= ENROWS) { - return; - } + if (ECURY >= ENROWS) { + return; + } - if (ECURY == 0 && ECURX == 0) { - return; - } + if (ECURY == 0 && ECURX == 0) { + return; + } - row = &EROW[ECURY]; - if (ECURX > 0) { - dch = (unsigned char)row->b[ECURX - 1]; - } else { - dch = '\n'; - } + row = &EROW[ECURY]; + if (ECURX > 0) { + dch = (unsigned char) row->b[ECURX - 1]; + } else { + dch = '\n'; + } - if (ECURX > 0) { - row_delete_ch(row, ECURX - 1); - ECURX--; - } else { - ECURX = (int)EROW[ECURY - 1].size; - row_append_row(&EROW[ECURY - 1], - row->b, - (int)row->size); + if (ECURX > 0) { + row_delete_ch(row, ECURX - 1); + ECURX--; + } else { + ECURX = (int) EROW[ECURY - 1].size; + row_append_row(&EROW[ECURY - 1], + row->b, + (int) row->size); - prev = editor.no_kill; - editor.no_kill = 1; + prev = editor.no_kill; + editor.no_kill = 1; - delete_row(ECURY); - editor.no_kill = prev; - ECURY--; - } + delete_row(ECURY); + editor.no_kill = prev; + ECURY--; + } if (op == KILLRING_FLUSH) { killring_flush(); @@ -1231,10 +1208,10 @@ open_file(const char *filename) char *line = NULL; size_t linecap = 0; ssize_t linelen = 0; + size_t i = 0; FILE *fp = NULL; buffer *cur = NULL; - /* Ensure we have a current buffer to load into */ cur = buffer_current(); if (cur == NULL) { return; @@ -1245,7 +1222,7 @@ open_file(const char *filename) reset_editor(); if (EROW != NULL && ENROWS > 0) { - for (int i = 0; i < ENROWS; i++) { + for (i = 0; i < ENROWS; i++) { ab_free(&EROW[i]); } free(EROW); @@ -1289,12 +1266,6 @@ open_file(const char *filename) free(line); line = NULL; fclose(fp); - - /* sync changes back */ - editor.row = EROW; - editor.nrows = ENROWS; - editor.filename = EFILENAME; - editor.dirty = EDIRTY; } @@ -1304,13 +1275,12 @@ open_file(const char *filename) char *rows_to_buffer(int *buflen) { - int len = 0; - int j = 0; + size_t len = 0; + size_t j = 0; char *buf = NULL; char *p = NULL; for (j = 0; j < ENROWS; j++) { - /* extra byte for newline */ len += EROW[j].size + 1; } @@ -1341,21 +1311,21 @@ save_file(void) int status = 1; char *buf = NULL; - if (!editor.dirty) { + if (!EDIRTY) { editor_set_status("No changes to save."); return 0; } - if (editor.filename == NULL) { - editor.filename = editor_prompt("Filename: %s", NULL); - if (editor.filename == NULL) { + if (EFILENAME == NULL) { + EFILENAME = editor_prompt("Filename: %s", NULL); + if (EFILENAME == NULL) { editor_set_status("Save aborted."); return 0; } } buf = rows_to_buffer(&len); - fd = open(editor.filename, O_RDWR | O_CREAT, 0644); + fd = open(EFILENAME, O_RDWR | O_CREAT, 0644); if (fd == -1) { goto save_exit; } @@ -1369,13 +1339,13 @@ save_file(void) goto save_exit; } - if ((ssize_t)len != write(fd, buf, len)) { + if ((ssize_t) len != write(fd, buf, len)) { goto save_exit; } status = 0; -save_exit: + save_exit: if (fd) { close(fd); } @@ -1387,14 +1357,10 @@ save_exit: if (status != 0) { buf = strerror(errno); - editor_set_status("Error writing %s: %s", - editor.filename, - buf); + editor_set_status("Error writing %s: %s", EFILENAME, buf); } else { - editor_set_status("Wrote %d bytes to %s.", - len, - editor.filename); - editor.dirty = 0; + editor_set_status("Wrote %d bytes to %s.", len, EFILENAME); + EDIRTY = 0; } return status; @@ -1584,19 +1550,23 @@ char void editor_find_callback(char* query, int16_t c) { - static int last_match = -1; /* row index of last match */ + static ssize_t last_match = -1; /* row index of last match */ static int direction = 1; /* 1 = forward, -1 = back */ static char last_query[128] = {0}; /* last successful query */ abuf *row = NULL; - const int saved_cx = editor.curx; - const int saved_cy = editor.cury; + const int saved_cx = ECURX; + const int saved_cy = ECURY; const size_t qlen = strlen(query); + const char *hay = NULL; /* the haystack, so to speak */ const char *match = NULL; - const char *search_start = NULL; - int i = 0; - int skip = 0; - int start_row = 0; - int start_col = 0; + size_t i = 0; + size_t limit = 0; + size_t skip = 0; + size_t haylen = 0; + size_t start_row = ECURY; + size_t start_col = ECURX; + size_t wrapped = 0; + ssize_t current = 0; if (c == '\r' || c == ESC_KEY || c == CTRL_KEY('g')) { last_match = -1; @@ -1613,26 +1583,22 @@ editor_find_callback(char* query, int16_t c) if (qlen > 0 && (qlen != strlen(last_query) || strcmp(query, last_query) != 0)) { last_match = -1; - strcpy(last_query, query); + /* copy query safely into last_query */ + strncpy(last_query, query, sizeof(last_query) - 1); + last_query[sizeof(last_query) - 1] = '\0'; } - start_row = editor.cury; - start_col = editor.curx; - if (last_match == -1) { - if (direction == 1) { - start_col += 1; - } - last_match = editor.cury; + last_match = ECURY; } - int current = last_match - direction; - int wrapped = 0; + current = last_match - direction; + wrapped = 0; - for (i = 0; i < editor.nrows; i++) { + for (i = 0; i < ENROWS; i++) { current += direction; - if (current >= editor.nrows) { + if ((size_t) current >= ENROWS) { current = 0; if (wrapped++) { break; @@ -1640,43 +1606,74 @@ editor_find_callback(char* query, int16_t c) } if (current < 0) { - current = editor.nrows - 1; + current = ENROWS - 1; if (wrapped++) { break; } } - row = &editor.row[current]; + row = &EROW[current]; - search_start = row->b; - if (current == start_row && direction == 1 && wrapped == 0) { - skip = start_col; - if (skip > (int)row->size) { - skip = (int)row->size; + /* Determine match based on direction. For forward searches, start just + * after the current cursor when on the same row. For backward searches, + * find the last occurrence before the current cursor when on the same row, + * and in other rows find the last occurrence in the row. */ + if (direction == 1) { + hay = row->b; + haylen = row->size; + if ((size_t) current == start_row && wrapped == 0) { + /* start just after the current position to avoid re-finding same match */ + skip = start_col + 1; + if (skip > haylen) { + skip = haylen; + } + + hay += skip; + haylen -= (size_t) skip; + } + match = (qlen > 0) ? + strnstr(hay, query, haylen) : NULL; + } else { + limit = row->size; + if ((size_t) current == start_row && wrapped == 0) { + /* Only consider text strictly before the cursor */ + if ((size_t) start_col < limit) limit = (size_t) start_col; + } + if (qlen > 0 && limit >= qlen) { + const char *p = row->b; + const char *last = NULL; + size_t remaining = limit; + while (remaining >= qlen) { + const char *q = strnstr(p, query, remaining); + if (!q) break; + last = q; + /* move one byte forward to look for later occurrences */ + size_t advance = (size_t) (q - p) + 1; + p += advance; + remaining = limit - (size_t) (p - row->b); + } + match = last; + } else { + match = NULL; } - search_start += skip; } - - match = strnstr(search_start, query, row->size - (search_start - row->b)); if (match) { last_match = current; - editor.cury = current; - editor.curx = erow_cursor_to_render(row, match - row->b); - if (current == start_row && direction == 1 && last_match == -1) { - editor.curx += start_col; /* adjust if we skipped prefix */ - } + ECURY = current; + /* ECURX stores the raw byte index into the row buffer. */ + ECURX = (int) (match - row->b); scroll(); display_refresh(); return; } } - /* No match found */ if (qlen > 0) { editor_set_status("Failing search: %s", query); } - editor.curx = saved_cx; - editor.cury = saved_cy; + + ECURX = saved_cx; + ECURY = saved_cy; display_refresh(); } @@ -1685,11 +1682,11 @@ void editor_find(void) { /* TODO(kyle): consider making this an abuf */ - char *query; - int scx = ECURX; - int scy = ECURY; - int sco = ECOLOFFS; - int sro = EROWOFFS; + char *query = NULL; + int scx = ECURX; + int scy = ECURY; + int sco = ECOLOFFS; + int sro = EROWOFFS; query = editor_prompt("Search (ESC to cancel): %s", editor_find_callback); @@ -1747,7 +1744,7 @@ first_nonwhitespace(abuf *row) } memset(&state, 0, sizeof(state)); - pos = editor.curx; + pos = ECURX; if (pos > (int)row->size) { pos = row->size; } @@ -1787,111 +1784,109 @@ move_cursor_once(const int16_t c, int interactive) abuf *row = NULL; int reps = 0; - /* Helper lambdas (as static inline functions would also work) */ - /* clamp ECURX within current row bounds */ - { - /* no-op block, kept for patch context */ - } - - row = (ECURY >= ENROWS) ? NULL : &EROW[ECURY]; + row = (ECURY >= ENROWS) ? NULL : &EROW[ECURY]; switch (c) { - case ARROW_UP: - case CTRL_KEY('p'): - if (ECURY > 0) { - ECURY--; - row = (ECURY >= ENROWS) ? NULL : &EROW[ECURY]; - if (interactive) { - ECURX = first_nonwhitespace(row); - } else if (row) { - if (ECURX > (int)row->size) ECURX = (int)row->size; - } - } - break; - case ARROW_DOWN: - case CTRL_KEY('n'): - if (ECURY < ENROWS - 1) { - ECURY++; - row = (ECURY >= ENROWS) ? NULL : &EROW[ECURY]; + case ARROW_UP: + case CTRL_KEY('p'): + if (ECURY > 0) { + ECURY--; + row = (ECURY >= ENROWS) ? NULL : &EROW[ECURY]; + if (interactive) { + ECURX = first_nonwhitespace(row); + } else if (row) { + if (ECURX > row->size) { + ECURX = row->size; + } + } + } + break; + case ARROW_DOWN: + case CTRL_KEY('n'): + if (ECURY < ENROWS - 1) { + ECURY++; + row = (ECURY >= ENROWS) ? NULL : &EROW[ECURY]; - if (interactive) { - ECURX = first_nonwhitespace(row); - } else if (row) { - if (ECURX > (int)row->size) ECURX = (int)row->size; - } - } - break; - case ARROW_RIGHT: - case CTRL_KEY('f'): - if (!row) { - break; - } + if (interactive) { + ECURX = first_nonwhitespace(row); + } else if (row) { + if (ECURX > row->size) { + ECURX = row->size; + } + } + } + break; + case ARROW_RIGHT: + case CTRL_KEY('f'): + if (!row) { + break; + } - if (ECURX < (int)row->size) { - ECURX++; - /* skip over UTF-8 continuation bytes */ - while (ECURX < (int)row->size && - ((unsigned char)row->b[ECURX] & - 0xC0) == 0x80) { - ECURX++; - } - } else if (ECURX == (int)row->size && ECURY < ENROWS - 1) { - ECURY++; - ECURX = 0; - } - break; - case ARROW_LEFT: - case CTRL_KEY('b'): - if (ECURX > 0) { - ECURX--; - while (ECURX > 0 && - ((unsigned char)row->b[ECURX] & - 0xC0) == 0x80) { - ECURX--; - } - } else if (ECURY > 0) { - ECURY--; - ECURX = (int)EROW[ECURY].size; + if (ECURX < row->size) { + ECURX++; + /* skip over UTF-8 continuation bytes */ + while (ECURX < row->size && + ((unsigned char) row->b[ECURX] & + 0xC0) == 0x80) { + ECURX++; + } + } else if (ECURX == row->size && ECURY < ENROWS - 1) { + ECURY++; + ECURX = 0; + } + break; + case ARROW_LEFT: + case CTRL_KEY('b'): + if (ECURX > 0) { + ECURX--; + while (ECURX > 0 && + ((unsigned char) row->b[ECURX] & + 0xC0) == 0x80) { + ECURX--; + } + } else if (ECURY > 0) { + ECURY--; + ECURX = (int) EROW[ECURY].size; - row = &EROW[ECURY]; - while (ECURX > 0 && - ((unsigned char)row->b[ECURX] & - 0xC0) == 0x80) { - ECURX--; - } - } - break; - case PG_UP: - case PG_DN: - if (c == PG_UP) { - ECURY = EROWOFFS; - } else if (c == PG_DN) { - ECURY = EROWOFFS + editor.rows - 1; - if (ECURY > ENROWS) { - ECURY = ENROWS; - } - } + row = &EROW[ECURY]; + while (ECURX > 0 && + ((unsigned char) row->b[ECURX] & + 0xC0) == 0x80) { + ECURX--; + } + } + break; + case PG_UP: + case PG_DN: + if (c == PG_UP) { + ECURY = EROWOFFS; + } else if (c == PG_DN) { + ECURY = EROWOFFS + editor.rows - 1; + if (ECURY > ENROWS) { + ECURY = ENROWS; + } + } - reps = editor.rows; - while (--reps) { - move_cursor(c == PG_UP ? ARROW_UP : ARROW_DOWN, 1); - } + reps = editor.rows; + while (--reps) { + move_cursor(c == PG_UP ? ARROW_UP : ARROW_DOWN, 1); + } - break; + break; - case HOME_KEY: - case CTRL_KEY('a'): - ECURX = 0; - break; - case END_KEY: - case CTRL_KEY('e'): - if (ECURY >= ENROWS) { - break; - } - ECURX = (int)EROW[ECURY].size; - break; - default: - break; + case HOME_KEY: + case CTRL_KEY('a'): + ECURX = 0; + break; + case END_KEY: + case CTRL_KEY('e'): + if (ECURY >= ENROWS) { + break; + } + ECURX = (int) EROW[ECURY].size; + break; + default: + break; } } @@ -1910,49 +1905,43 @@ move_cursor(const int16_t c, const int interactive) void newline(void) { - abuf *row = NULL; + abuf *row = NULL; + size_t rhs_len = 0; + char *tmp = NULL; - if (ECURY >= ENROWS) { - erow_insert(ECURY, "", 0); - ECURY++; - ECURX = 0; - } else if (ECURX == 0) { - erow_insert(ECURY, "", 0); - ECURY++; - ECURX = 0; - } else { - size_t rhs_len; - char *tmp = NULL; + if (ECURY >= ENROWS) { + erow_insert(ECURY, "", 0); + ECURY++; + ECURX = 0; + } else if (ECURX == 0) { + erow_insert(ECURY, "", 0); + ECURY++; + ECURX = 0; + } else { + row = &EROW[ECURY]; + rhs_len = row->size - (size_t) ECURX; + if (rhs_len > 0) { + tmp = malloc(rhs_len); + assert(tmp != NULL); + memcpy(tmp, &row->b[ECURX], rhs_len); + } - row = &EROW[ECURY]; - /* Snapshot RHS into a temporary buffer BEFORE we mutate rows array. */ - rhs_len = row->size - (size_t)ECURX; - if (rhs_len > 0) { - tmp = malloc(rhs_len); - assert(tmp != NULL); - memcpy(tmp, &row->b[ECURX], rhs_len); - } + row->size = ECURX; + if (row->cap <= row->size) { + ab_resize(row, row->size + 1); + } + row->b[row->size] = '\0'; - /* Trim the current (LHS) row BEFORE inserting the new row. */ - row->size = ECURX; - if (row->cap <= row->size) { - ab_resize(row, row->size + 1); - } - row->b[row->size] = '\0'; + erow_insert(ECURY + 1, tmp ? tmp : "", (int) rhs_len); + if (tmp) { + free(tmp); + } + ECURY++; + ECURX = 0; + } - /* Now insert the RHS as a new row; this may realloc/move EROW. */ - erow_insert(ECURY + 1, tmp ? tmp : "", (int)rhs_len); - if (tmp) { - free(tmp); - } - ECURY++; - ECURX = 0; - } - - /* BREAK THE KILL CHAIN \m/ */ - editor.kill = 0; - /* Buffer modified */ - EDIRTY++; + editor.kill = 0; /* BREAK THE KILL CHAIN \m/ */ + EDIRTY++; } @@ -1997,7 +1986,7 @@ uarg_clear(void) int uarg_get(void) { - int n = editor.ucount > 0 ? editor.ucount : 1; + int n = editor.ucount > 0 ? editor.ucount : 1; uarg_clear(); @@ -2009,211 +1998,212 @@ void process_kcommand(const int16_t c) { char *buf = NULL; - int len = 0; + size_t len = 0; int jumpx = 0; int jumpy = 0; int reps = 0; switch (c) { - case BACKSPACE: - while (editor.curx > 0) { - process_normal(BACKSPACE); - } - break; - case '=': - if (editor.mark_set) { - indent_region(); - } else { - editor_set_status("Mark not set."); - } - break; - case '-': - if (editor.mark_set) { - unindent_region(); - } else { - editor_set_status("Mark not set."); - } - break; - case CTRL_KEY('\\'): - /* sometimes it's nice to dump core */ - disable_termraw(); - abort(); - case '@': - if (!dump_pidfile()) { - break; - } - - /* FALLTHRU */ - case '!': - /* useful for debugging */ - editor_set_status("PID: %ld", (long)getpid()); - break; - case ' ': - toggle_markset(); - break; - case CTRL_KEY(' '): - jumpx = editor.mark_curx; - jumpy = editor.mark_cury; - editor.mark_curx = editor.curx; - editor.mark_cury = editor.cury; - - jump_to_position(jumpx, jumpy); - editor_set_status("Jumped to mark"); - break; - case 'c': - /* Close current buffer (was kill ring clear; that moved to C-k f) */ - buffer_close_current(); - break; - case 'd': - if (editor.curx == 0 && cursor_at_eol()) { - delete_row(editor.cury); - return; - } - - reps = uarg_get(); - while (reps--) { - while ((EROW[ECURY].size - - editor.curx) > 0) { - process_normal(DEL_KEY); + case BACKSPACE: + while (ECURX > 0) { + process_normal(BACKSPACE); } - if (reps) { - newline(); + break; + case '=': + if (EMARK_SET) { + indent_region(); + } else { + editor_set_status("Mark not set."); } - } - - break; - case DEL_KEY: - case CTRL_KEY('d'): - reps = uarg_get(); - - while (reps--) { - delete_row(editor.cury); - } - break; - case 'e': - case CTRL_KEY('e'): - if (editor.dirty && editor.dirtyex) { - editor_set_status( - "File not saved - C-k e again to open a new file anyways."); - editor.dirtyex = 0; - return; - } - editor_openfile(); - break; - case 'f': { - /* Rebound: clear kill ring on C-k f */ - len = editor.killring ? (int)editor.killring->size : 0; - killring_flush(); - editor_set_status("Kill ring cleared (%d characters)", len); - break; - } - case 'n': - buffer_next(); - break; - case 'p': - buffer_prev(); - break; - case 'b': - buffer_switch_by_name(); - break; - case 'g': - goto_line(); - break; - case 'j': - if (!editor.mark_set) { - editor_set_status("Mark not set."); break; - } - - jumpx = editor.mark_curx; - jumpy = editor.mark_cury; - editor.mark_curx = editor.curx; - editor.mark_cury = editor.cury; - - jump_to_position(jumpx, jumpy); - editor_set_status("Jumped to mark; mark is now the previous location."); - break; - case 'l': - buf = get_cloc_code_lines(editor.filename); - - editor_set_status("Lines of code: %s", buf); - free(buf); - break; - case 'm': - if (system("make") != 0) { - editor_set_status( - "process failed: %s", - strerror(errno)); - } else { - editor_set_status("make: ok"); - } - break; - case 'q': - if (editor.dirty && editor.dirtyex) { - editor_set_status( - "File not saved - C-k q again to quit."); - editor.dirtyex = 0; - return; - } - exit(0); - case CTRL_KEY('q'): - exit(0); - case CTRL_KEY('r'): - if (editor.dirty && editor.dirtyex) { - editor_set_status("File not saved - C-k C-r again to reload."); - editor.dirtyex = 0; - return; - } - - jumpx = editor.curx; - jumpy = editor.cury; - buf = strdup(editor.filename); - - reset_editor(); - open_file(buf); - display_refresh(); - free(buf); - - jump_to_position(jumpx, jumpy); - editor_set_status("file reloaded"); - break; - case CTRL_KEY('s'): - case 's': - save_file(); - break; - case CTRL_KEY('x'): - case 'x': - exit(save_file()); - case 'u': - reps = uarg_get(); - - while (reps--) {} - editor_set_status("Undo not implemented."); - break; - case 'U': - reps = uarg_get(); - - while (reps--) {} - editor_set_status("Redo not implemented."); - break; - case 'y': - reps = uarg_get(); - - while (reps--) { - killring_yank(); - } - break; - case ESC_KEY: - case CTRL_KEY('g'): - break; - default: - if (isprint(c)) { - editor_set_status("unknown kcommand '%c'", c); + case '-': + if (EMARK_SET) { + unindent_region(); + } else { + editor_set_status("Mark not set."); + } break; - } + case CTRL_KEY('\\'): + /* sometimes it's nice to dump core */ + disable_termraw(); + abort(); + case '@': + if (!dump_pidfile()) { + break; + } + /* FALLTHRU */ + case '!': + /* useful for debugging */ + editor_set_status("PID: %ld", (long) getpid()); + break; + case ' ': + toggle_markset(); + break; + case CTRL_KEY(' '): + jumpx = EMARK_CURX; + jumpy = EMARK_CURY; + EMARK_CURX = ECURX; + EMARK_CURY = ECURY; - editor_set_status("unknown kcommand: %04x", c); - return; + jump_to_position(jumpx, jumpy); + editor_set_status("Jumped to mark"); + break; + case 'c': + buffer_close_current(); + break; + case 'd': + if (ECURX == 0 && cursor_at_eol()) { + delete_row(ECURY); + return; + } + + reps = uarg_get(); + while (reps--) { + while ((EROW[ECURY].size - ECURX) > 0) { + process_normal(DEL_KEY); + } + if (reps) { + newline(); + } + } + + break; + case DEL_KEY: + case CTRL_KEY('d'): + reps = uarg_get(); + + while (reps--) { + delete_row(ECURY); + } + break; + case 'e': + case CTRL_KEY('e'): + if (EDIRTY && editor.dirtyex) { + editor_set_status( + "File not saved - C-k e again to open a new file anyways."); + editor.dirtyex = 0; + return; + } + editor_openfile(); + break; + case 'f': + if (editor.killring == NULL || editor.killring->size == 0) { + editor_set_status("The kill ring is empty."); + break; + } + + len = editor.killring ? editor.killring->size : 0; + killring_flush(); + editor_set_status("Kill ring cleared (%lu characters)", len); + break; + case 'n': + buffer_next(); + break; + case 'p': + buffer_prev(); + break; + case 'b': + buffer_switch_by_name(); + break; + case 'g': + goto_line(); + break; + case 'j': + if (!EMARK_SET) { + editor_set_status("Mark not set."); + break; + } + + jumpx = EMARK_CURX; + jumpy = EMARK_CURY; + EMARK_CURX = ECURX; + EMARK_CURY = ECURY; + + jump_to_position(jumpx, jumpy); + editor_set_status("Jumped to mark; mark is now the previous location."); + break; + case 'l': + buf = get_cloc_code_lines(EFILENAME); + + editor_set_status("Lines of code: %s", buf); + free(buf); + break; + case 'm': + /* todo: fix the process failed: success issue */ + if (system("make") != 0) { + editor_set_status( + "process failed: %s", + strerror(errno)); + } else { + editor_set_status("make: ok"); + } + break; + case 'q': + if (EDIRTY && editor.dirtyex) { + editor_set_status( + "File not saved - C-k q again to quit."); + editor.dirtyex = 0; + return; + } + exit(0); + case CTRL_KEY('q'): + exit(0); + case CTRL_KEY('r'): + if (EDIRTY && editor.dirtyex) { + editor_set_status("File not saved - C-k C-r again to reload."); + editor.dirtyex = 0; + return; + } + + jumpx = ECURX; + jumpy = ECURY; + buf = strdup(EFILENAME); + + reset_editor(); + open_file(buf); + display_refresh(); + free(buf); + + jump_to_position(jumpx, jumpy); + editor_set_status("file reloaded"); + break; + case CTRL_KEY('s'): + case 's': + save_file(); + break; + case CTRL_KEY('x'): + case 'x': + exit(save_file()); + case 'u': + reps = uarg_get(); + + while (reps--) {} + editor_set_status("Undo not implemented."); + break; + case 'U': + reps = uarg_get(); + + while (reps--) {} + editor_set_status("Redo not implemented."); + break; + case 'y': + reps = uarg_get(); + + while (reps--) { + killring_yank(); + } + break; + case ESC_KEY: + case CTRL_KEY('g'): + break; + default: + if (isprint(c)) { + editor_set_status("unknown kcommand '%c'", c); + break; + } + + editor_set_status("unknown kcommand: %04x", c); + return; } editor.dirtyex = 1; @@ -2223,8 +2213,8 @@ process_kcommand(const int16_t c) void process_normal(int16_t c) { - int cols = 0; - int rows = 0; + size_t cols = 0; + size_t rows = 0; int reps = 0; /* C-u handling – must be the very first thing */ @@ -2304,7 +2294,6 @@ process_normal(int16_t c) killring_yank(); } break; - case ESC_KEY: editor.mode = MODE_ESCAPE; break; @@ -2337,58 +2326,58 @@ process_escape(const int16_t c) editor_set_status("hi"); switch (c) { - case '>': - editor.cury = editor.nrows; - editor.curx = 0; - break; - case '<': - editor.cury = 0; - editor.curx = 0; - break; - case 'b': - reps = uarg_get(); - - while (reps--) { - find_prev_word(); - } - break; - case 'd': - reps = uarg_get(); - - while (reps--) { - delete_next_word(); - } - break; - case 'f': - reps = uarg_get(); - - while (reps--) { - find_next_word(); - } - break; - case 'm': - toggle_markset(); - break; - case 'w': - if (!editor.mark_set) { - editor_set_status("mark isn't set"); + case '>': + ECURY = ENROWS; + ECURX = 0; break; - } - kill_region(); - toggle_markset(); - break; - case BACKSPACE: - reps = uarg_get(); + case '<': + ECURY = 0; + ECURX = 0; + break; + case 'b': + reps = uarg_get(); - while (reps--) { - delete_prev_word(); - } - break; - case ESC_KEY: - case CTRL_KEY('g'): - break; /* escape out of escape-mode */ - default: - editor_set_status("unknown ESC key: %04x", c); + while (reps--) { + find_prev_word(); + } + break; + case 'd': + reps = uarg_get(); + + while (reps--) { + delete_next_word(); + } + break; + case 'f': + reps = uarg_get(); + + while (reps--) { + find_next_word(); + } + break; + case 'm': + toggle_markset(); + break; + case 'w': + if (!EMARK_SET) { + editor_set_status("mark isn't set"); + break; + } + kill_region(); + toggle_markset(); + break; + case BACKSPACE: + reps = uarg_get(); + + while (reps--) { + delete_prev_word(); + } + break; + case ESC_KEY: + case CTRL_KEY('g'): + break; /* escape from escape-mode the movie */ + default: + editor_set_status("unknown ESC key: %04x", c); } uarg_clear(); @@ -2400,8 +2389,6 @@ process_keypress(void) { const int16_t c = get_keypress(); - - /* we didn't actually read a key */ if (c <= 0) { return 0; } @@ -2437,7 +2424,7 @@ char FILE *pipe = NULL; size_t len = 0; - if (editor.filename == NULL) { + if (filename == NULL) { snprintf(command, sizeof(command), "buffer has no associated file."); result = malloc((kstrnlen(command, sizeof(command))) + 1); @@ -2446,7 +2433,7 @@ char return result; } - if (editor.dirty) { + if (EDIRTY) { snprintf(command, sizeof(command), "buffer must be saved first."); result = malloc((kstrnlen(command, sizeof(command))) + 1); @@ -2462,8 +2449,9 @@ char pipe = popen(command, "r"); if (!pipe) { - snprintf(command, sizeof(command), "Error getting LOC: %s", strerror(errno)); - result = (char*)malloc(sizeof(outbuf) + 1); + snprintf(command, sizeof(command), + "Error getting LOC: %s", strerror(errno)); + result = (char *) malloc(sizeof(outbuf) + 1); return NULL; } @@ -2512,18 +2500,16 @@ dump_pidfile(void) void draw_rows(abuf *ab) { - assert(editor.cols >= 0); - abuf *row = NULL; char buf[editor.cols]; char c = 0; size_t j = 0; - int len = 0; - int filerow = 0; - int padding = 0; - int printed = 0; - int rx = 0; - int y = 0; + size_t filerow = 0; + size_t y = 0; + size_t len = 0; + size_t padding = 0; + size_t printed = 0; + size_t rx = 0; for (y = 0; y < editor.rows; y++) { filerow = y + EROWOFFS; @@ -2612,46 +2598,46 @@ draw_status_bar(abuf *ab) char status[editor.cols]; char rstatus[editor.cols]; char mstatus[editor.cols]; + size_t len = 0; + size_t rlen = 0; - int len = 0; - int rlen = 0; - - len = snprintf(status, - sizeof(status), - "%c%cke: %.20s - %d lines", - status_mode_char(), - EDIRTY ? '!' : '-', - EFILENAME ? EFILENAME : "[no file]", + len = snprintf(status, + sizeof(status), + "%c%cke: %.20s - %lu lines", + status_mode_char(), + EDIRTY ? '!' : '-', + EFILENAME ? EFILENAME : "[no file]", ENROWS); - if (EMARK_SET) { - snprintf(mstatus, - sizeof(mstatus), - " | M: %d, %d ", - EMARK_CURX + 1, - EMARK_CURY + 1); - } else { - snprintf(mstatus, sizeof(mstatus), " | M:clear "); - } + if (EMARK_SET) { + snprintf(mstatus, + sizeof(mstatus), + " | M: %lu, %lu ", + EMARK_CURX + 1, + EMARK_CURY + 1); + } else { + snprintf(mstatus, sizeof(mstatus), " | M:clear "); + } - rlen = snprintf(rstatus, - sizeof(rstatus), - "L%d/%d C%d %s", - ECURY + 1, - ENROWS, - ECURX + 1, - mstatus); + rlen = snprintf(rstatus, + sizeof(rstatus), + "L%lu/%lu C%lu %s", + ECURY + 1, + ENROWS, + ECURX + 1, + mstatus); ab_append(ab, ESCSEQ "7m", 4); ab_append(ab, status, len); while (len < editor.cols) { - if ((editor.cols - len) == rlen) { + if (editor.cols - len == rlen) { ab_append(ab, rstatus, rlen); break; } ab_append(ab, " ", 1); len++; } + ab_append(ab, ESCSEQ "m", 3); ab_append(ab, "\r\n", 2); } @@ -2660,7 +2646,7 @@ draw_status_bar(abuf *ab) void draw_message_line(abuf *ab) { - int len = (int)strlen(editor.msg); + size_t len = strlen(editor.msg); ab_append(ab, ESCSEQ "K", 3); if (len > editor.cols) { @@ -2676,29 +2662,29 @@ draw_message_line(abuf *ab) void scroll(void) { - const abuf *row = NULL; + const abuf *row = NULL; - ERX = 0; - if (ECURY < ENROWS) { - row = &EROW[ECURY]; - ERX = erow_render_to_cursor(row, ECURX); - } + ERX = 0; + if (ECURY < ENROWS) { + row = &EROW[ECURY]; + ERX = erow_render_to_cursor(row, ECURX); + } - if (ECURY < EROWOFFS) { - EROWOFFS = ECURY; - } + if (ECURY < EROWOFFS) { + EROWOFFS = ECURY; + } - if (ECURY >= EROWOFFS + editor.rows) { - EROWOFFS = ECURY - editor.rows + 1; - } + if (ECURY >= EROWOFFS + editor.rows) { + EROWOFFS = ECURY - editor.rows + 1; + } - if (ERX < ECOLOFFS) { - ECOLOFFS = ERX; - } + if (ERX < ECOLOFFS) { + ECOLOFFS = ERX; + } - if (ERX >= ECOLOFFS + editor.cols) { - ECOLOFFS = ERX - editor.cols + 1; - } + if (ERX >= ECOLOFFS + editor.cols) { + ECOLOFFS = ERX - editor.cols + 1; + } } @@ -2718,11 +2704,11 @@ display_refresh(void) draw_status_bar(&ab); draw_message_line(&ab); - snprintf(buf, - sizeof(buf), - ESCSEQ "%d;%dH", - (ECURY - EROWOFFS) + 1, - (ERX - ECOLOFFS) + 1); + snprintf(buf, + sizeof(buf), + ESCSEQ "%lu;%luH", + (ECURY - EROWOFFS) + 1, + (ERX - ECOLOFFS) + 1); ab_append(&ab, buf, kstrnlen(buf, 32)); /* ab_append(&ab, ESCSEQ "1;2H", 7); */ ab_append(&ab, ESCSEQ "?25h", 6); @@ -2922,22 +2908,3 @@ main(int argc, char *argv[]) return 0; } - -/* Cursor helpers: keep per-buffer cursor consistent and clamped */ -static inline void clamp_curx_to_row(void) -{ - if (ECURY >= ENROWS) return; - abuf *row = &EROW[ECURY]; - if (ECURX < 0) ECURX = 0; - int maxx = (int)row->size; - if (ECURX > maxx) ECURX = maxx; -} - -static inline void set_cursor(int x, int y) -{ - if (y < 0) y = 0; - if (y > ENROWS) y = ENROWS; - ECURY = y; - ECURX = x; - clamp_curx_to_row(); -} diff --git a/scratch.c b/scratch.c index 35065af..b1c84cb 100644 --- a/scratch.c +++ b/scratch.c @@ -2,15 +2,20 @@ * scratch.c - ideas in progress */ +#include "buffer.h" +#include "abuf.h" +#include +#include + #define REFLOW_MARGIN 72 void reflow_region(void) { - int start_row, end_row, i, col, wlen, this_len; - struct erow *row; - struct abuf buf = ABUF_INIT; - struct abuf out = ABUF_INIT; + int start_row, end_row, i, col, wlen, this_len; + abuf *row; + struct abuf buf = ABUF_INIT; + struct abuf out = ABUF_INIT; int in_paragraph = 0; int indent_len = 0; char indent[REFLOW_MARGIN + 1]; @@ -19,38 +24,38 @@ reflow_region(void) char *p = NULL; char *s = NULL; - if (editor.mark_set) { - if (editor.mark_cury < editor.cury || - (editor.mark_cury == editor.cury && - editor.mark_curx < editor.curx)) { - start_row = editor.mark_cury; - end_row = editor.cury; - } else { - start_row = editor.cury; - end_row = editor.mark_cury; - } - } else { - start_row = end_row = editor.cury; - while (start_row > 0 && editor.row[start_row - 1].size > 0) { - start_row--; - } + if (EMARK_SET) { + if (EMARK_CURY < ECURY || + (EMARK_CURY == ECURY && + EMARK_CURX < ECURX)) { + start_row = EMARK_CURY; + end_row = ECURY; + } else { + start_row = ECURY; + end_row = EMARK_CURY; + } + } else { + start_row = end_row = ECURY; + while (start_row > 0 && EROW[start_row - 1].size > 0) { + start_row--; + } - while (end_row < editor.nrows - 1 && - editor.row[end_row + 1].size > 0) { - end_row++; - } - } + while (end_row < ENROWS - 1 && + EROW[end_row + 1].size > 0) { + end_row++; + } + } - if (start_row >= editor.nrows) { - return; - } + if (start_row >= ENROWS) { + return; + } - if (end_row >= editor.nrows) { - end_row = editor.nrows - 1; - } + if (end_row >= ENROWS) { + end_row = ENROWS - 1; + } - for (i = start_row; i <= end_row; i++) { - row = &editor.row[i]; + for (i = start_row; i <= end_row; i++) { + row = &EROW[i]; if (row->size == 0) { if (in_paragraph) { @@ -62,21 +67,21 @@ reflow_region(void) continue; } - if (!in_paragraph) { - indent_len = 0; - while (indent_len < row->size && - (row->line[indent_len] == ' ' || - row->line[indent_len] == '\t')) { - indent[indent_len] = row->line[indent_len], indent_len++; - } + if (!in_paragraph) { + indent_len = 0; + while (indent_len < (int)row->size && + (row->b[indent_len] == ' ' || + row->b[indent_len] == '\t')) { + indent[indent_len] = row->b[indent_len], indent_len++; + } - indent[indent_len] = '\0'; - in_paragraph = 1; - } + indent[indent_len] = '\0'; + in_paragraph = 1; + } - ab_append(&buf, row->line + indent_len, row->size - indent_len); - ab_append(&buf, " ", 1); - } + ab_append(&buf, row->b + indent_len, row->size - indent_len); + ab_append(&buf, " ", 1); + } if (in_paragraph) { ab_append(&buf, "\n", 1); @@ -145,18 +150,57 @@ reflow_region(void) ab_free(&out); - for (i = end_row; i >= start_row; i--) { - delete_row(i); - } + for (i = end_row; i >= start_row; i--) { + delete_row(i); + } - s = buf.b; - while ((e = strchr(s, '\n'))) { - erow_insert(start_row++, s, e - s); - s = e + 1; - } + s = buf.b; + while ((e = strchr(s, '\n'))) { + erow_insert(start_row++, s, e - s); + s = e + 1; + } ab_free(&buf); - editor.dirty++; - editor_set_status("Region reflowed to %d columns", REFLOW_MARGIN); -} \ No newline at end of file + EDIRTY++; + editor_set_status("Region reflowed to %d columns", REFLOW_MARGIN); +} + + +static inline +void clamp_curx_to_row(void) +{ + abuf *row = NULL; + int maxx = 0; + + if (ECURY >= ENROWS) { + return; + } + + row = &EROW[ECURY]; + if (ECURX < 0) { + ECURX = 0; + } + + maxx = (int) row->size; + if (ECURX > maxx) { + ECURX = maxx; + } +} + +static inline +void set_cursor(int col, int row) +{ + if (row < 0) { + row = 0; + } + + if (row > ENROWS) { + row = ENROWS; + } + + ECURY = row; + ECURX = col; + + clamp_curx_to_row(); +} diff --git a/term.c b/term.c index 0995dad..f7ff999 100644 --- a/term.c +++ b/term.c @@ -71,16 +71,16 @@ setup_terminal(void) int -get_winsz(int *rows, int *cols) +get_winsz(size_t *rows, size_t *cols) { - struct winsize ws; + struct winsize ws; - if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) == -1 || ws.ws_col == 0) { - return -1; - } + if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) == -1 || ws.ws_col == 0) { + return -1; + } - *cols = ws.ws_col; - *rows = ws.ws_row; + *cols = (size_t)ws.ws_col; + *rows = (size_t)ws.ws_row; - return 0; + return 0; } diff --git a/term.h b/term.h index 6575672..f2d4953 100644 --- a/term.h +++ b/term.h @@ -1,5 +1,5 @@ -#ifndef TERM_H -#define TERM_H +#ifndef KE_TERM_H +#define KE_TERM_H #include "abuf.h" @@ -17,6 +17,6 @@ void display_clear(abuf *ab); * on this for now because it's bloaty and this works on OpenBSD and * Linux, at least. */ -int get_winsz(int *rows, int *cols); +int get_winsz(size_t *rows, size_t *cols); -#endif /* TERM_H */ +#endif /* KE_TERM_H */ diff --git a/undo.c b/undo.c index a900507..50551c8 100644 --- a/undo.c +++ b/undo.c @@ -1,8 +1,10 @@ +#include +#include #include "abuf.h" #include "undo.h" -undo_node +undo_node * undo_node_new(undo_kind kind) { undo_node *node = NULL; @@ -13,10 +15,12 @@ undo_node_new(undo_kind kind) node->kind = kind; node->row = node->col = 0; - abuf_init(node->text); + ab_init(&node->text); node->next = NULL; node->parent = NULL; + + return node; } @@ -26,11 +30,10 @@ undo_node_free(undo_node *node) undo_node *next = NULL; if (node == NULL) { - return NULL; + return; } - abuf_free(node-text); - next = node->next; + ab_free(&node->text); } @@ -44,9 +47,10 @@ undo_node_free_all(undo_node *node) } while (node != NULL) { + next = node->next; undo_node_free(node); free(node); - node = node->next; + node = next; } } @@ -65,7 +69,7 @@ undo_tree_init(undo_tree *tree) void undo_tree_free(undo_tree *tree) { - assert(tree == NULL); + assert(tree != NULL); undo_node_free(tree->pending); undo_node_free_all(tree->root); @@ -86,19 +90,25 @@ undo_begin(undo_tree *tree, undo_kind kind) undo_commit(tree); } - pending = undo_new_new(kind); + pending = undo_node_new(kind); assert(pending != NULL); tree->pending = pending; } -void undo_prepend(abuf *buf); -void undo_append(buf *buf); -void undo_prependch(char c); -void undo_appendch(char c); -void undo_commit(void); -void undo_apply(undo_node *node); -void editor_undo(void); -void editor_redo(void); +void +undo_prepend(undo_tree *tree, abuf *buf) +{ + +} + + +void undo_append(undo_tree *tree, abuf *buf); +void undo_prependch(undo_tree *tree, char c); +void undo_appendch(undo_tree *tree, char c); +void undo_commit(undo_tree *tree); +void undo_apply(struct editor *editor); +void editor_undo(undo_tree *tree); +void editor_redo(undo_tree *tree); diff --git a/undo.h b/undo.h index 6c4bf1b..f33e5f5 100644 --- a/undo.h +++ b/undo.h @@ -1,5 +1,11 @@ -#ifndef KE_UNDO -#define KE_UNDO +#include + +#include "abuf.h" +#include "editor.h" + + +#ifndef KE_UNDO_H +#define KE_UNDO_H typedef enum undo_kind { @@ -9,7 +15,7 @@ typedef enum undo_kind { typedef struct undo_node { - undo_kind op; + undo_kind kind; size_t row, col; abuf text; @@ -31,14 +37,14 @@ void undo_node_free(undo_node *node); void undo_tree_init(undo_tree *tree); void undo_tree_free(undo_tree *tree); void undo_begin(undo_tree *tree, undo_kind kind); -void undo_prepend(abuf *buf); -void undo_append(buf *buf); -void undo_prependch(char c); -void undo_appendch(char c); +void undo_prepend(undo_tree *tree, abuf *buf); +void undo_append(undo_tree *tree, abuf *buf); +void undo_prependch(undo_tree *tree, char c); +void undo_appendch(undo_tree *tree, char c); void undo_commit(undo_tree *tree); -void undo_apply(undo_node *node); -void editor_undo(void); -void editor_redo(void); +void undo_apply(struct editor *editor); +void editor_undo(undo_tree *tree); +void editor_redo(undo_tree *tree); #endif