tsyn: syntax highlighting - neatvi - [fork] simple vi-type editor with UTF-8 support (HTM) git clone git://src.adamsgaard.dk/neatvi (DIR) Log (DIR) Files (DIR) Refs (DIR) README --- (DIR) commit 71b2ab030dbda59b9d8cf44fb78bc0ff4af93073 (DIR) parent 26f00e91254bf63cbd7a6e0bc966c158be004aea (HTM) Author: Ali Gholami Rudi <ali@rudi.ir> Date: Fri, 22 May 2015 09:51:43 +0430 syn: syntax highlighting Diffstat: M Makefile | 3 ++- M conf.c | 29 ++++++++++++++++++++++++++++- M conf.h | 30 ++++++++++++++++++++++++++++++ M ex.c | 2 ++ M led.c | 8 ++++++++ A syn.c | 98 +++++++++++++++++++++++++++++++ M term.c | 30 ++++++++++++++++++++++++++++++ M vi.c | 2 ++ M vi.h | 17 +++++++++++++++++ 9 files changed, 217 insertions(+), 2 deletions(-) --- (DIR) diff --git a/Makefile b/Makefile t@@ -2,7 +2,8 @@ CC = cc CFLAGS = -Wall -O2 LDFLAGS = -OBJS = vi.o ex.o lbuf.o sbuf.o ren.o dir.o reg.o led.o uc.o term.o rset.o cmd.o conf.o +OBJS = vi.o ex.o lbuf.o sbuf.o ren.o dir.o syn.o reg.o led.o \ + uc.o term.o rset.o cmd.o conf.o all: vi (DIR) diff --git a/conf.c b/conf.c t@@ -1,5 +1,6 @@ -#include "conf.h" +#include <stdio.h> #include "vi.h" +#include "conf.h" char *conf_kmapalt(void) { t@@ -44,3 +45,29 @@ int conf_placeholder(int idx, char **s, char **d, int *wid) *wid = placeholders[idx].wid; return 0; } + +int conf_highlight(int idx, char **ft, int *att, int *grp, char **pat) +{ + if (idx < 0 || idx >= LEN(highlights)) + return 1; + if (ft) + *ft = highlights[idx].ft; + if (att) + *att = highlights[idx].att; + if (grp) + *grp = highlights[idx].grp; + if (pat) + *pat = highlights[idx].pat; + return 0; +} + +int conf_filetype(int idx, char **ft, char **pat) +{ + if (idx < 0 || idx >= LEN(filetypes)) + return 1; + if (ft) + *ft = filetypes[idx].ft; + if (pat) + *pat = filetypes[idx].pat; + return 0; +} (DIR) diff --git a/conf.h b/conf.h t@@ -49,3 +49,33 @@ static struct placeholder { {"َ", "ـَ", 1}, {"ّ", "ـّ", 1}, }; + +/* syntax highlighting patterns */ +static struct highlight { + char *ft; /* the filetype of this pattern */ + int att; /* attributes of the matched region */ + int grp; /* regular expression subgroup to highlight */ + char *pat; /* regular expression */ +} highlights[] = { + {"c", 5, 0, "\\<(char|short|int|long|float|double|void|struct|enum|union)\\>"}, + {"c", 5, 0, "\\<(static|extern|register)\\>"}, + {"c", 5, 0, "\\<(return|for|while|if|else|do|sizeof|goto|switch|case|default|break|continue)\\>"}, + {"c", SYN_IT | 2, 0, "//.*$"}, + {"c", SYN_IT | 2, 0, "/\\*([^*]|\\*[^/])*\\*/"}, + {"c", 6, 0, "^#[ \t]*[a-zA-Z0-9_]+"}, + {"c", SYN_BD, 1, "([a-zA-Z][a-zA-Z0-9_]+)\\("}, + {"c", 4, 0, "\"([^\"]|\\\\\")*\""}, + {"c", 4, 0, "'([^\\]|\\\\.)'"}, + + {"tr", SYN_BD, 0, "^\\.SH.*$"}, + {"tr", 4, 0, "^\\.[a-zA-Z0-9]{2}.*$"}, +}; + +/* map file names to file types */ +static struct filetype { + char *ft; /* file type */ + char *pat; /* file name pattern */ +} filetypes[] = { + {"c", "\\.[hc]$"}, + {"tr", "\\.(ms|tr|roff)$"}, +}; (DIR) diff --git a/ex.c b/ex.c t@@ -11,6 +11,7 @@ char xpath[PATHLEN]; /* current file */ char xpath_alt[PATHLEN]; /* alternate file */ +char xft[32]; /* filetype */ int xquit; /* exit if set */ int xvis; /* visual mode */ int xai = 1; /* autoindent option */ t@@ -189,6 +190,7 @@ static void ec_edit(char *ec) xrow_alt = xrow; xrow = xvis ? 0 : 1 << 20; } + strcpy(xft, syn_filetype(xpath)); fd = open(xpath, O_RDONLY); lbuf_rm(xb, 0, lbuf_len(xb)); if (fd >= 0) { (DIR) diff --git a/led.c b/led.c t@@ -45,7 +45,9 @@ static char *led_render(char *s0) int n, maxcol = 0; int *pos; /* pos[i]: the screen position of the i-th character */ int *off; /* off[i]: the character at screen position i */ + int *att; /* att[i]: the attributes of i-th character */ char **chrs; /* chrs[i]: the i-th character in s1 */ + int att_old = 0; struct sbuf *out; int i, j; int ctx = dir_context(s0); t@@ -64,10 +66,14 @@ static char *led_render(char *s0) } } } + att = syn_highlight(xft, s0); out = sbuf_make(); i = 0; while (i <= maxcol) { int o = off[i]; + int att_new = o >= 0 ? att[o] : 0; + sbuf_str(out, term_att(att_new, att_old)); + att_old = att_new; if (o >= 0) { if (ren_translate(chrs[o], s0)) sbuf_str(out, ren_translate(chrs[o], s0)); t@@ -83,6 +89,8 @@ static char *led_render(char *s0) i++; } } + sbuf_str(out, term_att(0, att_old)); + free(att); free(pos); free(off); free(chrs); (DIR) diff --git a/syn.c b/syn.c t@@ -0,0 +1,98 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "vi.h" + +#define NFTS 16 + +/* mapping filetypes to regular expression sets */ +static struct ftmap { + char ft[32]; + struct rset *rs; +} ftmap[NFTS]; + +static struct rset *syn_ftrs; + +static struct rset *syn_find(char *ft) +{ + int i; + for (i = 0; i < LEN(ftmap); i++) + if (!strcmp(ft, ftmap[i].ft)) + return ftmap[i].rs; + return NULL; +} + +int *syn_highlight(char *ft, char *s) +{ + int subs[16 * 2]; + int n = uc_slen(s); + int *att = malloc(n * sizeof(att[0])); + int sidx = 0; + struct rset *rs = syn_find(ft); + int flg = 0; + int hl, j; + memset(att, 0, n * sizeof(att[0])); + if (!rs) + return att; + while ((hl = rset_find(rs, s + sidx, LEN(subs) / 2, subs, flg)) >= 0) { + int beg, end; + int catt, cgrp; + conf_highlight(hl, NULL, &catt, &cgrp, NULL); + beg = uc_off(s, sidx + subs[cgrp * 2 + 0]); + end = uc_off(s, sidx + subs[cgrp * 2 + 1]); + for (j = beg; j < end; j++) + att[j] = catt; + sidx += subs[cgrp * 2 + 1] ? subs[cgrp * 2 + 1] : 1; + flg = RE_NOTBOL; + } + return att; +} + +static void syn_initft(char *name) +{ + char *pats[128] = {NULL}; + char *ft, *pat; + int i, n; + for (i = 0; !conf_highlight(i, &ft, NULL, NULL, &pat) && i < LEN(pats); i++) + if (!strcmp(ft, name)) + pats[i] = pat; + n = i; + for (i = 0; i < LEN(ftmap); i++) { + if (!ftmap[i].ft[0]) { + strcpy(ftmap[i].ft, name); + ftmap[i].rs = rset_make(n, pats, 0); + return; + } + } +} + +char *syn_filetype(char *path) +{ + int hl = rset_find(syn_ftrs, path, 0, NULL, 0); + char *ft; + if (!conf_filetype(hl, &ft, NULL)) + return ft; + return ""; +} + +void syn_init(void) +{ + char *pats[128] = {NULL}; + char *pat, *ft; + int i; + for (i = 0; !conf_highlight(i, &ft, NULL, NULL, NULL); i++) + if (!syn_find(ft)) + syn_initft(ft); + for (i = 0; !conf_filetype(i, NULL, &pat) && i < LEN(pats); i++) + pats[i] = pat; + syn_ftrs = rset_make(i, pats, 0); +} + +void syn_done(void) +{ + int i; + for (i = 0; i < LEN(ftmap); i++) + if (ftmap[i].rs) + rset_free(ftmap[i].rs); + rset_free(syn_ftrs); +} (DIR) diff --git a/term.c b/term.c t@@ -113,3 +113,33 @@ int term_read(int ms) return -1; return (unsigned char) b; } + +/* return a static string that changes text attributes from old to att */ +char *term_att(int att, int old) +{ + static char buf[128]; + char *s = buf; + int fg = SYN_FG(att); + int bg = SYN_BG(att); + if (att == old) + return ""; + s += sprintf(s, "\33[m\33["); + if (fg & SYN_BD) + s += sprintf(s, "1;"); + if (fg & SYN_IT) + s += sprintf(s, "3;"); + else if (fg & SYN_RV) + s += sprintf(s, "7;"); + if ((fg & 0xff) < 8) + s += sprintf(s, "%d;", 30 + (fg & 0xff)); + else + s += sprintf(s, "38;5;%d;", (fg & 0xff)); + if (bg) { + if ((bg & 0xff) < 8) + s += sprintf(s, "%d;", 40 + (bg & 0xff)); + else + s += sprintf(s, "48;5;%d;", (bg & 0xff)); + } + s += sprintf(s, "m"); + return buf; +} (DIR) diff --git a/vi.c b/vi.c t@@ -1227,6 +1227,7 @@ int main(int argc, char *argv[]) xvis = 1; } dir_init(); + syn_init(); if (i < argc) { snprintf(ecmd, PATHLEN, "e %s", argv[i]); ex_command(ecmd); t@@ -1237,6 +1238,7 @@ int main(int argc, char *argv[]) ex(); lbuf_free(xb); reg_done(); + syn_done(); dir_done(); return 0; } (DIR) diff --git a/vi.h b/vi.h t@@ -103,6 +103,7 @@ int term_cols(void); int term_read(int timeout); void term_record(void); void term_commit(void); +char *term_att(int att, int old); #define TK_CTL(x) ((x) & 037) #define TK_INT(c) ((c) < 0 || (c) == TK_ESC || (c) == TK_CTL('c')) t@@ -124,11 +125,26 @@ void ex_show(char *msg); /* process management */ char *cmd_pipe(char *cmd, char *s); +/* syntax highlighting */ +#define SYN_BD 0x100 +#define SYN_IT 0x200 +#define SYN_RV 0x400 +#define SYN_ATTR(f, b) (((b) << 16) | (f)) +#define SYN_FG(a) ((a) & 0xffff) +#define SYN_BG(a) ((a) >> 16) + +int *syn_highlight(char *ft, char *s); +char *syn_filetype(char *path); +void syn_init(void); +void syn_done(void); + /* configuration variables */ char *conf_kmapalt(void); int conf_dirmark(int idx, char **pat, int *ctx, int *dir, int *grp); int conf_dircontext(int idx, char **pat, int *ctx); int conf_placeholder(int idx, char **s, char **d, int *wid); +int conf_highlight(int idx, char **ft, int *att, int *grp, char **pat); +int conf_filetype(int idx, char **ft, char **pat); /* global variables */ #define PATHLEN 512 t@@ -148,3 +164,4 @@ extern int xai; extern int xdir; extern int xshape; extern int xorder; +extern char xft[];