qemacs-commit
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemacs-commit] qemacs Makefile txl.c nim.c rebol.c elm.c jai.c...


From: Charlie Gordon
Subject: [Qemacs-commit] qemacs Makefile txl.c nim.c rebol.c elm.c jai.c...
Date: Fri, 2 Oct 2020 17:32:30 -0400 (EDT)

CVSROOT:        /sources/qemacs
Module name:    qemacs
Changes by:     Charlie Gordon <chqrlie>        20/10/02 17:32:30

Modified files:
        .              : Makefile 
Added files:
        .              : txl.c nim.c rebol.c elm.c jai.c ats.c 

Log message:
        add colorizers for txl, nim, rebol, elm, jai, ats

CVSWeb URLs:
http://cvs.savannah.gnu.org/viewcvs/qemacs/Makefile?cvsroot=qemacs&r1=1.107&r2=1.108
http://cvs.savannah.gnu.org/viewcvs/qemacs/txl.c?cvsroot=qemacs&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/qemacs/nim.c?cvsroot=qemacs&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/qemacs/rebol.c?cvsroot=qemacs&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/qemacs/elm.c?cvsroot=qemacs&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/qemacs/jai.c?cvsroot=qemacs&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/qemacs/ats.c?cvsroot=qemacs&rev=1.1

Patches:
Index: Makefile
===================================================================
RCS file: /sources/qemacs/qemacs/Makefile,v
retrieving revision 1.107
retrieving revision 1.108
diff -u -b -r1.107 -r1.108
--- Makefile    27 Mar 2019 07:41:54 -0000      1.107
+++ Makefile    2 Oct 2020 21:32:29 -0000       1.108
@@ -39,6 +39,12 @@
 #include local compiler configuration file
 -include $(DEPTH)/cflags.mk
 
+ifdef CONFIG_DARWIN
+  CFLAGS += -Wno-string-plus-int
+else
+  CFLAGS += -Wno-unused-result
+endif
+
 ifdef TARGET_GPROF
   CFLAGS  += -p
   LDFLAGS += -p
@@ -125,7 +131,8 @@
 ifdef CONFIG_ALL_MODES
   OBJS+= unihex.o bufed.o clang.o xml.o htmlsrc.o forth.o arm.o \
          lisp.o makemode.o markdown.o orgmode.o perl.o script.o \
-         ebnf.o cobol.o rlang.o $(EXTRA_MODES) extra-modes.o
+         ebnf.o cobol.o rlang.o txl.o nim.o rebol.o elm.o jai.o ats.o \
+         $(EXTRA_MODES) extra-modes.o
   ifndef CONFIG_WIN32
     OBJS+= shell.o dired.o latex-mode.o archive.o
   endif

Index: txl.c
===================================================================
RCS file: txl.c
diff -N txl.c
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ txl.c       2 Oct 2020 21:32:29 -0000       1.1
@@ -0,0 +1,166 @@
+/*
+ * TXL language mode for QEmacs.
+ *
+ * Copyright (c) 2015-2017 Charlie Gordon.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "qe.h"
+
+/*---------------- TXL coloring ----------------*/
+
+#define MAX_KEYWORD_SIZE  16
+
+static char const txl_keywords[] = {
+    "|all|assert|attr|by|comments|compounds|construct|deconstruct"
+    "|define|each|end|export|external|function|import|include"
+    "|keys|list|match|not|opt|push|pop|redefine|repeat|replace"
+    "|rule|see|skipping|tokens|where"
+};
+
+static char const txl_types[] = {
+    "|"
+};
+
+enum {
+    TXL_STYLE_TEXT =        QE_STYLE_DEFAULT,
+    TXL_STYLE_COMMENT =     QE_STYLE_COMMENT,
+    TXL_STYLE_STRING =      QE_STYLE_STRING,
+    TXL_STYLE_KEYWORD =     QE_STYLE_KEYWORD,
+    TXL_STYLE_SYMBOL =      QE_STYLE_NUMBER,
+    TXL_STYLE_TYPE =        QE_STYLE_TYPE,
+    TXL_STYLE_PREPROCESS =  QE_STYLE_PREPROCESS,
+    TXL_STYLE_IDENTIFIER =  QE_STYLE_VARIABLE,
+};
+
+enum {
+    IN_TXL_COMMENT1 = 0x01,
+    IN_TXL_COMMENT2 = 0x02,
+};
+
+static void txl_colorize_line(QEColorizeContext *cp,
+                              unsigned int *str, int n, ModeDef *syn)
+{
+    char keyword[MAX_KEYWORD_SIZE];
+    int i = 0, start = 0, c, style, klen;
+    int colstate = cp->colorize_state;
+
+    if (colstate & IN_TXL_COMMENT1)
+        goto in_comment1;
+
+    if (colstate & IN_TXL_COMMENT2)
+        goto in_comment2;
+
+    style = 0;
+    while (i < n) {
+        start = i;
+        c = str[i++];
+        switch (c) {
+        case '%':
+            if (str[i] == '(') {
+                colstate = IN_TXL_COMMENT1;
+                i++;
+            in_comment1:
+                while (i < n) {
+                    if (str[i++] == ')' && str[i] == '%') {
+                        colstate = 0;
+                        break;
+                    }
+                }
+            } else
+            if (str[i] == '{') {
+                colstate = IN_TXL_COMMENT2;
+                i++;
+            in_comment2:
+                while (i < n) {
+                    if (str[i++] == '}' && str[i] == '%') {
+                        colstate = 0;
+                        break;
+                    }
+                }
+            } else {
+                i = n;
+            }
+            style = TXL_STYLE_COMMENT;
+            break;
+        case '\'':
+            /* parse quoted token */
+            for (; i < n && !qe_isblank(str[i]); i++)
+                continue;
+            style = TXL_STYLE_SYMBOL;
+            break;
+        default:
+            /* parse numbers */
+            if (qe_isdigit(c)) {
+                for (; i < n; i++) {
+                    if (!qe_isalnum(str[i]) && str[i] != '.')
+                        break;
+                }
+                style = TXL_STYLE_IDENTIFIER;
+                break;
+            }
+            /* parse identifiers and keywords */
+            if (qe_isalpha_(c)) {
+                klen = 0;
+                keyword[klen++] = qe_tolower(c);
+                for (; i < n; i++) {
+                    if (qe_isalnum_(str[i])) {
+                        if (klen < countof(keyword) - 1)
+                            keyword[klen++] = qe_tolower(str[i]);
+                    } else {
+                        if (qe_findchar("$&!@%#", str[i]))
+                            i++;
+                        break;
+                    }
+                }
+                keyword[klen] = '\0';
+                if (strfind(syn->keywords, keyword)) {
+                    style = TXL_STYLE_KEYWORD;
+                    break;
+                }
+                if (strfind(syn->types, keyword)) {
+                    style = TXL_STYLE_TYPE;
+                    break;
+                }
+                style = TXL_STYLE_IDENTIFIER;
+                break;
+            }
+            continue;
+        }
+        if (style) {
+            SET_COLOR(str, start, i, style);
+            style = 0;
+        }
+    }
+    cp->colorize_state = colstate;
+}
+
+static ModeDef txl_mode = {
+    .name = "Txl",
+    .extensions = "txl",
+    .keywords = txl_keywords,
+    .types = txl_types,
+    .colorize_func = txl_colorize_line,
+};
+
+static int txl_init(void)
+{
+    qe_register_mode(&txl_mode, MODEF_SYNTAX);
+
+    return 0;
+}
+
+qe_module_init(txl_init);

Index: nim.c
===================================================================
RCS file: nim.c
diff -N nim.c
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ nim.c       2 Oct 2020 21:32:30 -0000       1.1
@@ -0,0 +1,334 @@
+/*
+ * Nim mode for QEmacs.
+ *
+ * Copyright (c) 2015-2017 Charlie Gordon.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "qe.h"
+
+#define MAX_KEYWORD_SIZE  16
+
+/*---------------- Nim coloring ----------------*/
+
+static char const nim_keywords[] = {
+    /* Nim keywords */
+    "addr|and|as|asm|atomic|bind|block|break|case|cast|concept|const|"
+    "continue|converter|defer|discard|distinct|div|do|elif|else|end|"
+    "enum|except|export|finally|for|from|func|generic|if|import|in|include|"
+    "interface|is|isnot|iterator|let|macro|method|mixin|mod|nil|not|notin|"
+    "object|of|or|out|proc|ptr|raise|ref|return|shl|shr|static|template|"
+    "try|tuple|type|using|var|when|while|with|without|xor|yield|"
+    /* predefined operators */
+    "inc|dec|"
+    /* predefined constants */
+    "true|false|"
+};
+
+static char const nim_types[] = {
+    "int|uint|cint|cuint|clong|cstring|string|char|byte|bool|"
+    "openArray|seq|array|void|pointer|float|csize|cdouble|"
+    "cchar|cschar|cshort|cu|nil|expr|stmt|typedesc|auto|any|"
+    "range|openarray|varargs|set|cfloat|"
+    "int8|int16|int32|int64|uint8|uint16|uint32|uint64|"
+};
+
+enum {
+    NIM_STYLE_TEXT =     QE_STYLE_DEFAULT,
+    NIM_STYLE_PREPROCESS = QE_STYLE_PREPROCESS,
+    NIM_STYLE_COMMENT =  QE_STYLE_COMMENT,
+    NIM_STYLE_STRING =   QE_STYLE_STRING,
+    NIM_STYLE_NUMBER =   QE_STYLE_NUMBER,
+    NIM_STYLE_KEYWORD =  QE_STYLE_KEYWORD,
+    NIM_STYLE_TYPE =     QE_STYLE_TYPE,
+    NIM_STYLE_FUNCTION = QE_STYLE_FUNCTION,
+    NIM_STYLE_PRAGMA =   QE_STYLE_PREPROCESS,
+};
+
+/* nim-mode colorization states */
+enum {
+    IN_NIM_COMMENT      = 0x80,
+    IN_NIM_CHARLIT      = 0x40,
+    IN_NIM_STRING       = 0x20,
+    IN_NIM_LONG_STRING  = 0x10,
+    IN_NIM_RAW_STRING   = 0x08,
+    IN_NIM_STRING_BQ    = 0x04,
+    IN_NIM_PRAGMA       = 0x02,
+};
+
+static void nim_colorize_line(QEColorizeContext *cp,
+                              unsigned int *str, int n, ModeDef *syn)
+{
+    int i = 0, start = i, style = 0, c, sep = 0, klen;
+    int state = cp->colorize_state;
+    char kbuf[64];
+
+    if (state & IN_NIM_COMMENT) {
+        goto parse_comment;
+    }
+    if (state & IN_NIM_CHARLIT) {
+        sep = '\'';
+        goto parse_string;
+    }
+    if (state & IN_NIM_STRING) {
+        sep = '\"';
+        goto parse_string;
+    }
+    if (state & IN_NIM_LONG_STRING) {
+        sep = '\"';
+        goto parse_long_string;
+    }
+    if (state & IN_NIM_STRING_BQ) {
+        sep = '`';
+        goto parse_string;
+    }
+
+    while (i < n) {
+        start = i;
+        c = str[i++];
+        switch (c) {
+        case '#':
+            if (start == 0 && str[i] == '!') {
+                i = n;
+                style = NIM_STYLE_PREPROCESS;
+                break;
+            }
+
+        parse_comment:
+            state &= ~IN_NIM_COMMENT;
+            /* XXX: should handle trailing backslash more generically */
+            for (; i < n; i++) {
+                if (str[i] == '\\')
+                    state |= IN_NIM_COMMENT;
+                else
+                if (!qe_isblank(str[i]))
+                    state &= ~IN_NIM_COMMENT;
+            }
+            style = NIM_STYLE_COMMENT;
+            break;
+#if 0
+        case 'r':
+        case 'R':
+            if (str[i] == '\"') {
+                state |= IN_NIM_RAW_STRING;
+                goto has_quote;
+            }
+            goto has_alpha;
+#endif
+        case '`':
+            sep = c;
+            style = IN_NIM_STRING_BQ;
+            goto parse_string;
+
+        case '\'':
+            sep = c;
+            style = IN_NIM_CHARLIT;
+            goto parse_string;
+
+        case '\"':
+            /* parse string const */
+            i--;
+        has_quote:
+            sep = str[i++];
+            if (str[i] == (unsigned int)sep && str[i + 1] == (unsigned 
int)sep) {
+                /* long string */
+                state |= IN_NIM_LONG_STRING | IN_NIM_RAW_STRING;
+                i += 2;
+            parse_long_string:
+                while (i < n) {
+                    c = str[i++];
+                    if (!(state & IN_NIM_RAW_STRING) && c == '\\') {
+                        if (i < n) {
+                            i += 1;
+                        }
+                    } else
+                    if (c == sep && str[i] == (unsigned int)sep
+                    &&  str[i + 1] == (unsigned int)sep && str[i + 2] != 
(unsigned int)sep) {
+                        i += 2;
+                        state &= ~(IN_NIM_LONG_STRING | IN_NIM_RAW_STRING);
+                        break;
+                    }
+                }
+            } else {
+                state = IN_NIM_STRING;
+            parse_string:
+                while (i < n) {
+                    c = str[i++];
+                    if (!(state & IN_NIM_RAW_STRING) && c == '\\') {
+                        if (i < n) {
+                            i += 1;
+                        }
+                        continue;
+                    }
+                    if (c == sep) {
+                        if ((state & IN_NIM_RAW_STRING) && str[i] == '"') {
+                            i += 1;
+                            continue;
+                        }
+                        state &= ~(IN_NIM_STRING | IN_NIM_RAW_STRING);
+                        break;
+                    }
+                }
+            }
+            style = NIM_STYLE_STRING;
+            break;
+
+        case '.':
+            if (str[i] == '}') {
+                i += 1;
+                state &= ~IN_NIM_PRAGMA;
+                style = NIM_STYLE_PRAGMA;
+                break;
+            }
+            continue;
+
+            break;
+
+            // Handle ( ) { } [ ] (. .) {. .} [. .] : :: .. `
+
+        case '{':
+            if (str[i] == '.' && str[i + 1] != '.') {
+                /* Nim pragmas */
+                for (i++;; i++) {
+                    if (qe_isalnum_(str[i]))
+                        continue;
+                    if (str[i] == '.' && str[i + 1] != '}')
+                        continue;
+                    break;
+                }
+                state |= IN_NIM_PRAGMA;
+                style = NIM_STYLE_PRAGMA;
+                break;
+            }
+            continue;
+
+        default:
+            if (qe_isdigit(c)) {
+                int j, k;
+                static const char * const suffixes[] = {
+                    "i8", "i16", "i32", "i64", "u8", "u16", "u32", "u64",
+                    "f32", "f64", "f128",
+                };
+
+                if (c == '0' && qe_match2(str[i], 'b', 'B')) {
+                    /* binary numbers */
+                    for (i += 1; qe_isbindigit_(str[i]); i++)
+                        continue;
+                } else
+                if (c == '0' && (str[i] == 'o' || qe_match2(str[i], 'c', 
'C'))) {
+                    /* octal numbers */
+                    for (i += 1; qe_isoctdigit_(str[i]); i++)
+                        continue;
+                } else
+                if (c == '0' && qe_match2(str[i], 'x', 'X')) {
+                    /* hexadecimal numbers */
+                    for (i += 1; qe_isxdigit_(str[i]); i++)
+                        continue;
+                } else {
+                    /* decimal numbers */
+                    for (; qe_isdigit_(str[i]); i++)
+                        continue;
+                    if (str[i] == '.' && qe_isdigit_(str[i + 1])) {
+                        i++;
+                        /* decimal floats require a digit after the '.' */
+                        for (; qe_isdigit_(str[i]); i++)
+                            continue;
+                    }
+                    if (qe_match2(str[i], 'e', 'E')) {
+                        int k = i + 1;
+                        if (qe_match2(str[i], '+', '-'))
+                            k++;
+                        if (qe_isdigit(str[k])) {
+                            for (i = k + 1; qe_isdigit_(str[i]); i++)
+                                continue;
+                        }
+                    }
+                }
+                /* handle optional ' and type suffix */
+                j = i;
+                if (str[j] == '\'')
+                    j++;
+                if (qe_isalpha(str[j])) {
+                    for (k = 0; k < countof(suffixes); k++) {
+                        if (ustrstart(str + j, suffixes[k], &klen)
+                        &&  !qe_isalnum_(str[j + klen])) {
+                            i = j + klen;
+                            break;
+                        }
+                    }
+                }
+                /* XXX: should detect malformed number constants */
+                style = NIM_STYLE_NUMBER;
+                break;
+            }
+        //has_alpha:
+            if (qe_isalpha_(c)) {
+                i += ustr_get_identifier(kbuf, countof(kbuf), c, str, i, n);
+                if (str[i] == '"') {
+                    /* generalized raw string literal */
+                    state |= IN_NIM_RAW_STRING;
+                    goto has_quote;
+                }
+
+                if (strfind(syn->keywords, kbuf)) {
+                    style = NIM_STYLE_KEYWORD;
+                    break;
+                }
+                if ((start == 0 || str[start - 1] != '.')
+                &&  (str[i] != '.')) {
+                    if (strfind(syn->types, kbuf)) {
+                        //|| (qe_isupper(c) && haslower)
+                        style = NIM_STYLE_TYPE;
+                        break;
+                    }
+                }
+                if (check_fcall(str, i)) {
+                    style = NIM_STYLE_FUNCTION;
+                    break;
+                }
+                continue;
+            }
+            continue;
+        }
+        if (style) {
+            SET_COLOR(str, start, i, style);
+            style = 0;
+        }
+    }
+    // XXX: should handle line continuation with trailing \\ followed
+    // by white space
+    SET_COLOR1(str, n, style);    /* set style on eol char */
+
+    cp->colorize_state = state;
+}
+
+static ModeDef nim_mode = {
+    .name = "Nim",
+    .extensions = "nim",
+    .shell_handlers = "nim",
+    .keywords = nim_keywords,
+    .types = nim_types,
+    .colorize_func = nim_colorize_line,
+};
+
+static int nim_init(void)
+{
+    qe_register_mode(&nim_mode, MODEF_SYNTAX);
+
+    return 0;
+}
+
+qe_module_init(nim_init);

Index: rebol.c
===================================================================
RCS file: rebol.c
diff -N rebol.c
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ rebol.c     2 Oct 2020 21:32:30 -0000       1.1
@@ -0,0 +1,309 @@
+/*
+ * REBOL language mode for QEmacs.
+ *
+ * Copyright (c) 2015-2017 Charlie Gordon.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "qe.h"
+
+/*---------------- REBOL coloring ----------------*/
+
+static char const rebol_keywords[] = {
+    /* Constants */
+    "none|true|false|on|off|yes|no|newline|tab|cr|lf|null|pi|"
+    /* Evalute */
+    "do|reduce|compose|"
+    /* Branch */
+    "if|either|all|any|case|switch|"
+    /* Loop */
+    "loop|repeat|foreach|while|remove-each|break|"
+    /* Function */
+    "function|funct|func|has|does|exit|return|"
+    /* Error */
+    "attempt|try|catch|throw|"
+    /* Help */
+    "help|what|docs|source|trace|probe|??|delta-time|"
+    /* Compare */
+    "<|>|<=|>=|=|==|<>|!=|!==|=?|same?|"
+    /* Math */
+    "+|-|*|/|**|remainder|negate|abs|absolute|round|min|max|"
+    "and|or|xor|not|random|shift|sine|log-e|to|"
+    /* Reflection */
+    "words-of|values-of|title-of|spec-of|body-of|"
+    /* Series */
+    "find|select|first|last|pick|length?|index?|next|back|skip|"
+    "make|copy|join|ajoin|rejoin|append|repend|insert|remove|"
+    "take|clear|change|replace|trim|split|sort|swap|"
+    /* Sets */
+    "unique|union|intersect|difference|exclude|"
+    /* Console */
+    "print|probe|input|ask|confirm|halt|quit|"
+    /* Output */
+    "mold|form|to|"
+    /* Files/Ports */
+    "read|write|load|save|open|close|delete|exists?|size?|"
+    "modified?|suffix?|dir?|split-path|dirize|to-local-file|"
+    /* Context */
+    "object|module|import|construct|bind|get|set|in|value?|use|"
+    /* Other */
+    "now|parse|secure|wait|browse|compress|decompress|"
+    "lowercase|uppercase|entab|detab|"
+    /* GUI/Graphics */
+    "view|unview|layout|alert|request|request-file|draw|show|"
+    "get-face|set-face|focus|"
+    //"then|forall|rebol|end|native|self|some|"
+};
+
+static char const rebol_types[] = {
+    "|"
+};
+
+enum {
+    REBOL_STYLE_TEXT =        QE_STYLE_DEFAULT,
+    REBOL_STYLE_COMMENT =     QE_STYLE_COMMENT,
+    REBOL_STYLE_STRING =      QE_STYLE_STRING,
+    REBOL_STYLE_NUMBER =      QE_STYLE_NUMBER,
+    REBOL_STYLE_KEYWORD =     QE_STYLE_KEYWORD,
+    REBOL_STYLE_TYPE =        QE_STYLE_TYPE,
+    REBOL_STYLE_BINARY =      QE_STYLE_PREPROCESS,
+    REBOL_STYLE_DEFINITION =  QE_STYLE_FUNCTION,
+    REBOL_STYLE_ERROR =       QE_STYLE_ERROR,
+};
+
+enum {
+    IN_REBOL_STRING1 = 0x0F,  /* allow embedded balanced { } */
+    IN_REBOL_STRING2 = 0x10,
+    IN_REBOL_BINARY =  0x20,
+    IN_REBOL_COMMENT = 0x40,
+};
+
+static void rebol_colorize_line(QEColorizeContext *cp,
+                              unsigned int *str, int n, ModeDef *syn)
+{
+    char keyword[64];
+    int i = 0, start = 0, c, style, style0 = 0, k, klen, level;
+    int colstate = cp->colorize_state;
+
+    level = colstate & IN_REBOL_STRING1;
+    if (level)
+        goto in_string1;
+
+    if (colstate & IN_REBOL_STRING2)
+        goto in_string2;
+
+    if (colstate & IN_REBOL_BINARY)
+        goto in_binary;
+
+    if (colstate & IN_REBOL_COMMENT)
+        style0 = REBOL_STYLE_COMMENT;
+
+    style = style0;
+    while (i < n) {
+        start = i;
+        c = str[i++];
+        switch (c) {
+        case ';':
+            i = n;
+            style = REBOL_STYLE_COMMENT;
+            break;
+
+        case '{':
+            level++;
+        in_string1:
+            while (i < n) {
+                switch (str[i++]) {
+                case '^':
+                    if (i < n)
+                        i++;
+                    continue;
+                case '{':
+                    level++;
+                    continue;
+                case '}':
+                    --level;
+                    if (!level)
+                        break;
+                default:
+                    continue;
+                }
+                break;
+            }
+            colstate &= ~IN_REBOL_STRING1;
+            colstate |= level & IN_REBOL_STRING1;
+            style = REBOL_STYLE_STRING;
+            break;
+
+        case '"':
+        in_string2:
+            colstate |= IN_REBOL_STRING2;
+            while (i < n) {
+                c = str[i++];
+                if (c == '^' && i < n)
+                    i++;
+                else
+                if (c == '"') {
+                    colstate &= ~IN_REBOL_STRING2;
+                    break;
+                }
+            }
+            if (colstate & IN_REBOL_STRING2) {
+                /* double quoted strings do not span lines */
+                colstate &= ~IN_REBOL_STRING2;
+                style = REBOL_STYLE_ERROR;
+                break;
+            }
+            style = REBOL_STYLE_STRING;
+            break;
+
+        case '[':       /* start block */
+            break;
+        case ']':       /* end block */
+            colstate &= ~IN_REBOL_COMMENT;
+            break;
+        case '(':
+        case ')':
+            break;
+
+        case '<':
+            /* XXX: should skip tag with embedded strings */
+            goto normal;
+
+        case '#':
+            if (str[i] == '"') {
+                /* character constant */
+                break; /* keep # in default color */
+            }
+            if (str[i] == '{') {
+            in_binary:
+                colstate |= IN_REBOL_BINARY;
+                while (i < n) {
+                    if (str[i++] == '}') {
+                        colstate &= ~IN_REBOL_BINARY;
+                        break;
+                    }
+                }
+                style = REBOL_STYLE_BINARY;
+                break;
+            }
+            goto normal;
+
+        case '6':  /* 64#{ base64 encoded data } */
+            if (str[i] == '4' && str[i + 1] == '#' && str[i + 2] == '{')
+                goto in_binary;
+            goto normal;
+        case '1':  /* 16#{ hex encoded data } */
+            if (str[i] == '6' && str[i + 1] == '#' && str[i + 2] == '{')
+                goto in_binary;
+            goto normal;
+        case '2':  /* 2#{ binary encoded data } */
+            if (str[i] == '#' && str[i + 1] == '{')
+                goto in_binary;
+            goto normal;
+
+        default:
+        normal:
+            if (c <= ' ')
+                break;
+
+            /* parse words */
+            klen = 0;
+            keyword[klen++] = qe_tolower(c);
+            for (; i < n; i++) {
+                if (qe_findchar(" \t;()[]\"", str[i]))
+                    break;
+                if (klen < countof(keyword) - 1)
+                    keyword[klen++] = qe_tolower(str[i]);
+            }
+            keyword[klen] = '\0';
+            if (qe_isdigit(c) || c == '+' || c == '-') {
+                /* check numbers */
+                int dots = 0;
+                for (k = 1; k < klen; k++) {
+                    if (qe_match2(keyword[k], '.', ',')) {
+                        dots++;
+                    } else
+                    if (keyword[k] == 'e') {
+                        if (qe_match2(keyword[k + 1], '+', '-'))
+                            k++;
+                    } else
+                    if (!qe_match2(keyword[k], '\'', '%')
+                    &&  !qe_isdigit(keyword[k]))
+                        break;
+                }
+                if (k == klen && dots <= 1) {
+                    style = REBOL_STYLE_NUMBER;
+                    break;
+                }
+            }
+            if (qe_isalpha_(c)) {
+                /* check identifiers and keywords */
+                if (strequal(keyword, "comment")) {
+                    colstate |= IN_REBOL_COMMENT;
+                    style = style0 = REBOL_STYLE_COMMENT;
+                    break;
+                }
+                if (strfind(syn->keywords, keyword)) {
+                    style = REBOL_STYLE_KEYWORD;
+                    break;
+                }
+                if (strfind(syn->types, keyword)) {
+                    style = REBOL_STYLE_TYPE;
+                    break;
+                }
+            }
+            if (klen > 1 && str[i - 1] == ':') {
+                i--;
+                style = REBOL_STYLE_DEFINITION;
+                break;
+            }
+            break;
+        }
+        if (style) {
+            SET_COLOR(str, start, i, style);
+            style = style0;
+        }
+    }
+    cp->colorize_state = colstate;
+}
+
+static int rebol_mode_probe(ModeDef *mode, ModeProbeData *p)
+{
+    /* trust the file extension and/or shell handler */
+    if (match_extension(p->filename, mode->extensions)
+    &&  !qe_memicmp(cs8(p->buf), "REBOL", 5)) {
+        return 81;
+    }
+    return 1;
+}
+
+static ModeDef rebol_mode = {
+    .name = "Rebol",
+    .extensions = "r",
+    .mode_probe = rebol_mode_probe,
+    .keywords = rebol_keywords,
+    .types = rebol_types,
+    .colorize_func = rebol_colorize_line,
+};
+
+static int rebol_init(void)
+{
+    qe_register_mode(&rebol_mode, MODEF_SYNTAX);
+
+    return 0;
+}
+
+qe_module_init(rebol_init);

Index: elm.c
===================================================================
RCS file: elm.c
diff -N elm.c
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ elm.c       2 Oct 2020 21:32:30 -0000       1.1
@@ -0,0 +1,267 @@
+/*
+ * Elm mode for QEmacs.
+ *
+ * Copyright (c) 2015-2017 Charlie Gordon.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "qe.h"
+
+/*---------------- Elm coloring ----------------*/
+
+static char const elm_keywords[] = {
+    /* Elm keywords */
+    "if|then|else|case|of|let|in|type|"
+    "module|where|import|as|hiding|exposing|port|export|foreign|"
+    "perform|deriving|var|"
+    /* operators */
+    "not|"
+    /* predefined constants */
+    "False|True|_|"
+};
+
+static char const elm_types[] = {
+    "number|"
+    //"Bool|Char|String|Int|Float|" // matched generically
+};
+
+enum {
+    ELM_STYLE_DEFAULT    = 0,
+    ELM_STYLE_COMMENT    = QE_STYLE_COMMENT,
+    ELM_STYLE_PP_COMMENT = QE_STYLE_PREPROCESS,
+    ELM_STYLE_STRING     = QE_STYLE_STRING,
+    ELM_STYLE_STRING_Q   = QE_STYLE_STRING_Q,
+    ELM_STYLE_NUMBER     = QE_STYLE_NUMBER,
+    ELM_STYLE_KEYWORD    = QE_STYLE_KEYWORD,
+    ELM_STYLE_TYPE       = QE_STYLE_TYPE,
+    ELM_STYLE_FUNCTION   = QE_STYLE_FUNCTION,
+};
+
+/* elm-mode colorization states */
+enum {
+    IN_ELM_COMMENT     = 0x0F,  /* multiline comment (nested) */
+    IN_ELM_COMMENT_SHIFT = 0,
+    IN_ELM_PP_COMMENT  = 0x10,  /* compiler directives {-# ... #-} */
+    IN_ELM_STRING      = 0x20,  /* double-quoted string */
+    IN_ELM_LONG_STRING = 0x40,  /* double-quoted multiline string */
+    IN_ELM_STRING_Q    = 0x80,  /* single-quoted string */
+};
+
+static void elm_colorize_line(QEColorizeContext *cp,
+                              unsigned int *str, int n, ModeDef *syn)
+{
+    int i = 0, start = i, style = 0, c = 0, delim, level, klen;
+    int state = cp->colorize_state;
+    char kbuf[64];
+
+    if (state) {
+        /* if already in a state, go directly in the code parsing it */
+        if (state & IN_ELM_COMMENT)
+            goto parse_comment;
+        if (state & IN_ELM_STRING)
+            goto parse_string;
+        if (state & IN_ELM_LONG_STRING)
+            goto parse_long_string;
+        if (state & IN_ELM_STRING_Q)
+            goto parse_string_q;
+    }
+
+    while (i < n) {
+        start = i;
+        c = str[i++];
+        switch (c) {
+        case '-':
+            if (str[i] == '-') {
+                /* line comment */
+                i = n;
+                style = ELM_STYLE_COMMENT;
+                break;
+            }
+            continue;
+
+        case '{':
+            if (str[i] == '-') {
+                /* multi-line nested (!) comment */
+                state |= 1 << IN_ELM_COMMENT_SHIFT;
+                i++;
+                if (str[i] == '#') {
+                    state |= IN_ELM_PP_COMMENT;
+                    i++;
+                }
+            parse_comment:
+                level = (state & IN_ELM_COMMENT) >> IN_ELM_COMMENT_SHIFT;
+                style = ELM_STYLE_COMMENT;
+                if (state & IN_ELM_PP_COMMENT)
+                    style = ELM_STYLE_PP_COMMENT;
+                while (i < n) {
+                    c = str[i++];
+                    if (c == '{' && str[i] == '-') {
+                        level++;
+                        i++;
+                        continue;
+                    }
+                    if (c == '-' && str[i] == '}') {
+                        i++;
+                        level--;
+                        if (level == 0) {
+                            state &= ~IN_ELM_PP_COMMENT;
+                            i++;
+                            break;
+                        }
+                    }
+                }
+                state &= ~IN_ELM_COMMENT;
+                state |= level << IN_ELM_COMMENT_SHIFT;
+                break;
+            }
+            continue;
+
+        case '\'':      /* character constant */
+        parse_string_q:
+            state |= IN_ELM_STRING_Q;
+            style = ELM_STYLE_STRING_Q;
+            delim = '\'';
+            goto string;
+
+        case '\"':      /* string literal */
+            state |= IN_ELM_STRING;
+            if (str[i] == '"' && str[i + 1] == '"') {
+                state ^= IN_ELM_STRING | IN_ELM_LONG_STRING;
+            parse_long_string:
+                style = ELM_STYLE_STRING;
+                while (i < n) {
+                    c = str[i++];
+                    if (c == '\\') {
+                        if (i >= n)
+                            break;
+                        i++;
+                    } else
+                    if (c == '"' && str[i] == '"' && str[i + 1] == '"') {
+                        state &= ~IN_ELM_LONG_STRING;
+                        break;
+                    }
+                }
+                break;
+            }
+        parse_string:
+            style = ELM_STYLE_STRING;
+            delim = '\"';
+        string:
+            while (i < n) {
+                c = str[i++];
+                if (c == '\\') {
+                    if (i >= n)
+                        break;
+                    i++;
+                } else
+                if (c == delim) {
+                    state &= ~(IN_ELM_STRING | IN_ELM_STRING_Q);
+                    break;
+                }
+            }
+            break;
+
+        default:
+            if (qe_isdigit(c)) {
+                int j;
+                // Integers:
+                // 0x[0-9a-fA-F]+
+                // [0-9]+
+                // Floats:
+                // [0-9]+\.[0-9]*([eE][-\+]?[0-9]+)?
+                // [0-9]+(\.[0-9]*)?[eE][-\+]?[0-9]+
+                if (c == '0' && str[i] == 'x' && qe_isxdigit(str[i + 1])) {
+                    for (i += 3; qe_isxdigit(str[i]); i++)
+                        continue;
+                } else {
+                    while (qe_isdigit(str[i]))
+                        i++;
+                    if (str[i] == '.' && qe_isdigit(str[i + 1])) {
+                        for (i += 2; qe_isdigit(str[i]); i++)
+                            continue;
+                    }
+                    if (str[i] == 'e' || str[i] == 'E') {
+                        j = i + 1;
+                        if (str[j] == '+' || str[j] == '-')
+                            j++;
+                        if (qe_isdigit(str[j])) {
+                            for (i = j + 1; qe_isdigit(str[i]); i++)
+                                continue;
+                        }
+                    }
+                }
+                style = ELM_STYLE_NUMBER;
+                break;
+            }
+            if (qe_isalpha_(c)) {
+                int haslower = 0;
+                for (klen = 0, i--; qe_isalnum_(str[i]) || str[i] == '\''; 
i++) {
+                    haslower |= qe_islower(str[i]);
+                    if (klen < countof(kbuf) - 1)
+                        kbuf[klen++] = str[i];
+                }
+                kbuf[klen] = '\0';
+
+                if (strfind(syn->keywords, kbuf)) {
+                    style = ELM_STYLE_KEYWORD;
+                    break;
+                }
+
+                if ((start == 0 || str[start - 1] != '.')
+                &&  (str[i] != '.')) {
+                    if (strfind(syn->types, kbuf)
+                    ||  (qe_isupper(c) && haslower)) {
+                        style = ELM_STYLE_TYPE;
+                        break;
+                    }
+                }
+#if 0
+                if (check_fcall(str, i)) {
+                    style = ELM_STYLE_FUNCTION;
+                    break;
+                }
+#endif
+                continue;
+            }
+            continue;
+        }
+        if (style) {
+            SET_COLOR(str, start, i, style);
+            style = 0;
+        }
+    }
+    /* set style on eol char */
+    SET_COLOR1(str, n, style);    /* set style on eol char */
+
+    cp->colorize_state = state;
+}
+
+static ModeDef elm_mode = {
+    .name = "Elm",
+    .extensions = "elm",
+    .keywords = elm_keywords,
+    .types = elm_types,
+    .colorize_func = elm_colorize_line,
+};
+
+static int elm_init(void)
+{
+    qe_register_mode(&elm_mode, MODEF_SYNTAX);
+
+    return 0;
+}
+
+qe_module_init(elm_init);

Index: jai.c
===================================================================
RCS file: jai.c
diff -N jai.c
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ jai.c       2 Oct 2020 21:32:30 -0000       1.1
@@ -0,0 +1,247 @@
+/*
+ * Jai mode for QEmacs.
+ *
+ * Copyright (c) 2015-2017 Charlie Gordon.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "qe.h"
+
+/*---------------- Jai coloring ----------------*/
+
+static char const jai_keywords[] = {
+    /* Jai keywords */
+    // #char #foreign #import #run
+    "using|new|remove|delete|cast|struct|enum|if|else|for|while|switch|"
+    "case|continue|break|return|defer|inline|"
+    /* predefined constants */
+    "false|true|null|it|void|"
+};
+
+static char const jai_types[] = {
+    "bool|string|int|float|float32|float64|"
+    "u8|u16|u32|u64|s8|s16|s32|s64|"
+};
+
+enum {
+    JAI_STYLE_DEFAULT    = 0,
+    JAI_STYLE_DIRECTIVE  = QE_STYLE_PREPROCESS,
+    JAI_STYLE_COMMENT    = QE_STYLE_COMMENT,
+    JAI_STYLE_REGEX      = QE_STYLE_STRING_Q,
+    JAI_STYLE_STRING     = QE_STYLE_STRING,
+    JAI_STYLE_STRING_Q   = QE_STYLE_STRING_Q,
+    JAI_STYLE_NUMBER     = QE_STYLE_NUMBER,
+    JAI_STYLE_KEYWORD    = QE_STYLE_KEYWORD,
+    JAI_STYLE_TYPE       = QE_STYLE_TYPE,
+    JAI_STYLE_FUNCTION   = QE_STYLE_FUNCTION,
+    JAI_STYLE_VARIABLE   = QE_STYLE_VARIABLE,
+};
+
+/* jai-mode colorization states */
+enum {
+    IN_JAI_COMMENT    = 0x0F,  /* multiline comment (nested) */
+    IN_JAI_COMMENT_SHIFT = 0,
+    IN_JAI_STRING     = 0x10,  /* double-quoted string */
+    IN_JAI_STRING_Q   = 0x20,  /* single-quoted string */
+};
+
+static void jai_colorize_line(QEColorizeContext *cp,
+                              unsigned int *str, int n, ModeDef *syn)
+{
+    int i = 0, start = i, style = 0, c = 0, i1, i2, delim, level;
+    int state = cp->colorize_state;
+    char kbuf[64];
+
+    if (state) {
+        /* if already in a state, go directly in the code parsing it */
+        if (state & IN_JAI_COMMENT)
+            goto parse_comment;
+        if (state & IN_JAI_STRING)
+            goto parse_string;
+        if (state & IN_JAI_STRING_Q)
+            goto parse_string_q;
+    }
+
+    while (i < n) {
+        start = i;
+        c = str[i++];
+        switch (c) {
+        case '/':
+            if (str[i] == '*') {
+                /* multi-line nested (!) comment */
+                state |= 1 << IN_JAI_COMMENT_SHIFT;
+                i++;
+            parse_comment:
+                level = (state & IN_JAI_COMMENT) >> IN_JAI_COMMENT_SHIFT;
+                while (i < n) {
+                    c = str[i++];
+                    if (c == '/' && str[i] == '*') {
+                        level++;
+                        i++;
+                        continue;
+                    }
+                    if (c == '*' && str[i] == '/') {
+                        i++;
+                        level--;
+                        if (level == 0)
+                            break;
+                    }
+                }
+                state &= ~IN_JAI_COMMENT;
+                state |= level << IN_JAI_COMMENT_SHIFT;
+                style = JAI_STYLE_COMMENT;
+                break;
+            } else
+            if (str[i] == '/') {
+                /* line comment */
+                style = JAI_STYLE_COMMENT;
+                i = n;
+                break;
+            }
+            break;
+        case '#':       /* directive */
+            while (qe_isalnum(str[i])) {
+                i++;
+            }
+            style = JAI_STYLE_DIRECTIVE;
+            break;
+
+        case '\'':      /* character constant */
+            /* jai accepts quoted characters and quoted symbols */
+            if (i + 1 < n && (str[i] == '\\' || str[i+1] == '\''))
+                goto parse_string_q;
+            else
+                goto normal;
+
+        parse_string_q:
+            state |= IN_JAI_STRING_Q;
+            style = JAI_STYLE_STRING_Q;
+            delim = '\'';
+            goto string;
+
+        case '\"':      /* string literal */
+        parse_string:
+            state |= IN_JAI_STRING;
+            style = JAI_STYLE_STRING;
+            delim = '\"';
+        string:
+            while (i < n) {
+                c = str[i++];
+                if (c == '\\') {
+                    if (i >= n)
+                        break;
+                    i++;
+                } else
+                if (c == delim) {
+                    state &= ~(IN_JAI_STRING | IN_JAI_STRING_Q);
+                    break;
+                }
+            }
+            break;
+        default:
+        normal:
+            if (qe_isdigit(c)) {
+                int j;
+                // Integers:
+                // 0x[0-9a-fA-F]+
+                // [0-9]+
+                // Floats:
+                // [0-9]+\.[0-9]+([eE][-\+]?[0-9]+)?
+                // [0-9]+(\.[0-9]+)?[eE][-\+]?[0-9]+
+                if (c == '0' && str[i] == 'x' && qe_isxdigit_(str[i + 1])) {
+                    for (i += 3; qe_isxdigit_(str[i]); i++)
+                        continue;
+                } else {
+                    while (qe_isdigit_(str[i]))
+                        i++;
+                    if (str[i] == '.' && qe_isdigit_(str[i + 1])) {
+                        for (i += 2; qe_isdigit_(str[i]); i++)
+                            continue;
+                    }
+                    if (str[i] == 'e' || str[i] == 'E') {
+                        j = i + 1;
+                        if (str[j] == '+' || str[j] == '-')
+                            j++;
+                        if (qe_isdigit_(str[j])) {
+                            for (i = j + 1; qe_isdigit_(str[i]); i++)
+                                continue;
+                        }
+                    }
+                }
+                style = JAI_STYLE_NUMBER;
+                break;
+            }
+            if (qe_isalpha_(c)) {
+                i += ustr_get_identifier(kbuf, countof(kbuf), c, str, i, n);
+
+                if (strfind(syn->keywords, kbuf)) {
+                    style = JAI_STYLE_KEYWORD;
+                    break;
+                }
+
+                i1 = i;
+                while (qe_isblank(str[i1]))
+                    i1++;
+                i2 = i1;
+                while (qe_isblank(str[i2]))
+                    i2++;
+
+                if ((start == 0 || str[start - 1] != '.')
+                &&  !qe_findchar(".(:", str[i])
+                &&  strfind(syn->types, kbuf)) {
+                    style = JAI_STYLE_TYPE;
+                    break;
+                }
+                if (str[i1] == '(') {
+                    /* function call */
+                    /* XXX: different styles for call and definition */
+                    style = JAI_STYLE_FUNCTION;
+                    break;
+                }
+                break;
+            }
+            continue;
+        }
+        if (style) {
+            SET_COLOR(str, start, i, style);
+            style = 0;
+        }
+    }
+    /* set style on eol char */
+    SET_COLOR1(str, n, style);
+
+    cp->colorize_state = state;
+}
+
+static ModeDef jai_mode = {
+    .name = "Jai",
+    .extensions = "jai",
+    .keywords = jai_keywords,
+    .types = jai_types,
+    .colorize_func = jai_colorize_line,
+    //.indent_func = c_indent_line,
+    .auto_indent = 1,
+    .fallback = &c_mode,
+};
+
+static int jai_init(void)
+{
+    qe_register_mode(&jai_mode, MODEF_SYNTAX);
+
+    return 0;
+}
+
+qe_module_init(jai_init);

Index: ats.c
===================================================================
RCS file: ats.c
diff -N ats.c
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ ats.c       2 Oct 2020 21:32:30 -0000       1.1
@@ -0,0 +1,232 @@
+/*
+ * ATS (Applied Type System) mode for QEmacs.
+ *
+ * Copyright (c) 2016-2017 Charlie Gordon.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "qe.h"
+
+/*---------------- ATS (Applied Type System) coloring ----------------*/
+
+static char const ats_keywords[] = {
+    "|extern|symintr|overload|exception|staload|dynload"
+    "|fun|prfun|fn|prfn|implement|fnx|castfn|praxi|val|prval"
+    "|abstype|absprop|absview|absviewtype|absvtype"
+    "|datatype|dataprop|dataview|dataviewtype|datavtype"
+    "|stadef|sortdef|typedef|propdef|viewdef|viewtypedef|vtypedef"
+    "|var|let|local|of|with|in|and|when|assume|macdef"
+    "|if|then|else|for|fix|where|while|case|end|try"
+    "|mod|true|false"
+    "|infix|infixl|infixr|prefix|postfix|nonfix|op|lam|rec"
+    "|"
+};
+
+static char const ats_types[] = {
+    "|bool|int|double|void|string|type|prop|view|viewtype|vtype|ptr|ref|nat"
+    "|"
+};
+
+/* XXX: should colorize $MACRO substitutions. */
+
+enum {
+    IN_ATS_COMMENT  = 0x0F,
+    ATS_COMMENT_MAX_LEVEL = 0x0F,
+    ATS_COMMENT_SHIFT = 0,
+    IN_ATS_STRING   = 0x10,
+    IN_ATS_CBLOCK   = 0x8000,
+};
+
+enum {
+    ATS_STYLE_TEXT =       QE_STYLE_DEFAULT,
+    ATS_STYLE_KEYWORD =    QE_STYLE_KEYWORD,
+    ATS_STYLE_TYPE =       QE_STYLE_TYPE,
+    ATS_STYLE_PREPROCESS = QE_STYLE_PREPROCESS,
+    ATS_STYLE_COMMENT =    QE_STYLE_COMMENT,
+    ATS_STYLE_STRING =     QE_STYLE_STRING,
+    ATS_STYLE_IDENTIFIER = QE_STYLE_DEFAULT,
+    ATS_STYLE_NUMBER =     QE_STYLE_NUMBER,
+    ATS_STYLE_FUNCTION =   QE_STYLE_FUNCTION,
+};
+
+static void ats_colorize_line(QEColorizeContext *cp,
+                              unsigned int *str, int n, ModeDef *syn)
+{
+    char keyword[32];
+    int i = 0, start = i, c, k, style = 0, len, level;
+    int colstate = cp->colorize_state;
+
+    if (colstate & IN_ATS_CBLOCK) {
+        if (str[i] == '%' && str[i + 1] == '}') {
+            colstate = 0;
+            SET_COLOR(str, i, n, ATS_STYLE_PREPROCESS);
+            i = n;
+        } else {
+            ModeDef *md = &c_mode;
+            cp->colorize_state = colstate & ~IN_ATS_CBLOCK;
+            md->colorize_func(cp, str + i, n - i, md);
+            colstate = cp->colorize_state | IN_ATS_CBLOCK;
+            i = n;
+        }
+    } else {
+        level = (colstate & IN_ATS_COMMENT) >> ATS_COMMENT_SHIFT;
+        if (level > 0)
+            goto in_comment;
+        if (colstate & IN_ATS_STRING)
+            goto in_string;
+    }
+
+    while (i < n) {
+        start = i;
+        c = str[i++];
+        switch (c) {
+        case '/':
+            if (str[i] == '/') {    /* C++ comments, recent extension */
+                i = n;
+                style = ATS_STYLE_COMMENT;
+                break;
+            }
+            continue;
+        case '%':
+            if (i == 1 && str[i] == '{') {
+                colstate = IN_ATS_CBLOCK;
+                i = n;
+                style = ATS_STYLE_PREPROCESS;
+                break;
+            }
+            continue;
+        case '(':
+            /* check for preprocessor */
+            if (str[i] == '*') {
+                /* regular comment (recursive?) */
+                i++;
+                level = 1;
+            in_comment:
+                while (i < n) {
+                    c = str[i++];
+                    if (c == '(' && str[i] == '*'
+                    &&  level < ATS_COMMENT_MAX_LEVEL) {
+                        i++;
+                        level++;
+                    } else
+                    if (c == '*' && str[i] == ')') {
+                        i++;
+                        level--;
+                        if (level <= 0)
+                            break;
+                    }
+                }
+                colstate &= ~(IN_ATS_COMMENT << ATS_COMMENT_SHIFT);
+                colstate |= level << ATS_COMMENT_SHIFT;
+                style = ATS_STYLE_COMMENT;
+                break;
+            }
+            continue;
+        case '"':
+            /* parse string or char const */
+        in_string:
+            colstate &= ~IN_ATS_STRING;
+            while (i < n) {
+                c = str[i++];
+                if (c == '"')
+                    break;
+                if (c == '\\') {
+                    if (i == n) {
+                        colstate |= IN_ATS_STRING;
+                        break;
+                    }
+                    /* skip next character */
+                    i++;
+                }
+            }
+            style = ATS_STYLE_STRING;
+            break;
+        case '#':
+            while (qe_isalpha(str[i]))
+                i++;
+            style = ATS_STYLE_PREPROCESS;
+            break;
+        case '~':
+            if (qe_isdigit(str[i]))
+                goto number;
+            continue;
+        default:
+            /* parse numbers */
+            if (qe_isdigit(c)) {
+            number:
+                for (; i < n; i++) {
+                    if (!qe_isalnum(str[i]) && str[i] != '.')
+                        break;
+                }
+                style = ATS_STYLE_NUMBER;
+                break;
+            }
+            /* parse identifiers and keywords */
+            if (qe_isalpha_(c) || c == '$') {
+                len = 0;
+                keyword[len++] = qe_tolower(c);
+                for (; qe_isalnum_(str[i]); i++) {
+                    if (len < countof(keyword) - 1)
+                        keyword[len++] = qe_tolower(str[i]);
+                }
+                if (str[i] == '!') {
+                    if (len < countof(keyword) - 1)
+                        keyword[len++] = str[i];
+                    i++;
+                }
+                keyword[len] = '\0';
+                if (strfind(syn->keywords, keyword)) {
+                    style = ATS_STYLE_KEYWORD;
+                } else
+                if (strfind(syn->types, keyword)) {
+                    style = ATS_STYLE_TYPE;
+                } else {
+                    k = i;
+                    if (qe_isblank(str[k]))
+                        k++;
+                    if (str[k] == '(' && str[k + 1] != '*')
+                        style = ATS_STYLE_FUNCTION;
+                    else
+                        style = ATS_STYLE_IDENTIFIER;
+                }
+                break;
+            }
+            continue;
+        }
+        if (style) {
+            SET_COLOR(str, start, i, style);
+            style = 0;
+        }
+    }
+    cp->colorize_state = colstate;
+}
+
+static ModeDef ats_mode = {
+    .name = "ATS",
+    .extensions = "dats|sats|hats", // dats for dynamic, sats for static files
+    .keywords = ats_keywords,
+    .types = ats_types,
+    .colorize_func = ats_colorize_line,
+};
+
+static int ats_init(void)
+{
+    qe_register_mode(&ats_mode, MODEF_SYNTAX);
+
+    return 0;
+}
+
+qe_module_init(ats_init);



reply via email to

[Prev in Thread] Current Thread [Next in Thread]