jim

Simple, lightweight, modal, vim-inspired text editor
git clone git://git.janpasierb.com/jim.git
Log | Files | Refs | README | LICENSE

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 }