added Erlang colorizer
This commit is contained in:
parent
5acb53ef0f
commit
e4e213680f
1 changed files with 260 additions and 0 deletions
260
extra-modes.c
260
extra-modes.c
|
|
@ -2893,6 +2893,265 @@ static int ruby_init(void)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*---------------- Erlang coloring ----------------*/
|
||||
|
||||
static char const erlang_keywords[] = {
|
||||
"|after|and|andalso|band|begin|bnot|bor|bsl|bsr|bxor|case|catch|cond"
|
||||
"|div|end|fun|if|let|not|of|or|orelse|receive|rem|try|when|xor"
|
||||
"|true|false|_"
|
||||
"|"
|
||||
};
|
||||
|
||||
static char const erlang_commands[] = {
|
||||
"|module|compile|define|export|import|vsn|on_load|record|include|file"
|
||||
"|mode|author|include_lib|behaviour"
|
||||
"|type|opaque|spec|callback|export_type"
|
||||
"|ifdef|ifndef|undef|else|endif"
|
||||
"|"
|
||||
};
|
||||
|
||||
static char const erlang_types[] = {
|
||||
"|"
|
||||
};
|
||||
|
||||
enum {
|
||||
IN_ERLANG_STRING = 0x01,
|
||||
};
|
||||
|
||||
enum {
|
||||
ERLANG_STYLE_TEXT = QE_STYLE_DEFAULT,
|
||||
ERLANG_STYLE_PREPROCESS = QE_STYLE_PREPROCESS,
|
||||
ERLANG_STYLE_COMMENT = QE_STYLE_COMMENT,
|
||||
ERLANG_STYLE_STRING = QE_STYLE_STRING,
|
||||
ERLANG_STYLE_CHARCONST = QE_STYLE_STRING,
|
||||
ERLANG_STYLE_ATOM = QE_STYLE_DEFAULT,
|
||||
ERLANG_STYLE_INTEGER = QE_STYLE_NUMBER,
|
||||
ERLANG_STYLE_FLOAT = QE_STYLE_NUMBER,
|
||||
ERLANG_STYLE_KEYWORD = QE_STYLE_KEYWORD,
|
||||
ERLANG_STYLE_TYPE = QE_STYLE_TYPE,
|
||||
ERLANG_STYLE_IDENTIFIER = QE_STYLE_DEFAULT,
|
||||
ERLANG_STYLE_FUNCTION = QE_STYLE_FUNCTION,
|
||||
};
|
||||
|
||||
static inline int qe_basedigit(int c)
|
||||
{
|
||||
if (c >= '0' && c <= '9') return c - '0';
|
||||
if (c >= 'a' && c <= 'z') return c - 'a' + 10;
|
||||
if (c >= 'A' && c <= 'Z') return c - 'A' + 10;
|
||||
return 255;
|
||||
}
|
||||
|
||||
static int erlang_match_char(unsigned int *str, int i)
|
||||
{
|
||||
/* erlang character constant */
|
||||
if (str[i++] == '\\') {
|
||||
switch (str[i++]) {
|
||||
case '0': case '1': case '2': case '3':
|
||||
case '4': case '5': case '6': case '7':
|
||||
if (qe_isoctdigit(str[i])) i++;
|
||||
if (qe_isoctdigit(str[i])) i++;
|
||||
break;
|
||||
case 'x':
|
||||
case 'X':
|
||||
if (str[i] == '{') {
|
||||
for (i++; qe_isxdigit(str[i]); i++)
|
||||
continue;
|
||||
if (str[i] == '}')
|
||||
i++;
|
||||
break;
|
||||
}
|
||||
if (qe_isxdigit(str[i])) i++;
|
||||
if (qe_isxdigit(str[i])) i++;
|
||||
break;
|
||||
case '^':
|
||||
if (qe_isalpha(str[i])) i++;
|
||||
break;
|
||||
case 'b': /* backspace (8) */
|
||||
case 'd': /* delete (127) */
|
||||
case 'e': /* escape (27) */
|
||||
case 'f': /* formfeed (12) */
|
||||
case 'n': /* newline (10) */
|
||||
case 'r': /* return (13) */
|
||||
case 's': /* space (32) */
|
||||
case 't': /* tab (9) */
|
||||
case 'v': /* vtab (?) */
|
||||
case '\'': /* single quote */
|
||||
case '\"': /* double quote */
|
||||
case '\\': /* backslash */
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
static void erlang_colorize_line(QEColorizeContext *cp,
|
||||
unsigned int *str, int n, ModeDef *syn)
|
||||
{
|
||||
char keyword[MAX_KEYWORD_SIZE];
|
||||
int i = 0, start = i, c, k, style, len, base;
|
||||
int colstate = cp->colorize_state;
|
||||
|
||||
if (colstate & IN_ERLANG_STRING)
|
||||
goto parse_string;
|
||||
|
||||
if (str[i] == '#' && str[i + 1] == '!') {
|
||||
/* Handle shbang script heading ^#!.+
|
||||
* and preprocessor # line directives
|
||||
*/
|
||||
i = n;
|
||||
SET_COLOR(str, start, i, ERLANG_STYLE_PREPROCESS);
|
||||
}
|
||||
|
||||
while (i < n) {
|
||||
start = i;
|
||||
style = ERLANG_STYLE_TEXT;
|
||||
c = str[i++];
|
||||
switch (c) {
|
||||
case '%':
|
||||
i = n;
|
||||
style = ERLANG_STYLE_COMMENT;
|
||||
SET_COLOR(str, start, i, style);
|
||||
continue;
|
||||
case '$':
|
||||
i = erlang_match_char(str, i);
|
||||
style = ERLANG_STYLE_CHARCONST;
|
||||
SET_COLOR(str, start, i, style);
|
||||
continue;
|
||||
|
||||
case '\"':
|
||||
colstate = IN_ERLANG_STRING;
|
||||
parse_string:
|
||||
/* parse string */
|
||||
style = ERLANG_STYLE_STRING;
|
||||
while (i < n) {
|
||||
c = str[i++];
|
||||
if (c == '\\' && i < n)
|
||||
i++;
|
||||
else
|
||||
if (c == '\"') {
|
||||
colstate = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
SET_COLOR(str, start, i, style);
|
||||
continue;
|
||||
case '\'':
|
||||
/* parse an Erlang atom */
|
||||
style = ERLANG_STYLE_ATOM;
|
||||
while (i < n) {
|
||||
c = str[i++];
|
||||
if (c == '\\' && i < n)
|
||||
i++;
|
||||
else
|
||||
if (c == '\'') {
|
||||
break;
|
||||
}
|
||||
}
|
||||
SET_COLOR(str, start, i, style);
|
||||
continue;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (qe_isdigit(c)) {
|
||||
/* parse numbers */
|
||||
style = ERLANG_STYLE_INTEGER;
|
||||
base = c - '0';
|
||||
while (qe_isdigit(str[i])) {
|
||||
base = base * 10 + str[i++] - '0';
|
||||
}
|
||||
if (base >= 2 && base <= 36 && str[i] == '#') {
|
||||
for (i += 1; qe_basedigit(str[i]) < base; i++)
|
||||
continue;
|
||||
if (str[i - 1] == '#')
|
||||
i--;
|
||||
} else {
|
||||
/* float: [0-9]+(.[0-9]+])?([eE][-+]?[0-9]+)? */
|
||||
if (str[i] == '.' && qe_isdigit(str[i + 1])) {
|
||||
style = ERLANG_STYLE_FLOAT;
|
||||
for (i += 2; qe_isdigit(str[i]); i++)
|
||||
continue;
|
||||
}
|
||||
if (qe_tolower(str[i]) == 'e') {
|
||||
int k = i + 1;
|
||||
if (str[k] == '+' || str[k] == '-')
|
||||
k++;
|
||||
if (qe_isdigit(str[k])) {
|
||||
style = ERLANG_STYLE_FLOAT;
|
||||
for (i = k + 1; qe_isdigit(str[i]); i++)
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
SET_COLOR(str, start, i, style);
|
||||
continue;
|
||||
}
|
||||
if (qe_isalpha_(c) || c == '@') {
|
||||
/* parse an Erlang atom or identifier */
|
||||
len = 0;
|
||||
keyword[len++] = c;
|
||||
for (; qe_isalnum_(str[i]) || str[i] == '@'; i++) {
|
||||
if (len < countof(keyword) - 1)
|
||||
keyword[len++] = str[i];
|
||||
}
|
||||
keyword[len] = '\0';
|
||||
if (start && str[start - 1] == '-'
|
||||
&& strfind(erlang_commands, keyword)) {
|
||||
style = ERLANG_STYLE_PREPROCESS;
|
||||
} else
|
||||
if (strfind(syn->types, keyword)) {
|
||||
style = ERLANG_STYLE_TYPE;
|
||||
} else
|
||||
if (strfind(syn->keywords, keyword)) {
|
||||
style = ERLANG_STYLE_KEYWORD;
|
||||
} else {
|
||||
k = i;
|
||||
if (qe_isblank(str[k]))
|
||||
k++;
|
||||
if (str[k] == '(') {
|
||||
style = ERLANG_STYLE_FUNCTION;
|
||||
} else
|
||||
if (qe_islower(keyword[0])) {
|
||||
style = ERLANG_STYLE_ATOM;
|
||||
} else {
|
||||
style = ERLANG_STYLE_IDENTIFIER;
|
||||
}
|
||||
}
|
||||
SET_COLOR(str, start, i, style);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
cp->colorize_state = colstate;
|
||||
}
|
||||
|
||||
static int erlang_mode_probe(ModeDef *mode, ModeProbeData *p)
|
||||
{
|
||||
if (match_extension(p->filename, mode->extensions)
|
||||
|| match_shell_handler(cs8(p->buf), mode->shell_handlers)
|
||||
|| strstr(cs8(p->buf), "-*- erlang -*-")) {
|
||||
return 80;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static ModeDef erlang_mode = {
|
||||
.name = "Erlang",
|
||||
.extensions = "erl|hrl",
|
||||
.shell_handlers = "erlang",
|
||||
.mode_probe = erlang_mode_probe,
|
||||
.keywords = erlang_keywords,
|
||||
.types = erlang_types,
|
||||
.colorize_func = erlang_colorize_line,
|
||||
};
|
||||
|
||||
static int erlang_init(void)
|
||||
{
|
||||
qe_register_mode(&erlang_mode, MODEF_SYNTAX);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*---------------- ML/Ocaml coloring ----------------*/
|
||||
|
||||
static char const ocaml_keywords[] = {
|
||||
|
|
@ -3244,6 +3503,7 @@ static int extra_modes_init(void)
|
|||
haskell_init();
|
||||
python_init();
|
||||
ruby_init();
|
||||
erlang_init();
|
||||
ocaml_init();
|
||||
emf_init();
|
||||
return 0;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue