syntax.c (4745B)
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <string.h> 4 #include <ctype.h> 5 6 #include "vip.h" 7 #include "row.h" 8 #include "syntax.h" 9 10 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 }; 11 char *c_ext[] = { ".c", ".h", ".cpp", NULL }; 12 13 language langs[] = { 14 { 15 "c", 16 HL_NUMBERS | HL_STRINGS, 17 "//", 18 "/*", 19 "*/", 20 c_keywords, 21 c_ext, 22 }, 23 }; 24 25 #define LANGS_LEN (sizeof(langs) / sizeof(langs[0])) 26 27 int is_separator(int c) 28 { 29 return isspace(c) || c == '\0' || strchr(",.()+-/*=~%<>[];", c) != NULL; 30 } 31 32 void update_highlight(row *row) 33 { 34 row->hl = realloc(row->hl, row->render_size); 35 memset(row->hl, NORMAL, row->render_size); 36 37 if (vip.syntax == NULL) return; 38 39 char **keywords = vip.syntax->keywords; 40 41 char *scs = vip.syntax->singleline_comment_start; 42 char *mcs = vip.syntax->multiline_comment_start; 43 char *mce = vip.syntax->multiline_comment_end; 44 45 int scs_len = scs ? strlen(scs) : 0; 46 int mcs_len = mcs ? strlen(mcs) : 0; 47 int mce_len = mce ? strlen(mce) : 0; 48 49 int prev_sep = 1; 50 int in_string = 0; 51 int in_comment = (row->idx > 0 && vip.row[row->idx - 1].opened_comment); 52 53 int i = 0; 54 while (i < row->render_size) { 55 char c = row->render[i]; 56 unsigned char prev_hl = (i > 0) ? row->hl[i - 1] : NORMAL; 57 58 if (scs_len && !in_string && !in_comment) { 59 if (!strncmp(&row->render[i], scs, scs_len)) { 60 memset(&row->hl[i], COMMENT, row->render_size - i); 61 break; 62 } 63 } 64 65 if (mcs_len && mce_len && !in_string) { 66 if (in_comment) { 67 row->hl[i] = MLCOMMENT; 68 if (!strncmp(&row->render[i], mce, mce_len)) { 69 memset(&row->hl[i], MLCOMMENT, mce_len); 70 i += mce_len; 71 in_comment = 0; 72 prev_sep = 1; 73 continue; 74 } else { 75 i++; 76 continue; 77 } 78 } else if (!strncmp(&row->render[i], mcs, mcs_len)) { 79 memset(&row->hl[i], MLCOMMENT, mcs_len); 80 i += mcs_len; 81 in_comment = 1; 82 continue; 83 } 84 } 85 86 if (vip.syntax->flags & HL_STRINGS) { 87 if (in_string) { 88 row->hl[i] = STRING; 89 if (c == '\\' && i + 1 < row->render_size) { 90 row->hl[i + 1] = STRING; 91 i += 2; 92 continue; 93 } 94 if (c == in_string) in_string = 0; 95 i++; 96 prev_sep = 1; 97 continue; 98 } else { 99 if (c == '"') { 100 in_string = c; 101 row->hl[i] = STRING; 102 i++; 103 continue; 104 } 105 } 106 } 107 108 if (vip.syntax->flags & HL_NUMBERS) { 109 if ((isdigit(c) && (prev_sep || prev_hl == NUMBER)) || 110 (c == '.' && prev_hl == NUMBER)) { 111 row->hl[i] = NUMBER; 112 i++; 113 prev_sep = 0; 114 continue; 115 } 116 } 117 118 if (prev_sep) { 119 int j; 120 for (j = 0; keywords[j]; j++) { 121 int klen = strlen(keywords[j]); 122 int type_keyword = keywords[j][klen - 1] == '|'; 123 if (type_keyword) klen--; 124 if (!strncmp(&row->render[i], keywords[j], klen) && 125 is_separator(row->render[i + klen])) { 126 memset(&row->hl[i], type_keyword ? KEYWORD2 : KEYWORD1, klen); 127 i += klen; 128 break; 129 } 130 } 131 if (keywords[j] != NULL) { 132 prev_sep = 0; 133 continue; 134 } 135 } 136 137 prev_sep = is_separator(c); 138 i++; 139 } 140 int changed = (row->opened_comment != in_comment); 141 row->opened_comment = in_comment; 142 if (changed && row->idx + 1 < vip.rows) 143 update_highlight(&vip.row[row->idx + 1]); 144 } 145 146 char *syntax_to_color(int hl, size_t *len) 147 { 148 switch (hl) { 149 case NUMBER: 150 *len = COLOR_LEN; 151 return strdup(PEACH_BG); 152 153 case STRING: 154 *len = COLOR_LEN; 155 return strdup(GREEN_BG); 156 157 case COMMENT: 158 case MLCOMMENT: 159 *len = COLOR_LEN; 160 return strdup(OVERLAY_0_BG); 161 162 case KEYWORD1: 163 *len = COLOR_LEN; 164 return strdup(MAUVE_BG); 165 166 case KEYWORD2: 167 *len = COLOR_LEN; 168 return strdup(YELLOW_BG); 169 170 case MATCH:; 171 char *str = malloc(COLOR_LEN * 2 + 1); 172 snprintf(str, COLOR_LEN * 2 + 1, "%s%s", BLACK_BG, SKY_FG); 173 *len = COLOR_LEN * 2; 174 return str; 175 176 case RESET:; 177 char *res = malloc(COLOR_LEN * 2 + 1); 178 snprintf(res, COLOR_LEN * 2 + 1, "%s%s", WHITE_BG, BLACK_FG); 179 *len = COLOR_LEN * 2; 180 return res; 181 182 default: 183 *len = COLOR_LEN; 184 return strdup(WHITE_BG); 185 } 186 } 187 188 void select_syntax_highlight() 189 { 190 vip.syntax = NULL; 191 if (vip.filename == NULL) return; 192 char *ext = strrchr(vip.filename, '.'); 193 for (unsigned int j = 0; j < LANGS_LEN; j++) { 194 language *s = &langs[j]; 195 unsigned int i = 0; 196 while (s->extensions[i]) { 197 int is_ext = (s->extensions[i][0] == '.'); 198 if ((is_ext && ext && !strcmp(ext, s->extensions[i])) || 199 (!is_ext && strstr(vip.filename, s->extensions[i]))) { 200 vip.syntax = s; 201 202 for (int row = 0; row < vip.rows; row++) { 203 update_highlight(&vip.row[row]); 204 } 205 return; 206 } 207 i++; 208 } 209 } 210 } 211