syntax.c (7620B)
1 #include"syntax.h" 2 #include<stdlib.h> 3 #include<ctype.h> 4 #include<string.h> 5 6 #define FG_RED 31 7 #define FG_GREEN 32 8 #define FG_YELLOW 33 9 #define FG_BLUE 34 10 #define FG_MAGENTA 35 11 #define FG_CYAN 36 12 #define FG_WHITE 37 13 #define BG_GREY 100 14 15 #define HL_HIGHLIGHT_NUMBERS (1<<0) 16 #define HL_HIGHLIGHT_STRINGS (1<<1) 17 18 struct editorSyntax { 19 char* filetype; 20 char** filematch; 21 char** directives; 22 char** keywords; 23 char** datatypes; 24 char* sl_comment_start; 25 char* ml_comment_start; 26 char* ml_comment_end; 27 int flags; 28 }; 29 30 char* C_HL_extensions[] = {".c", ".h", NULL}; 31 char* C_HL_keywords[] = {"switch", "if", "while", "for", "break", "continue", 32 "return", "else", "union", "static", "case", "sizeof", "const", "default", NULL}; 33 char* C_HL_datatypes[] = {"int", "long", "double", "float", "char", "unsigned", "signed", 34 "void", "struct", "typedef", "enum", "size_t", "va_list", "ssize_t", "FILE", NULL}; 35 char* C_HL_directives[] = {"#define", "#include", "#ifdef", "#undef", "#ifndef", "#if", "#else", 36 "#elif", "#endif", "#error", "#pragma", NULL}; 37 38 struct editorSyntax HLDB[] = { 39 { 40 "c", 41 C_HL_extensions, 42 C_HL_directives, 43 C_HL_keywords, 44 C_HL_datatypes, 45 "//", 46 "/*", 47 "*/", 48 HL_HIGHLIGHT_NUMBERS | HL_HIGHLIGHT_STRINGS 49 }, 50 }; 51 52 #define HLDB_ENTRIES (sizeof(HLDB) / sizeof(HLDB[0])) 53 54 int isSeparator(int c) { 55 return isspace(c) || c == '\0' || strchr(",.()+-/'*=~%<>[];:{}\"", c) != NULL; 56 } 57 58 void editorUpdateSyntax(erow* row) { 59 row->hl = realloc(row->hl, row->rsize); 60 memset(row->hl, HL_NORMAL, row->rsize); 61 62 if(E.syntax == NULL) 63 return; 64 65 char** directives = E.syntax->directives; 66 char** keywords = E.syntax->keywords; 67 char** datatypes = E.syntax->datatypes; 68 69 char* scs = E.syntax->sl_comment_start; 70 char* mcs = E.syntax->ml_comment_start; 71 char* mce = E.syntax->ml_comment_end; 72 73 int scs_len = scs ? strlen(scs) : 0; 74 int mcs_len = mcs ? strlen(mcs) : 0; 75 int mce_len = mce ? strlen(mce) : 0; 76 77 int prev_sep = 1; 78 int in_string = 0; 79 int in_comment = (row->idx > 0 && E.row[row->idx - 1].hl_open_comment); 80 int cont_dir = 0, dir_lt = 0; 81 82 int i = 0; 83 while(i < row->rsize) { 84 char c = row->render[i]; 85 unsigned char prev_hl = (i > 0) ? row->hl[i - 1] : HL_NORMAL; 86 87 if(scs_len && !in_string && !in_comment) { 88 if(!strncmp(&row->render[i], scs, scs_len)) { 89 memset(&row->hl[i], HL_COMMENT, row->rsize - i); 90 break; 91 } 92 } 93 94 if(mcs_len && mce_len && !in_string) { 95 if(in_comment) { 96 row->hl[i] = HL_MLCOMMENT; 97 if(!strncmp(&row->render[i], mce, mce_len)) { 98 memset(&row->hl[i], HL_MLCOMMENT, mce_len); 99 i += mce_len; 100 in_comment = 0; 101 prev_sep = 1; 102 continue; 103 } else { 104 i++; 105 continue; 106 } 107 } else if(!strncmp(&row->render[i], mcs, mcs_len)) { 108 memset(&row->hl[i], HL_MLCOMMENT, mcs_len); 109 i += mcs_len; 110 in_comment = 1; 111 continue; 112 } 113 } 114 115 for(int j = 0; directives[j]; j++) { 116 int dir_len = strlen(directives[j]); 117 118 if(!strncmp(&row->render[i], directives[j], dir_len) && 119 isSeparator(row->render[i + dir_len]) && !in_string) { 120 memset(&row->hl[i], HL_DIRECTIVE, dir_len); 121 cont_dir = 1; 122 i += dir_len; 123 c = row->render[i]; 124 break; 125 } 126 } 127 128 if(E.syntax->flags & HL_HIGHLIGHT_STRINGS) { 129 if(in_string) { 130 row->hl[i] = HL_STRING; 131 if(c == BACKSLASH && i + 1 < row->rsize) { 132 row->hl[i + 1] = HL_STRING; 133 i += 2; 134 continue; 135 } 136 if(c == in_string) 137 in_string = 0; 138 i++; 139 prev_sep = 1; 140 continue; 141 } else { 142 if(c == DOUBLE_QUOTE || c == SINGLE_QUOTE) { 143 in_string = c; 144 row->hl[i] = HL_STRING; 145 i++; 146 continue; 147 } 148 } 149 } 150 151 if(cont_dir && !in_string) { 152 if(c == LESS_THAN) { 153 dir_lt = i; 154 } else if(c == MORE_THAN) { 155 memset(&row->hl[dir_lt], HL_STRING, i - dir_lt + 1); 156 } else if(dir_lt) { 157 row->hl[i] = HL_NORMAL; 158 } else { 159 row->hl[i] = HL_DIRECTIVE; 160 } 161 } 162 163 if(E.syntax->flags & HL_HIGHLIGHT_NUMBERS) { 164 if((isdigit(c) && (prev_sep || prev_hl == HL_NUMBER)) || 165 (c == PERIOD && prev_hl == HL_NUMBER)) { 166 row->hl[i] = HL_NUMBER; 167 i++; 168 prev_sep = 0; 169 continue; 170 } 171 } 172 173 if(prev_sep) { 174 int j, found = 0; 175 for(j = 0; keywords[j]; j++) { 176 int kwd_len = strlen(keywords[j]); 177 178 if(!strncmp(&row->render[i], keywords[j], kwd_len) && 179 isSeparator(row->render[i + kwd_len])) { 180 memset(&row->hl[i], HL_KEYWORD, kwd_len); 181 i += kwd_len; 182 found++; 183 break; 184 } 185 } 186 for(j = 0; datatypes[j]; j++) { 187 int dt_len = strlen(datatypes[j]); 188 189 if(!strncmp(&row->render[i], datatypes[j], dt_len) && 190 isSeparator(row->render[i + dt_len])) { 191 memset(&row->hl[i], HL_DATATYPE, dt_len); 192 i += dt_len; 193 found++; 194 break; 195 } 196 } 197 198 if(found) { 199 prev_sep = 0; 200 continue; 201 } 202 } 203 204 prev_sep = isSeparator(c); 205 i++; 206 } 207 208 int changed = (row->hl_open_comment != in_comment); 209 row->hl_open_comment = in_comment; 210 if(changed && row->idx + 1 < E.numrows) 211 editorUpdateSyntax(&E.row[row->idx + 1]); 212 } 213 214 int editorSyntaxToColour(int hl) { 215 switch(hl) { 216 case HL_COMMENT: 217 case HL_MLCOMMENT: 218 return FG_CYAN; 219 case HL_DIRECTIVE: 220 return FG_MAGENTA; 221 case HL_KEYWORD: 222 return FG_YELLOW; 223 case HL_DATATYPE: 224 return FG_GREEN; 225 case HL_STRING: 226 return FG_RED; 227 case HL_NUMBER: 228 return FG_RED; 229 case HL_MATCH: 230 return BG_GREY; 231 default: 232 return FG_WHITE; 233 } 234 } 235 236 void editorSelectSyntaxHighlight() { 237 E.syntax = NULL; 238 if(E.filename == NULL) 239 return; 240 241 char* ext = strrchr(E.filename, PERIOD); 242 243 for(unsigned int j = 0; j < HLDB_ENTRIES; j++) { 244 struct editorSyntax* s = &HLDB[j]; 245 unsigned int i = 0; 246 while(s->filematch[i]) { 247 int is_ext = (s->filematch[i][0] == PERIOD); 248 if((is_ext && ext && !strcmp(ext, s->filematch[i])) || 249 (!is_ext && strstr(E.filename, s->filematch[i]))) { 250 E.syntax = s; 251 252 for(int filerow = 0; filerow < E.numrows; filerow++) { 253 editorUpdateSyntax(&E.row[filerow]); 254 } 255 256 return; 257 } 258 259 i++; 260 } 261 } 262 }