diff --git a/.gitignore b/.gitignore index 2b9f023..5b988c6 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,5 @@ build/ kilo .cache +.clangd compile_commands.json diff --git a/Makefile b/Makefile index 25695b3..878964a 100644 --- a/Makefile +++ b/Makefile @@ -6,7 +6,7 @@ WARNING_FLAGS := -Wall -Wextra INCLUDE_FLAGS := -I include CC := clang -CFLAGS := $(WARNING_FLAGS) $(INCLUDE_FLAGS) -MMD -MP -std=c99 +CFLAGS := $(WARNING_FLAGS) $(INCLUDE_FLAGS) -MMD -MP -std=c99 -ggdb kilo: $(OBJS) $(CC) $(CFLAGS) $^ -o $@ diff --git a/include/append_buf.h b/include/append_buf.h deleted file mode 100644 index 4db2a71..0000000 --- a/include/append_buf.h +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef APPEND_BUF_H -#define APPEND_BUF_H - -// A simple append only buffer to build strings - -struct append_buf { - char *chars; - int n_chars; -}; - -struct append_buf *ab_init(void); -void ab_append(struct append_buf *ab, const char *chars, int n_chars); -void ab_free(struct append_buf *ab); - -#endif // APPEND_BUF_H diff --git a/include/buffer.h b/include/buffer.h new file mode 100644 index 0000000..14d4aa2 --- /dev/null +++ b/include/buffer.h @@ -0,0 +1,26 @@ +#ifndef BUFFER_H +#define BUFFER_H + +struct erow { + char *chars; + int n_chars; + + char *rchars; + int n_rchars; +}; + +struct buffer { + char *filename; + struct erow *rows; + int n_rows; +}; + +struct buffer *buffer_create(void); +void buffer_read_file(struct buffer *buffer, const char *filename); +void buffer_append_row(struct buffer *buffer, const char *chars, int n_chars); + +void erow_update_rendering(struct erow *erow); +int erow_cx_to_rx(struct erow *erow, int cx); +int erow_rx_to_cx(struct erow *erow, int rx); + +#endif // BUFFER_H diff --git a/include/commands.h b/include/commands.h new file mode 100644 index 0000000..a08b6f5 --- /dev/null +++ b/include/commands.h @@ -0,0 +1,8 @@ +#ifndef COMMANDS_H +#define COMMANDS_H + +#include "input.h" + +void editor_move_cursor(KEY key); + +#endif // COMMANDS_H diff --git a/include/input.h b/include/input.h new file mode 100644 index 0000000..39a3676 --- /dev/null +++ b/include/input.h @@ -0,0 +1,23 @@ +#ifndef INPUT_H +#define INPUT_H + +#include + +enum KEYS { + TAB = 9, + HOME = 0x100, + DEL, + PG_UP, + PG_DOWN, + END, + ARROW_UP, + ARROW_DOWN, + ARROW_LEFT, + ARROW_RIGHT, + NOP +}; +typedef uint16_t KEY; + +void input_process_key(void); + +#endif // INPUT_H diff --git a/include/kilo.h b/include/kilo.h index ea845b0..c63200a 100644 --- a/include/kilo.h +++ b/include/kilo.h @@ -1,47 +1,23 @@ #ifndef KILO_H #define KILO_H -#include -#include +#define KILO_VERSION "0.0.1" +#define KILO_TAB_STOP 4 + #include #include -// Stuff I couldn' figure out where else to put - -typedef int ERRCODE; - struct editor_state { - char *filename; - int cx, cy; - int rx; - int screenrows, screencols; + int cx, cy, rx; int row_off, col_off; + int screenrows, screencols; - struct EROW *rows; - int n_rows; + struct buffer *current_buf; + struct termios orig_termios; char message[256]; time_t message_time; - - struct termios orig_termios; }; extern struct editor_state E; -enum KEYS { - TAB = 9, - HOME = 0x100, - DEL, - PG_UP, - PG_DOWN, - END, - ARROW_UP, - ARROW_DOWN, - ARROW_LEFT, - ARROW_RIGHT, - NOP -}; -typedef uint16_t KEY; - -void die(const char *context); - #endif // KILO_H diff --git a/include/terminal.h b/include/terminal.h index 356a471..616c13c 100644 --- a/include/terminal.h +++ b/include/terminal.h @@ -1,9 +1,8 @@ #ifndef TERMINAL_H #define TERMINAL_H -#include - -#include "kilo.h" +#include "input.h" +#include "utils.h" // Functions to perform low level terminal operations, using escape codes diff --git a/include/ui.h b/include/ui.h new file mode 100644 index 0000000..9fd9dd6 --- /dev/null +++ b/include/ui.h @@ -0,0 +1,6 @@ +#ifndef UI_H +#define UI_H + +void ui_draw_screen(void); + +#endif // UI_H diff --git a/include/utils.h b/include/utils.h new file mode 100644 index 0000000..c2132db --- /dev/null +++ b/include/utils.h @@ -0,0 +1,24 @@ +#ifndef UTIL_H +#define UTIL_H + +#define CTRL_KEY(key) ((key) & 0x1f) + +#define MAX(a,b) (((a)>(b))?(a):(b)) +#define MIN(a,b) (((a)<(b))?(a):(b)) + +typedef int ERRCODE; + +void die(const char *context); + +/*****************************************************************************/ + +struct append_buf { + char *chars; + int n_chars; +}; + +struct append_buf *ab_create(void); +void ab_append(struct append_buf *ab, const char *chars, int n_chars); +void ab_free(struct append_buf *ab); + +#endif // APPEND_BUF_H diff --git a/src/buffer.c b/src/buffer.c new file mode 100644 index 0000000..18f48fb --- /dev/null +++ b/src/buffer.c @@ -0,0 +1,149 @@ +#include +#include +#include +#include + +#include "buffer.h" +#include "kilo.h" +#include "utils.h" + +static void buffer_free_rows(struct buffer *buffer); + +struct buffer *buffer_create(void) { + struct buffer *buf = malloc(sizeof(struct buffer)); + + buf->filename = NULL; + buf->rows = NULL; + buf->n_rows = 0; + + return buf; +} + +void buffer_read_file(struct buffer *buffer, const char *filename) { + if (buffer->filename) + free(buffer->filename); + + if (buffer->rows) + buffer_free_rows(buffer); + + size_t filename_len = strlen(filename); + buffer->filename = malloc(filename_len); + memcpy(buffer->filename, filename, filename_len); + + FILE *file = fopen(filename, "r"); + if (!file) die("fopen"); + + size_t line_buffer_size = 64; + char *line_buffer = malloc(line_buffer_size); + + bool file_remaining = true; + while (file_remaining) { + char c; + int i; + + for (i = 0; (c = getc(file)) != '\n' && c != EOF; i++) { + if (i >= (int) line_buffer_size) + line_buffer = realloc(line_buffer, line_buffer_size *= 2); + + line_buffer[i] = c; + } + + buffer_append_row(buffer, line_buffer, i); + file_remaining = (c != EOF); + } + + free(line_buffer); + fclose(file); +} + +void buffer_append_row(struct buffer *buffer, const char *chars, int n_chars) { + buffer->rows = realloc(buffer->rows, sizeof(struct erow) * (buffer->n_rows + 1)); + struct erow *new_row = &buffer->rows[buffer->n_rows++]; + + new_row->chars = malloc(n_chars); + memcpy(new_row->chars, chars, n_chars); + new_row->n_chars = n_chars; + + erow_update_rendering(new_row); +} + +void buffer_free(struct buffer *buffer) { + free(buffer->filename); + buffer_free_rows(buffer); +} + +static void buffer_free_rows(struct buffer *buffer) { + for (int i = 0; i < buffer->n_rows; i++) { + if (buffer->rows->chars) free(buffer->rows->chars); + if (buffer->rows->rchars) free(buffer->rows->rchars); + } +} + +/*****************************************************************************/ + +void erow_update_rendering(struct erow *erow) { + size_t line_buffer_size = 64; + char *line_buffer = malloc(line_buffer_size); + size_t n_rchars = 0; + + for (int i = 0; i < erow->n_chars; i++) { + switch (erow->chars[i]) { + case '\t': { + int spaces = KILO_TAB_STOP - (n_rchars % KILO_TAB_STOP); + while (spaces--) { + if (n_rchars >= line_buffer_size) + line_buffer = realloc(line_buffer, 2*line_buffer_size); + + line_buffer[n_rchars++] = ' '; + } + break; + } + default: + if (n_rchars >= line_buffer_size) + line_buffer = realloc(line_buffer, 2*line_buffer_size); + + line_buffer[n_rchars++] = erow->chars[i]; + } + } + + if (erow->rchars) + free(erow->rchars); + + erow->rchars = malloc(n_rchars); + erow->n_rchars = n_rchars; + memcpy(erow->rchars, line_buffer, n_rchars); + + free(line_buffer); +} + +int erow_cx_to_rx(struct erow *erow, int cx) { + int rx = 0; + + if (erow == NULL) + return 0; + + for (int i = 0; i < MIN(cx, erow->n_chars); i++) { + if (erow->chars[i] == '\t') + rx += KILO_TAB_STOP - (rx % KILO_TAB_STOP); + else rx++; + } + + return rx; +} + +int erow_rx_to_cx(struct erow *erow, int rx) { + int cx = 0, _rx = 0; + + if (erow == NULL) + return 0; + + while (_rx < rx && cx < erow->n_chars) { + if (erow->chars[cx] == '\t') { + _rx += KILO_TAB_STOP - (_rx % KILO_TAB_STOP); + } else _rx++; + + cx++; + } + + return (_rx >= rx ? cx : erow->n_chars); +} diff --git a/src/commands.c b/src/commands.c new file mode 100644 index 0000000..c6d07a0 --- /dev/null +++ b/src/commands.c @@ -0,0 +1,79 @@ +#include + +#include "commands.h" +#include "kilo.h" +#include "buffer.h" + +void editor_move_cursor(KEY key) { + struct erow *rows = E.current_buf->rows; + int n_rows = E.current_buf->n_rows; + + struct erow *current_row = (E.cy < n_rows ? rows + E.cy : NULL); + int max_x = (current_row ? current_row->n_chars : 0); + + switch (key) { + case ARROW_LEFT: + if (E.cx > 0) E.cx--; + else if (E.cy > 0) E.cx = rows[--E.cy].n_chars; + break; + case ARROW_DOWN: + if (E.cy < n_rows) E.cy++; + break; + case ARROW_UP: + if (E.cy > 0) E.cy--; + break; + case ARROW_RIGHT: + if (E.cx < max_x) E.cx++; + else if (E.cy < n_rows) { + E.cx = 0; + E.cy++; + } + break; + + case HOME: + E.cx = 0; + break; + case END: + E.cx = max_x; + break; + + case PG_UP: + if ((E.cy -= E.screenrows) < 0) + E.cy = 0; + break; + case PG_DOWN: + if ((E.cy += E.screenrows) > n_rows) + E.cy = n_rows; + break; + } + + current_row = (E.cy < n_rows ? rows + E.cy : NULL); + max_x = (current_row ? current_row->n_chars : 0); + + static int saved_rx = 0; + bool horizontal = (key == ARROW_LEFT || key == ARROW_RIGHT || + key == HOME || key == END); + if (horizontal) saved_rx = erow_cx_to_rx(current_row, E.cx); + else E.cx = erow_rx_to_cx(current_row, saved_rx); + + if (E.cx > max_x) + E.cx = max_x; + + E.rx = erow_cx_to_rx(&E.current_buf->rows[E.cy], E.cx); + + 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; +} diff --git a/src/input.c b/src/input.c new file mode 100644 index 0000000..2f88de1 --- /dev/null +++ b/src/input.c @@ -0,0 +1,27 @@ +#include + +#include "input.h" +#include "terminal.h" +#include "commands.h" + +void input_process_key(void) { + KEY c = terminal_read_key(); + + switch (c) { + case ARROW_LEFT: + case ARROW_DOWN: + case ARROW_UP: + case ARROW_RIGHT: + case HOME: + case END: + case PG_UP: + case PG_DOWN: + editor_move_cursor(c); + break; + + case CTRL_KEY('Q'): + terminal_clear(); + exit(0); + break; + } +} diff --git a/src/kilo.c b/src/kilo.c index 8a4cb05..d002726 100644 --- a/src/kilo.c +++ b/src/kilo.c @@ -1,146 +1,53 @@ -#define _DEFAULT_SOURCE - -#define KILO_VERSION "0.0.1" -#define KILO_TAB_STOP 4 - #include +#include #include #include -#include #include +#include "buffer.h" #include "kilo.h" -#include "append_buf.h" +#include "ui.h" +#include "input.h" #include "terminal.h" -#define CTRL_KEY(key) ((key) & 0x1f) - -#define MAX(a,b) (((a)>(b))?(a):(b)) -#define MIN(a,b) (((a)<(b))?(a):(b)) - -/*****************************************************************************/ - -struct EROW { - char *chars; - int n_chars; - - char *rchars; - int n_rchars; -}; +void editor_init(char *filename); +void editor_set_message(const char *, ...); struct editor_state E; -/*****************************************************************************/ - -void editor_init(void); -void editor_open(const char *); -void editor_append_row(const char *, int); -void editor_set_message(const char *, ...); - -void editor_redraw_screen(void); -void editor_draw_rows(struct append_buf *); -void editor_draw_statusbar(struct append_buf *); -void editor_draw_messagebar(struct append_buf *); - -void editor_process_key(void); -void editor_move_cursor(KEY); -void editor_adjust_viewport(void); -int editor_get_rx(int); -int editor_get_cx(int); - -/*****************************************************************************/ - int main(int argc, char **argv) { - editor_init(); - - if (argc >= 2) - editor_open(argv[1]); + editor_init(argc >= 2 ? argv[1] : NULL); while (true) { - editor_redraw_screen(); - editor_process_key(); + ui_draw_screen(); + input_process_key(); } return 0; } -/*****************************************************************************/ - -void editor_init(void) { +void editor_init(char *filename) { if (!isatty(STDIN_FILENO)) { printf("kilo only supports a terminal at standard in. Exiting."); exit(1); } if (terminal_enable_raw() == -1) die("term_enable_raw"); - if (terminal_get_win_size(&E.screenrows, &E.screencols) == -1) - die("term_get_win_size"); - E.filename = NULL; - E.cx = E.cy = 0; - E.rx = 0; - E.screenrows -= 2; + E.cx = E.cy = E.rx = 0; E.row_off = E.col_off = 0; - E.rows = NULL; - E.n_rows = 0; + if (terminal_get_win_size(&E.screenrows, &E.screencols) == -1) + die("term_get_win_size"); + E.screenrows -= 2; + + E.current_buf = buffer_create(); + if (filename) + buffer_read_file(E.current_buf, filename); editor_set_message("Welcome to kilo. Press CTRL-Q to quit."); } -void editor_open(const char *filename) { - free(E.filename); - E.filename = strdup(filename); - - FILE *file = fopen(E.filename, "r"); - if (!file) die("fopen"); - - char *line = NULL; - size_t linecap = 0; - int linelen = -1; - - while ((linelen = getline(&line, &linecap, file)) != -1) { - while (linelen > 0 && (line[linelen-1] == '\n' || line[linelen-1] == '\r')) - linelen--; - - editor_append_row(line, linelen); - } - - free(line); - fclose(file); -} - -void editor_append_row(const char *s, int len) { - E.rows = realloc(E.rows, sizeof(struct EROW) * (E.n_rows + 1)); - struct EROW *new_row = E.rows + E.n_rows; - - new_row->chars = malloc(len); - new_row->n_chars = len; - - struct append_buf *sb = ab_init(); - for (int i = 0; i < len; i++) { - new_row->chars[i] = s[i]; - - switch (s[i]) { - case TAB: { - int tabs = KILO_TAB_STOP - (sb->n_chars % KILO_TAB_STOP); - while (tabs--) ab_append(sb, " ", 1); - break; - } - default: - ab_append(sb, s+i, 1); - } - } - - new_row->rchars = malloc(sb->n_chars); - new_row->n_rchars = sb->n_chars; - memcpy(new_row->rchars, sb->chars, sb->n_chars); - - ab_free(sb); - - E.n_rows++; -} - void editor_set_message(const char *fmt, ...) { va_list ap; va_start(ap, fmt); @@ -149,217 +56,3 @@ void editor_set_message(const char *fmt, ...) { E.message_time = time(NULL); } - - -void editor_redraw_screen(void) { - if (terminal_cursor_visibility(CURSOR_HIDDEN) == -1) - die("term_cursor_hidden"); - - - struct append_buf *draw_buf = ab_init(); - - editor_draw_rows(draw_buf); - editor_draw_statusbar(draw_buf); - editor_draw_messagebar(draw_buf); - - write(STDIN_FILENO, draw_buf->chars, draw_buf->n_chars); - ab_free(draw_buf); - - int row_pos = E.cy - E.row_off + 1; - int col_pos = E.rx - E.col_off + 1; - if (terminal_set_cursor_pos(row_pos, col_pos) == -1) - die("term_set_cursor_pos"); - - if (terminal_cursor_visibility(CURSOR_SHOWN) == -1) - die("term_cursor_hidden"); -} - -void editor_draw_rows(struct append_buf *draw_buf) { - terminal_set_cursor_pos(1, 1); - for (int y = 0; y < E.screenrows; y++) { - bool in_file = y < E.n_rows - E.row_off; - bool no_file = E.n_rows == 0; - - if (in_file) { - struct EROW curr_row = E.rows[y + E.row_off]; - int max_len = MIN(curr_row.n_rchars - E.col_off, E.screencols); - - ab_append(draw_buf, curr_row.rchars + E.col_off, MAX(max_len, 0)); - } else if (no_file && y == E.screenrows / 2) { - char welcome[64]; - int len = snprintf(welcome, sizeof(welcome), - "Welcome to kilo! -- v%s", KILO_VERSION); - - int padding = (E.screencols - len) / 2; - for (int i = 0; i < padding; i++) - ab_append(draw_buf, (i == 0 ? "~" : " "), 1); - - ab_append(draw_buf, welcome, len); - } else ab_append(draw_buf, "~", 1); - - ab_append(draw_buf, "\x1b[K\r\n", 5); - } -} - -void editor_draw_statusbar(struct append_buf *draw_buf) { - char *status_buf = malloc(E.screencols), buf[256]; - int len; - - memset(status_buf, ' ', E.screencols); - - ab_append(draw_buf, "\x1b[7m", 4); - - len = sprintf(buf, "%s -- %d lines", - (E.filename ? E.filename : "[NO NAME]"), E.n_rows); - memcpy(status_buf, buf, len); - - len = sprintf(buf, "%d:%d", E.cy + 1, E.rx + 1); - memcpy(status_buf + E.screencols - len, buf, len); - - ab_append(draw_buf, status_buf, E.screencols); - ab_append(draw_buf, "\x1b[m\r\n", 5); - - free(status_buf); -} -void editor_draw_messagebar(struct append_buf *draw_buf) { - ab_append(draw_buf, "\x1b[K", 3); - - int len = strlen(E.message); - if (len > E.screencols) len = E.screencols; - - if (len && time(NULL) - E.message_time < 5) - ab_append(draw_buf, E.message, len); -} - - -void editor_process_key(void) { - KEY c = terminal_read_key(); - - switch (c) { - case ARROW_LEFT: - case ARROW_DOWN: - case ARROW_UP: - case ARROW_RIGHT: - case HOME: - case END: - case PG_UP: - case PG_DOWN: - editor_move_cursor(c); - break; - - case CTRL_KEY('Q'): - terminal_clear(); - exit(0); - break; - } -} - -void editor_move_cursor(KEY key) { - int max_x = (E.cy < E.n_rows ? E.rows[E.cy].n_chars : 0); - - switch (key) { - case ARROW_LEFT: - if (E.cx > 0) E.cx--; - else if (E.cy > 0) E.cx = E.rows[--E.cy].n_chars; - break; - case ARROW_DOWN: - if (E.cy < E.n_rows) E.cy++; - break; - case ARROW_UP: - if (E.cy > 0) E.cy--; - break; - case ARROW_RIGHT: - if (E.cx < max_x) E.cx++; - else if (E.cy < E.n_rows) { - E.cx = 0; - E.cy++; - } - break; - - case HOME: - E.cx = 0; - break; - case END: - E.cx = max_x; - break; - - case PG_UP: - if ((E.cy -= E.screenrows) < 0) - E.cy = 0; - break; - case PG_DOWN: - if ((E.cy += E.screenrows) > E.n_rows) - E.cy = E.n_rows; - break; - } - - static int saved_rx = 0; - bool horizontal = (key == ARROW_LEFT || key == ARROW_RIGHT || - key == HOME || key == END); - if (horizontal) saved_rx = editor_get_rx(E.cx); - else E.cx = editor_get_cx(saved_rx); - - max_x = (E.cy < E.n_rows ? E.rows[E.cy].n_chars : 0); - if (E.cx > max_x) - E.cx = max_x; - - E.rx = editor_get_rx(E.cx); - editor_adjust_viewport(); -} - -void editor_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; -} - -int editor_get_rx(int cx) { - if (E.cy >= E.n_rows) return 0; - int rx = 0; - - struct EROW *row = E.rows+E.cy; - for (int i = 0; i < MIN(cx, row->n_chars); i++) { - if (row->chars[i] == TAB) - rx += KILO_TAB_STOP - (rx % KILO_TAB_STOP); - else rx++; - } - - return rx; -} - -int editor_get_cx(int rx_target) { - if (E.cy >= E.n_rows) return 0; - int cx = 0, rx = 0; - - struct EROW *row = E.rows+E.cy; - while (rx < rx_target && cx < row->n_chars) { - if (row->chars[cx] == TAB) { - rx += KILO_TAB_STOP - (rx % KILO_TAB_STOP); - } else rx++; - - cx++; - } - - return (rx >= rx_target ? cx : row->n_chars); -} - -/*****************************************************************************/ - -void die(const char *s) { - terminal_clear(); - - perror(s); - exit(1); -} diff --git a/src/terminal.c b/src/terminal.c index d724788..2a46376 100644 --- a/src/terminal.c +++ b/src/terminal.c @@ -5,6 +5,7 @@ #include #include "kilo.h" +#include "utils.h" #include "terminal.h" ERRCODE terminal_enable_raw(void) { diff --git a/src/ui.c b/src/ui.c new file mode 100644 index 0000000..bafb98a --- /dev/null +++ b/src/ui.c @@ -0,0 +1,95 @@ +#include +#include +#include +#include +#include + +#include "buffer.h" +#include "kilo.h" +#include "terminal.h" +#include "ui.h" +#include "utils.h" + +static void ui_draw_rows(struct append_buf *draw_buffer); +static void ui_draw_statusbar(struct append_buf *draw_buffer); +static void ui_draw_messagebar(struct append_buf *draw_buffer); + +void ui_draw_screen(void) { + if (terminal_cursor_visibility(CURSOR_HIDDEN) == -1) + die("term_cursor_hidden"); + + struct append_buf *draw_buf = ab_create(); + + ui_draw_rows(draw_buf); + ui_draw_statusbar(draw_buf); + ui_draw_messagebar(draw_buf); + + write(STDIN_FILENO, draw_buf->chars, draw_buf->n_chars); + ab_free(draw_buf); + + int row_pos = E.cy - E.row_off + 1; + int col_pos = E.rx - E.col_off + 1; + if (terminal_set_cursor_pos(row_pos, col_pos) == -1) + die("term_set_cursor_pos"); + + if (terminal_cursor_visibility(CURSOR_SHOWN) == -1) + die("term_cursor_hidden"); +} + +static void ui_draw_rows(struct append_buf *draw_buf) { + terminal_set_cursor_pos(1, 1); + for (int y = 0; y < E.screenrows; y++) { + bool in_file = (y < E.current_buf->n_rows - E.row_off); + bool no_file = (E.current_buf->n_rows == 0); + + if (in_file) { + struct erow curr_row = E.current_buf->rows[y + E.row_off]; + int max_len = MIN(curr_row.n_rchars - E.col_off, E.screencols); + + ab_append(draw_buf, curr_row.rchars + E.col_off, MAX(max_len, 0)); + } else if (no_file && y == E.screenrows / 2) { + char welcome[64]; + int len = snprintf(welcome, sizeof(welcome), + "Welcome to kilo! -- v%s", KILO_VERSION); + + int padding = (E.screencols - len) / 2; + for (int i = 0; i < padding; i++) + ab_append(draw_buf, (i == 0 ? "~" : " "), 1); + + ab_append(draw_buf, welcome, len); + } else ab_append(draw_buf, "~", 1); + + ab_append(draw_buf, "\x1b[K\r\n", 5); + } +} + +static void ui_draw_statusbar(struct append_buf *draw_buf) { + char *status_buf = malloc(E.screencols), buf[256]; + int len; + + memset(status_buf, ' ', E.screencols); + + 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); + memcpy(status_buf, buf, len); + + len = sprintf(buf, "%d:%d", E.cy + 1, E.rx + 1); + memcpy(status_buf + E.screencols - len, buf, len); + + ab_append(draw_buf, status_buf, E.screencols); + ab_append(draw_buf, "\x1b[m\r\n", 5); + + free(status_buf); +} + +static void ui_draw_messagebar(struct append_buf *draw_buf) { + ab_append(draw_buf, "\x1b[K", 3); + + int len = strlen(E.message); + if (len > E.screencols) len = E.screencols; + + if (len && time(NULL) - E.message_time < 5) + ab_append(draw_buf, E.message, len); +} diff --git a/src/append_buf.c b/src/utils.c similarity index 65% rename from src/append_buf.c rename to src/utils.c index 531e877..f1b27d8 100644 --- a/src/append_buf.c +++ b/src/utils.c @@ -1,9 +1,20 @@ +#include #include #include -#include "append_buf.h" +#include "utils.h" +#include "terminal.h" -struct append_buf *ab_init(void) { +void die(const char *context) { + terminal_clear(); + + perror(context); + exit(1); +} + +/*****************************************************************************/ + +struct append_buf *ab_create(void) { size_t buf_size = sizeof(struct append_buf); struct append_buf *sb = (struct append_buf *) malloc(buf_size);