added Perl mode: perl.c

added Makefile mode: makemode.c
added HTML source mode: htmlsrc.c
added more dependencies in Makefile
added styles for HTML source coloring:
    html-comment, html-string, html-script, html-entity, html-tag
no longer rely on \n at end of line in c_colorize_line
This commit is contained in:
Charlie Gordon 2007-12-18 18:07:03 +00:00
commit fa760147c8
6 changed files with 959 additions and 64 deletions

View file

@ -128,7 +128,8 @@ OBJS+=charsetjis.o charsetmore.o
endif
ifdef CONFIG_ALL_MODES
OBJS+= unihex.o clang.o latex-mode.o xml.o bufed.o
OBJS+= unihex.o clang.o latex-mode.o xml.o bufed.o \
makemode.o perl.o htmlsrc.o
ifndef CONFIG_WIN32
OBJS+= shell.o dired.o
endif
@ -189,13 +190,15 @@ libqhtml: force
qe_g$(EXE): $(OBJS) $(DEP_LIBS)
$(CC) $(LDFLAGS) -o $@ $^ $(LIBS)
qe$(EXE): qe_g$(EXE)
qe$(EXE): qe_g$(EXE) Makefile
rm -f $@
cp $< $@
$(STRIP) $@
@ls -l $@
echo `size qe` `wc --bytes qe` qe $(OPTIONS) \
| cut -d ' ' -f 7-10,13,15-40 >> STATS
ffplay$(EXE): qe$(EXE)
ffplay$(EXE): qe$(EXE) Makefile
ln -sf $< $@
qe.o: qe.c qe.h qfribidi.h qeconfig.h
@ -216,13 +219,13 @@ fbfrender.o: fbfrender.c fbfrender.h libfbf.h
html2png.o: html2png.c qe.h
%.o : %.c
%.o: %.c qe.h Makefile
$(CC) $(DEFINES) $(CFLAGS) -o $@ -c $<
clean:
make -C libqhtml clean
rm -f *.o *.exe *~ TAGS gmon.out core *.exe.stackdump \
qe qe_g qfribidi kmaptoqe ligtoqe html2png fbftoqe fbffonts.c \
rm -f *~ *.o *.a *.exe *_g TAGS gmon.out core *.exe.stackdump \
qe qfribidi kmaptoqe ligtoqe html2png fbftoqe fbffonts.c \
cptoqe jistoqe
distclean: clean
@ -391,7 +394,7 @@ OBJS=util.o cutils.o \
libfbf.o fbfrender.o cfb.o fbffonts.o
html2png$(EXE): html2png.o $(OBJS) libqhtml/libqhtml.a
$(HOST_CC) $(LDFLAGS) -o $@ html2png.o $(OBJS) \
$(CC) $(LDFLAGS) -o $@ html2png.o $(OBJS) \
-L./libqhtml -lqhtml $(HTMLTOPPM_LIBS)
# autotest target

134
clang.c
View file

@ -20,18 +20,34 @@
#include "qe.h"
static const char c_keywords[] =
"|auto|break|case|const|continue|default|do|else|enum|extern|for|goto|"
#if 0
static const char cc_keywords[] =
"asm|catch|class|delete|friend|inline|new|operator|"
"private|protected|public|template|try|this|virtual|throw|";
static const char java_keywords[] =
"abstract|boolean|byte|catch|class|extends|false|final|"
"finally|function|implements|import|in|instanceof|"
"interface|native|new|null|package|private|protected|"
"public|super|synchronized|this|throw|throws|transient|"
"true|try|var|with|";
#endif
static const char *c_mode_keywords =
"auto|break|case|const|continue|default|do|else|enum|extern|for|goto|"
"if|inline|register|restrict|return|sizeof|static|struct|switch|"
"typedef|union|volatile|while|";
/* NOTE: 'var' is added for javascript */
static const char c_types[] =
"|char|double|float|int|long|unsigned|short|signed|void|var|"
"_Bool|_Complex|_Imaginary";
static const char *c_mode_types =
"char|double|float|int|long|unsigned|short|signed|void|var|"
"_Bool|_Complex|_Imaginary|";
static const char *c_mode_extensions =
"c|h|y|e|cc|cs|cpp|cxx|hpp|hxx|jav|java|js|qe|";
#if 0
static int get_c_keyword(char *buf, int buf_size, unsigned int *p)
static int get_c_identifier(char *buf, int buf_size, unsigned int *p)
{
unsigned int c;
char *q;
@ -51,26 +67,31 @@ static int get_c_keyword(char *buf, int buf_size, unsigned int *p)
}
#endif
/* colorization states */
/* c-mode colorization states */
enum {
C_COMMENT = 1,
C_COMMENT1 = 2,
C_STRING = 4,
C_STRING_Q = 8,
C_PREPROCESS = 16,
C_COMMENT = 1, /* multiline comment pending */
C_COMMENT1 = 2, /* single line comment with \ at EOL */
C_STRING = 4, /* double quoted string spanning multiple lines */
C_STRING_Q = 8, /* single quoted string spanning multiple lines */
C_PREPROCESS = 16, /* preprocessor directive with \ at EOL */
};
void c_colorize_line(unsigned int *buf, int len,
int *colorize_state_ptr, __unused__ int state_only)
{
int c, state, style, klen, type_decl;
unsigned int *p, *p_start, *p1, *p2;
unsigned int *p, *p_start, *p_end, *p1, *p2;
char kbuf[32];
state = *colorize_state_ptr;
p = buf;
p_start = p;
p_end = p + len;
type_decl = 0;
if (p >= p_end)
goto the_end;
c = 0; /* turn off stupid egcs-2.91.66 warning */
style = 0;
@ -88,7 +109,7 @@ void c_colorize_line(unsigned int *buf, int len,
goto parse_string_q;
}
for (;;) {
while (p < p_end) {
p_start = p;
c = *p++;
@ -97,20 +118,12 @@ void c_colorize_line(unsigned int *buf, int len,
p--;
goto the_end;
case '/':
if (*p == '/') {
/* line comment */
parse_comment1:
state |= C_COMMENT1;
p = buf + len;
set_color(p_start, p, QE_STYLE_COMMENT);
goto the_end;
} else
if (*p == '*') {
/* normal comment */
p++;
parse_comment:
state |= C_COMMENT;
while (*p != '\n') {
while (p < p_end) {
if (p[0] == '*' && p[1] == '/') {
p += 2;
state &= ~C_COMMENT;
@ -121,6 +134,14 @@ void c_colorize_line(unsigned int *buf, int len,
}
set_color(p_start, p, QE_STYLE_COMMENT);
continue;
} else
if (*p == '/') {
/* line comment */
parse_comment1:
state |= C_COMMENT1;
p = p_end;
set_color(p_start, p, QE_STYLE_COMMENT);
goto the_end;
}
break;
case '#': /* preprocessor */
@ -143,10 +164,10 @@ void c_colorize_line(unsigned int *buf, int len,
case '\'': /* character constant */
parse_string_q:
state |= C_STRING_Q;
for (; *p != '\n'; p++) {
for (; p < p_end; p++) {
if (*p == '\\') {
p++;
if (*p == '\n')
if (p >= p_end)
break;
} else
if (*p == '\'') {
@ -162,10 +183,10 @@ void c_colorize_line(unsigned int *buf, int len,
case '\"': /* strings literal */
parse_string:
state |= C_STRING;
for (; *p != '\n'; p++) {
for (; p < p_end; p++) {
if (*p == '\\') {
p++;
if (*p == '\n')
if (p >= p_end)
break;
} else
if (*p == '\"') {
@ -209,18 +230,19 @@ void c_colorize_line(unsigned int *buf, int len,
p++;
c = *p;
} while (qe_isalnum(c) || c == '_');
kbuf[klen] = '\0';
p1 = p;
while (qe_isblank(*p1))
p1++;
p2 = p1;
while (*p2 == '*' || qe_isblank(*p2))
p2++;
if (strfind(c_keywords, kbuf, 0)) {
if (strfind(c_mode_keywords, kbuf, 0)) {
set_color(p_start, p, QE_STYLE_KEYWORD);
} else
if (strfind(c_types, kbuf, 0)
if (strfind(c_mode_types, kbuf, 0)
|| (klen > 2 && kbuf[klen - 2] == '_' && kbuf[klen - 1] == 't')) {
/* c type */
/* if not cast, assume type declaration */
@ -515,7 +537,7 @@ static void do_c_indent(EditState *s)
/* the number of needed spaces is in 'pos' */
/* CG: should not modify buffer is indentation in correct */
/* CG: should not modify buffer if indentation in correct */
/* suppress leading spaces */
offset1 = offset;
@ -561,6 +583,7 @@ static void do_c_indent_region(EditState *s)
}
/* move point to end of region, and mark to begin of first row */
s->offset = s->b->mark;
/* XXX: begin may have moved? */
s->b->mark = begin;
}
@ -570,30 +593,6 @@ static void do_c_electric(EditState *s, int key)
do_c_indent(s);
}
static int c_mode_probe(ModeProbeData *p)
{
const char *r;
/* currently, only use the file extension */
r = extension(p->filename);
if (*r) {
if (strfind("|c|e|h|js|cs|jav|java|cxx|cpp|", r + 1, 1))
return 100;
}
return 0;
}
static int c_mode_init(EditState *s, ModeSavedData *saved_data)
{
int ret;
ret = text_mode_init(s, saved_data);
if (ret)
return ret;
set_colorize_func(s, c_colorize_line);
return ret;
}
/* forward / backward preprocessor */
static void do_c_forward_preprocessor(EditState *s, int dir)
{
@ -602,6 +601,7 @@ static void do_c_forward_preprocessor(EditState *s, int dir)
/* forward / backward block */
#define MAX_LEVEL 20
/* CG: move this to generic command */
static void do_c_forward_block(EditState *s, int dir)
{
unsigned int buf[MAX_BUF_SIZE];
@ -721,6 +721,7 @@ the_end:
s->offset = offset;
}
/* CG: move this to generic command */
static void do_c_kill_block(EditState *s, int dir)
{
int start = s->offset;
@ -732,7 +733,27 @@ static void do_c_kill_block(EditState *s, int dir)
do_kill(s, start, s->offset, dir);
}
/* specific C commands */
static int c_mode_probe(ModeProbeData *p)
{
/* currently, only use the file extension */
if (match_extension(p->filename, c_mode_extensions))
return 80;
return 0;
}
static int c_mode_init(EditState *s, ModeSavedData *saved_data)
{
int ret;
ret = text_mode_init(s, saved_data);
if (ret)
return ret;
set_colorize_func(s, c_colorize_line);
return ret;
}
/* specific C mode commands */
static CmdDef c_commands[] = {
CMD_( KEY_CTRL('i'), KEY_NONE, "c-indent-command", do_c_indent, "*")
CMD_( KEY_META(KEY_CTRL('\\')), KEY_NONE, "c-indent-region",
@ -770,7 +791,6 @@ static int c_init(void)
c_mode.mode_init = c_mode_init;
qe_register_mode(&c_mode);
qe_register_cmd_table(c_commands, "C");
return 0;

307
htmlsrc.c Normal file
View file

@ -0,0 +1,307 @@
/*
* HTML Source mode for QEmacs.
*
* Copyright (c) 2000-2007 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"
static const char *html_mode_extensions = "html|htm|asp|shtml|hta|htp|phtml";
static int get_html_entity(unsigned int *p)
{
unsigned int *p_start, c;
p_start = p;
c = (u8)*p;
if (c != '&')
return 0;
p++;
c = (u8)*p;
if (c == '#') {
do {
p++;
c = (u8)*p;
} while (qe_isdigit(c));
} else
if (qe_isalpha(c)) {
do {
p++;
c = (u8)*p;
} while (qe_isalnum(c));
} else {
/* not an entity */
return 0;
}
if (c == ';') {
p++;
}
return p - p_start;
}
/* color colorization states */
enum {
HTML_COMMENT = 0x01, /* <!-- <> --> */
HTML_COMMENT1 = 0x02, /* <! ... > */
HTML_STRING = 0x04, /* " ... " */
HTML_STRING1 = 0x08, /* ' ... ' */
HTML_TAG = 0x10, /* <tag ... > */
HTML_ENTITY = 0x20, /* &name[;] / &#123[;] */
HTML_SCRIPTTAG = 0x40, /* <SCRIPT ...> */
HTML_SCRIPT = 0x80, /* <SCRIPT> [...] </SCRIPT> */
};
/* CG: Should rely on len instead of '\n' */
static void htmlsrc_colorize_line(unsigned int *buf, int len,
int *colorize_state_ptr, int state_only)
{
int c, state, js_state, l;
unsigned int *p, *p_start, *p_end;
state = *colorize_state_ptr;
p = buf;
p_start = p;
p_end = p + len;
/* Kludge for preprocessed html */
if (*p == '#') {
p = p_end;
set_color(p_start, p, QE_STYLE_PREPROCESS);
goto the_end;
}
while (p < p_end) {
p_start = p;
c = *p;
if (c == '\n')
break;
if (state & HTML_SCRIPTTAG) {
while (p < p_end) {
if (*p++ == '>') {
state = HTML_SCRIPT;
break;
}
}
set_color(p_start, p, QE_STYLE_HTML_SCRIPT);
continue;
}
if (state & HTML_SCRIPT) {
for (; p < p_end; p++) {
if (*p == '<' && ustristart(p, "</script>", NULL))
break;
}
js_state = state & ~HTML_SCRIPT;
c_colorize_line (p_start, p - p_start,
&js_state, state_only);
state = js_state | HTML_SCRIPT;
if (p < p_end) {
p_start = p;
p += strlen("</script>");
state = 0;
set_color(p_start, p, QE_STYLE_HTML_SCRIPT);
}
continue;
}
if (state & HTML_COMMENT) {
for (; p < p_end; p++) {
if (*p == '-' && p[1] == '-'
&& p[2] == '>') {
p += 2;
state &= ~HTML_COMMENT;
break;
}
}
set_color(p_start, p, QE_STYLE_HTML_COMMENT);
continue;
}
if (state & HTML_COMMENT1) {
for (; p < p_end; p++) {
if (*p == '>') {
p++;
state &= ~HTML_COMMENT1;
break;
}
}
set_color(p_start, p, QE_STYLE_HTML_COMMENT);
continue;
}
if (state & HTML_ENTITY) {
if ((l = get_html_entity(p)) == 0)
p++;
else
p += l;
state &= ~HTML_ENTITY;
set_color(p_start, p, QE_STYLE_HTML_ENTITY);
continue;
}
if (state & (HTML_STRING|HTML_STRING1)) {
char delim = (char)((state & HTML_STRING1) ? '\'' : '\"');
for (; p < p_end; p++) {
if (*p == '&' && get_html_entity(p)) {
state |= HTML_ENTITY;
break;
}
if (*p == delim) {
p++;
state &= ~(HTML_STRING|HTML_STRING1);
break;
}
/* Premature end of string */
if (*p == '>') {
state &= ~(HTML_STRING|HTML_STRING1);
break;
}
}
set_color(p_start, p, QE_STYLE_HTML_STRING);
continue;
}
if (state & HTML_TAG) {
for (; p < p_end; p++) {
if (*p == '&' && get_html_entity(p)) {
state |= HTML_ENTITY;
break;
}
if (*p == '\"') {
state |= HTML_STRING;
break;
}
if (*p == '\'') {
state |= HTML_STRING1;
break;
}
if (*p == '>') {
p++;
state &= ~HTML_TAG;
break;
}
}
set_color(p_start, p, QE_STYLE_HTML_TAG);
if (state & (HTML_STRING|HTML_STRING1)) {
set_color1(p, QE_STYLE_HTML_STRING);
p++;
}
continue;
}
/* Plain text stream */
for (; p < p_end; p++) {
if (*p == '<'
&& (qe_isalpha(p[1])
|| p[1] == '!' || p[1] == '/' || p[1] == '?')) {
//set_color(p_start, p, QE_STYLE_HTML_TEXT);
p_start = p;
if (ustristart (p, "<script", NULL)) {
state |= HTML_SCRIPTTAG;
break;
}
if (p[1] == '!') {
state |= HTML_COMMENT1;
p += 2;
if (*p == '-' && p[1] == '-') {
p += 2;
state |= HTML_COMMENT;
}
set_color(p_start, p, QE_STYLE_HTML_COMMENT);
p_start = p;
} else
state |= HTML_TAG;
break;
}
if (*p == '&' && get_html_entity (p)) {
state |= HTML_ENTITY;
break;
}
}
//set_color(p_start, p - p_start, QE_STYLE_HTML_TEXT);
}
the_end:
*colorize_state_ptr = state;
}
static int html_tagcmp(const char *s1, const char *s2)
{
int d;
while (*s2) {
d = *s2 - qe_toupper(*s1);
if (d)
return d;
s2++;
s1++;
}
return 0;
}
static int htmlsrc_mode_probe(ModeProbeData *p)
{
const char *buf = (const char*)p->buf;
/* first check file extension */
if (match_extension(p->filename, html_mode_extensions))
return 80;
/* then try buffer contents */
if (p->buf_size >= 5 &&
(!html_tagcmp(buf, "<HTML") ||
!html_tagcmp(buf, "<SCRIPT") ||
!html_tagcmp(buf, "<?XML") ||
!html_tagcmp(buf, "<!DOCTYPE"))) {
return 80;
}
return 0;
}
static int htmlsrc_mode_init(EditState *s, ModeSavedData *saved_data)
{
int ret;
ret = text_mode_init(s, saved_data);
if (ret)
return ret;
set_colorize_func(s, htmlsrc_colorize_line);
return ret;
}
/* specific htmlsrc commands */
/* CG: need move / kill by tag level */
static CmdDef htmlsrc_commands[] = {
CMD_DEF_END,
};
static ModeDef htmlsrc_mode;
static int htmlsrc_init(void)
{
/* c mode is almost like the text mode, so we copy and patch it */
memcpy(&htmlsrc_mode, &text_mode, sizeof(ModeDef));
htmlsrc_mode.name = "html-src";
htmlsrc_mode.mode_probe = htmlsrc_mode_probe;
htmlsrc_mode.mode_init = htmlsrc_mode_init;
qe_register_mode(&htmlsrc_mode);
qe_register_cmd_table(htmlsrc_commands, "html-src");
return 0;
}
qe_module_init(htmlsrc_init);

191
makemode.c Normal file
View file

@ -0,0 +1,191 @@
/*
* Makefile mode for QEmacs.
*
* Copyright (c) 2000-2007 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"
/*---------------- Makefile colors ----------------*/
#define MAKEFILE_TEXT QE_STYLE_DEFAULT
#define MAKEFILE_COMMENT QE_STYLE_COMMENT
#define MAKEFILE_STRING QE_STYLE_STRING
#define MAKEFILE_PREPROCESS QE_STYLE_PREPROCESS
#define MAKEFILE_TARGET QE_STYLE_FUNCTION
#define MAKEFILE_VARIABLE QE_STYLE_VARIABLE
#define MAKEFILE_MACRO QE_STYLE_TYPE
static void makefile_colorize_line(unsigned int *str, int n, int *statep,
int state_only)
{
int i, j, level;
i = j = 0;
/* CG: should check for end of word */
if (str[0] == 'i') {
if (ustristart(str, "ifeq", NULL)
|| ustristart(str, "ifneq", NULL)
|| ustristart(str, "ifdef", NULL)
|| ustristart(str, "ifndef", NULL)
|| ustristart(str, "include", NULL))
goto preprocess;
} else
if (str[0] == 'e') {
if (ustristart(str, "else", NULL)
|| ustristart(str, "endif", NULL))
goto preprocess;
}
while (i < n) {
switch (str[i]) {
case '$':
i += 1;
j = i + 1;
if (str[i] == '(') {
i += 1;
level = 1;
for (j = i; j < n; j++) {
if (str[j] == '(')
level++;
if (str[j] == ')' && --level <= 0)
break;
if (str[j] == ' ' || str[j] == '$') {
/* should have function color */
j = i;
break;
}
}
}
if (i < j)
set_color(str + i, str + j, MAKEFILE_MACRO);
i = j;
continue;
case ' ':
case '\t':
if (i == 0)
j = 1;
break;
case '+':
if (!j && str[i+1] == '=')
goto variable;
case ':':
if (j)
break;
if (str[i+1] == '=')
goto variable;
set_color(str + j, str + i, MAKEFILE_TARGET);
break;
case '=':
if (j)
break;
variable:
set_color(str + j, str + i, MAKEFILE_VARIABLE);
break;
case '#':
if (i > 0 && str[i - 1] == '\\')
break;
set_color(str + i, str + n, MAKEFILE_COMMENT);
i = n;
continue;
case '!':
/* case '.':*/
if (i > 0)
break;
preprocess:
/* scan for comment */
for (j = i + 1; j < n; j++) {
if (str[j] == '#')
break;
}
set_color(str + i, str + j, MAKEFILE_PREPROCESS);
i = j;
continue;
case '\'':
case '`':
case '"':
/* parse string const */
for (j = i + 1; j < n; j++) {
if (str[j] == str[i]) {
j++;
break;
}
}
set_color(str + i, str + j, MAKEFILE_STRING);
i = j;
continue;
default:
break;
}
i++;
}
}
#undef MAKEFILE_TEXT
#undef MAKEFILE_COMMENT
#undef MAKEFILE_STRING
#undef MAKEFILE_PREPROCESS
#undef MAKEFILE_VARIABLE
#undef MAKEFILE_TARGET
#undef MAKEFILE_MACRO
static int makefile_mode_probe(ModeProbeData *p)
{
const char *base = basename(p->filename);
/* check file name or extension */
if (match_extension(base, "mk|mak")
|| stristart(base, "makefile", NULL))
return 70;
return 0;
}
static int makefile_mode_init(EditState *s, ModeSavedData *saved_data)
{
int ret;
ret = text_mode_init(s, saved_data);
if (ret)
return ret;
set_colorize_func(s, makefile_colorize_line);
return ret;
}
/* specific makefile commands */
static CmdDef makefile_commands[] = {
CMD_DEF_END,
};
static ModeDef makefile_mode;
static int makefile_init(void)
{
/* c mode is almost like the text mode, so we copy and patch it */
memcpy(&makefile_mode, &text_mode, sizeof(ModeDef));
makefile_mode.name = "Makefile";
makefile_mode.mode_probe = makefile_mode_probe;
makefile_mode.mode_init = makefile_mode_init;
qe_register_mode(&makefile_mode);
qe_register_cmd_table(makefile_commands, "Makefile");
return 0;
}
qe_module_init(makefile_init);

357
perl.c Normal file
View file

@ -0,0 +1,357 @@
/*
* Perl Source mode for QEmacs.
*
* Copyright (c) 2000-2007 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"
static const char *perl_mode_extensions = "pl|perl";
/*---------------- Perl colors ----------------*/
#define PERL_TEXT QE_STYLE_DEFAULT
#define PERL_COMMENT QE_STYLE_COMMENT
#define PERL_STRING QE_STYLE_STRING
#define PERL_REGEX QE_STYLE_STRING
#define PERL_DELIM QE_STYLE_KEYWORD
#define PERL_KEYWORD QE_STYLE_KEYWORD
#define PERL_VAR QE_STYLE_VARIABLE
#define PERL_NUMBER QE_STYLE_NUMBER
#define IN_STRING1 0x01 /* single quote */
#define IN_STRING2 0x02 /* double quote */
#define IN_FORMAT 0x04 /* format = ... */
#define IN_INPUT 0x08
/* CG: bogus if multiple regions are colorized */
static unsigned int perl_eos[100];
static int perl_eos_len;
static int perl_var(const unsigned int *str, int j, int n)
{
n = n;
if (qe_isdigit(str[j]))
return j;
for (; j < n; j++) {
if (qe_isalnum(str[j]) || str[j] == '_')
continue;
if (str[j] == '\''
&& (qe_isalpha(str[j + 1]) || str[j + 1] == '_'))
j++;
else
break;
}
return j;
}
static int perl_number(const unsigned int *str, int j, int n)
{
n = n;
if (str[j] == '0') {
j++;
if (str[j] == 'x' || str[j] == 'X') {
do j++; while (qe_isxdigit(str[j]));
return j;
}
if (str[j] >= '0' && str[j] <= '7') {
do j++; while (str[j] >= '0' && str[j] <= '7');
return j;
}
}
while (qe_isdigit(str[j]))
j++;
if (str[j] == '.')
do j++; while (qe_isdigit(str[j]));
if (str[j] == 'E' || str[j] == 'e') {
j++;
if (str[j] == '-' || str[j] == '+')
j++;
while (qe_isdigit(str[j]))
j++;
}
return j;
}
/* return offset of matching delimiter or end of string */
static int perl_string(const unsigned int *str, unsigned int delim, int j, int n)
{
for (; j < n; j++) {
if (str[j] == '\\')
j++;
else
if (str[j] == delim)
return j;
}
return j;
}
static void perl_colorize_line(unsigned int *str, int n, int *statep, int state_only)
{
int i = 0, c, c1, c2, j = i, s1, s2, delim = 0;
int colstate = *statep;
if (colstate & (IN_STRING1|IN_STRING2)) {
delim = (colstate & IN_STRING1) ? '\'' : '\"';
i = perl_string(str, delim, j, n);
if (i < n) {
i++;
colstate &= ~(IN_STRING1|IN_STRING2);
}
set_color(str + j, str + i, PERL_STRING);
} else
if (colstate & IN_FORMAT) {
i = n;
set_color(str + j, str + i, PERL_STRING);
if (n == 1 && str[0] == '.')
colstate &= ~IN_FORMAT;
}
if (colstate & IN_INPUT) {
//vdm_noRetrievalKey = 1;
i = n;
set_color(str + j, str + i, PERL_STRING);
if (n == perl_eos_len && !umemcmp(perl_eos, str, n))
colstate &= ~IN_INPUT;
}
while (i < n) {
j = i + 1;
c1 = str[j];
switch (c = str[i]) {
case '$':
if (c1 == '^' && qe_isalpha(str[i + 2])) {
j = i + 3;
goto keyword;
}
if (c1 == '#'
&& (qe_isalpha(str[i + 2]) || str[i + 2] == '_'))
j++;
else
if (!qe_isalpha(c1) && c1 != '_') {
/* Special variable */
j = i + 2;
goto keyword;
}
/* FALL THRU */
case '*':
case '@':
case '%':
case '&':
if (j >= n)
break;
s1 = perl_var(str, j, n);
if (s1 > j) {
set_color(str + i, str + s1, PERL_VAR);
i = s1;
continue;
}
break;
case '-':
if (c1 == '-') {
i += 2;
continue;
}
if (qe_isalpha(c1) && !qe_isalnum(str[i + 2])) {
j = i + 2;
goto keyword;
}
break;
case '#':
set_color(str + i, str + n, PERL_COMMENT);
i = n;
continue;
case '<':
if (c1 == '<') {
/* Should check for unary context */
s1 = i + 2;
c2 = str[s1];
if (c2 == '"' || c2 == '\'' || c2 == '`')
s2 = perl_string(str, c2, ++s1, n);
else
s2 = perl_var(str, s1, n);
if (s2 > s1) {
umemcpy(perl_eos, str + s1, s2 - s1);
perl_eos_len = s2 - s1;
colstate |= IN_INPUT;
}
i += 2;
continue;
}
delim = '>';
goto string;
case '/':
case '?':
/* Should check for unary context */
/* parse regex */
s1 = perl_string(str, c, j, n);
if (s1 >= n)
break;
set_color1(str + i, PERL_DELIM);
set_color(str + i + 1, str + s1, PERL_REGEX);
i = s1;
while (++i < n && qe_isalpha(str[i]))
continue;
set_color(str + s1, str + i, PERL_DELIM);
continue;
case '\'':
case '`':
case '"':
delim = c;
string:
/* parse string const */
s1 = perl_string(str, delim, j, n);
if (s1 >= n) {
if (c == '\'') {
set_color(str + i, str + n, PERL_STRING);
i = n;
colstate |= IN_STRING1;
continue;
}
if (c == '\"') {
set_color(str + i, str + n, PERL_STRING);
i = n;
colstate |= IN_STRING2;
continue;
}
break;
}
s1++;
set_color(str + i, str + s1, PERL_STRING);
i = s1;
continue;
default:
if (qe_isdigit(c)) {
j = perl_number(str, i, n);
set_color(str + i, str + j, PERL_NUMBER);
i = j;
continue;
}
if (!qe_isalpha(c) && c != '_')
break;
j = perl_var(str, i, n);
if (j == i)
break;
if (j >= n)
goto keyword;
/* Should check for context */
if ((j == i + 1 && (c == 'm' || c == 'q'))
|| (j == i + 2 && c == 'q' && (c1 == 'q' || c1 == 'x'))) {
s1 = perl_string(str, str[j], j + 1, n);
if (s1 >= n)
goto keyword;
set_color(str + i, str + j + 1, PERL_DELIM);
set_color(str + j + 1, str + s1, PERL_REGEX);
i = s1;
while (++i < n && qe_isalpha(str[i]))
continue;
set_color(str + s1, str + i, PERL_DELIM);
continue;
}
/* Should check for context */
if ((j == i + 1 && (c == 's' /* || c == 'y' */))
|| (j == i + 2 && c == 't' && c1 == 'r')) {
s1 = perl_string(str, str[j], j + 1, n);
if (s1 >= n)
goto keyword;
s2 = perl_string(str, str[j], s1 + 1, n);
if (s2 >= n)
goto keyword;
set_color(str + i, str + j + 1, PERL_DELIM);
set_color(str + j + 1, str + s1, PERL_REGEX);
set_color1(str + s1, PERL_DELIM);
set_color(str + s1 + 1, str + s2, PERL_REGEX);
i = s2;
while (++i < n && qe_isalpha(str[i]))
continue;
set_color(str + s2, str + i, PERL_DELIM);
continue;
}
keyword:
if (j - i == 6 && ustristart(str + i, "format", NULL))
colstate |= IN_FORMAT;
set_color(str + i, str + j, PERL_KEYWORD);
i = j;
continue;
}
i++;
continue;
}
*statep = colstate;
}
#undef PERL_TEXT
#undef PERL_COMMENT
#undef PERL_STRING
#undef PERL_REGEX
#undef PERL_DELIM
#undef PERL_KEYWORD
#undef PERL_VAR
#undef PERL_NUMBER
#undef IN_STRING1
#undef IN_STRING2
#undef IN_FORMAT
#undef IN_INPUT
static int perl_mode_probe(ModeProbeData *p)
{
/* just check file extension */
if (match_extension(p->filename, perl_mode_extensions))
return 80;
return 0;
}
static int perl_mode_init(EditState *s, ModeSavedData *saved_data)
{
int ret;
ret = text_mode_init(s, saved_data);
if (ret)
return ret;
set_colorize_func(s, perl_colorize_line);
return ret;
}
/* specific perl commands */
static CmdDef perl_commands[] = {
CMD_DEF_END,
};
static ModeDef perl_mode;
static int perl_init(void)
{
/* c mode is almost like the text mode, so we copy and patch it */
memcpy(&perl_mode, &text_mode, sizeof(ModeDef));
perl_mode.name = "Perl";
perl_mode.mode_probe = perl_mode_probe;
perl_mode.mode_init = perl_mode_init;
qe_register_mode(&perl_mode);
qe_register_cmd_table(perl_commands, "Perl");
return 0;
}
qe_module_init(perl_init);

View file

@ -62,3 +62,20 @@
STYLE_DEF(QE_STYLE_CSS, "css",
QERGB(0x98, 0xf8, 0x98), COLOR_TRANSPARENT,
0, 0)
/* HTML coloring styles */
STYLE_DEF(QE_STYLE_HTML_COMMENT, "html-comment",
QERGB(0xf8, 0x44, 0x00), QERGB(0x00, 0x00, 0x00),
0, 0)
STYLE_DEF(QE_STYLE_HTML_STRING, "html-string",
QERGB(0xf8, 0xa0, 0x78), QERGB(0x00, 0x00, 0x00),
0, 0)
STYLE_DEF(QE_STYLE_HTML_SCRIPT, "html-script",
QERGB(0x98, 0xf8, 0x98), QERGB(0x00, 0x00, 0x00),
0, 0)
STYLE_DEF(QE_STYLE_HTML_ENTITY, "html-entity",
QERGB(0xe8, 0xdc, 0x80), QERGB(0x00, 0x00, 0x00),
0, 0)
STYLE_DEF(QE_STYLE_HTML_TAG, "html-tag",
QERGB(0x80, 0xcc, 0xf0), QERGB(0x00, 0x00, 0x00),
0, 0)