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[];