Archived
1
Fork 0

Finish refactoring

This commit is contained in:
Hadeed 2023-09-09 01:32:29 +05:00
parent fc5e50e4db
commit 2f560997e5
14 changed files with 160 additions and 170 deletions

View file

@ -20,7 +20,7 @@ gcc -I include src/*.c -o kilo
## My additions ## My additions
- Split it up into multiple files and tried to follow good design and - Split it up into multiple files and tried to follow good design and
organization practices (WIP). organization practices.
## References ## References
- [antirez/kilo][1] - [antirez/kilo][1]

View file

@ -4,8 +4,10 @@
#include <stdbool.h> #include <stdbool.h>
#include <stddef.h> #include <stddef.h>
#include "utils.h"
#include "erow.h" #include "erow.h"
#include "utils.h"
struct erow;
struct buffer { struct buffer {
char *filename; char *filename;
@ -25,6 +27,7 @@ ERRCODE buffer_write_file(struct buffer *buffer, size_t *bytes_written);
void buffer_insert_row(struct buffer *buffer, struct erow *erow, int at); void buffer_insert_row(struct buffer *buffer, struct erow *erow, int at);
void buffer_delete_row(struct buffer *buffer, int at); void buffer_delete_row(struct buffer *buffer, int at);
struct erow *buffer_get_crow(struct buffer *buffer); struct erow *buffer_get_crow(struct buffer *buffer);
size_t buffer_get_crow_len(struct buffer *buffer);
void buffer_free(struct buffer *buffer); void buffer_free(struct buffer *buffer);

10
include/cursor.h Normal file
View file

@ -0,0 +1,10 @@
#ifndef CURSOR_H
#define CURSOR_H
#include "buffer.h"
struct buffer;
void cursor_move(struct buffer *buffer, int dx, int dy);
#endif // CURSOR_H

View file

@ -3,6 +3,8 @@
#include <stdlib.h> #include <stdlib.h>
struct buffer;
struct erow { struct erow {
char *chars; char *chars;
size_t n_chars; size_t n_chars;
@ -15,7 +17,7 @@ struct erow {
struct erow *erow_create(const char* chars, size_t n_chars, struct buffer *buffer); struct erow *erow_create(const char* chars, size_t n_chars, struct buffer *buffer);
void erow_insert_chars(struct erow *erow, const char *chars, size_t n_chars, int at); void erow_insert_chars(struct erow *erow, const char *chars, size_t n_chars, int at);
void erow_delete_char(struct erow *erow, int at); void erow_delete_chars(struct erow *erow, size_t n_chars, int at);
int erow_cx_to_rx(struct erow *erow, int cx); int erow_cx_to_rx(struct erow *erow, int cx);
int erow_rx_to_cx(struct erow *erow, int rx); int erow_rx_to_cx(struct erow *erow, int rx);
void erow_free(struct erow *erow); void erow_free(struct erow *erow);

View file

@ -3,6 +3,8 @@
#include <stdint.h> #include <stdint.h>
#define CTRL_KEY(key) ((key) & 0x1f)
enum KEYS { enum KEYS {
TAB = 9, TAB = 9,
ENTER = 13, ENTER = 13,
@ -21,6 +23,6 @@ enum KEYS {
}; };
typedef uint16_t KEY; typedef uint16_t KEY;
void input_process_key(void); void input_process_key(KEY c);
#endif // INPUT_H #endif // INPUT_H

View file

@ -1,10 +1,9 @@
#ifndef UTIL_H #ifndef UTIL_H
#define UTIL_H #define UTIL_H
#define CTRL_KEY(key) ((key) & 0x1f)
#define MAX(a,b) (((a)>(b))?(a):(b)) #define MAX(a,b) (((a)>(b))?(a):(b))
#define MIN(a,b) (((a)<(b))?(a):(b)) #define MIN(a,b) (((a)<(b))?(a):(b))
#define CLAMP(value, min, max) MIN(MAX(value, min), max)
#define _STRINGIZE(x) #x #define _STRINGIZE(x) #x
#define STRINGIZE(x) _STRINGIZE(x) #define STRINGIZE(x) _STRINGIZE(x)

View file

@ -1,4 +1,5 @@
# Progress log # Progress log
- (4/9/2023) Finished 5 chapters out of 7, basic text editing is fully - (4/9/2023) Finished 5 chapters out of 7, basic text editing is fully
possible. It has fun been working on this, but semester is starting now and I possible. It has fun been working on this, but semester is starting now and I
might not get to work on this a lot anymore. It might have lots of bugs, and might not get to work on this a lot anymore. It might have lots of bugs, and
@ -6,3 +7,11 @@ there's lots of things I don't like, there are TODOs everywhere. So many leaky
abstractions, near the end I started blindly following the tutorial and didn't abstractions, near the end I started blindly following the tutorial and didn't
stop to think how it fits with the abstractions I have defined, but I might fix stop to think how it fits with the abstractions I have defined, but I might fix
it all one of these days... it all one of these days...
- (9/9/2023) Didn't implement any new features, but refactored heavily. All the
previous features should be working unless I introduced a bug. But I like the
abstractions better now, and I cleaned up most of TODOs. This was painful to
get right and I contemplated quitting, but proud of myself. I find it very
interesting that the total of amount of code barely changed, it actually
decreased as measured by tokei. It increased slightly in the header files and
decreased in the source files, yet it was a lot of work.

View file

@ -1,4 +1,6 @@
#include <stdbool.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h>
#include <string.h> #include <string.h>
#include "buffer.h" #include "buffer.h"
@ -36,7 +38,6 @@ ERRCODE buffer_read_file(struct buffer *buffer, const char *filename) {
buffer_free_rows(buffer); buffer_free_rows(buffer);
size_t buf_cap = 64; size_t buf_cap = 64;
size_t buf_size = 0;
char *buf = malloc(buf_cap); char *buf = malloc(buf_cap);
FILE *file = fopen(filename, "r"); FILE *file = fopen(filename, "r");
@ -45,6 +46,7 @@ ERRCODE buffer_read_file(struct buffer *buffer, const char *filename) {
while (true) { while (true) {
char c; char c;
size_t buf_size = 0;
while ((c = getc(file)) != '\n' && c != EOF) { while ((c = getc(file)) != '\n' && c != EOF) {
if (buf_size >= buf_cap) if (buf_size >= buf_cap)
@ -139,7 +141,6 @@ void buffer_insert_row(struct buffer *buffer, struct erow *erow, int at) {
memmove(buffer->rows + at + 1, buffer->rows + at, sizeof(struct erow *) * (buffer->n_rows - at)); memmove(buffer->rows + at + 1, buffer->rows + at, sizeof(struct erow *) * (buffer->n_rows - at));
buffer->rows[at] = erow; buffer->rows[at] = erow;
buffer->n_rows++; buffer->n_rows++;
} }
@ -164,6 +165,12 @@ void buffer_free(struct buffer *buffer) {
buffer_free_rows(buffer); buffer_free_rows(buffer);
} }
size_t buffer_get_crow_len(struct buffer *buffer) {
struct erow *crow = buffer_get_crow(buffer);
return crow ? crow->n_chars : 0;
}
static void buffer_free_rows(struct buffer *buffer) { static void buffer_free_rows(struct buffer *buffer) {
for (int i = 0; i < buffer->n_rows; i++) for (int i = 0; i < buffer->n_rows; i++)
erow_free(buffer->rows[i]); erow_free(buffer->rows[i]);

View file

@ -1,19 +1,16 @@
#include <errno.h> #include <errno.h>
#include <stdbool.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include "buffer.h" #include "buffer.h"
#include "commands.h" #include "commands.h"
#include "cursor.h"
#include "erow.h"
#include "input.h" #include "input.h"
#include "kilo.h" #include "kilo.h"
#include "terminal.h" #include "terminal.h"
#include "utils.h" #include "utils.h"
static void cursor_adjust_viewport(void);
static void cursor_check_file_bounds(bool horizontal);
static void cursor_update_rx(bool horizontal);
void command_quit(void) { void command_quit(void) {
if (E.current_buf->modified && E.quit_times) { if (E.current_buf->modified && E.quit_times) {
editor_set_message("Unsaved changed! Press quit %d more time(s)", E.quit_times); editor_set_message("Unsaved changed! Press quit %d more time(s)", E.quit_times);
@ -25,110 +22,87 @@ void command_quit(void) {
} }
void command_move_cursor(KEY key) { void command_move_cursor(KEY key) {
struct erow *rows = E.current_buf->rows;
int n_rows = E.current_buf->n_rows;
struct erow *erow = (rows && E.cy < n_rows ? rows + E.cy : NULL);
int max_x = (erow ? erow->n_chars : 0);
switch (key) { switch (key) {
case ARROW_LEFT: case ARROW_LEFT:
E.cx--; cursor_move(E.current_buf, -1, 0);
break; break;
case ARROW_DOWN: case ARROW_DOWN:
E.cy++; cursor_move(E.current_buf, 0, 1);
break; break;
case ARROW_UP: case ARROW_UP:
E.cy--; cursor_move(E.current_buf, 0, -1);
break; break;
case ARROW_RIGHT: case ARROW_RIGHT:
E.cx++; cursor_move(E.current_buf, 1, 0);
break; break;
case HOME: case HOME:
E.cx = 0; cursor_move(E.current_buf, -E.current_buf->cx, 0);
break; break;
case END: case END:
E.cx = max_x; cursor_move(E.current_buf, buffer_get_crow_len(E.current_buf) - E.current_buf->cx, 0);
break; break;
case PG_UP: case PG_UP:
E.cy -= E.screenrows; cursor_move(E.current_buf, 0, -E.screenrows);
break; break;
case PG_DOWN: case PG_DOWN:
E.cy += E.screenrows; cursor_move(E.current_buf, 0, E.screenrows);
break; break;
} }
bool horizontal = (key == ARROW_LEFT ||
key == ARROW_RIGHT ||
key == HOME ||
key == END);
cursor_check_file_bounds(horizontal);
cursor_update_rx(horizontal);
cursor_adjust_viewport();
} }
// TODO: Improve this
void command_insert_line(void) { void command_insert_line(void) {
if (E.cy == E.current_buf->n_rows) { struct erow *erow = erow_create(NULL, 0, E.current_buf);
buffer_insert_row(E.current_buf, NULL, 0, E.cy);
if (E.current_buf->cy == E.current_buf->n_rows) {
buffer_insert_row(E.current_buf, erow, E.current_buf->cy);
} else { } else {
buffer_insert_row(E.current_buf, NULL, 0, E.cy + 1); buffer_insert_row(E.current_buf, erow, E.current_buf->cy + 1);
struct erow *c_row = E.current_buf->rows + E.cy; struct erow *crow = buffer_get_crow(E.current_buf);
struct erow *n_row = E.current_buf->rows + E.cy + 1;
erow_append_string(n_row, c_row->chars + E.cx, c_row->n_chars - E.cx); erow_insert_chars(erow, crow->chars + E.current_buf->cx, crow->n_chars - E.current_buf->cx, 0);
erow_delete_chars(crow, crow->n_chars - E.current_buf->cx, E.current_buf->cx);
c_row->chars = realloc(c_row->chars, E.cx);
c_row->n_chars = E.cx;
erow_update_rendering(c_row);
} }
E.cx = E.rx = 0; input_process_key(ARROW_DOWN);
E.cy++; input_process_key(HOME);
cursor_adjust_viewport();
} }
void command_insert_char(char c) { void command_insert_char(char c) {
if (E.cy == E.current_buf->n_rows) struct erow *erow;
buffer_insert_row(E.current_buf, NULL, 0, E.current_buf->n_rows);
erow_insert_char(E.current_buf->rows+E.cy, E.cx++, c); if (E.current_buf->cy == E.current_buf->n_rows) {
E.rx = erow_cx_to_rx(E.current_buf->rows+E.cy, E.cx); erow = erow_create(NULL, 0, E.current_buf);
buffer_insert_row(E.current_buf, erow, E.current_buf->n_rows);
} else erow = buffer_get_crow(E.current_buf);
cursor_adjust_viewport(); erow_insert_chars(erow, &c, 1, E.current_buf->cx);
input_process_key(ARROW_RIGHT);
} }
void command_delete_char(void) { // TODO void command_delete_char(void) {
if (E.cx == 0 && E.cy == 0) return; if (E.current_buf->cy == E.current_buf->n_rows)
if (E.cy == E.current_buf->n_rows) { input_process_key(ARROW_LEFT);
E.cx = E.current_buf->rows[--E.cy].n_chars;
E.rx = erow_cx_to_rx(E.current_buf->rows+E.cy, E.cx); struct erow *crow = buffer_get_crow(E.current_buf);
return;
if (E.current_buf->cx == 0) {
if (E.current_buf->cy == 0)
return;
struct erow *prow = E.current_buf->rows[E.current_buf->cy - 1];
input_process_key(ARROW_UP);
cursor_move(E.current_buf, prow->n_chars, 0);
erow_insert_chars(prow, crow->chars, crow->n_chars, prow->n_chars);
buffer_delete_row(E.current_buf, E.current_buf->cy + 1);
} else {
erow_delete_chars(crow, 1, E.current_buf->cx - 1);
input_process_key(ARROW_LEFT);
} }
if (E.cx > 0) {
erow_delete_char(E.current_buf->rows+E.cy, E.cx - 1);
}
else {
struct erow *c_row = E.current_buf->rows + E.cy;
struct erow *p_row = E.current_buf->rows + E.cy - 1;
E.cx = p_row->n_chars;
erow_append_string(p_row, c_row->chars, c_row->n_chars);
buffer_delete_row(E.current_buf, E.cy);
E.cy--;
}
E.rx = erow_cx_to_rx(E.current_buf->rows+E.cy, E.cx);
cursor_adjust_viewport();
} }
void command_save_buffer(void) { void command_save_buffer(void) {
@ -140,79 +114,11 @@ void command_save_buffer(void) {
} }
} }
int bytes_written; size_t bytes_written;
ERRCODE errcode = buffer_write_file(E.current_buf, &bytes_written); ERRCODE errcode = buffer_write_file(E.current_buf, &bytes_written);
if (errcode == 0) if (errcode == 0)
editor_set_message("%d bytes written", bytes_written); editor_set_message("%d bytes written", bytes_written);
else else
editor_set_message("Save failed: ERRCODE %d: %s", errcode, strerror(errno)); editor_set_message("Write error %d: %s", errcode, strerror(errno));
}
static void cursor_check_file_bounds(bool horizontal) {
struct erow *rows = E.current_buf->rows;
int n_rows = E.current_buf->n_rows;
struct erow *erow = (rows && E.cy < n_rows ? rows + E.cy : NULL);
int max_x = (erow ? erow->n_chars : 0);
if (E.cy < 0)
E.cy = 0;
if (E.cy > n_rows)
E.cy = n_rows;
if (E.cx < 0) {
if (E.cy > 0 && horizontal)
{
erow = &rows[--E.cy];
max_x = erow->n_chars;
E.cx = max_x;
}
else E.cx = 0;
}
if (E.cx > max_x) {
if (E.cy < n_rows && horizontal) {
E.cx = 0;
E.cy++;
} else E.cx = max_x;
}
}
static void cursor_update_rx(bool horizontal) {
struct erow *rows = E.current_buf->rows;
int n_rows = E.current_buf->n_rows;
struct erow *erow = (rows && E.cy < n_rows ? rows + E.cy : NULL);
int max_x = (erow ? erow->n_chars : 0);
static int saved_rx = 0;
if (horizontal) saved_rx = erow_cx_to_rx(erow, E.cx);
else {
E.cx = erow_rx_to_cx(erow, saved_rx);
if (E.cx > max_x)
E.cx = max_x;
}
E.rx = erow_cx_to_rx(rows + E.cy, E.cx);
}
static void cursor_adjust_viewport(void) {
int max_row_off = E.cy;
if (E.row_off > max_row_off)
E.row_off = max_row_off;
int max_col_off = E.rx;
if (E.col_off > max_col_off)
E.col_off = max_col_off;
int min_row_off = E.cy - (E.screenrows - 1);
if (E.row_off < min_row_off)
E.row_off = min_row_off;
int min_col_off = E.rx - (E.screencols - 1);
if (E.col_off < min_col_off)
E.col_off = min_col_off;
} }

45
src/cursor.c Normal file
View file

@ -0,0 +1,45 @@
#include "buffer.h"
#include "cursor.h"
#include "erow.h"
#include "kilo.h"
#include "utils.h"
static void cursor_adjust_viewport(struct buffer *buffer);
void cursor_move(struct buffer *buffer, int dx, int dy) {
static int saved_rx = 0;
buffer->cy = CLAMP(buffer->cy + dy, 0, buffer->n_rows);
if (dx == 0)
E.current_buf->cx = erow_rx_to_cx(buffer_get_crow(E.current_buf), saved_rx);
int new_x = buffer->cx + dx, max_x = buffer_get_crow_len(buffer);
if (new_x < 0) {
if (buffer->cy > 0) {
buffer->cy--;
buffer->cx = buffer_get_crow_len(buffer);
} else buffer->cx = 0;
} else if (new_x > max_x) {
if (buffer->cy < buffer->n_rows) {
buffer->cy++;
buffer->cx = 0;
} else buffer->cx = max_x;
} else buffer->cx = new_x;
cursor_adjust_viewport(buffer);
buffer->rx = erow_cx_to_rx(buffer_get_crow(buffer), buffer->cx);
if (dy == 0)
saved_rx = buffer->rx;
}
static void cursor_adjust_viewport(struct buffer *buffer) {
int min_row_off = buffer->cy - (E.screenrows - 1);
int max_row_off = buffer->cy;
buffer->row_off = CLAMP(buffer->row_off, min_row_off, max_row_off);
int min_col_off = buffer->rx - (E.screencols - 1);
int max_col_off = buffer->rx;
buffer->col_off = CLAMP(buffer->col_off, min_col_off, max_col_off);
}

View file

@ -1,9 +1,11 @@
#include <stdbool.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include "buffer.h" #include "buffer.h"
#include "erow.h" #include "erow.h"
#include "kilo.h" #include "kilo.h"
#include "utils.h"
static void erow_update_rchars(struct erow *erow); static void erow_update_rchars(struct erow *erow);
@ -14,6 +16,8 @@ struct erow *erow_create(const char* chars, size_t n_chars, struct buffer *buffe
erow->n_chars = n_chars; erow->n_chars = n_chars;
memcpy(erow->chars, chars, erow->n_chars); memcpy(erow->chars, chars, erow->n_chars);
erow->rchars = NULL;
erow_update_rchars(erow); erow_update_rchars(erow);
erow->buffer = buffer; erow->buffer = buffer;
@ -23,7 +27,7 @@ struct erow *erow_create(const char* chars, size_t n_chars, struct buffer *buffe
void erow_insert_chars(struct erow *erow, const char *chars, size_t n_chars, int at) { void erow_insert_chars(struct erow *erow, const char *chars, size_t n_chars, int at) {
erow->chars = realloc(erow->chars, erow->n_chars + n_chars); erow->chars = realloc(erow->chars, erow->n_chars + n_chars);
memmove(erow->chars + at + n_chars, erow->chars + at, n_chars - at); memmove(erow->chars + at + n_chars, erow->chars + at, erow->n_chars - at);
memcpy(erow->chars + at, chars, n_chars); memcpy(erow->chars + at, chars, n_chars);
erow->n_chars += n_chars; erow->n_chars += n_chars;
@ -34,9 +38,9 @@ void erow_insert_chars(struct erow *erow, const char *chars, size_t n_chars, int
erow->buffer->modified = true; erow->buffer->modified = true;
} }
void erow_delete_char(struct erow *erow, int at) { void erow_delete_chars(struct erow *erow, size_t n_chars, int at) {
memmove(erow->chars + at, erow->chars + at + 1, erow->n_chars - at); memmove(erow->chars + at, erow->chars + at + n_chars, erow->n_chars - at - n_chars);
erow->chars = realloc(erow->chars, --erow->n_chars); erow->chars = realloc(erow->chars, erow->n_chars -= n_chars);
erow_update_rchars(erow); erow_update_rchars(erow);
@ -45,6 +49,11 @@ void erow_delete_char(struct erow *erow, int at) {
} }
int erow_cx_to_rx(struct erow *erow, int cx) { int erow_cx_to_rx(struct erow *erow, int cx) {
if (erow == NULL)
return 0;
cx = CLAMP(cx, 0, (int) erow->n_chars);
int rx = 0; int rx = 0;
for (char *c = erow->chars; c < erow->chars + cx; c++) { for (char *c = erow->chars; c < erow->chars + cx; c++) {
@ -58,17 +67,18 @@ int erow_cx_to_rx(struct erow *erow, int cx) {
} }
int erow_rx_to_cx(struct erow *erow, int rx) { int erow_rx_to_cx(struct erow *erow, int rx) {
if ((size_t) rx >= erow->n_rchars) if (erow == NULL)
return erow->n_chars; return 0;
int c_rx = 0; int cx = 0, c_rx = 0;
while ((size_t) cx < erow->n_chars) {
for (int cx = 0; (size_t) cx < erow->n_chars; cx++) {
if (erow->chars[cx] == '\t') if (erow->chars[cx] == '\t')
c_rx += KILO_TAB_STOP - (c_rx % KILO_TAB_STOP); c_rx += KILO_TAB_STOP - (c_rx % KILO_TAB_STOP);
else else
c_rx++; c_rx++;
cx++;
if (c_rx >= rx) if (c_rx >= rx)
return cx; return cx;
} }
@ -86,7 +96,7 @@ static void erow_update_rchars(struct erow *erow) {
free(erow->rchars); free(erow->rchars);
size_t n_rchars_max = 16; size_t n_rchars_max = 16;
erow->rchars = malloc(erow->n_rchars); erow->rchars = malloc(n_rchars_max);
erow->n_rchars = 0; erow->n_rchars = 0;
for (char *c = erow->chars; c < erow->chars + erow->n_chars; c++) { for (char *c = erow->chars; c < erow->chars + erow->n_chars; c++) {

View file

@ -1,12 +1,8 @@
#include "commands.h" #include "commands.h"
#include "input.h" #include "input.h"
#include "kilo.h" #include "kilo.h"
#include "terminal.h"
#include "utils.h"
void input_process_key(void) {
KEY c = terminal_read_key();
void input_process_key(KEY c) {
switch (c) { switch (c) {
case ARROW_LEFT: case ARROW_LEFT:
case ARROW_DOWN: case ARROW_DOWN:
@ -20,7 +16,7 @@ void input_process_key(void) {
break; break;
case CTRL_KEY('S'): case CTRL_KEY('S'):
command_save_buffer(); // command_save_buffer();
break; break;
case ENTER: case ENTER:
@ -28,7 +24,7 @@ void input_process_key(void) {
break; break;
case DEL: case DEL:
command_move_cursor(ARROW_RIGHT); input_process_key(ARROW_RIGHT);
case BACKSPACE: case BACKSPACE:
case CTRL_KEY('H'): case CTRL_KEY('H'):
command_delete_char(); command_delete_char();

View file

@ -22,7 +22,7 @@ int main(int argc, char **argv) {
while (true) { while (true) {
ui_draw_screen(); ui_draw_screen();
input_process_key(); input_process_key(terminal_read_key());
} }
return 0; return 0;

View file

@ -6,6 +6,7 @@
#include <unistd.h> #include <unistd.h>
#include "buffer.h" #include "buffer.h"
#include "erow.h"
#include "kilo.h" #include "kilo.h"
#include "terminal.h" #include "terminal.h"
#include "ui.h" #include "ui.h"
@ -44,7 +45,7 @@ static void ui_draw_rows(struct append_buf *draw_buf) {
bool no_file = (E.current_buf->filename == NULL && E.current_buf->n_rows == 0); bool no_file = (E.current_buf->filename == NULL && E.current_buf->n_rows == 0);
if (in_file) { if (in_file) {
struct erow *crow = buffer_get_crow(E.current_buf); struct erow *crow = E.current_buf->rows[y + E.current_buf->row_off];
size_t len = crow->n_rchars - E.current_buf->col_off; size_t len = crow->n_rchars - E.current_buf->col_off;
len = MIN(len, (size_t) E.screencols); len = MIN(len, (size_t) E.screencols);