Change white color, support enter and backspace and refactor
This commit is contained in:
parent
5df8a3fb5f
commit
4854d4bcee
6 changed files with 196 additions and 91 deletions
|
@ -2,5 +2,7 @@
|
||||||
#define EDITOR_H_
|
#define EDITOR_H_
|
||||||
|
|
||||||
void insert_char(int c);
|
void insert_char(int c);
|
||||||
|
void insert_new_line();
|
||||||
|
void del_char();
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
14
include/row.h
Normal file
14
include/row.h
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
#ifndef ROW_H_
|
||||||
|
#define ROW_H_
|
||||||
|
|
||||||
|
int row_cx_to_rx(row *row, int cx);
|
||||||
|
void update_row(row *row);
|
||||||
|
void insert_row(int at, char *s, size_t len);
|
||||||
|
void free_row(row *row);
|
||||||
|
void del_row(int at);
|
||||||
|
void row_insert_char(row *row, int at, int c);
|
||||||
|
void row_append_str(row *row, char *s, size_t len);
|
||||||
|
void row_del_char(row *row, int at);
|
||||||
|
char *rows_to_str(int *buflen);
|
||||||
|
|
||||||
|
#endif
|
|
@ -7,6 +7,8 @@
|
||||||
/* CONFIG */
|
/* CONFIG */
|
||||||
#define TAB_SIZE 4
|
#define TAB_SIZE 4
|
||||||
|
|
||||||
|
#define VERSION "0.0.1"
|
||||||
|
|
||||||
/* number of times of warning before quitting when there is modified text */
|
/* number of times of warning before quitting when there is modified text */
|
||||||
#define QUIT_CONFIRM 2
|
#define QUIT_CONFIRM 2
|
||||||
|
|
||||||
|
@ -15,12 +17,15 @@
|
||||||
#define SURFACE_1_BG "\x1b[38;2;49;50;68m"
|
#define SURFACE_1_BG "\x1b[38;2;49;50;68m"
|
||||||
#define BLACK_BG "\x1b[38;2;0;0;0m"
|
#define BLACK_BG "\x1b[38;2;0;0;0m"
|
||||||
#define BLACK_FG "\x1b[48;2;0;0;0m"
|
#define BLACK_FG "\x1b[48;2;0;0;0m"
|
||||||
#define WHITE_FG "\x1b[48;2;255;255;255m"
|
#define WHITE_FG "\x1b[48;2;205;214;244m"
|
||||||
#define BLUE_FG "\x1b[48;2;137;180;250m"
|
#define BLUE_FG "\x1b[48;2;137;180;250m"
|
||||||
#define BLUE_BG "\x1b[38;2;137;180;250m"
|
#define BLUE_BG "\x1b[38;2;137;180;250m"
|
||||||
#define GREEN_FG "\x1b[48;2;166;227;161m"
|
#define GREEN_FG "\x1b[48;2;166;227;161m"
|
||||||
|
|
||||||
#define VERSION "0.0.1"
|
|
||||||
|
#define NORMAL 0
|
||||||
|
#define INSERT 1
|
||||||
|
#define VISUAL 2
|
||||||
|
|
||||||
typedef struct row {
|
typedef struct row {
|
||||||
int size;
|
int size;
|
||||||
|
@ -38,6 +43,7 @@ typedef struct editor {
|
||||||
int rows;
|
int rows;
|
||||||
row *row;
|
row *row;
|
||||||
int dirty;
|
int dirty;
|
||||||
|
int mode;
|
||||||
char *filename;
|
char *filename;
|
||||||
char statusmsg[80];
|
char statusmsg[80];
|
||||||
time_t statusmsg_time;
|
time_t statusmsg_time;
|
||||||
|
@ -55,6 +61,7 @@ void abAppend(struct abuf *ab, const char *s, int len);
|
||||||
|
|
||||||
void append_row(char *s, size_t len);
|
void append_row(char *s, size_t len);
|
||||||
void row_insert_char(row *row, int at, int c);
|
void row_insert_char(row *row, int at, int c);
|
||||||
|
void row_del_char(row *row, int at);
|
||||||
|
|
||||||
extern editor vip;
|
extern editor vip;
|
||||||
|
|
||||||
|
|
36
src/editor.c
36
src/editor.c
|
@ -1,12 +1,46 @@
|
||||||
#include "vip.h"
|
#include "vip.h"
|
||||||
|
#include "row.h"
|
||||||
|
|
||||||
extern editor vip;
|
extern editor vip;
|
||||||
|
|
||||||
void insert_char(int c)
|
void insert_char(int c)
|
||||||
{
|
{
|
||||||
if (vip.cy == vip.rows) {
|
if (vip.cy == vip.rows) {
|
||||||
append_row("", 0);
|
insert_row(vip.rows, "", 0);
|
||||||
}
|
}
|
||||||
row_insert_char(&vip.row[vip.cy], vip.cx, c);
|
row_insert_char(&vip.row[vip.cy], vip.cx, c);
|
||||||
vip.cx++;
|
vip.cx++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void insert_new_line()
|
||||||
|
{
|
||||||
|
if (vip.cx == 0) {
|
||||||
|
insert_row(vip.cy, "", 0);
|
||||||
|
} else {
|
||||||
|
row *row = &vip.row[vip.cy];
|
||||||
|
insert_row(vip.cy + 1, &row->chars[vip.cx], row->size - vip.cx);
|
||||||
|
row = &vip.row[vip.cy];
|
||||||
|
row->size = vip.cx;
|
||||||
|
row->chars[row->size] = '\0';
|
||||||
|
update_row(row);
|
||||||
|
}
|
||||||
|
vip.cy++;
|
||||||
|
vip.cx = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void del_char()
|
||||||
|
{
|
||||||
|
if (vip.cy == vip.rows) return;
|
||||||
|
if (vip.cx == 0 && vip.cy == 0) return;
|
||||||
|
|
||||||
|
row *row = &vip.row[vip.cy];
|
||||||
|
if (vip.cx > 0) {
|
||||||
|
row_del_char(row, vip.cx - 1);
|
||||||
|
vip.cx--;
|
||||||
|
} else {
|
||||||
|
vip.cx = vip.row[vip.cy - 1].size;
|
||||||
|
row_append_str(&vip.row[vip.cy - 1], row->chars, row->size);
|
||||||
|
del_row(vip.cy);
|
||||||
|
vip.cy--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
127
src/row.c
Normal file
127
src/row.c
Normal file
|
@ -0,0 +1,127 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "vip.h"
|
||||||
|
|
||||||
|
extern editor vip;
|
||||||
|
|
||||||
|
int row_cx_to_rx(row *row, int cx)
|
||||||
|
{
|
||||||
|
int rx = 0;
|
||||||
|
for (int j = 0; j < cx; j++) {
|
||||||
|
if (row->chars[j] == '\t') {
|
||||||
|
rx += (TAB_SIZE - 1) - (rx % TAB_SIZE);
|
||||||
|
}
|
||||||
|
rx++;
|
||||||
|
}
|
||||||
|
return rx;
|
||||||
|
}
|
||||||
|
|
||||||
|
void update_row(row *row)
|
||||||
|
{
|
||||||
|
int tabs = 0;
|
||||||
|
for (int j = 0; j < row->size; j++)
|
||||||
|
if (row->chars[j] == '\t') tabs++;
|
||||||
|
free(row->render);
|
||||||
|
row->render = malloc(row->size + tabs * (TAB_SIZE - 1) + 1);
|
||||||
|
int idx = 0;
|
||||||
|
for (int j = 0; j < row->size; j++) {
|
||||||
|
if (row->chars[j] == '\t') {
|
||||||
|
row->render[idx++] = ' ';
|
||||||
|
while (idx % TAB_SIZE != 0) {
|
||||||
|
row->render[idx++] = ' ';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
row->render[idx++] = row->chars[j];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
row->render[idx] = '\0';
|
||||||
|
row->render_size = idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
void insert_row(int at, char *s, size_t len)
|
||||||
|
{
|
||||||
|
if (at < 0 || at > vip.rows) return;
|
||||||
|
|
||||||
|
vip.row = realloc(vip.row, sizeof(row) * (vip.rows + 1));
|
||||||
|
memmove(&vip.row[at + 1], &vip.row[at], sizeof(row) * (vip.rows - at));
|
||||||
|
|
||||||
|
vip.row[at].size = len;
|
||||||
|
vip.row[at].chars = malloc(len + 1);
|
||||||
|
memcpy(vip.row[at].chars, s, len);
|
||||||
|
vip.row[at].chars[len] = '\0';
|
||||||
|
|
||||||
|
vip.row[at].render_size = 0;
|
||||||
|
vip.row[at].render = NULL;
|
||||||
|
update_row(&vip.row[at]);
|
||||||
|
|
||||||
|
vip.rows++;
|
||||||
|
vip.dirty++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void free_row(row *row)
|
||||||
|
{
|
||||||
|
free(row->render);
|
||||||
|
free(row->chars);
|
||||||
|
}
|
||||||
|
|
||||||
|
void del_row(int at)
|
||||||
|
{
|
||||||
|
if (at < 0 || at >= vip.rows) return;
|
||||||
|
free_row(&vip.row[at]);
|
||||||
|
memmove(&vip.row[at], &vip.row[at + 1], sizeof(row) * (vip.rows - at - 1));
|
||||||
|
vip.rows--;
|
||||||
|
vip.dirty++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void row_insert_char(row *row, int at, int c)
|
||||||
|
{
|
||||||
|
if (at < 0 || at > row->size) {
|
||||||
|
at = row->size;
|
||||||
|
}
|
||||||
|
row->chars = realloc(row->chars, row->size + 2);
|
||||||
|
memmove(&row->chars[at + 1], &row->chars[at], row->size - at + 1);
|
||||||
|
row->size++;
|
||||||
|
row->chars[at] = c;
|
||||||
|
update_row(row);
|
||||||
|
vip.dirty++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void row_append_str(row *row, char *s, size_t len)
|
||||||
|
{
|
||||||
|
row->chars = realloc(row->chars, row->size + len + 1);
|
||||||
|
memcpy(&row->chars[row->size], s, len);
|
||||||
|
row->size += len;
|
||||||
|
row->chars[row->size] = '\0';
|
||||||
|
update_row(row);
|
||||||
|
vip.dirty++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void row_del_char(row *row, int at)
|
||||||
|
{
|
||||||
|
if (at < 0 || at >= row->size) return;
|
||||||
|
memmove(&row->chars[at], &row->chars[at + 1], row->size - at);
|
||||||
|
row->size--;
|
||||||
|
update_row(row);
|
||||||
|
vip.dirty++;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *rows_to_str(int *buflen)
|
||||||
|
{
|
||||||
|
int total_len = 0;
|
||||||
|
for (int j = 0; j < vip.rows; j++) {
|
||||||
|
total_len += vip.row[j].size + 1;
|
||||||
|
}
|
||||||
|
*buflen = total_len;
|
||||||
|
char *buf = malloc(total_len);
|
||||||
|
char *p = buf;
|
||||||
|
for (int j = 0; j < vip.rows; j++) {
|
||||||
|
memcpy(p, vip.row[j].chars, vip.row[j].size);
|
||||||
|
p += vip.row[j].size;
|
||||||
|
*p = '\n';
|
||||||
|
p++;
|
||||||
|
}
|
||||||
|
return buf;
|
||||||
|
}
|
97
src/vip.c
97
src/vip.c
|
@ -13,6 +13,7 @@
|
||||||
#include "term.h"
|
#include "term.h"
|
||||||
#include "bar.h"
|
#include "bar.h"
|
||||||
#include "editor.h"
|
#include "editor.h"
|
||||||
|
#include "row.h"
|
||||||
|
|
||||||
#define CTRL_KEY(k) ((k) & 0x1f)
|
#define CTRL_KEY(k) ((k) & 0x1f)
|
||||||
|
|
||||||
|
@ -90,90 +91,6 @@ int read_key()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int row_cx_to_rx(row *row, int cx)
|
|
||||||
{
|
|
||||||
int rx = 0;
|
|
||||||
for (int j = 0; j < cx; j++) {
|
|
||||||
if (row->chars[j] == '\t') {
|
|
||||||
rx += (TAB_SIZE - 1) - (rx % TAB_SIZE);
|
|
||||||
}
|
|
||||||
rx++;
|
|
||||||
}
|
|
||||||
return rx;
|
|
||||||
}
|
|
||||||
|
|
||||||
void update_row(row *row)
|
|
||||||
{
|
|
||||||
int tabs = 0;
|
|
||||||
for (int j = 0; j < row->size; j++)
|
|
||||||
if (row->chars[j] == '\t') tabs++;
|
|
||||||
free(row->render);
|
|
||||||
row->render = malloc(row->size + tabs * (TAB_SIZE - 1) + 1);
|
|
||||||
int idx = 0;
|
|
||||||
for (int j = 0; j < row->size; j++) {
|
|
||||||
if (row->chars[j] == '\t') {
|
|
||||||
row->render[idx++] = ' ';
|
|
||||||
while (idx % TAB_SIZE != 0) {
|
|
||||||
row->render[idx++] = ' ';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
row->render[idx++] = row->chars[j];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
row->render[idx] = '\0';
|
|
||||||
row->render_size = idx;
|
|
||||||
}
|
|
||||||
|
|
||||||
void append_row(char *s, size_t len)
|
|
||||||
{
|
|
||||||
vip.row = realloc(vip.row, sizeof(row) * (vip.rows + 1));
|
|
||||||
|
|
||||||
int at = vip.rows;
|
|
||||||
vip.row[at].size = len;
|
|
||||||
vip.row[at].chars = malloc(len + 1);
|
|
||||||
memcpy(vip.row[at].chars, s, len);
|
|
||||||
vip.row[at].chars[len] = '\0';
|
|
||||||
|
|
||||||
vip.row[at].render_size = 0;
|
|
||||||
vip.row[at].render = NULL;
|
|
||||||
update_row(&vip.row[at]);
|
|
||||||
|
|
||||||
vip.rows++;
|
|
||||||
vip.dirty++;
|
|
||||||
}
|
|
||||||
|
|
||||||
void row_insert_char(row *row, int at, int c)
|
|
||||||
{
|
|
||||||
if (at < 0 || at > row->size) {
|
|
||||||
at = row->size;
|
|
||||||
}
|
|
||||||
row->chars = realloc(row->chars, row->size + 2);
|
|
||||||
memmove(&row->chars[at + 1], &row->chars[at], row->size - at + 1);
|
|
||||||
row->size++;
|
|
||||||
row->chars[at] = c;
|
|
||||||
update_row(row);
|
|
||||||
vip.dirty++;
|
|
||||||
}
|
|
||||||
|
|
||||||
char *rows_to_str(int *buflen)
|
|
||||||
{
|
|
||||||
int total_len = 0;
|
|
||||||
for (int j = 0; j < vip.rows; j++) {
|
|
||||||
total_len += vip.row[j].size + 1;
|
|
||||||
}
|
|
||||||
*buflen = total_len;
|
|
||||||
char *buf = malloc(total_len);
|
|
||||||
char *p = buf;
|
|
||||||
for (int j = 0; j < vip.rows; j++) {
|
|
||||||
memcpy(p, vip.row[j].chars, vip.row[j].size);
|
|
||||||
p += vip.row[j].size;
|
|
||||||
*p = '\n';
|
|
||||||
p++;
|
|
||||||
}
|
|
||||||
return buf;
|
|
||||||
}
|
|
||||||
|
|
||||||
void open_editor(char *filename)
|
void open_editor(char *filename)
|
||||||
{
|
{
|
||||||
free(vip.filename);
|
free(vip.filename);
|
||||||
|
@ -190,7 +107,7 @@ void open_editor(char *filename)
|
||||||
while (len > 0 && (line[len - 1] == '\n' || line[len - 1] == '\r')) {
|
while (len > 0 && (line[len - 1] == '\n' || line[len - 1] == '\r')) {
|
||||||
len--;
|
len--;
|
||||||
}
|
}
|
||||||
append_row(line, len);
|
insert_row(vip.rows, line, len);
|
||||||
}
|
}
|
||||||
free(line);
|
free(line);
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
|
@ -345,11 +262,12 @@ void move_cursor(int key)
|
||||||
|
|
||||||
void process_key()
|
void process_key()
|
||||||
{
|
{
|
||||||
static int quit_times = QUIT_CONFIRM
|
static int quit_times = QUIT_CONFIRM;
|
||||||
|
|
||||||
int c = read_key();
|
int c = read_key();
|
||||||
switch (c) {
|
switch (c) {
|
||||||
case '\r':
|
case '\r':
|
||||||
/* TBC */
|
insert_new_line();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CTRL_KEY('q'):
|
case CTRL_KEY('q'):
|
||||||
|
@ -380,7 +298,9 @@ void process_key()
|
||||||
case BACKSPACE:
|
case BACKSPACE:
|
||||||
case CTRL_KEY('h'):
|
case CTRL_KEY('h'):
|
||||||
case DEL_KEY:
|
case DEL_KEY:
|
||||||
/* TBC */
|
if (c == DEL_KEY)
|
||||||
|
move_cursor(ARROW_RIGHT);
|
||||||
|
del_char();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PAGE_UP:
|
case PAGE_UP:
|
||||||
|
@ -426,6 +346,7 @@ void init_editor()
|
||||||
vip.rows = 0;
|
vip.rows = 0;
|
||||||
vip.row = NULL;
|
vip.row = NULL;
|
||||||
vip.dirty = 0;
|
vip.dirty = 0;
|
||||||
|
vip.mode = NORMAL;
|
||||||
vip.filename = NULL;
|
vip.filename = NULL;
|
||||||
vip.statusmsg[0] = '\0';
|
vip.statusmsg[0] = '\0';
|
||||||
vip.statusmsg_time = 0;
|
vip.statusmsg_time = 0;
|
||||||
|
|
Loading…
Reference in a new issue