tsyn: syntax highlighting - neatvi - [fork] simple vi-type editor with UTF-8 su… | |
git clone git://src.adamsgaard.dk/neatvi | |
Log | |
Files | |
Refs | |
README | |
--- | |
commit 71b2ab030dbda59b9d8cf44fb78bc0ff4af93073 | |
parent 26f00e91254bf63cbd7a6e0bc966c158be004aea | |
Author: Ali Gholami Rudi <[email protected]> | |
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(-) | |
--- | |
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.… | |
+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 | |
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; | |
+} | |
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|uni… | |
+ {"c", 5, 0, "\\<(static|extern|register)\\>"}, | |
+ {"c", 5, 0, "\\<(return|for|while|if|else|do|sizeof|goto|switch|case|d… | |
+ {"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)$"}, | |
+}; | |
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) { | |
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); | |
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)… | |
+ 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); | |
+} | |
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; | |
+} | |
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; | |
} | |
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[]; |