src/highlighter.c

changeset 75
c72b250866ab
parent 67
5da2cb5aea6b
child 76
44c7423d6ce2
--- a/src/highlighter.c	Sun Oct 01 14:41:17 2023 +0200
+++ b/src/highlighter.c	Wed Jul 10 21:35:37 2024 +0200
@@ -29,12 +29,11 @@
 
 #include "highlighter.h"
 
-#include <stdlib.h>
-#include <stdio.h>
 #include <string.h>
 #include <ctype.h>
 
 #include <cx/string.h>
+#include <cx/printf.h>
 
 static void put_htmlescaped(CxBuffer *dest, char c) {
     if (c == '>') {
@@ -106,45 +105,101 @@
     
     /* local information */
     size_t sp = (size_t)-1;
+
     int isstring = 0, iscomment = 0, isinclude = 0, parseinclude = 0;
     char quote = '\0';
     int isescaping = 0;
-    
+
+    int continuation_enabled = 0;
+    const char* current_highlight = NULL;
+
+    /* define convenience macros */
+#define start_span(cl) \
+        current_highlight = cl; \
+        cx_bprintf(dest, "<span class=\"c2html-%s\">", current_highlight)
+#define stop_span \
+        current_highlight = NULL;\
+        cxBufferPutString(dest, "</span>")
+
     /* continue a multi line comment highlighting */
     if (hd->multiline_comment) {
         iscomment = 1;
-        cxBufferPutString(dest, "<span class=\"c2html-comment\">");
+        start_span("comment");
+    }
+
+    /* continue highlighting in case of line continuation */
+    if (hd->continue_highlight) {
+        start_span(hd->continue_highlight);
+        hd->continue_highlight = NULL;
+        isinclude = hd->continuation_info & 0x1;
+        isstring = hd->continuation_info & 0x2;
+        iscomment = hd->continuation_info & 0x4;
+        if (hd->continuation_info & 0x10) {
+            quote = '\'';
+        } else if (hd->continuation_info & 0x20) {
+            quote = '\"';
+        }
+        hd->continuation_info = 0;
     }
 
     char c;
     do {
         c = src[++sp];
         if (c == '\r') continue;
+
+        /* line continuation */
+        if (c == '\\') {
+            /* currently do not support continuations in user includes */
+            // TODO: also support user includes
+            if (!parseinclude) {
+                continuation_enabled = 1;
+            }
+        } else if (continuation_enabled) {
+            if (!isspace(c)) {
+                continuation_enabled = 0;
+            } else if (c == '\n') {
+                cxBufferPut(dest, '\n');
+                hd->continue_highlight = current_highlight;
+                hd->continuation_info =     \
+                        isinclude         | \
+                        (isstring << 1)   | \
+                        (iscomment << 2);
+                if (quote == '\'') {
+                    hd->continuation_info |= 0x10;
+                } else if (quote == '\"') {
+                    hd->continuation_info |= 0x20;
+                }
+                stop_span;
+                continue;
+            }
+        }
         
         /* comments */
         if (!isstring && c == '/') {
             if (hd->multiline_comment && sp > 0 && src[sp-1] == '*') {
                 iscomment = 0;
                 hd->multiline_comment = 0;
-                cxBufferPutString(dest, "/</span>");
+                cxBufferPut(dest, '/');
+                stop_span;
                 continue;
             } else if (!iscomment && (src[sp+1] == '/' || src[sp+1] == '*')) {
                 iscomment = 1;
                 hd->multiline_comment = (src[sp+1] == '*');
-                cxBufferPutString(dest, "<span class=\"c2html-comment\">");
+                start_span("comment");
             }
         }
 
         if (iscomment) {
             if (c == '\n') {
-                cxBufferPutString(dest, "</span>\n");
+                stop_span;
+                cxBufferPut(dest, '\n');
             } else {
                 put_htmlescaped(dest, c);
             }
         } else if (isinclude) {
             if (c == '<') {
-                cxBufferPutString(dest,
-                        "<span class=\"c2html-stdinclude\">&lt;");
+                start_span("stdinclude");
+                cxBufferPutString(dest, "&lt;");
             } else if (c == '\"') {
                 if (parseinclude) {
                     cxBufferPutString(dest, "\">");
@@ -158,7 +213,8 @@
                     parseinclude = 1;
                 }
             } else if (c == '>') {
-                cxBufferPutString(dest,  "&gt;</span>");
+                cxBufferPutString(dest,  "&gt;");
+                stop_span;
             } else {
                 if (parseinclude) {
                     cxBufferPut(ifilebuf, c);
@@ -172,14 +228,14 @@
                     put_htmlescaped(dest, c);
                     if (c == quote) {
                         isstring = 0;
-                        cxBufferPutString(dest, "</span>");
+                        stop_span;
                     } else {
                         put_htmlescaped(dest, c);
                     }
                 } else {
                     isstring = 1;
                     quote = c;
-                    cxBufferPutString(dest, "<span class=\"c2html-string\">");
+                    start_span("string");
                     put_htmlescaped(dest, c);
                 }
             } else {
@@ -195,24 +251,20 @@
                         int closespan = 1;
                         cxstring typesuffix = CX_STR("_t");
                         if (check_keyword(word, ckeywords)) {
-                            cxBufferPutString(dest,
-                                    "<span class=\"c2html-keyword\">");
+                            start_span("keyword");
                         } else if (cx_strsuffix(word, typesuffix)) {
-                            cxBufferPutString(dest,
-                                "<span class=\"c2html-type\">");
+                            start_span("type");
                         } else if (word.ptr[0] == '#') {
                             isinclude = !cx_strcmp(word, CX_STR("#include"));
-                            cxBufferPutString(dest,
-                                "<span class=\"c2html-directive\">");
+                            start_span("directive");
                         } else if (check_capsonly(word)) {
-                            cxBufferPutString(dest,
-                                "<span class=\"c2html-macroconst\">");
+                            start_span("macroconst");
                         } else {
                             closespan = 0;
                         }
                         put_htmlescapedstr(dest, word);
                         if (closespan) {
-                            cxBufferPutString(dest, "</span>");
+                            stop_span;
                         }
                     }
                     wbuf->pos = wbuf->size = 0; /* reset word buffer */
@@ -225,6 +277,9 @@
             isescaping = !isescaping & (c == '\\');
         }
     } while (c && c != '\n');
+
+#undef start_span
+#undef stop_span
 }
 
 /* Java Highlighter */

mercurial