diff --git a/.gitignore b/.gitignore index 5b988c6..c30cc64 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ kilo .cache .clangd compile_commands.json +test_file diff --git a/include/buffer.h b/include/buffer.h index 10695e0..5f7a3ad 100644 --- a/include/buffer.h +++ b/include/buffer.h @@ -1,6 +1,8 @@ #ifndef BUFFER_H #define BUFFER_H +#include + #include "utils.h" struct erow { @@ -15,6 +17,7 @@ struct buffer { char *filename; struct erow *rows; int n_rows; + bool modified; }; struct buffer *buffer_create(void); @@ -24,6 +27,7 @@ ERRCODE buffer_write_file(struct buffer *buffer); void erow_update_rendering(struct erow *erow); void erow_insert_char(struct erow *erow, int at, char c); +void erow_delete_char(struct erow *erow, int at); int erow_cx_to_rx(struct erow *erow, int cx); int erow_rx_to_cx(struct erow *erow, int rx); diff --git a/include/commands.h b/include/commands.h index 0b2881e..1292cce 100644 --- a/include/commands.h +++ b/include/commands.h @@ -3,8 +3,10 @@ #include "input.h" +void command_quit(void); void command_move_cursor(KEY key); void command_insert_char(char c); +void command_delete_char(void); void command_save_buffer(void); #endif // COMMANDS_H diff --git a/include/kilo.h b/include/kilo.h index 169821c..4018fb3 100644 --- a/include/kilo.h +++ b/include/kilo.h @@ -11,6 +11,7 @@ struct editor_state { int cx, cy, rx; int row_off, col_off; int screenrows, screencols; + int quit_times; struct buffer *current_buf; struct termios orig_termios; diff --git a/include/utils.h b/include/utils.h index c2132db..efa9ef9 100644 --- a/include/utils.h +++ b/include/utils.h @@ -7,6 +7,7 @@ #define MIN(a,b) (((a)<(b))?(a):(b)) typedef int ERRCODE; +#define RETURN(code) do {errcode = code; goto END;} while(0) void die(const char *context); diff --git a/src/buffer.c b/src/buffer.c index 9423a31..2900052 100644 --- a/src/buffer.c +++ b/src/buffer.c @@ -10,15 +10,17 @@ #include "utils.h" static void buffer_free_rows(struct buffer *buffer); +static char *buffer_get_string(struct buffer *buffer, size_t *len_p); struct buffer *buffer_create(void) { - struct buffer *buf = malloc(sizeof(struct buffer)); + struct buffer *buffer = malloc(sizeof(struct buffer)); - buf->filename = NULL; - buf->rows = NULL; - buf->n_rows = 0; + buffer->filename = NULL; + buffer->rows = NULL; + buffer->n_rows = 0; + buffer->modified = false; - return buf; + return buffer; } // TODO: Handle file not existing @@ -57,33 +59,40 @@ void buffer_read_file(struct buffer *buffer, const char *filename) { free(line_buffer); fclose(file); + + buffer->modified = false; } ERRCODE buffer_write_file(struct buffer *buffer) { + ERRCODE errcode = 0; + + int fd = -1; + char *write_buffer = NULL; + if (buffer->filename == NULL) - return -1; + RETURN(-1); - size_t len = 0; + size_t len; + write_buffer = buffer_get_string(buffer, &len); - for (int i = 0; i < buffer->n_rows; i++) - len += buffer->rows[i].n_chars + 1; + fd = open(buffer->filename, O_RDWR | O_TRUNC | O_CREAT, 0644); + if (fd == -1) + RETURN(-2); - char *write_buffer = malloc(len); - char *p = write_buffer; - for (int i = 0; i < buffer->n_rows; i++) { - struct erow *row = buffer->rows+i; - memcpy(p, row->chars, row->n_chars); - p += row->n_chars; - *p = '\n'; - p++; - } + if (write(fd, write_buffer, len) != (ssize_t) len) + RETURN(-3); - int fd = open(buffer->filename, O_RDWR | O_TRUNC | O_CREAT, 0644); - write(fd, write_buffer, len); - close(fd); - free(write_buffer); +END: + if (fd != -1) + close(fd); - return 0; + if (write_buffer) + free(write_buffer); + + if (errcode == 0) + buffer->modified = false; + + return errcode; } void buffer_append_row(struct buffer *buffer, const char *chars, int n_chars) { @@ -98,6 +107,8 @@ void buffer_append_row(struct buffer *buffer, const char *chars, int n_chars) { new_row->n_rchars = 0; erow_update_rendering(new_row); + + buffer->modified = true; } void buffer_free(struct buffer *buffer) { @@ -112,6 +123,25 @@ static void buffer_free_rows(struct buffer *buffer) { } } +static char *buffer_get_string(struct buffer *buffer, size_t *len_p) { + *len_p = 0; + + for (int i = 0; i < buffer->n_rows; i++) + *len_p += buffer->rows[i].n_chars + 1; + + char *write_buffer = malloc(*len_p); + char *p = write_buffer; + for (int i = 0; i < buffer->n_rows; i++) { + struct erow *row = buffer->rows+i; + memcpy(p, row->chars, row->n_chars); + p += row->n_chars; + *p = '\n'; + p++; + } + + return write_buffer; +} + /*****************************************************************************/ void erow_update_rendering(struct erow *erow) { @@ -160,6 +190,25 @@ void erow_insert_char(struct erow *erow, int at, char c) { erow->n_chars++; erow_update_rendering(erow); + + // TODO: Seems like a bad idea + E.current_buf->modified = true; +} + +void erow_delete_char(struct erow *erow, int at) { + if (at < 0) at = 0; + if (at > erow->n_chars) at = erow->n_chars; + + if (at != 0) { + memmove(erow->chars + at, erow->chars + at + 1, erow->n_chars - at); + erow->n_chars--; + erow->chars = realloc(erow->chars, erow->n_chars); + E.cx--; + erow_update_rendering(erow); + } + + // TODO + E.current_buf->modified = true; } int erow_cx_to_rx(struct erow *erow, int cx) { diff --git a/src/commands.c b/src/commands.c index 792443b..8fab52c 100644 --- a/src/commands.c +++ b/src/commands.c @@ -1,15 +1,29 @@ +#include #include +#include +#include +#include "buffer.h" #include "commands.h" #include "input.h" #include "kilo.h" -#include "buffer.h" +#include "terminal.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) { + if (E.current_buf->modified && E.quit_times) { + editor_set_message("Unsaved changed! Press quit %d more time(s)", E.quit_times); + E.quit_times--; + } else { + terminal_clear(); + exit(0); + } +} + void command_move_cursor(KEY key) { struct erow *rows = E.current_buf->rows; int n_rows = E.current_buf->n_rows; @@ -47,9 +61,9 @@ void command_move_cursor(KEY key) { } bool horizontal = (key == ARROW_LEFT || - key == ARROW_RIGHT || - key == HOME || - key == END); + key == ARROW_RIGHT || + key == HOME || + key == END); cursor_check_file_bounds(horizontal); cursor_update_rx(horizontal); @@ -64,13 +78,24 @@ void command_insert_char(char c) { E.rx = erow_cx_to_rx(E.current_buf->rows+E.cy, E.cx); } +void command_delete_char(void) { + struct erow *row = E.current_buf->rows + E.cy; + + if (E.cx == 0) { + // TODO + } else + erow_delete_char(row, E.cx); + + E.rx = erow_cx_to_rx(E.current_buf->rows+E.cy, E.cx); +} + void command_save_buffer(void) { ERRCODE errcode = buffer_write_file(E.current_buf); if (errcode == 0) editor_set_message("Saved file %s", E.current_buf->filename); - else if (errcode == -1) - editor_set_message("Save failed, no filename"); + else + editor_set_message("Save failed: ERRCODE %d: %s", errcode, strerror(errno)); } static void cursor_check_file_bounds(bool horizontal) { @@ -87,7 +112,13 @@ static void cursor_check_file_bounds(bool horizontal) { E.cy = n_rows; if (E.cx < 0) { - if (E.cy > 0 && horizontal) E.cx = rows[--E.cy].n_chars; + if (E.cy > 0 && horizontal) + { + current_row = &rows[--E.cy]; + max_x = current_row->n_chars; + + E.cx = max_x; + } else E.cx = 0; } diff --git a/src/input.c b/src/input.c index f0e7f41..d5502e9 100644 --- a/src/input.c +++ b/src/input.c @@ -1,8 +1,9 @@ #include -#include "input.h" -#include "terminal.h" #include "commands.h" +#include "input.h" +#include "kilo.h" +#include "terminal.h" #include "utils.h" void input_process_key(void) { @@ -20,28 +21,31 @@ void input_process_key(void) { command_move_cursor(c); break; + case CTRL_KEY('Q'): + command_quit(); + return; + case CTRL_KEY('S'): command_save_buffer(); break; - case CTRL_KEY('Q'): - terminal_clear(); - exit(0); - break; - case '\r': + // TODO break; case BACKSPACE: case CTRL_KEY('H'): case DEL: + command_delete_char(); break; case CTRL_KEY('L'): - // case NOP: + case NOP: break; default: command_insert_char(c); } + + E.quit_times = 3; } diff --git a/src/kilo.c b/src/kilo.c index 10953fc..3e1324b 100644 --- a/src/kilo.c +++ b/src/kilo.c @@ -40,6 +40,7 @@ void editor_init(char *filename) { if (terminal_get_win_size(&E.screenrows, &E.screencols) == -1) die("term_get_win_size"); E.screenrows -= 2; + E.quit_times = 3; E.current_buf = buffer_create(); if (filename) diff --git a/src/ui.c b/src/ui.c index bafb98a..2ca0151 100644 --- a/src/ui.c +++ b/src/ui.c @@ -72,7 +72,9 @@ static void ui_draw_statusbar(struct append_buf *draw_buf) { ab_append(draw_buf, "\x1b[7m", 4); char *display = E.current_buf->filename ? E.current_buf->filename : "[NO NAME]"; - len = sprintf(buf, "%s -- %d lines", display, E.current_buf->n_rows); + char *modified = E.current_buf->modified ? "(modified) " : ""; + int n_rows = E.current_buf->n_rows; + len = sprintf(buf, "%s %s-- %d lines", display, modified, n_rows); memcpy(status_buf, buf, len); len = sprintf(buf, "%d:%d", E.cy + 1, E.rx + 1);