Adds syntax highlighting and more vim controls

This commit is contained in:
sloumdrone 2019-12-31 15:54:43 -08:00
parent b754278f2e
commit b05771bc75
5 changed files with 291 additions and 47 deletions

View File

@ -1,5 +1,9 @@
static const int tabwidth = 4;
#define UNSAVED_QUIT_COUNT 1
static const int tabwidth = 4;
static const int HL_NUMBER_COLOR = 31;
static const int HL_DEFAULT_COLOR = 37;

BIN
csedit

Binary file not shown.

319
csedit.c
View File

@ -24,12 +24,19 @@
// -----------
#define CSEDIT_VERSION "0.0.1"
#define CTRL_KEY(k) ((k) & 0x1f)
#define HL_HIGHLIGHT_NUMBERS (1<<0)
//
// definitions for config file
// ---------------------------
enum editorMode {CommandMode, InputMode, VisualMode};
enum editorHighlight {
HL_NORMAL,
HL_NUMBER
};
enum editorKey {
BACKSPACE = 127,
ARROW_LEFT = 1000,
@ -52,6 +59,7 @@ typedef struct erow {
int rendersize;
char *chars;
char *render;
unsigned char *hl;
} erow;
struct editorConfig {
@ -68,10 +76,33 @@ struct editorConfig {
char statusmsg[80];
time_t statusmsg_time;
struct termios orig_termios;
struct editorSyntax *syntax;
};
struct editorSyntax {
char *filetype;
char **filematch;
int flags;
};
struct editorConfig E;
//
// filetypes
// ---------
char *C_HL_extensions[] = {".c", ".h", ".cpp", NULL};
struct editorSyntax HLDB[] = {
{
"c",
C_HL_extensions,
HL_HIGHLIGHT_NUMBERS
},
};
#define HLDB_ENTRIES (sizeof(HLDB) / sizeof(HLDB[0]))
//
// prototypes
// ----------
@ -194,6 +225,68 @@ int getWindowSize(int *rows, int *cols) {
return 0;
}
//
// syntax highlighting
// -------------------
int is_separator(int c) {
return isspace(c) || c == '\0' || strchr(",.()+-/*=~%<>[];", c) != NULL;
}
void editorUpdateSyntax(erow *row) {
row->hl = realloc(row->hl, row->rendersize);
memset(row->hl, HL_NORMAL, row->rendersize);
if (E.syntax == NULL) return;
int prev_sep = 1;
int i;
while (i < row->size) {
char c = row->render[i];
unsigned char prev_hl = (i > 0) ? row->hl[i - 1] : HL_NORMAL;
if (E.syntax->flags & HL_HIGHLIGHT_NUMBERS) {
if ((isdigit(c) && (prev_sep || prev_hl == HL_NUMBER)) ||
(c == '.' && prev_hl == HL_NUMBER)) {
row->hl[i] = HL_NUMBER;
i++;
prev_sep = 0;
continue;
}
}
prev_sep = is_separator(c);
i++;
}
}
int editorSyntaxToColor(int hl) {
switch (hl) {
case HL_NUMBER: return HL_NUMBER_COLOR;
default: return HL_DEFAULT_COLOR;
}
}
void editorSelectSyntaxHighlight() {
E.syntax = NULL;
if (E.filename == NULL) return;
char *ext = strrchr(E.filename, '.');
for (unsigned int j = 0; j < HLDB_ENTRIES; j++) {
struct editorSyntax *s = &HLDB[j];
unsigned int i = 0;
while (s->filematch[i]) {
int is_ext = (s->filematch[i][0] == '.');
if ((is_ext && ext && !strcmp(ext, s->filematch[i])) ||
(!is_ext && strstr(E.filename, s->filematch[i]))) {
E.syntax = s;
return;
}
i++;
}
}
}
//
// row ops
// -------
@ -228,6 +321,8 @@ void editorUpdateRow(erow *row) {
}
row->render[idx] = '\0';
row->rendersize = idx;
editorUpdateSyntax(row);
}
void editorInsertRow(int at, char *s, size_t len) {
@ -243,6 +338,7 @@ void editorInsertRow(int at, char *s, size_t len) {
E.row[at].rendersize = 0;
E.row[at].render = NULL;
E.row[at].hl = NULL;
editorUpdateRow(&E.row[at]);
E.numRows++;
@ -252,6 +348,7 @@ void editorInsertRow(int at, char *s, size_t len) {
void editorFreeRow(erow *row) {
free(row->render);
free(row->chars);
free(row->hl);
}
void editorDelRow(int at) {
@ -357,6 +454,8 @@ void editorOpen(char *filename) {
free(E.filename);
E.filename = strdup(filename);
editorSelectSyntaxHighlight();
FILE *fp = fopen(filename, "r");
if (!fp) die("Open file");
@ -374,14 +473,15 @@ void editorOpen(char *filename) {
E.unsaved = 0;
}
void editorSave() {
if (E.filename == NULL) {
void editorSave(int saveAs) {
if (E.filename == NULL || saveAs) {
E.filename = editorPrompt("Save as: %s");
if (E.filename == NULL) {
E.filename = NULL;
editorStatusMessage("Save cancelled");
return;
}
editorSelectSyntaxHighlight();
}
int len;
@ -473,7 +573,29 @@ void editorDrawRows(struct abuf *ab) {
int len = E.row[filerow].rendersize - E.coloff;
if (len < 0) len = 0;
if (len > E.screenCols) len = E.screenCols;
abAppend(ab, &E.row[filerow].render[E.coloff], len);
char *c = &E.row[filerow].render[E.coloff];
int current_color = -1;
unsigned char *hl = &E.row[filerow].hl[E.coloff];
int j;
for (j = 0; j < len; j++) {
if (hl[j] == HL_NORMAL) {
if (current_color != -1) {
abAppend(ab, "\033[39m", 5);
current_color = -1;
}
abAppend(ab, &c[j], 1);
} else {
int color = editorSyntaxToColor(hl[j]);
if (color != current_color) {
current_color = color;
char buf[16];
int clen = snprintf(buf, sizeof(buf), "\033[%dm", color);
abAppend(ab, buf, clen);
}
abAppend(ab, &c[j], 1);
}
}
abAppend(ab, "\033[39m", 5);
}
abAppend(ab, "\033[K", 3);
@ -500,8 +622,8 @@ void editorDrawStatusBar(struct abuf *ab) {
int len = snprintf(status, sizeof(status), "%.20s - %d lines %s",
E.filename ? E.filename : "[No name]", E.numRows, E.unsaved ? "(modified)" : "");
int rlen = snprintf(rstatus, sizeof(rstatus), "%d:%d/%d [%c]",
E.cx, E.cy + 1, E.numRows, editorMode);
int rlen = snprintf(rstatus, sizeof(rstatus), "<%s> %d:%d/%d [%c] ",
E.syntax ? E.syntax->filetype : "generic" ,E.cx, E.cy + 1, E.numRows, editorMode);
if (len > E.screenCols) len = E.screenCols;
abAppend(ab, status, len);
while (len < E.screenCols) {
@ -558,7 +680,7 @@ void editorPrevWord() {
int x = E.cx;
int y = E.cy;
int moved = 0;
erow *row = (y >= E.numRows) ? NULL : &E.row[y];
erow *row = (y >= E.numRows || y < 0) ? NULL : &E.row[y];
while (row) {
if (moved && row->chars[x] != ' ' && row->chars[x] != '\t' && (x == 0 || row->chars[x - 1] == ' ' || row->chars[x - 1] == '\t')) {
@ -568,7 +690,7 @@ void editorPrevWord() {
break;
} else if (x == 0) {
y--;
row = (y <= 0) ? NULL : &E.row[y];
row = (y >= E.numRows || y < 0) ? NULL : &E.row[y];
if (!row) return;
x = row->size;
moved++;
@ -583,7 +705,7 @@ void editorNextWord() {
int ws = 0;
int x = E.cx;
int y = E.cy;
erow *row = (y >= E.numRows) ? NULL : &E.row[y];
erow *row = (y >= E.numRows || y < 0) ? NULL : &E.row[y];
while (row) {
if (ws > 0 && row->chars[x] != ' ' && row->chars[x] != '\t') {
@ -597,7 +719,7 @@ void editorNextWord() {
y++;
x = 0;
ws++;
row = (y >= E.numRows) ? NULL : &E.row[y];
row = (y >= E.numRows || y < 0) ? NULL : &E.row[y];
if (!row) return;
} else {
x++;
@ -685,9 +807,12 @@ void editorMoveCursor(int key) {
break;
case 'l':
case ARROW_RIGHT:
if (row && E.cx < row->size)
E.cx++;
break;
{
int mod = E.mode == CommandMode ? 1 : 0;
if (row && E.cx < row->size - mod)
E.cx++;
break;
}
}
row = (E.cy >= E.numRows) ? NULL : &E.row[E.cy];
@ -727,6 +852,7 @@ void editorInputKp(int c) {
switch (c) {
case '\033':
case CTRL_KEY('l'):
if (E.cx == E.row[E.cy].size) editorMoveCursor(ARROW_LEFT);
E.mode = CommandMode;
break;
case '\r':
@ -745,12 +871,18 @@ void editorInputKp(int c) {
}
void editorCommandKp(int c) {
static int deleting = 0;
static int counter = 1;
static int place = 1;
switch (c) {
case 'j':
case 'k':
case 'h':
case 'l':
editorMoveCursor(c);
while (counter > 0) {
editorMoveCursor(c);
counter--;
}
break;
case 'g':
E.cy = 0;
@ -765,48 +897,144 @@ void editorCommandKp(int c) {
break;
case 'o':
editorCommandKp('$');
editorInsertNewline();
editorCommandKp('i');
editorMoveCursor(ARROW_RIGHT);
editorInsertNewline();
break;
case 'O':
editorCommandKp('0');
editorCommandKp('^');
editorInsertNewline();
editorMoveCursor(ARROW_UP);
editorCommandKp('i');
break;
case 'x':
editorMoveCursor(ARROW_RIGHT);
editorDeleteChar();
while (counter > 0) {
E.mode = InputMode;
editorMoveCursor(ARROW_RIGHT);
E.mode = CommandMode;
editorDeleteChar();
if (E.cx == E.row[E.cy].size) editorMoveCursor(ARROW_LEFT);
}
break;
case 'i':
case 'a':
if (c == 'a') editorMoveCursor('l');
E.mode = InputMode;
break;
case 'u':
editorPageCursor(PAGE_UP);
if (c == 'a') editorMoveCursor('l');
break;
case 'd':
editorPageCursor(PAGE_DOWN);
break;
if (!deleting) {
deleting++;
return;
} else {
while (counter > 0) {
editorDelRow(E.cy);
if (E.cy == E.numRows) E.cy--;
if (E.cy < 0) E.cy = 0;
counter--;
}
break;
}
case '$':
if (E.cy < E.numRows)
E.cx = E.row[E.cy].size;
if (deleting) {
int diff = E.row[E.cy].size - E.cx;
E.cx = E.row[E.cy].size - 1;
if (E.cx < 0) E.cx = 0;
while (diff > 0) {
E.mode = InputMode;
editorMoveCursor(ARROW_RIGHT);
E.mode = CommandMode;
editorDeleteChar();
if (E.cx == E.row[E.cy].size) editorMoveCursor(ARROW_LEFT);
diff--;
}
} else if (E.cy < E.numRows) {
E.cx = E.row[E.cy].size - 1;
if (E.cx < 0) E.cx = 0;
}
break;
case 'w':
editorNextWord();
while (counter > 0) {
counter--;
if (deleting) {
int orig = E.cx;
editorNextWord();
int diff = E.cx - orig;
if (diff < 0) {
editorPrevWord();
editorEndOfWord();
editorMoveCursor(ARROW_RIGHT);
diff = E.cx - orig;
}
while (diff > 0) {
editorDeleteChar();
diff--;
}
} else {
editorNextWord();
}
}
break;
case 'b':
editorPrevWord();
while (counter > 0) {
if (deleting) {
// TODO
} else {
editorPrevWord();
}
counter--;
}
break;
case 'e':
editorEndOfWord();
while (counter > 0) {
if (deleting) {
// TODO
} else {
editorEndOfWord();
}
counter--;
}
break;
case '^':
if (deleting) {
while (E.cx > 0) {
editorDeleteChar();
}
} else {
E.cx = 0;
}
break;
case '0':
case '^':
E.cx = 0;
break;
if (counter == 1) {
if (deleting) {
while (E.cx > 0) {
editorDeleteChar();
}
} else {
E.cx = 0;
}
break;
}
/* fall through */
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
{
if (counter <= 1 && place == 1) counter--;
int num = c - 48;
counter += num * place;
place *= 10;
}
return;
}
deleting = 0;
place = 1;
counter = 1;
}
void editorProcessKeypress() {
@ -838,7 +1066,10 @@ void editorProcessKeypress() {
editorPageCursor(PAGE_DOWN);
return;
case CTRL_KEY('s'):
editorSave();
editorSave(0);
return;
case CTRL_KEY('a'):
editorSave(1);
return;
case HOME_KEY:
E.cx = 0;
@ -862,18 +1093,20 @@ void editorProcessKeypress() {
// init
// ----
void initEditor() {
E.mode = CommandMode;
E.rowoff = 0;
E.coloff = 0;
E.numRows = 0;
E.unsaved = 0;
E.row = NULL;
E.filename = NULL;
E.statusmsg[0] = '\0';
E.mode = CommandMode;
E.rowoff = 0;
E.coloff = 0;
E.numRows = 0;
E.unsaved = 0;
E.statusmsg_time = 0;
E.cx = 0;
E.cy = 0;
E.rx = 0;
E.cx = 0;
E.cy = 0;
E.rx = 0;
E.row = NULL;
E.filename = NULL;
E.syntax = NULL;
E.statusmsg[0] = '\0';
if (getWindowSize(&E.screenRows, &E.screenCols) == -1) die("getWindowSize");
E.screenRows -= 2;
}

10
filetypesdb.h Normal file
View File

@ -0,0 +1,10 @@
// File extensions by language
char *C_HL_extensions[] = {".c", ".h", ".cpp", NULL};
struct editorSyntax HLDB[] {
{
"c",
C_HL_extensions,
HL_HIGHLIGHT_NUMBERS
}
}

View File

@ -1,3 +0,0 @@
Hello, world!
typing.
and such.