Begin work on text editing
Along with lots of stuff I was too lazy to commit separately
This commit is contained in:
parent
bd8da6f4ee
commit
f866add58f
8 changed files with 119 additions and 31 deletions
|
@ -20,6 +20,7 @@ void buffer_read_file(struct buffer *buffer, const char *filename);
|
||||||
void buffer_append_row(struct buffer *buffer, const char *chars, int n_chars);
|
void buffer_append_row(struct buffer *buffer, const char *chars, int n_chars);
|
||||||
|
|
||||||
void erow_update_rendering(struct erow *erow);
|
void erow_update_rendering(struct erow *erow);
|
||||||
|
void erow_insert_char(struct erow *erow, int at, char c);
|
||||||
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);
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
#include "input.h"
|
#include "input.h"
|
||||||
|
|
||||||
void editor_move_cursor(KEY key);
|
void command_move_cursor(KEY key);
|
||||||
|
void command_insert_char(char c);
|
||||||
|
|
||||||
#endif // COMMANDS_H
|
#endif // COMMANDS_H
|
||||||
|
|
|
@ -20,4 +20,6 @@ struct editor_state {
|
||||||
};
|
};
|
||||||
extern struct editor_state E;
|
extern struct editor_state E;
|
||||||
|
|
||||||
|
void editor_set_message(const char *, ...);
|
||||||
|
|
||||||
#endif // KILO_H
|
#endif // KILO_H
|
||||||
|
|
16
src/buffer.c
16
src/buffer.c
|
@ -64,6 +64,9 @@ void buffer_append_row(struct buffer *buffer, const char *chars, int n_chars) {
|
||||||
memcpy(new_row->chars, chars, n_chars);
|
memcpy(new_row->chars, chars, n_chars);
|
||||||
new_row->n_chars = n_chars;
|
new_row->n_chars = n_chars;
|
||||||
|
|
||||||
|
new_row->rchars = NULL;
|
||||||
|
new_row->n_rchars = 0;
|
||||||
|
|
||||||
erow_update_rendering(new_row);
|
erow_update_rendering(new_row);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -116,6 +119,19 @@ void erow_update_rendering(struct erow *erow) {
|
||||||
free(line_buffer);
|
free(line_buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void erow_insert_char(struct erow *erow, int at, char c) {
|
||||||
|
if (at < 0) at = 0;
|
||||||
|
if (at > erow->n_chars) at = erow->n_chars;
|
||||||
|
|
||||||
|
erow->chars = realloc(erow->chars, erow->n_chars + 1);
|
||||||
|
memmove(erow->chars + at + 1, erow->chars + at, erow->n_chars - at);
|
||||||
|
|
||||||
|
erow->chars[at] = c;
|
||||||
|
erow->n_chars++;
|
||||||
|
|
||||||
|
erow_update_rendering(erow);
|
||||||
|
}
|
||||||
|
|
||||||
int erow_cx_to_rx(struct erow *erow, int cx) {
|
int erow_cx_to_rx(struct erow *erow, int cx) {
|
||||||
int rx = 0;
|
int rx = 0;
|
||||||
|
|
||||||
|
|
|
@ -1,33 +1,33 @@
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|
||||||
#include "commands.h"
|
#include "commands.h"
|
||||||
|
#include "input.h"
|
||||||
#include "kilo.h"
|
#include "kilo.h"
|
||||||
#include "buffer.h"
|
#include "buffer.h"
|
||||||
|
|
||||||
void editor_move_cursor(KEY key) {
|
static void cursor_adjust_viewport(void);
|
||||||
|
static void cursor_check_file_bounds(bool horizontal);
|
||||||
|
static void cursor_update_rx(bool horizontal);
|
||||||
|
|
||||||
|
void command_move_cursor(KEY key) {
|
||||||
struct erow *rows = E.current_buf->rows;
|
struct erow *rows = E.current_buf->rows;
|
||||||
int n_rows = E.current_buf->n_rows;
|
int n_rows = E.current_buf->n_rows;
|
||||||
|
|
||||||
struct erow *current_row = (E.cy < n_rows ? rows + E.cy : NULL);
|
struct erow *current_row = (rows && E.cy < n_rows ? rows + E.cy : NULL);
|
||||||
int max_x = (current_row ? current_row->n_chars : 0);
|
int max_x = (current_row ? current_row->n_chars : 0);
|
||||||
|
|
||||||
switch (key) {
|
switch (key) {
|
||||||
case ARROW_LEFT:
|
case ARROW_LEFT:
|
||||||
if (E.cx > 0) E.cx--;
|
E.cx--;
|
||||||
else if (E.cy > 0) E.cx = rows[--E.cy].n_chars;
|
|
||||||
break;
|
break;
|
||||||
case ARROW_DOWN:
|
case ARROW_DOWN:
|
||||||
if (E.cy < n_rows) E.cy++;
|
E.cy++;
|
||||||
break;
|
break;
|
||||||
case ARROW_UP:
|
case ARROW_UP:
|
||||||
if (E.cy > 0) E.cy--;
|
E.cy--;
|
||||||
break;
|
break;
|
||||||
case ARROW_RIGHT:
|
case ARROW_RIGHT:
|
||||||
if (E.cx < max_x) E.cx++;
|
E.cx++;
|
||||||
else if (E.cy < n_rows) {
|
|
||||||
E.cx = 0;
|
|
||||||
E.cy++;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case HOME:
|
case HOME:
|
||||||
|
@ -38,29 +38,76 @@ void editor_move_cursor(KEY key) {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PG_UP:
|
case PG_UP:
|
||||||
if ((E.cy -= E.screenrows) < 0)
|
E.cy -= E.screenrows;
|
||||||
E.cy = 0;
|
|
||||||
break;
|
break;
|
||||||
case PG_DOWN:
|
case PG_DOWN:
|
||||||
if ((E.cy += E.screenrows) > n_rows)
|
E.cy += E.screenrows;
|
||||||
E.cy = n_rows;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
current_row = (E.cy < n_rows ? rows + E.cy : NULL);
|
bool horizontal = (key == ARROW_LEFT ||
|
||||||
max_x = (current_row ? current_row->n_chars : 0);
|
key == ARROW_RIGHT ||
|
||||||
|
key == HOME ||
|
||||||
|
key == END);
|
||||||
|
|
||||||
|
cursor_check_file_bounds(horizontal);
|
||||||
|
cursor_update_rx(horizontal);
|
||||||
|
cursor_adjust_viewport();
|
||||||
|
}
|
||||||
|
|
||||||
|
void command_insert_char(char c) {
|
||||||
|
if (E.cy == E.current_buf->n_rows)
|
||||||
|
buffer_append_row(E.current_buf, NULL, 0);
|
||||||
|
|
||||||
|
erow_insert_char(E.current_buf->rows+E.cy, E.cx++, c);
|
||||||
|
E.rx = erow_cx_to_rx(E.current_buf->rows+E.cy, E.cx);
|
||||||
|
}
|
||||||
|
|
||||||
|
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 *current_row = (rows && E.cy < n_rows ? rows + E.cy : NULL);
|
||||||
|
int max_x = (current_row ? current_row->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) E.cx = rows[--E.cy].n_chars;
|
||||||
|
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 *current_row = (rows && E.cy < n_rows ? rows + E.cy : NULL);
|
||||||
|
int max_x = (current_row ? current_row->n_chars : 0);
|
||||||
|
|
||||||
static int saved_rx = 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);
|
if (horizontal) saved_rx = erow_cx_to_rx(current_row, E.cx);
|
||||||
else E.cx = erow_rx_to_cx(current_row, saved_rx);
|
else {
|
||||||
|
E.cx = erow_rx_to_cx(current_row, saved_rx);
|
||||||
if (E.cx > max_x)
|
if (E.cx > max_x)
|
||||||
E.cx = max_x;
|
E.cx = max_x;
|
||||||
|
}
|
||||||
|
|
||||||
E.rx = erow_cx_to_rx(&E.current_buf->rows[E.cy], E.cx);
|
E.rx = erow_cx_to_rx(rows + E.cy, E.cx);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void cursor_adjust_viewport(void) {
|
||||||
int max_row_off = E.cy;
|
int max_row_off = E.cy;
|
||||||
if (E.row_off > max_row_off)
|
if (E.row_off > max_row_off)
|
||||||
E.row_off = max_row_off;
|
E.row_off = max_row_off;
|
||||||
|
|
14
src/input.c
14
src/input.c
|
@ -3,6 +3,7 @@
|
||||||
#include "input.h"
|
#include "input.h"
|
||||||
#include "terminal.h"
|
#include "terminal.h"
|
||||||
#include "commands.h"
|
#include "commands.h"
|
||||||
|
#include "utils.h"
|
||||||
|
|
||||||
void input_process_key(void) {
|
void input_process_key(void) {
|
||||||
KEY c = terminal_read_key();
|
KEY c = terminal_read_key();
|
||||||
|
@ -16,12 +17,23 @@ void input_process_key(void) {
|
||||||
case END:
|
case END:
|
||||||
case PG_UP:
|
case PG_UP:
|
||||||
case PG_DOWN:
|
case PG_DOWN:
|
||||||
editor_move_cursor(c);
|
command_move_cursor(c);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CTRL_KEY('Q'):
|
case CTRL_KEY('Q'):
|
||||||
terminal_clear();
|
terminal_clear();
|
||||||
exit(0);
|
exit(0);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case '\r':
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 127:
|
||||||
|
case DEL:
|
||||||
|
case CTRL_KEY('H'):
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
command_insert_char(c);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
#include <ctype.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
@ -11,7 +12,6 @@
|
||||||
#include "terminal.h"
|
#include "terminal.h"
|
||||||
|
|
||||||
void editor_init(char *filename);
|
void editor_init(char *filename);
|
||||||
void editor_set_message(const char *, ...);
|
|
||||||
|
|
||||||
struct editor_state E;
|
struct editor_state E;
|
||||||
|
|
||||||
|
@ -46,6 +46,7 @@ void editor_init(char *filename) {
|
||||||
buffer_read_file(E.current_buf, filename);
|
buffer_read_file(E.current_buf, filename);
|
||||||
|
|
||||||
editor_set_message("Welcome to kilo. Press CTRL-Q to quit.");
|
editor_set_message("Welcome to kilo. Press CTRL-Q to quit.");
|
||||||
|
terminal_clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void editor_set_message(const char *fmt, ...) {
|
void editor_set_message(const char *fmt, ...) {
|
||||||
|
|
|
@ -89,6 +89,7 @@ ERRCODE terminal_set_cursor_pos(int row, int col) {
|
||||||
|
|
||||||
KEY terminal_read_key(void) {
|
KEY terminal_read_key(void) {
|
||||||
char c;
|
char c;
|
||||||
|
int n;
|
||||||
while (read(STDIN_FILENO, &c, 1) == 0);
|
while (read(STDIN_FILENO, &c, 1) == 0);
|
||||||
|
|
||||||
if (c == '\x1b') {
|
if (c == '\x1b') {
|
||||||
|
@ -98,7 +99,11 @@ KEY terminal_read_key(void) {
|
||||||
if (read(STDIN_FILENO, buf+i, 1) == 0) break;
|
if (read(STDIN_FILENO, buf+i, 1) == 0) break;
|
||||||
|
|
||||||
char escape_char;
|
char escape_char;
|
||||||
if (sscanf(buf, "[%c~", &escape_char) != EOF) {
|
int escape_int;
|
||||||
|
|
||||||
|
n = 0;
|
||||||
|
sscanf(buf, "[%c%n", &escape_char, &n);
|
||||||
|
if (n > 0) {
|
||||||
switch (escape_char) {
|
switch (escape_char) {
|
||||||
case 'A': return ARROW_UP;
|
case 'A': return ARROW_UP;
|
||||||
case 'B': return ARROW_DOWN;
|
case 'B': return ARROW_DOWN;
|
||||||
|
@ -109,15 +114,18 @@ KEY terminal_read_key(void) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sscanf(buf, "O%c", &escape_char) != EOF) {
|
n = 0;
|
||||||
|
sscanf(buf, "O%c%n", &escape_char, &n);
|
||||||
|
if (n > 0) {
|
||||||
switch (escape_char) {
|
switch (escape_char) {
|
||||||
case 'H': return HOME;
|
case 'H': return HOME;
|
||||||
case 'F': return END;
|
case 'F': return END;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int escape_int;
|
n = 0;
|
||||||
if (sscanf(buf, "[%d~", &escape_int) != EOF) {
|
sscanf(buf, "[%d~%n", &escape_int, &n);
|
||||||
|
if (n > 0) {
|
||||||
switch (escape_int) {
|
switch (escape_int) {
|
||||||
case 1:
|
case 1:
|
||||||
case 7:
|
case 7:
|
||||||
|
|
Reference in a new issue