From cd8e86eac700777e4aeb47aa659cf3d5319cd379 Mon Sep 17 00:00:00 2001 From: night0721 Date: Thu, 4 Jul 2024 17:03:37 +0100 Subject: [PATCH] Filetype detect, syntax highlight for single and multiline comment, strings, keywords --- src/bar.c | 6 +- src/row.c | 10 +++ src/syntax.c | 200 +++++++++++++++++++++++++++++++++++++++++++++------ 3 files changed, 191 insertions(+), 25 deletions(-) diff --git a/src/bar.c b/src/bar.c index 98355c6..be4efc2 100644 --- a/src/bar.c +++ b/src/bar.c @@ -32,11 +32,12 @@ void draw_status_bar(struct abuf *ab) abAppend(ab, "\x1b[22m", 5); - char git_branch[80], git_diff[80], file[80], lines[80], coord[80]; + char git_branch[80], git_diff[80], file[80], info[80], lines[80], coord[80]; int gitb_len = snprintf(git_branch, sizeof(git_branch), " %s ", "master"); int gitd_len = snprintf(git_diff, sizeof(git_diff), " %s ", "+1"); int file_len = snprintf(file, sizeof(file), " %.20s %s", vip.filename ? vip.filename : "[No Name]", vip.dirty ? "[+]" : ""); + int info_len = snprintf(info, sizeof(info), " %s ", vip.syntax ? vip.syntax->filetype : ""); int lines_len; if (vip.rows == 0 || vip.rows == vip.cy + 1) { lines_len = snprintf(lines, sizeof(lines), " %s ", vip.rows == 0 ? "Top" : "Bot"); @@ -63,7 +64,8 @@ void draw_status_bar(struct abuf *ab) while (file_len < vip.screencols) { - if (vip.screencols - mode_len - file_len - gitb_len - gitd_len - 1 == lines_len + coord_len) { + if (vip.screencols - mode_len - file_len - gitb_len - gitd_len - 1 == info_len + lines_len + coord_len) { + abAppend(ab, info, info_len); abAppend(ab, SURFACE_1_BG, COLOR_LEN); if (vip.mode == NORMAL) { abAppend(ab, BLUE_FG, COLOR_LEN); diff --git a/src/row.c b/src/row.c index 90c08b9..7bf9c2c 100644 --- a/src/row.c +++ b/src/row.c @@ -3,6 +3,7 @@ #include #include "vip.h" +#include "row.h" #include "syntax.h" extern editor vip; @@ -64,6 +65,11 @@ void insert_row(int at, char *s, size_t len) vip.row = realloc(vip.row, sizeof(row) * (vip.rows + 1)); memmove(&vip.row[at + 1], &vip.row[at], sizeof(row) * (vip.rows - at)); + for (int j = at + 1; j <= vip.rows; j++) { + vip.row[j].idx++; + } + + vip.row[at].idx = at; vip.row[at].size = len; vip.row[at].chars = malloc(len + 1); @@ -73,6 +79,7 @@ void insert_row(int at, char *s, size_t len) vip.row[at].render_size = 0; vip.row[at].render = NULL; vip.row[at].hl = NULL; + vip.row[at].opened_comment = 0; update_row(&vip.row[at]); vip.rows++; @@ -91,6 +98,9 @@ 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)); + for (int j = at; j < vip.rows - 1; j++) { + vip.row[j].idx--; + } vip.rows--; vip.dirty++; } diff --git a/src/syntax.c b/src/syntax.c index 860b741..11ced68 100644 --- a/src/syntax.c +++ b/src/syntax.c @@ -4,54 +4,208 @@ #include #include "vip.h" +#include "row.h" +#include "syntax.h" -int is_separator(int c) { +char *c_keywords[] = { "switch", "if", "while", "for", "break", "continue", "return", "else", "struct", "union", "typedef", "static", "enum", "case", "sizeof", "int|", "long|", "double|", "float|", "char|", "unsigned|", "void|", NULL }; +char *c_ext[] = { ".c", ".h", ".cpp", NULL }; + +language langs[] = { + { + "c", + HL_NUMBERS | HL_STRINGS, + "//", + "/*", + "*/", + c_keywords, + c_ext, + }, +}; + +#define LANGS_LEN (sizeof(langs) / sizeof(langs[0])) + +int is_separator(int c) +{ return isspace(c) || c == '\0' || strchr(",.()+-/*=~%<>[];", c) != NULL; } void update_highlight(row *row) { row->hl = realloc(row->hl, row->render_size); - memset(row->hl, HL_NORMAL, row->render_size); + memset(row->hl, NORMAL, row->render_size); + + if (vip.syntax == NULL) return; + + char **keywords = vip.syntax->keywords; + + char *scs = vip.syntax->singleline_comment_start; + char *mcs = vip.syntax->multiline_comment_start; + char *mce = vip.syntax->multiline_comment_end; + + int scs_len = scs ? strlen(scs) : 0; + int mcs_len = mcs ? strlen(mcs) : 0; + int mce_len = mce ? strlen(mce) : 0; int prev_sep = 1; + int in_string = 0; + int in_comment = (row->idx > 0 && vip.row[row->idx - 1].opened_comment); + int i = 0; while (i < row->render_size) { char c = row->render[i]; - unsigned char prev_hl = (i > 0) ? row->hl[i - 1] : HL_NORMAL; - if ((isdigit(c) && (prev_sep || prev_hl == HL_NUMBER)) || - (c == '.' && prev_hl == HL_NUMBER)) { - row->hl[i] = HL_NUMBER; - i++; - prev_sep = 0; - continue; + unsigned char prev_hl = (i > 0) ? row->hl[i - 1] : NORMAL; + + if (scs_len && !in_string && !in_comment) { + if (!strncmp(&row->render[i], scs, scs_len)) { + memset(&row->hl[i], COMMENT, row->render_size - i); + break; + } } + + if (mcs_len && mce_len && !in_string) { + if (in_comment) { + row->hl[i] = MLCOMMENT; + if (!strncmp(&row->render[i], mce, mce_len)) { + memset(&row->hl[i], MLCOMMENT, mce_len); + i += mce_len; + in_comment = 0; + prev_sep = 1; + continue; + } else { + i++; + continue; + } + } else if (!strncmp(&row->render[i], mcs, mcs_len)) { + memset(&row->hl[i], MLCOMMENT, mcs_len); + i += mcs_len; + in_comment = 1; + continue; + } + } + + if (vip.syntax->flags & HL_STRINGS) { + if (in_string) { + row->hl[i] = STRING; + if (c == '\\' && i + 1 < row->render_size) { + row->hl[i + 1] = STRING; + i += 2; + continue; + } + if (c == in_string) in_string = 0; + i++; + prev_sep = 1; + continue; + } else { + if (c == '"') { + in_string = c; + row->hl[i] = STRING; + i++; + continue; + } + } + } + + if (vip.syntax->flags & HL_NUMBERS) { + if ((isdigit(c) && (prev_sep || prev_hl == NUMBER)) || + (c == '.' && prev_hl == NUMBER)) { + row->hl[i] = NUMBER; + i++; + prev_sep = 0; + continue; + } + } + + if (prev_sep) { + int j; + for (j = 0; keywords[j]; j++) { + int klen = strlen(keywords[j]); + int type_keyword = keywords[j][klen - 1] == '|'; + if (type_keyword) klen--; + if (!strncmp(&row->render[i], keywords[j], klen) && + is_separator(row->render[i + klen])) { + memset(&row->hl[i], type_keyword ? KEYWORD2 : KEYWORD1, klen); + i += klen; + break; + } + } + if (keywords[j] != NULL) { + prev_sep = 0; + continue; + } + } + prev_sep = is_separator(c); i++; - }} + } + int changed = (row->opened_comment != in_comment); + row->opened_comment = in_comment; + if (changed && row->idx + 1 < vip.rows) + update_highlight(&vip.row[row->idx + 1]); +} char *syntax_to_color(int hl, size_t *len) { switch (hl) { - case HL_NUMBER: + case NUMBER: *len = COLOR_LEN; return strdup(PEACH_BG); - case HL_MATCH:; - char *str = malloc(COLOR_LEN * 2 + 1); - snprintf(str, COLOR_LEN * 2 + 1, "%s%s", BLACK_BG, SKY_FG); - *len = COLOR_LEN * 2; - return str; + case STRING: + *len = COLOR_LEN; + return strdup(GREEN_BG); - case HL_RESET:; - char *res = malloc(COLOR_LEN * 2 + 1); - snprintf(res, COLOR_LEN * 2 + 1, "%s%s", WHITE_BG, BLACK_FG); - *len = COLOR_LEN * 2; - return res; + case COMMENT: + case MLCOMMENT: + *len = COLOR_LEN; + return strdup(OVERLAY_0_BG); + + case KEYWORD1: + *len = COLOR_LEN; + return strdup(MAUVE_BG); + + case KEYWORD2: + *len = COLOR_LEN; + return strdup(YELLOW_BG); + + case MATCH:; + char *str = malloc(COLOR_LEN * 2 + 1); + snprintf(str, COLOR_LEN * 2 + 1, "%s%s", BLACK_BG, SKY_FG); + *len = COLOR_LEN * 2; + return str; + + case RESET:; + char *res = malloc(COLOR_LEN * 2 + 1); + snprintf(res, COLOR_LEN * 2 + 1, "%s%s", WHITE_BG, BLACK_FG); + *len = COLOR_LEN * 2; + return res; default: - *len = COLOR_LEN; - return strdup(WHITE_BG); + *len = COLOR_LEN; + return strdup(WHITE_BG); + } +} + +void select_syntax_highlight() +{ + vip.syntax = NULL; + if (vip.filename == NULL) return; + char *ext = strrchr(vip.filename, '.'); + for (unsigned int j = 0; j < LANGS_LEN; j++) { + language *s = &langs[j]; + unsigned int i = 0; + while (s->extensions[i]) { + int is_ext = (s->extensions[i][0] == '.'); + if ((is_ext && ext && !strcmp(ext, s->extensions[i])) || + (!is_ext && strstr(vip.filename, s->extensions[i]))) { + vip.syntax = s; + + for (int row = 0; row < vip.rows; row++) { + update_highlight(&vip.row[row]); + } + return; + } + i++; + } } }