vip

VI Plus
git clone https://codeberg.org/night0721/vip
Log | Files | Refs | README | LICENSE

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