]> git.mdlowis.com Git - projs/tide.git/commitdiff
first attempt at syntax highlighting. just colors comments
authorMichael D. Lowis <mike.lowis@gentex.com>
Fri, 9 Jun 2017 13:55:26 +0000 (09:55 -0400)
committerMichael D. Lowis <mike.lowis@gentex.com>
Fri, 9 Jun 2017 13:55:26 +0000 (09:55 -0400)
Makefile
inc/edit.h
lib/colors.c [new file with mode: 0644]
lib/view.c
lib/win.c

index 72208423e009015d8d192fa83c2006890114a27c..4d58821e0010e8af49c725de227125cfba96dd2f 100644 (file)
--- 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  \
index 6b8cca29c73ea077ce466d929fc60dccc99d2011..1c699be57e5a04f46ce37512d07a465d58a42f39 100644 (file)
@@ -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 (file)
index 0000000..9b83833
--- /dev/null
@@ -0,0 +1,85 @@
+#include <stdc.h>
+#include <utf.h>
+#include <edit.h>
+#include <config.h>
+
+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;
+}
index 0a36dd5a5ba7e0a863586d9449e898c056aa9e91..bf32960c606fa1750aef1af5a90c2387149b83e6 100644 (file)
@@ -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) {
index 609f6b6256913a0e70d655f43da9f1c29623b0d2..76e72de8a9bb4eb4a81cad91b37f0757b6316b87 100644 (file)
--- 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) {