From: Michael D. Lowis Date: Fri, 9 Jun 2017 13:55:26 +0000 (-0400) Subject: first attempt at syntax highlighting. just colors comments X-Git-Url: https://git.mdlowis.com/?a=commitdiff_plain;h=3470e86ecd68ae79f8a7c467bdc7c28a501f40f9;p=projs%2Ftide.git first attempt at syntax highlighting. just colors comments --- diff --git a/Makefile b/Makefile index 7220842..4d58821 100644 --- a/Makefile +++ b/Makefile @@ -11,7 +11,8 @@ LIBEDIT_OBJS = \ lib/exec.o \ lib/view.o \ lib/x11.o \ - lib/win.o + lib/win.o \ + lib/colors.o TEST_BINS = \ tests/tide \ diff --git a/inc/edit.h b/inc/edit.h index 6b8cca2..1c699be 100644 --- a/inc/edit.h +++ b/inc/edit.h @@ -120,6 +120,29 @@ void utf8save(Buf* buf, FILE* file); void binload(Buf* buf, FMap file); void binsave(Buf* buf, FILE* file); +/* Syntax Highlighting + *****************************************************************************/ +typedef struct { + char* name; + char** extensions; + struct { + char* line_beg; + char* multi_beg; + char* multi_end; + } comments; +} SyntaxDef; + +typedef struct SyntaxSpan { + size_t beg; + size_t end; + size_t color; + struct SyntaxSpan* prev; + struct SyntaxSpan* next; +} SyntaxSpan; + +SyntaxDef* colors_find(char* path); +SyntaxSpan* colors_scan(SyntaxDef* syntax, Buf* buf); + /* Screen management functions *****************************************************************************/ typedef struct { @@ -136,15 +159,17 @@ typedef struct { } Row; typedef struct { - bool sync_needed; /* whether the view needs to be synced with cursor */ - bool sync_center; /* cursor should be centered on screen if possible */ - bool sync_lines; /* whether the line numbers should be recalculated */ - size_t nrows; /* number of rows in the view */ - size_t ncols; /* number of columns in the view */ - Row** rows; /* array of row data structures */ - Buf buffer; /* the buffer used to populate the view */ - Sel selection; /* range of currently selected text */ - size_t prev_csr; /* previous cursor location */ + bool sync_needed; /* whether the view needs to be synced with cursor */ + bool sync_center; /* cursor should be centered on screen if possible */ + bool sync_lines; /* whether the line numbers should be recalculated */ + size_t nrows; /* number of rows in the view */ + size_t ncols; /* number of columns in the view */ + Row** rows; /* array of row data structures */ + Buf buffer; /* the buffer used to populate the view */ + Sel selection; /* range of currently selected text */ + size_t prev_csr; /* previous cursor location */ + SyntaxDef* syntax; /* syntax rules object */ + SyntaxSpan* spans; /* list of colored regions */ } View; enum { diff --git a/lib/colors.c b/lib/colors.c new file mode 100644 index 0000000..9b83833 --- /dev/null +++ b/lib/colors.c @@ -0,0 +1,85 @@ +#include +#include +#include +#include + +static SyntaxDef Syntaxes[] = { + { + .name = "Text", + .extensions = (char*[]){ 0 }, + .comments = { .line_beg = "#" } + }, + { + .name = "C", + .extensions = (char*[]){ + ".c", ".h", ".C", ".cpp", ".CPP", ".hpp", ".cc", ".c++", ".cxx", 0 }, + .comments = { + .line_beg = "//", .multi_beg = "/*", .multi_end = "*/" } + }, + { + .name = "Ruby", + .extensions = (char*[]){ ".rb", 0 }, + .comments = { .line_beg = "#" } + }, + { + .name = "Shell", + .extensions = (char*[]){ ".sh", 0 }, + .comments = { .line_beg = "#" } + } +}; + +SyntaxDef* colors_find(char* path) { + char* ext = strrchr(path, '.'); + for (int i = 0; i < nelem(Syntaxes); i++) { + char** synext = Syntaxes[i].extensions; + for (; ext && *synext; synext++) { + if (!strcmp(*synext, ext)) + return &Syntaxes[i]; + } + } + return &Syntaxes[0]; +} + +static bool matches(Buf* buf, size_t* off, char* str) { + size_t curr = *off; + if (str) { + while (*str && *str == buf_get(buf, curr)) + curr++, str++; + if (*str == '\0') { + *off = curr; + return true; + } + } + return false; +} + +static SyntaxSpan* mkspan(size_t beg, size_t end, size_t clr, SyntaxSpan* span) { + SyntaxSpan* newspan = malloc(sizeof(SyntaxSpan)); + newspan->beg = beg; + newspan->end = end; + newspan->color = clr; + newspan->prev = span; + newspan->next = NULL; + if (span) + span->next = newspan; + return newspan; +} + +SyntaxSpan* colors_scan(SyntaxDef* syntax, Buf* buf) { + SyntaxSpan* firstspan = NULL; + SyntaxSpan* spans = NULL; + if (!syntax) return spans; + for (size_t end = buf_end(buf), off = 0; off < end; off++) { + size_t start = off; + if (matches(buf, &off, syntax->comments.line_beg)) + for (; off < end && !buf_iseol(buf, off); off++); + else if (matches(buf, &off, syntax->comments.multi_beg)) + for (; off < end && !matches(buf, &off, syntax->comments.multi_end); off++); + if (start != off) { + spans = mkspan(start, ++off, CLR_Cursor, spans); + } + if (!firstspan && spans) + firstspan = spans; + } + return firstspan; +} diff --git a/lib/view.c b/lib/view.c index 0a36dd5..bf32960 100644 --- a/lib/view.c +++ b/lib/view.c @@ -39,8 +39,10 @@ void view_init(View* view, char* file, void (*errfn)(char*)) { view->prev_csr = 0; /* load the file and jump to the address returned from the load function */ buf_init(&(view->buffer), errfn); - if (file) + if (file) { view_jumpto(view, false, buf_load(&(view->buffer), file)); + view->syntax = colors_find(view->buffer.path); + } } void view_reload(View* view) { @@ -100,6 +102,31 @@ void view_update(View* view, size_t* csrx, size_t* csry) { view_scrollto(view, csr); /* locate the cursor if visible */ find_cursor(view, csrx, csry); + + view->spans = colors_scan(view->syntax, &(view->buffer)); + SyntaxSpan* curr = view->spans; + for (size_t r = 0; curr && r < view->nrows; r++) { + Row* row = view->rows[r]; + for (; curr && curr->end < row->off; curr = curr->next); + if (curr) { + size_t off = row->off, col = 0; + while (col < row->len) { + if (curr->beg <= off && off < curr->end) { + uint32_t attr = row->cols[col].attr; + row->cols[col].attr = (attr & 0xF0) | curr->color; + } + off++, col++; + while (col < row->len && row->cols[col].rune == '\0') + col++; + } + } + } + + while (view->spans) { + SyntaxSpan* deadite = view->spans; + view->spans = deadite->next; + free(deadite); + } } Row* view_getrow(View* view, size_t row) { diff --git a/lib/win.c b/lib/win.c index 609f6b6..76e72de 100644 --- a/lib/win.c +++ b/lib/win.c @@ -367,8 +367,8 @@ static void onwheeldn(WinRegion id, bool pressed, size_t row, size_t col) { } static void draw_line_num(size_t x, size_t y, size_t gcols, size_t num) { - UGlyph glyphs[gcols]; if (ShowLineNumbers) { + UGlyph glyphs[gcols]; for (int i = gcols-1; i >= 0; i--) { glyphs[i].attr = CLR_GutterText; if (num > 0) {