diff --git a/Changes b/Changes index 1b627369..bfcc2b5b 100644 --- a/Changes +++ b/Changes @@ -2,6 +2,17 @@ * BUILD 24, version: 3.2.2 +Sun Aug 28 20:44:56 2022 adamy + + * html/xml + + o tag matching/hiliting syntax flags + + - SYNF_HTMLTAG + - SYNF_XMLTAG + + o void tags + Wed Aug 10 22:52:02 2022 adamy * syntax diff --git a/gr/Makefile.in b/gr/Makefile.in index bf2392a1..87546cd5 100644 --- a/gr/Makefile.in +++ b/gr/Makefile.in @@ -1,5 +1,5 @@ # -*- mode: mak; indent-tabs-mode: t; tab-width: 8 -*- -# $Id: Makefile.in,v 1.85 2022/07/10 13:12:24 cvsuser Exp $ +# $Id: Makefile.in,v 1.86 2022/08/22 15:40:47 cvsuser Exp $ # GRIEF editor makefile. # # @@ -335,6 +335,7 @@ CSRC=\ syntaxhl.c \ syntaxdfa.c \ syntaxcol.c \ + syntaxln.c \ \ tags.c \ tagsex.c \ diff --git a/gr/hilite.c b/gr/hilite.c index 5546e404..8a80c3d9 100644 --- a/gr/hilite.c +++ b/gr/hilite.c @@ -1,8 +1,8 @@ #include -__CIDENT_RCSID(gr_hilite_c,"$Id: hilite.c,v 1.18 2022/08/10 15:44:56 cvsuser Exp $") +__CIDENT_RCSID(gr_hilite_c,"$Id: hilite.c,v 1.19 2022/08/16 12:25:22 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: hilite.c,v 1.18 2022/08/10 15:44:56 cvsuser Exp $ +/* $Id: hilite.c,v 1.19 2022/08/16 12:25:22 cvsuser Exp $ * Hilite management. * * @@ -97,9 +97,9 @@ hilite_create(BUFFER_t *bp, int type, int32_t timeout, hp->h_magic = HILITE_MAGIC; hp->h_type = type; hp->h_timeout = timeout; - if (hp->h_timeout > 0) { - hp->h_timeout += (time(NULL) - 1); // expire time. - } else if (-1 == timeout) { + if (timeout > 0) { //note: owc time_t is unsigned + hp->h_timeout += time(NULL) - 1; // relative expire time. + } else if (timeout < 0) { hp->h_ctime = bp->b_ctime; // expire on buffer change. } hp->h_seqno = ++x_hilite_seqno; @@ -361,3 +361,4 @@ hilite_zap(BUFFER_t *bp, int update) } /*end*/ + diff --git a/gr/syntax.c b/gr/syntax.c index dee700c9..90fcf8a2 100644 --- a/gr/syntax.c +++ b/gr/syntax.c @@ -1,8 +1,8 @@ #include -__CIDENT_RCSID(gr_syntax_c, "$Id: syntax.c,v 1.63 2022/08/10 16:22:34 cvsuser Exp $") +__CIDENT_RCSID(gr_syntax_c, "$Id: syntax.c,v 1.67 2022/08/28 12:38:55 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: syntax.c,v 1.63 2022/08/10 16:22:34 cvsuser Exp $ +/* $Id: syntax.c,v 1.67 2022/08/28 12:38:55 cvsuser Exp $ * Syntax pre-processor. * * @@ -38,33 +38,6 @@ __CIDENT_RCSID(gr_syntax_c, "$Id: syntax.c,v 1.63 2022/08/10 16:22:34 cvsuser Ex #include "tags.h" /* tags_check() */ #include "tty.h" /* ttrows() */ -struct match_element { - LINENO line; /* Current line */ - LINENO col; /* Current col */ - LINENO offset; /* Offset within line */ -}; - -struct match_stack { - const LINECHAR **data; /* Element stack */ - size_t capacity; /* Capacity, in elements */ - size_t top; /* Stack top */ -}; - -struct match_state { - SyntaxTable_t *st; /* Current syntaxtable */ - struct match_element start; /* Start position */ - struct match_element end; /* End position */ - const LINECHAR *text; /* Current line start */ - const LINECHAR *filter; /* First line filter */ - struct match_stack stack; /* Line stack */ - unsigned char open; /* Characters being matched */ - unsigned char close; - int backwards; /* backwards, otherwise forward */ - int lines; /* Numbers of lines to scan */ - int hilites; - int level; /* Matching level */ -}; - static int syntax_table2attr(int table); static SyntaxTable_t * syntax_new(const char *name); @@ -81,20 +54,12 @@ static int keyword_push_list(SyntaxWordList_t *words, int l static void keyword_free_list(SyntaxWordList_t *words); static int keyword_push_pat(SyntaxTable_t *st, int attr, int length, int total, const char *keywords, int sep); -static int fndmatching(SyntaxTable_t *st); - static int style_lookup(const char *name); static int style_getc(int n); static const char * style_gets(int n); static int style_once(SyntaxTable_t *st, SyntaxChar_t style, const char *description); static const char * style_charset(const char *fmt, unsigned char *tab); -typedef void (*Parser_t)(const LINECHAR *cursor, void *udata); - -static void find_matching(struct match_state *ms); -static int parse_lines(SyntaxTable_t *st, LINENO lineno, LINENO num); -static lineflags_t parse_line(SyntaxTable_t *st, const LINE_t *l, Parser_t parser, void *udata); - static const struct flag { const char *f_name; /* name/label */ int f_length; @@ -835,15 +800,15 @@ keyword_push_pat(SyntaxTable_t *st, int attr, int length, int total, const char { const int count = (total / length); /* word count */ unsigned elements = 0; - struct trie *t; + struct trie *patterns; assert(attr >= ATTR_NORMAL); if (attr < ATTR_NORMAL) { return -1; } - if (NULL == (t = st->keyword_patterns)) { - st->keyword_patterns = t = trie_create(); + if (NULL == (patterns = st->keyword_patterns)) { + st->keyword_patterns = patterns = trie_create(); } if (sep) { @@ -851,7 +816,7 @@ keyword_push_pat(SyntaxTable_t *st, int attr, int length, int total, const char while (keywords < end) { assert(sep == keywords[length] || 0 == keywords[length]); trace_ilog("\t%.*s\n", length, keywords); - trie_insert_nwild(t, (const char *)keywords, length, (void *)attr); + trie_insert_nwild(patterns, (const char *)keywords, length, (void *)attr); keywords += length + /*sep*/1; ++elements; } @@ -860,7 +825,7 @@ keyword_push_pat(SyntaxTable_t *st, int attr, int length, int total, const char const char *end = keywords + total; while (keywords < end) { trace_ilog("\t%.*s\n", length, keywords); - trie_insert_nwild(t, (const char *)keywords, length, (void *)attr); + trie_insert_nwild(patterns, (const char *)keywords, length, (void *)attr); keywords += length; ++elements; } @@ -924,6 +889,8 @@ keyword_push_pat(SyntaxTable_t *st, int attr, int length, int total, const char SYNT_HTML - , , + SYNT_TAG - , , + SYNT_WORD - , Defines the character-set which represent a single word. @@ -1042,7 +1009,6 @@ do_syntax_token(void) /* int (int type|string type, [arg1], [arg2], [i } break; -#if defined(SYNT_LINEJOIN) case SYNT_LINEJOIN: /* , */ if ((c = style_getc(ARG1)) > 0) { if (style_once(st, SYNC_LINEJOIN, "LINEJOIN")) { @@ -1050,7 +1016,6 @@ do_syntax_token(void) /* int (int type|string type, [arg1], [arg2], [i } } break; -#endif case SYNT_QUOTE: /* , */ if ((c = style_getc(ARG1)) > 0) @@ -1082,8 +1047,8 @@ do_syntax_token(void) /* int (int type|string type, [arg1], [arg2], [i charmap[(unsigned char) s2[i]] |= SYNC_BRACKET_CLOSE; if (idx < 3) { - st->bracket_chars[idx][0] = s1[i]; - st->bracket_chars[idx][1] = s2[i]; + st->bracket_chars[idx].open = s1[i]; + st->bracket_chars[idx].close = s2[i]; ++idx; } } @@ -1252,6 +1217,32 @@ do_syntax_token(void) /* int (int type|string type, [arg1], [arg2], [i } break; + case SYNT_TAG: /* , , "" */ + if (NULL != (s1 = get_xstr(ARG1))) { + if ((0 == str_icmp(s1, "ivoid") || 0 == str_icmp(s1, "void")) && + NULL != (s2 = get_xstr(ARG2)) && *s2) { + struct trie *tags; + + if (NULL == (tags = st->void_tags)) { + st->void_tags = tags = + (0 == str_icmp(s1, "ivoid") ? trie_icreate() : trie_create()); + } + + while (s2 && *s2) { + const char *end = strchr(s2, ','); + if (end) { + if (end != s2) + trie_ninsert(tags, s2, end - s2, ""); + s2 = end + 1; + } else { + trie_insert(tags, s2, ""); + s2 = NULL; + } + } + } + } + break; + default: if (stylename) { errorf("syntax: unknown syntax style '%s'", stylename); @@ -1266,103 +1257,6 @@ do_syntax_token(void) /* int (int type|string type, [arg1], [arg2], [i } -void -do_syntax_find() /* int ([int mode = 0], [int &line], [int &col], ... */ -{ - SyntaxTable_t *st = syntax_current(); - const int mode = get_xinteger(1, 1); /* find mode */ - int ret = -1; /* nothing to match */ - // -2 = Unknown character. - // -1 = Nothing to match. - // 0 = Matched. - // 1 = Unmatched. - - if (NULL == curbp || NULL == st) { - ret = -2; /* no syntax definition */ - - } else if (0 == mode) { - ret = fndmatching(st); - } - - acc_assign_int(ret); -} - - -static int -fndmatching(SyntaxTable_t *st) -{ - const SyntaxChar_t *charmap = st->syntax_charmap; - const char *ch = get_xstr(6); /* element */ - unsigned char match = (ch ? *((unsigned char *)ch) : 0); - struct match_state ms = {0}; - int brackets = -1; - int ret = 1; - LINE_t *lp; - - /* int (mode = 1, [int &line], [int &col], [int hilites = 1], [int lines = 75], [string element = ""]) */ - - ms.st = st; - ms.hilites = get_xinteger(4, 1); /* auto hilite results */ - ms.lines = get_xinteger(5, 75); /* scan lines */ - ms.start.line = *cur_line; - ms.start.col = *cur_col; - ms.start.offset = line_offset(ms.start.line, ms.start.col, LOFFSET_NORMAL); - - if (match) { - ms.level = 1; - - } else if (NULL != (lp = vm_lock_line2(ms.start.line))) { - if (NULL != (ms.text = ltext(lp))) { - if ((LINENO)llength(lp) > ms.start.offset) { - match = ms.text[ms.start.offset]; - } - } - } - - if (SYNC_BRACKET_OPEN & charmap[match]) { - unsigned b; - for (b = 0; b < (sizeof(st->bracket_chars)/2); ++b) { - if (st->bracket_chars[b][0] == match) { - ms.end.line = curbp->b_numlines; - brackets = b; - break; - } - } - } else if (SYNC_BRACKET_CLOSE & charmap[match]) { - unsigned b; - for (b = 0; b < (sizeof(st->bracket_chars)/2); ++b) { - if (st->bracket_chars[b][1] == match) { - ms.end.line = 1; - ms.backwards = 1; - brackets = b; - break; - } - } - } else { - ret = -2; - } - - if (brackets >= 0) { /* open/close */ - ms.open = st->bracket_chars[brackets][0]; - ms.close = st->bracket_chars[brackets][1]; - find_matching(&ms); - if (ms.end.line) { /* matched, return */ - if (! isa_undef(2)) { - sym_assign_int(get_symbol(2), (accint_t) ms.end.line); - } - if (! isa_undef(3)) { - sym_assign_int(get_symbol(3), (accint_t) ms.end.col); - } - ret = 0; - } - } - - chk_free((void *)ms.stack.data); - - return ret; -} - - static int style_lookup(const char *name) { @@ -1548,12 +1442,12 @@ syntax_init(void) charmap[(unsigned char) '('] = SYNC_BRACKET_OPEN; charmap[(unsigned char) ')'] = SYNC_BRACKET_CLOSE; charmap[(unsigned char) '{'] = SYNC_BRACKET_OPEN; charmap[(unsigned char) '}'] = SYNC_BRACKET_CLOSE; - x_default_table->bracket_chars[0][0] = '['; - x_default_table->bracket_chars[0][1] = ']'; - x_default_table->bracket_chars[1][0] = '('; - x_default_table->bracket_chars[1][1] = ')'; - x_default_table->bracket_chars[2][0] = '{'; - x_default_table->bracket_chars[2][1] = '}'; + x_default_table->bracket_chars[0].open = '['; + x_default_table->bracket_chars[0].close = ']'; + x_default_table->bracket_chars[1].open = '('; + x_default_table->bracket_chars[1].close = ')'; + x_default_table->bracket_chars[2].open = '{'; + x_default_table->bracket_chars[2].close = '}'; } @@ -1824,7 +1718,7 @@ writex_spell(SyntaxTable_t *st, const LINECHAR *word, int wordlen, int colour, i } } - if (SYNW_TAGS & flags) { /* tabdb */ + if (SYNW_TAGS & flags) { /* tabdb */ if (tags_check(/*TODO, scope by filename*/ (const char *)word, wordlen) > 0) { return ATTR_TAG; } @@ -2031,7 +1925,7 @@ keyword_strcmp(const void * k1, const void * k2) } -static SyntaxTable_t * +SyntaxTable_t * syntax_select(void) { register SyntaxTable_t *st; @@ -2235,39 +2129,6 @@ syntax_preprocessor(const SyntaxTable_t *st, const LINECHAR *token, int length) } -/* - * syntax_parse --- - * Parse the current buffer, updating the syntax status of the requested line. - */ -int -syntax_parse(int all) -{ - SyntaxTable_t *st; - LINENO min_line, max_line; - - if (NULL == (st = syntax_select())) { - return 0; - } - - if (st != curbp->b_syntax) { - curbp->b_syntax = st; - all = 1; /* new assignment, reset */ - } - - if (all) { /* all of the buffer */ - min_line = 1; - max_line = curbp->b_numlines; - } else { /* otherwise modified */ - if ((min_line = curbp->b_syntax_min) <= 0) { - return (0); - } - max_line = curbp->b_syntax_max; - } - - curbp->b_syntax_min = curbp->b_syntax_max = 0; - return parse_lines(st, min_line, max_line - min_line); -} - /* * syntax_highlight --- @@ -2299,68 +2160,6 @@ syntax_highlight(const LINE_t *lp) } -/* - * syntax_virtual_cursor --- - * Visual cursor update event. - */ -void -syntax_virtual_cursor() -{ - SyntaxTable_t *st; - - if (! BFTST(curbp, BF_SYNTAX_MATCH)) - return; /* disabled? */ - - if (NULL != (st = curbp->b_syntax) && st->st_active) { - const SyntaxChar_t *charmap = st->syntax_charmap; - const unsigned match = (unsigned) curbp->b_vchar[0]; - struct match_state ms = {0}; - int brackets = -1; - - if (match > 0xff) - return; /* non-ascii */ - - // TODO/optional: if vchar is space, scan from start of line. - - if (SYNC_BRACKET_OPEN & charmap[match]) { - unsigned b; - for (b = 0; b < (sizeof(st->bracket_chars)/2); ++b) { - if (st->bracket_chars[b][0] == match) { - ms.end.line = curbp->b_numlines; - brackets = b; - break; - } - } - - } else if (SYNC_BRACKET_CLOSE & charmap[match]) { - unsigned b; - for (b = 0; b < (sizeof(st->bracket_chars)/2); ++b) { - if (st->bracket_chars[b][1] == match) { - ms.end.line = 1; - ms.backwards = 1; - brackets = b; - break; - } - } - } - - if (brackets < 0) /* non-open/close */ - return; - - ms.st = st; - ms.hilites = 1; /* auto hilite results */ - ms.lines = ttrows() + 1; - ms.start.line = curbp->b_vline; - ms.start.col = curbp->b_vcol; - ms.start.offset = curbp->b_voffset; - ms.open = st->bracket_chars[brackets][0]; - ms.close = st->bracket_chars[brackets][1]; - find_matching(&ms); - chk_free((void *)ms.stack.data); - } -} - - /* * leading_write --- * Common handling for leading line conditions. @@ -2608,420 +2407,4 @@ syntax_string_end( return NULL; } - -/* - * find_matching --- - * Parse the specified line block, matching brackets. - */ -static void -find_matching_callback(const LINECHAR *cursor, void *udata) -{ - struct match_state *ms = (struct match_state *)udata; - const unsigned char ch = *cursor; - - if (ch != ms->open && ch != ms->close) - return; - - if (ms->filter) { /* line filter */ - if (ms->backwards) { - if (cursor > ms->filter) - return; - } else { - if (cursor < ms->filter) - return; - } - } - - if (ms->stack.top == ms->stack.capacity) { /* extend? */ - const size_t capacity = (ms->stack.capacity + 64); - void *data = chk_realloc((void *)ms->stack.data, capacity * sizeof(LINECHAR *)); - if (NULL == data) - return; - - ms->stack.capacity = capacity; - ms->stack.data = data; - } - - ms->stack.data[ms->stack.top++] = cursor; - assert(ms->stack.top <= ms->stack.capacity); -} - - -static void -find_matching(struct match_state *ms) -{ - const int backwards = ms->backwards; - const LINENO end_line = ms->end.line; - SyntaxTable_t *st = ms->st; - LINENO lineno = ms->start.line; - LINE_t *lp; - - ms->end.line = 0; - ms->end.offset = -1; - - if (NULL != (lp = vm_lock_line2(lineno))) { - if (NULL != (ms->text = ltext(lp))) { - if ((LINENO)llength(lp) > ms->start.offset) { - ms->filter = ms->text + ms->start.offset; - } - } - } - - while (lp) { /* parse current line */ - if (NULL != (ms->text = ltext(lp))) { - parse_line(st, lp, find_matching_callback, ms); - if (ms->stack.top) { - if (backwards) { - size_t e; - for (e = ms->stack.top; e;) { - const LINECHAR *t_cursor = ms->stack.data[--e]; - if (*t_cursor == ms->close) { - ++ms->level; - } else { - assert(*t_cursor == ms->open && ms->level); - if (--ms->level <= 0) { - liflagset(lp, LI_DIRTY); - ms->end.offset = (t_cursor - ms->text); - break; - } - } - } - } else { - const size_t top = ms->stack.top; - size_t e; - for (e = 0; e != top;) { - const LINECHAR *t_cursor = ms->stack.data[e++]; - if (*t_cursor == ms->open) { - ++ms->level; - } else { - assert(*t_cursor == ms->close && ms->level); - if (--ms->level <= 0) { - liflagset(lp, LI_DIRTY); - ms->end.offset = (t_cursor - ms->text); - break; - } - } - } - } - ms->stack.top = 0; - } - } - - vm_unlock(lineno); - if (ms->end.offset >= 0) { /* match */ - ms->end.line = lineno; - ms->end.col = line_column(ms->end.line, ms->end.offset); - break; - } else if (ms->level <= 0) { - break; /* no match, inside comment etc */ - } - - ms->filter = NULL; - if (0 == ms->lines) - break; - --ms->lines; - - if (backwards) { /* new line */ - if (lineno-- <= end_line || NULL == (lp = lback(lp))) { - break; - } - } else { - if (lineno++ >= end_line || NULL == (lp = lforw(lp))) { - break; /* EOF */ - } - } - } - - if (ms->hilites) { /* optional, hilite results */ - HILITE_t *open; - - hilite_destroy(curbp, HILITE_SYNTAX_MATCH); - if (NULL != (open = hilite_create(curbp, HILITE_SYNTAX_MATCH, -1, ms->start.line, ms->start.col, ms->start.line, ms->start.col))) { - if (ms->end.line) { - HILITE_t *close = hilite_create(curbp, HILITE_SYNTAX_MATCH, -1, ms->end.line, ms->end.col, ms->end.line, ms->end.col); - if (close) { - close->h_attr = ATTR_HILITE; - open->h_attr = ATTR_HILITE; - } - } - } - } -} - - -/* - * parse_lines --- - * Parse the specified line block, determining the arena in which hilite is dirty due to content change. - */ -static int -parse_lines(SyntaxTable_t *st, LINENO lineno, LINENO num) -{ - LINE_t *lp; - - if (lineno > 1) { - --lineno, ++num; - } - - ED_TRACE(("syntax::parse_lines(flags:0x%04x, lineno:%d, num:%d, numline:%d)\n", \ - st->st_flags, lineno, num, (int)curbp->b_numlines)) - - lp = vm_lock_line2(lineno); - while (lp) { /* parse current line */ - lineflags_t state = parse_line(st, lp, NULL, NULL); - - liflagclr(lp, LI_DIRTY); - lp->l_uflags &= ~L_HAS_EOL_COMMENT; - - switch (state) { - case L_IN_COMMENT: - case L_IN_COMMENT2: - break; - case L_IN_STRING: - case L_IN_LITERAL: - case L_IN_CHARACTER: - if (st->st_flags & SYNF_STRING_ONELINE) { - state = 0; /* fuse string at EOL */ - } - break; - case L_HAS_EOL_COMMENT: - lp->l_uflags |= L_HAS_EOL_COMMENT; - state = 0; - break; - } - - /* retrieve next */ - vm_unlock(lineno); - if (NULL == (lp = lforw(lp))) { /* NEWLINE */ - break; /* EOF */ - } - ++lineno; /* new line */ - - /* check range or status */ - if (num > 0) { /* required rescan min */ - --num; - - } else if (state == (L_SYNTAX_MASK & lp->l_uflags)) { - break; /* state in-sync, no need to continue */ - } - - /* update status */ - lp->l_uflags &= ~L_SYNTAX_MASK; - lp->l_uflags |= state; - } - return lineno; -} - - -static lineflags_t -parse_line(SyntaxTable_t *st, const LINE_t *line, Parser_t callback, void *udata) -{ - const uint32_t flags = st->st_flags; - const lineflags_t lsyntax = (L_SYNTAX_MASK & line->l_uflags); - const SyntaxChar_t *charmap = st->syntax_charmap; - const LINECHAR *cursor, *begin, *end; - unsigned char schar, ichar, cchar, quote; - - /* Retrieve line buffer and length */ - if (NULL == (cursor = begin = ltext(line))) { - return lsyntax; - } - end = begin + llength(line); - if (end == begin) { - return lsyntax; - } - - ED_TRACE2(("\t<%.*s>\n", end - cursor, cursor)) - - /* fixed style comments (aka FORTRAN, plus also COBOL) */ - if (SYNF_FORTRAN & flags) { - if (cursor + st->comment_fixed_pos < end) { - unsigned char ch = cursor[st->comment_fixed_pos]; - - if (st->comment_fixed_char[ch]) { - return L_HAS_EOL_COMMENT; - } - } - } - - /* cache string/comment delimiters */ - schar = st->string_char; - cchar = st->char_char; - ichar = st->literal_char; - quote = st->quote_char; - - /* terminate current comment or string */ - if (lsyntax) { - const lineflags_t lsyntaxin = (lsyntax & L_SYNTAX_IN); - - switch (lsyntaxin) { - case L_IN_COMMENT: /* comment, type-1 */ - if (NULL == (cursor = syntax_comment_end(st, 0, cursor, end))) { - return L_IN_COMMENT; - } - break; - case L_IN_COMMENT2: /* comment, type-2 */ - if (NULL == (cursor = syntax_comment_end(st, 1, cursor, end))) { - return L_IN_COMMENT2; - } - break; - case L_IN_STRING: /* string */ - if (NULL == (cursor = syntax_string_end(st, cursor, end, quote, schar))) { - return L_IN_STRING; - } - break; - case L_IN_LITERAL: /* literals, optional quoting */ - if (NULL == (cursor = syntax_string_end(st, cursor, end, - (char)(flags & SYNF_LITERAL_NOQUOTES ? 0 : quote), ichar))) { - return L_IN_LITERAL; - } - break; - case L_IN_CHARACTER: - if (NULL == (cursor = syntax_string_end(st, cursor, end, quote, cchar))) { - return L_IN_CHARACTER; - } - /*FALLTHRU*/ - case L_IN_CONTINUE: - case L_IN_PREPROC: - if (begin < end) { - unsigned char lchar; - - if (0 != (lchar = st->linecont_char)) { - if (lchar == end[-1]) { - return lsyntax; /* last character is continuation */ - - } else if (SYNF_LINECONT_WS & flags) { - const LINECHAR *back = end; /* scan backward consuming white-space */ - - while (back > begin) { /* MCHAR??? */ - const unsigned char ch = (unsigned char) *--back; - - if (lchar == ch) { - return lsyntax; /* trailing continuation */ - } - if (' ' == ch || '\t' == ch) { - continue; - } - break; - } - } - } - } - break; - default: - assert(0 == lsyntaxin); - break; - } - } - - /* outside string/comment */ - while (cursor < end) { /* MCHAR??? */ - const unsigned char ch = (unsigned char) *cursor; - - if (0 == ch) { /* NULs, ignore */ - ++cursor; - continue; - } - - if (ch == quote) { /* quotes */ - if ((cursor + 1) < end) { - cursor += 2; - continue; - } - break; - } - - if (ch == schar || ch == cchar) { /* string/character */ - const LINECHAR *ocursor = cursor; - cursor = syntax_string_end(st, ocursor + 1, end, quote, ch); - if (NULL == cursor) { - if (0 == (st->st_flags & SYNF_STRING_MATCHED)) { - return (ch == schar ? L_IN_STRING : L_IN_CHARACTER); - } - cursor = ocursor + 1; /* normal */ - } - continue; - } - - if (ch == ichar) { /* literals, optional quoting */ - const LINECHAR *ocursor = cursor; - cursor = syntax_string_end(st, ocursor + 1, end, (char)(SYNF_LITERAL_NOQUOTES & flags ? 0 : quote), ch); - if (NULL == cursor) { - return L_IN_LITERAL; - } - continue; - } - - if (charmap[ch] & SYNC_COMMENT) { /* comments */ - const LINECHAR *t_end; - - switch (syntax_comment(st, cursor, begin, end, &t_end)) { - case COMMENT_NORMAL: - cursor = t_end; - break; - case COMMENT_EOL: - return L_HAS_EOL_COMMENT; - case COMMENT_OPEN: - return L_IN_COMMENT; - case COMMENT_OPEN2: - return L_IN_COMMENT2; - case COMMENT_NONE: - default: - ++cursor; - } - continue; - } - - if (callback) callback(cursor, udata); - ++cursor; - } - - if (begin < end) { - unsigned char lchar; - - if (0 != (lchar = st->linecont_char)) { - int iscont = FALSE; - - if (lchar == end[-1]) { - iscont = TRUE; /* last character is continuation */ - - } else if (SYNF_LINECONT_WS & flags) { - cursor = end; /* scan backward consuming white-space */ - while (cursor > begin) { /* MCHAR??? */ - const unsigned char ch = (unsigned char) *--cursor; - - if (ch == lchar) { - iscont = TRUE; /* trailing continuation */ - break; - } - if (' ' == ch || '\t' == ch) { - continue; - } - break; - } - } - - if (iscont) { - unsigned char pchar; - - if (0 != (pchar = st->preprocessor_char)) { - cursor = begin; - while (cursor < end) { /* MCHAR??? */ - const unsigned char ch = (unsigned char) *cursor++; - - if (0 == charmap[ch]) { - continue; /* normal character */ - } - if (ch == pchar) { - return L_IN_PREPROC; - } - break; - } - } - return L_IN_CONTINUE; /* continuation */ - } - } - } - return 0; -} - /*end*/ diff --git a/gr/syntax.h b/gr/syntax.h index 18297e23..252b07cd 100644 --- a/gr/syntax.h +++ b/gr/syntax.h @@ -1,11 +1,11 @@ #ifndef GR_SYNTAX_H_INCLUDED #define GR_SYNTAX_H_INCLUDED #include -__CIDENT_RCSID(gr_syntax_h,"$Id: syntax.h,v 1.36 2022/08/10 15:44:58 cvsuser Exp $") +__CIDENT_RCSID(gr_syntax_h,"$Id: syntax.h,v 1.39 2022/08/28 12:38:01 cvsuser Exp $") __CPRAGMA_ONCE /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: syntax.h,v 1.36 2022/08/10 15:44:58 cvsuser Exp $ +/* $Id: syntax.h,v 1.39 2022/08/28 12:38:01 cvsuser Exp $ * Syntax hiliting constructs. * * @@ -31,6 +31,33 @@ __CBEGIN_DECLS /*--export--defines--*/ /* * Syntax rules/types + * + * Flag Description + * ---------------------------------------------------------------------------- + * SYNT_COMMENT , [, -string>] + * SYNT_CSTYLE , | + * SYNT_PREPROCESSOR , + * + * SYNT_STRING , + * SYNT_LITERAL , + * + * SYNT_LINECONT , + * SYNT_LINEJOIN , + * + * SYNT_QUOTE , + * SYNT_CHARACTER , + * + * SYNT_BRACKET , [, ] + * SYNT_HTML , , + * SYNT_TAG , , + * + * SYNT_WORD , + * SYNT_KEYWORD , + * + * SYNT_NUMERIC , [, ] + * SYNT_OPERATOR , + * SYNT_DELIMITER , + * SYNT_FORTRAN , , <[left-margin], code [, comment-margin]> */ #define SYNT_COMMENT 1 #define SYNT_PREPROCESSOR 2 @@ -42,6 +69,7 @@ __CBEGIN_DECLS #define SYNT_HTML 20 #define SYNT_BRACKET 21 +#define SYNT_TAG 22 #define SYNT_OPERATOR 30 #define SYNT_DELIMITER 31 @@ -67,14 +95,15 @@ __CBEGIN_DECLS * SYNF_LITERAL_NOQUOTES Literal strings don't translate quoted characters. * SYNF_STRING_MATCHED String open/close must be matched; otherwise ignored. * - * SYNF_COMMENTS_LEADINGWS xxx - * SYNF_COMMENTS_TRAILINGWS xxx - * SYNF_COMMENTS_QUOTE xxx + * SYNF_COMMENTS_LEADINGWS Dont hilite leading white-space. + * SYNF_COMMENTS_TRAILINGWS Dont hilite trailing white-space. + * SYNF_COMMENTS_QUOTE Allow comment character to be quoted. * SYNF_COMMENTS_CSTYLE C-style comments. * - * SYNF_PREPROCESSOR_WS xxx - * SYNF_LINECONT_WS xxx - * SYNF_MANDOC xxx + * SYNF_PREPROCESSOR_WS Dont hilite leading white-space. + * SYNF_LINECONT_WS Allow white-space after cont token. + * + * SYNF_MANDOC MANDOC hiliting. * * SYNF_HILITE_WS Hilite white-space. * SYNF_HILITE_LINECONT Hilite line continuations. @@ -83,28 +112,34 @@ __CBEGIN_DECLS * SYNF_SPELL_WORD Enable word spell check. * SYNF_SPELL_COMMENT Enable comment spell check. * + * SYNF_HTMLTAGS HTML tags. + * SYNF_XMLTAGS XML tags. */ -#define SYNF_CASEINSENSITIVE 0x0001 -#define SYNF_FORTRAN 0x0002 -#define SYNF_STRING_ONELINE 0x0004 -#define SYNF_LITERAL_NOQUOTES 0x0008 -#define SYNF_STRING_MATCHED 0x4000 - -#define SYNF_COMMENTS_LEADINGWS 0x0010 -#define SYNF_COMMENTS_TRAILINGWS 0x0020 -#define SYNF_COMMENTS_QUOTE 0x0040 -#define SYNF_COMMENTS_CSTYLE 0x0080 - -#define SYNF_PREPROCESSOR_WS 0x0100 -#define SYNF_LINECONT_WS 0x0200 -#define SYNF_MANDOC 0x0400 - -#define SYNF_HILITE_WS 0x1000 -#define SYNF_HILITE_LINECONT 0x2000 -#define SYNF_HILITE_PREPROCESSOR 0x0400 - -#define SYNF_SPELL_WORD 0x1000 -#define SYNF_SPELL_COMMENT 0x2000 +#define SYNF_CASEINSENSITIVE 0x000001 +#define SYNF_FORTRAN 0x000002 +#define SYNF_STRING_ONELINE 0x000004 +#define SYNF_LITERAL_NOQUOTES 0x000008 +#define SYNF_STRING_MATCHED 0x000800 + +#define SYNF_COMMENTS_LEADINGWS 0x000010 +#define SYNF_COMMENTS_TRAILINGWS 0x000020 +#define SYNF_COMMENTS_QUOTE 0x000040 +#define SYNF_COMMENTS_CSTYLE 0x000080 + +#define SYNF_PREPROCESSOR_WS 0x000100 +#define SYNF_LINECONT_WS 0x000200 + +#define SYNF_MANDOC 0x000400 + +#define SYNF_HILITE_WS 0x001000 +#define SYNF_HILITE_LINECONT 0x002000 +#define SYNF_HILITE_PREPROCESSOR 0x004000 + +#define SYNF_SPELL_WORD 0x010000 +#define SYNF_SPELL_COMMENT 0x020000 + +#define SYNF_HTMLTAG 0x040000 +#define SYNF_XMLTAG 0x080000 /*--end--*/ /*--export--defines--*/ @@ -237,6 +272,11 @@ typedef struct { SyntaxWords_t kw_words[1]; /* slots [0] ... */ } SyntaxKeywords_t; +typedef struct CharacterPair { + unsigned char open; + unsigned char close; +} CharacterPair_t; + typedef struct SyntaxTable { /* * Name status etc @@ -318,7 +358,8 @@ typedef struct SyntaxTable { unsigned char quote_char; unsigned char preprocessor_char; unsigned char linecont_char; - unsigned char bracket_chars[4][2]; /* open/close, max 4 pairs */ + CharacterPair_t bracket_chars[4]; /* open/close, max 4 pairs */ + struct trie * void_tags; SyntaxChar_t syntax_charmap[256]; @@ -345,8 +386,9 @@ extern void syntax_shutdown(void); extern SyntaxTable_t * syntax_current(void); extern SyntaxTable_t * syntax_argument(int argi, int err); extern SyntaxTable_t * syntax_lookup(const char *name, int err); -extern int syntax_keyword(const SyntaxTable_t *st, const LINECHAR *token, int length); +extern SyntaxTable_t * syntax_select(void); extern int syntax_keywordx(const SyntaxTable_t *st, const LINECHAR *token, int length, int start, int end, int icase); +extern int syntax_keyword(const SyntaxTable_t *st, const LINECHAR *token, int length); extern int syntax_preprocessor(const SyntaxTable_t *st, const LINECHAR *token, int length); extern const LINECHAR * syntax_write(SyntaxTable_t *st, const LINECHAR *start, const LINECHAR *end, int colour); diff --git a/gr/syntaxln.c b/gr/syntaxln.c new file mode 100644 index 00000000..b8186545 --- /dev/null +++ b/gr/syntaxln.c @@ -0,0 +1,1032 @@ +#include +__CIDENT_RCSID(gr_syntaxln_c, "$Id: syntaxln.c,v 1.2 2022/08/29 13:47:47 cvsuser Exp $") + +/* -*- mode: c; indent-width: 4; -*- */ +/* $Id: syntaxln.c,v 1.2 2022/08/29 13:47:47 cvsuser Exp $ + * Syntax support. + * + * + * This file is part of the GRIEF Editor. + * + * The GRIEF Editor is free software: you can redistribute it + * and/or modify it under the terms of the GRIEF Editor License. + * + * The GRIEF Editor 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 + * License for more details. + * ==end== + */ + +#include +#include /* str_...()/sxprintf() */ + +#include "accum.h" +#include "color.h" /* attribute_value() */ +#include "builtin.h" +#include "debug.h" +#include "display.h" +#include "hilite.h" +#include "echo.h" /* errorf() */ +#include "eval.h" /* get_str() */ +#include "lisp.h" +#include "main.h" +#include "map.h" +#include "spell.h" /* spell_check/nextword() */ +#include "symbol.h" /* argv_assign() */ +#include "syntax.h" +#include "tags.h" /* tags_check() */ +#include "tty.h" /* ttrows() */ + + +struct match_element { + LINENO line; /* Line */ + LINENO col; /* Column */ + LINENO offset; /* Offset within line */ + LINENO line2; /* Secondary line */ + LINENO col2; /* Secondary column */ + LINENO offset2; /* Secondary Offset within line */ + int matched; /* Matched status */ +}; + + +struct match_tag { + const LINECHAR *data; /* Value */ + uint16_t length; /* length */ +}; + + +struct match_stack { + struct element { + const LINECHAR *cursor; + struct match_tag tag; + } *elements; /* Element stack */ + size_t capacity; /* Capacity, in elements */ + size_t top; /* Stack top */ +}; + + +struct match_state { + SyntaxTable_t *st; /* Current syntaxtable */ + struct match_element start; /* Start position */ + struct match_element end; /* Completion position */ + const LINECHAR *text; /* Current line start */ + const LINECHAR *eol; /* and end-of-line */ + const LINECHAR *filter; /* First line filter */ + LINENO lineno; /* Current line number */ + struct match_stack stack; /* Line stack */ + struct match_tag tag; /* Active tag, level=0 */ + unsigned char open, close; /* Characters being matched */ + unsigned char tagtype; /* Matching tags logic: NUL,X=XML or H=HTML */ + unsigned backwards : 1; /* backwards, otherwise forward */ + unsigned hilites : 1; /* Hilite results */ + int nesting; /* Nesting level */ + int void_nesting; /* Void nesting level */ + int lines; /* Numbers of lines to scan */ +}; + + +typedef void (*Parser_t)(const LINECHAR *cursor, void *udata); + +static int find_paired(SyntaxTable_t *st); +static int find_elements(struct match_state *ms, unsigned matching, SyntaxChar_t flags); +static void find_elements_pairs(const LINECHAR *cursor, void *udata); +static void find_elements_tagged(const LINECHAR *cursor, void *udata); +static int find_point(struct match_state *ms); + +static void tag_get(struct match_state *ms, struct match_tag *tag, const LINECHAR *cursor); +static int tag_empty(const struct match_tag *tag); +static int tag_equal(struct match_state *ms, const struct match_tag *open, const struct match_tag *close); +static int tag_isvoid(struct match_state *ms, const struct match_tag *tag); + +static int parse_lines(SyntaxTable_t *st, LINENO lineno, LINENO num); +static lineflags_t parse_line(SyntaxTable_t *st, const LINE_t *lp, const LINECHAR *text, const LINECHAR *end, Parser_t parser, void *udata); + + +void +do_syntax_find() /* int ([int mode = 0], [int &line], [int &col], ... */ +{ + SyntaxTable_t *st = syntax_current(); + const int mode = get_xinteger(1, 0); /* find mode */ + int ret = -1; /* nothing to match */ + /* + // -2 = Unknown character. + // -1 = Nothing to match. + // 0 = Matched. + // 1 = Unmatched. + */ + + if (NULL == curbp || NULL == st) { + ret = -2; /* no syntax definition */ + + } else if (0 == mode) { + ret = find_paired(st); + } + + acc_assign_int(ret); +} + + +static int +find_paired(SyntaxTable_t *st) +{ + const char *ch = get_xstr(6); /* element */ + unsigned match = (ch ? *((unsigned char *)ch) : 0); + struct match_state ms = {0}; + int ret = 1; + + /* int (mode = 0, [int &line], [int &col], [int hilites = 1], [int lines = 75], [string element = ""]) */ + + ms.st = st; + ms.hilites = get_xinteger(4, 1); /* auto hilite results */ + ms.lines = get_xinteger(5, 75); /* scan lines */ + ms.start.line = *cur_line; + ms.start.col = *cur_col; + ms.start.offset = line_offset(ms.start.line, ms.start.col, LOFFSET_NORMAL); + + if (match) { + ms.nesting = 1; + } else { + match = curbp->b_vchar[0]; /* note: resolved by line_offset() */ + } + + if (0 == find_elements(&ms, match, (SyntaxChar_t)-1L)) { + if (ms.end.line) { /* matched, return */ + if (! isa_undef(2)) { + sym_assign_int(get_symbol(2), (accint_t) ms.end.line); + } + if (! isa_undef(3)) { + sym_assign_int(get_symbol(3), (accint_t) ms.end.col); + } + ret = 0; + } + } else { + ret = -2; + } + + chk_free((void *)ms.stack.elements); + + return ret; +} + + +/* + * syntax_parse --- + * Parse the current buffer, updating the syntax status of the requested line. + */ +int +syntax_parse(int all) +{ + SyntaxTable_t *st; + LINENO min_line, max_line; + + if (NULL == (st = syntax_select())) { + return 0; + } + + if (st != curbp->b_syntax) { + curbp->b_syntax = st; + all = 1; /* new assignment, reset */ + } + + if (all) { /* all of the buffer */ + min_line = 1; + max_line = curbp->b_numlines; + } else { /* otherwise modified */ + if ((min_line = curbp->b_syntax_min) <= 0) { + return (0); + } + max_line = curbp->b_syntax_max; + } + + curbp->b_syntax_min = curbp->b_syntax_max = 0; + return parse_lines(st, min_line, max_line - min_line); +} + + +/* + * syntax_virtual_cursor --- + * Visual cursor update event. + */ +void +syntax_virtual_cursor() +{ + SyntaxTable_t *st; + + if (! BFTST(curbp, BF_SYNTAX_MATCH)) + return; /* disabled? */ + + if (NULL != (st = curbp->b_syntax) && st->st_active) { + const unsigned match = (unsigned) curbp->b_vchar[0]; + struct match_state ms = {0}; + + // TODO/optional: if vchar is space, scan from start of line. + + ms.st = st; + ms.hilites = 1; /* auto hilite results */ + ms.lines = ttrows() * 2; /* ??? */ + ms.start.line = curbp->b_vline; + ms.start.col = curbp->b_vcol; + ms.start.offset = curbp->b_voffset; + find_elements(&ms, match, SYNC_BRACKET_OPEN | SYNC_BRACKET_CLOSE); + chk_free((void *)ms.stack.elements); + } +} + + +/* + * find_matching --- + * Parse the specified line block, matching brackets. + */ +static struct element * +push(struct match_stack *stack, const LINECHAR *cursor) +{ + struct element *elm = stack->elements; + + if (stack->top == stack->capacity) { /* extend? */ + const size_t capacity = (stack->capacity + 64); + + if (NULL == (elm = chk_realloc((void *)elm, capacity * sizeof(struct element)))) + return NULL; + + stack->capacity = capacity; + stack->elements = elm; + } + + assert(stack->top < stack->capacity); + elm += stack->top++; + elm->cursor = cursor; + memset(&elm->tag, 0, sizeof(elm->tag)); + return elm; +} + + +static const LINECHAR * +unstack_pairs(struct match_state *ms) +{ + size_t e; + + if (ms->backwards) { + for (e = ms->stack.top; e;) { + const LINECHAR *cursor = ms->stack.elements[--e].cursor; + if (ms->open == ms->close) { + if (ms->nesting) + return cursor; + ms->nesting = 1; + + } else { + if (*cursor == ms->close) { + ++ms->nesting; + } else { + assert(*cursor == ms->open && ms->nesting); + if (--ms->nesting <= 0) + return cursor; + } + } + } + + } else { + const size_t top = ms->stack.top; + for (e = 0; e != top;) { + const LINECHAR *cursor = ms->stack.elements[e++].cursor; + if (ms->open == ms->close) { + if (ms->nesting) + return cursor; + ms->nesting = 1; + + } else { + if (*cursor == ms->open) { + ++ms->nesting; + } else { + assert(*cursor == ms->close && ms->nesting); + if (--ms->nesting <= 0) + return cursor; + } + } + } + } + + ms->stack.top = 0; + return NULL; +} + + + +static const LINECHAR * +unstack_tagged(struct match_state *ms) +{ + size_t e; + + if (ms->backwards) { + for (e = ms->stack.top; e;) { + const LINECHAR *cursor = ms->stack.elements[--e].cursor; + if (*cursor == ms->close) { + ++ms->nesting; + } else { + assert(*cursor == ms->open && ms->nesting); + if (--ms->nesting <= 0) + return cursor; + } + } + + } else { + const size_t top = ms->stack.top; + for (e = 0; e != top;) { + const struct element *elm = ms->stack.elements + e++; + + if (elm->cursor[0] == ms->open) { + if (elm->tag.length && elm->tag.data[0] == '/') { + if (0 == --ms->nesting) { /* end.line2 = ms->lineno; + ms->end.offset2 = (elm->cursor - ms->text); + ms->end.matched = tag_equal(ms, &ms->tag, &elm->tag); + } + + } else { + if (ms->void_nesting) { /* void, ignore */ + //++ms->void_nesting; + continue; + } else if (tag_isvoid(ms, &elm->tag)) { + ms->void_nesting = 1; + } + + if (0 == ms->nesting++) { /* start.line2 = ms->lineno; + ms->start.offset2 = (elm->cursor - ms->text) + elm->tag.length; + ms->tag = elm->tag; + } + } + /*scan continues until closing*/ + + } else { + if (1 == elm->tag.length && + ('/' == elm->tag.data[0] || '?' == elm->tag.data[0])) { + if (--ms->nesting <= 0) { /* /> or ?> */ + ms->end.line2 = ms->lineno; + ms->end.offset2 = (elm->cursor - ms->text) - 1; + ms->end.matched = 2; + return elm->cursor; + } + + } else if (ms->void_nesting) { /* void nesting level */ + if (0 == --ms->void_nesting) + --ms->nesting; + } + + if (ms->nesting <= 0) { /* closing > */ + return elm->cursor; + + } else if (1 == ms->nesting) { /* > */ + if ((ms->tag.data + ms->tag.length) == elm->cursor) { + ms->start.offset2 = (elm->cursor - ms->text); + } + } + } + } + } + + ms->stack.top = 0; + return NULL; +} + + +static int +find_elements(struct match_state *ms, unsigned match, SyntaxChar_t mask) +{ + SyntaxTable_t *st = ms->st; + LINENO lineno = ms->start.line, eline = 0; + Parser_t callback = find_elements_pairs; + LINE_t *lp = NULL; + + ms->open = 0; + + if (match < 0xff) { + const SyntaxChar_t charbits = st->syntax_charmap[match] & mask; + unsigned b; + + if (SYNC_BRACKET_OPEN & charbits) { + for (b = 0; b < (sizeof(st->bracket_chars)/2); ++b) { + if (st->bracket_chars[b].open == match) { + eline = curbp->b_numlines; + ms->open = st->bracket_chars[b].open; + ms->close = st->bracket_chars[b].close; + ms->backwards = 0; + break; + } + } + + } else if (SYNC_BRACKET_CLOSE & charbits) { + for (b = 0; b < (sizeof(st->bracket_chars)/2); ++b) { + if (st->bracket_chars[b].close == match) { + eline = 1; + ms->open = st->bracket_chars[b].open; + ms->close = st->bracket_chars[b].close; + ms->backwards = 1; + break; + } + } + + } else if ((SYNC_STRING|SYNC_LITERAL) & charbits) { + const int state = find_point(ms); + switch (state) { + case L_IN_STRING: + case L_IN_LITERAL: + case L_IN_CHARACTER: + ms->backwards = 1; + /*FALLTHRU*/ + case 0: + ms->open = ms->close = (unsigned char)match; + break; + } + } + } + + if (0 == ms->open) /* non-open/close */ + return -1; + + ms->end.line = 0; + ms->end.offset = -1; + if ((SYNF_HTMLTAG|SYNF_XMLTAG) & st->st_flags) { + ms->tagtype = (SYNF_XMLTAG & st->st_flags ? 'X' : 'H'); + callback = find_elements_tagged; + } + + if (NULL != (lp = vm_lock_line2(lineno))) { + if (NULL != (ms->text = ltext(lp))) { + if ((LINENO)llength(lp) > ms->start.offset) { + ms->filter = ms->text + ms->start.offset; + } + } + } + + while (lp) { /* parse current line */ + if (NULL != (ms->text = ltext(lp))) { + ms->eol = ms->text + llength(lp); + ms->lineno = lineno; + parse_line(st, lp, ms->text, ms->eol, callback, ms); + if (ms->stack.top) { /* unstack */ + const LINECHAR *cursor = (ms->tagtype ? unstack_tagged(ms) : unstack_pairs(ms)); + if (cursor) { + ms->end.offset = (cursor - ms->text); + ms->end.line = lineno; + ms->end.col = line_column(lineno, ms->end.offset); + if (lineno != ms->start.line) + liflagset(lp, LI_DIRTY); + vm_unlock(lineno); + break; + } + } + } + + vm_unlock(lineno); + if (ms->nesting <= 0) + break; /* no match, inside comment etc */ + + ms->filter = NULL; + if (0 == ms->lines) + break; + --ms->lines; + + if (ms->backwards) { /* new line */ + if (lineno-- <= eline || NULL == (lp = lback(lp))) { + break; + } + } else { + if (lineno++ >= eline || NULL == (lp = lforw(lp))) { + break; /* EOF */ + } + } + } + + if (ms->hilites) { /* optional, hilite results */ + HILITE_t *open; + + hilite_destroy(curbp, HILITE_SYNTAX_MATCH); + + if (ms->start.line2) { + if (0 == ms->start.col2) + ms->start.col2 = line_column(ms->start.line2, ms->start.offset2); + open = hilite_create(curbp, HILITE_SYNTAX_MATCH, -1, ms->start.line, ms->start.col, ms->start.line2, ms->start.col2); + } else { + open = hilite_create(curbp, HILITE_SYNTAX_MATCH, -1, ms->start.line, ms->start.col, ms->start.line, ms->start.col); + } + + if (open && ms->end.line) { + HILITE_t *close; + + if (ms->end.line2 && ms->end.matched) { + if (0 == ms->end.col2) + ms->end.col2 = line_column(ms->end.line2, ms->end.offset2); + close = hilite_create(curbp, HILITE_SYNTAX_MATCH, -1, ms->end.line, ms->end.col, ms->end.line2, ms->end.col2); + } else { + close = hilite_create(curbp, HILITE_SYNTAX_MATCH, -1, ms->end.line, ms->end.col, ms->end.line, ms->end.col); + } + if (close) { + close->h_attr = ATTR_HILITE; + open->h_attr = ATTR_HILITE; + } + } + } + + return 0; +} + + +static void +find_elements_pairs(const LINECHAR *cursor, void *udata) +{ + struct match_state *ms = (struct match_state *)udata; + const unsigned char ch = *cursor; + + if (ms->filter) { /* line filter */ + if (ms->backwards) { + if (cursor > ms->filter) + return; + } else { + if (cursor < ms->filter) + return; + } + } + + if (ch == ms->open || ch == ms->close) { /* '{' or '}' */ + push(&ms->stack, cursor); + } +} + + +static void +find_elements_tagged(const LINECHAR *cursor, void *udata) +{ + struct match_state *ms = (struct match_state *)udata; + const unsigned char ch = *cursor; + + if (ms->filter) { /* line filter */ + if (ms->backwards) { + if (cursor > ms->filter) + return; + } else { + if (cursor < ms->filter) + return; + } + } + + if (ch == ms->open) { + struct element *elm = push(&ms->stack, cursor); + if (elm) { + tag_get(ms, &elm->tag, cursor + 1); /* '<[/] ...' */ + } + + } else if (ch == ms->close) { + struct element *elm = push(&ms->stack, cursor); + if (elm && cursor != ms->text) { + const unsigned char chback = cursor[-1]; + if ('/' == chback || /* '/>' */ + ('?' == chback && 1 == ms->lineno)) { /* '?>' */ + elm->tag.data = cursor - 1; + elm->tag.length = 1; + } + } + } +} + + +static int +find_point(struct match_state *ms) +{ + SyntaxTable_t *st = ms->st; + LINENO lineno = ms->start.line; + LINE_t *lp; + + if (NULL != (lp = vm_lock_line2(lineno))) { + if (NULL != (ms->text = ltext(lp))) { + return parse_line(st, lp, ms->text, ms->text + ms->start.offset, NULL, NULL); + } + } + return -1; +} + + +#if defined(TODO) +static int +xml_start(unsigned ch) +{ + // https://www.w3.org/TR/xml/#NT-NameStartChar + if (isalpha(ch) || '_' == ch || ':' == ch) + return 1; + if (ch >= 0xC0) { + if ((ch >= 0xC0 && ch <= 0xD6) || + (ch >= 0xD8 && ch <= 0xF6) || + (ch >= 0xF8 && ch <= 0x2FF) || + (ch >= 0x370 && ch <= 0x37D) || + (ch >= 0x37F && ch <= 0x1FFF) || + (ch >= 0x200C && ch <= 0x200D) || + (ch >= 0x2070 && ch <= 0x218F) || + (ch >= 0x2C00 && ch <= 0x2FEF) || + (ch >= 0x3001 && ch <= 0xD7FF) || + (ch >= 0xF900 && ch <= 0xFDCF) || + (ch >= 0xFDF0 && ch <= 0xFFFD)) + return 1; + } + return 0; +} + + +static int +xml_next(unsigned ch) +{ + // https://www.w3.org/TR/xml/#NT-NameStartChar + if (xml_start(ch)) + return 1; + if (isdigit(ch) || '-' == ch || '.' == ch || 0xB7 == ch || + ((ch >= 0x300 && ch <= 0x36F) || (ch >= 0x203F && ch <= 0x2040)) { + return 1; + } + return 0; +} +#endif //TODO + + +static void +tag_get(struct match_state *ms, struct match_tag *tag, const LINECHAR *cursor) +{ + const LINECHAR ch0 = *cursor; + + tag->length = 0; + tag->data = NULL; + + switch (ms->tagtype) { + case 'X': // XML + if (isalpha(ch0) || '_' == ch0 || ':' == ch0 || + '/' == ch0 /*closure*/ || ('?' == ch0 /*XMLDecl*/ && 1 == ms->lineno)) { + const LINECHAR *end = ms->eol; + + // letters, digits, hyphens, underscores, and periods. + tag->length = 1; + tag->data = cursor++; + while (cursor < end) { + const LINECHAR ch = *cursor++; + if (!(isalnum(ch) || '_' == ch || ':' == ch || '-' == ch || '.' == ch)) + break; + ++tag->length; + } + } + break; + + case 'H': // HTML + if (isalpha(ch0) || + '/' == ch0 /*closure*/ || ('!' == ch0 /*DOCTYPE*/ && 1 == ms->lineno)) { + const LINECHAR *end = ms->eol; + + // alphanumerics. + tag->length = 1; + tag->data = cursor++; + while (cursor < end) { + const LINECHAR ch = *cursor++; + if (!isalnum(ch)) + break; + ++tag->length; + } + } + break; + } +} + + +static int +tag_empty(const struct match_tag *tag) +{ + return (0 == tag->length); +} + + +static unsigned char +caseinsensitive(unsigned char c) +{ + return (isupper(c) ? c - 'A' + 'a' : c); +} + + +static int +tag_equal(struct match_state *ms, const struct match_tag *open, const struct match_tag *close) +{ + const LINECHAR *d1 = open->data, *d2 = close->data; + uint16_t l1 = open->length, l2 = close->length; + + if (l2 && *d2 == '/') { + --l2, ++d2; + } + + switch (ms->tagtype) { + case 'X': // XML - case sensitive. + while (l1 && l2) { + if (*d1++ != *d2++) + return 0; + l1--, l2--; + } + break; + + case 'H': // HTML - case insensitive. + while (l1 && l2) { + if (caseinsensitive(*d1++) != caseinsensitive(*d2++)) + return 0; + l1--, l2--; + } + break; + } + return (0 == (l1 | l2)); +} + + +static int +tag_isvoid(struct match_state *ms, const struct match_tag *tag) +{ + if (tag->length) { + SyntaxTable_t *st = ms->st; + + if (st->void_tags && + trie_nsearch(st->void_tags, (const char *)tag->data, tag->length)) { + return 1; + } + } + return 0; +} + + +/* + * parse_lines --- + * Parse the specified line block, determining the arena in which hilite is dirty due to content change. + */ +static int +parse_lines(SyntaxTable_t *st, LINENO lineno, LINENO num) +{ + LINE_t *lp; + + if (lineno > 1) { + --lineno, ++num; + } + + ED_TRACE(("syntax::parse_lines(flags:0x%04x, lineno:%d, num:%d, numline:%d)\n", \ + st->st_flags, lineno, num, (int)curbp->b_numlines)) + + lp = vm_lock_line2(lineno); + while (lp) { /* parse current line */ + const LINECHAR *text = ltext(lp), *end = text + llength(lp); + lineflags_t state = parse_line(st, lp, text, end, NULL, NULL); + + liflagclr(lp, LI_DIRTY); + lp->l_uflags &= ~L_HAS_EOL_COMMENT; + + switch (state) { + case L_IN_COMMENT: + case L_IN_COMMENT2: + break; + case L_IN_STRING: + case L_IN_LITERAL: + case L_IN_CHARACTER: + if (st->st_flags & SYNF_STRING_ONELINE) + state = 0; /* fuse string at EOL */ + break; + case L_HAS_EOL_COMMENT: + lp->l_uflags |= L_HAS_EOL_COMMENT; + state = 0; + break; + } + + /* retrieve next */ + vm_unlock(lineno); + if (NULL == (lp = lforw(lp))) { /* NEWLINE */ + break; /* EOF */ + } + ++lineno; /* new line */ + + /* check range or status */ + if (num > 0) { /* required rescan min */ + --num; + + } else if (state == (L_SYNTAX_MASK & lp->l_uflags)) { + break; /* state in-sync, no need to continue */ + } + + /* update status */ + lp->l_uflags &= ~L_SYNTAX_MASK; + lp->l_uflags |= state; + } + return lineno; +} + + +static lineflags_t +parse_line(SyntaxTable_t *st, const LINE_t *line, const LINECHAR *begin, const LINECHAR *end, Parser_t callback, void *udata) +{ + const uint32_t flags = st->st_flags; + const unsigned char schar = st->string_char, ichar = st->char_char, + cchar = st->literal_char, quote = st->quote_char; + const lineflags_t lsyntax = (L_SYNTAX_MASK & line->l_uflags); + const SyntaxChar_t *charmap = st->syntax_charmap; + const LINECHAR *cursor; + + if (NULL == (cursor = begin) || end <= begin) + return lsyntax; + + ED_TRACE2(("\t<%.*s>\n", end - cursor, cursor)) + + /* fixed style comments (aka FORTRAN, plus also COBOL) */ + if (SYNF_FORTRAN & flags) { + if (cursor + st->comment_fixed_pos < end) { + const unsigned char ch = cursor[st->comment_fixed_pos]; + if (st->comment_fixed_char[ch]) { + return L_HAS_EOL_COMMENT; + } + } + } + + /* terminate current comment or string */ + if (lsyntax) { + const lineflags_t lsyntaxin = (lsyntax & L_SYNTAX_IN); + + switch (lsyntaxin) { + case L_IN_COMMENT: /* comment, type-1 */ + if (NULL == (cursor = syntax_comment_end(st, 0, cursor, end))) { + return L_IN_COMMENT; + } + break; + case L_IN_COMMENT2: /* comment, type-2 */ + if (NULL == (cursor = syntax_comment_end(st, 1, cursor, end))) { + return L_IN_COMMENT2; + } + break; + case L_IN_STRING: /* string */ + if (NULL == (cursor = syntax_string_end(st, cursor, end, quote, schar))) { + return L_IN_STRING; + } + break; + case L_IN_LITERAL: /* literals, optional quoting */ + if (NULL == (cursor = syntax_string_end(st, cursor, end, + (char)(flags & SYNF_LITERAL_NOQUOTES ? 0 : quote), ichar))) { + return L_IN_LITERAL; + } + break; + case L_IN_CHARACTER: + if (NULL == (cursor = syntax_string_end(st, cursor, end, quote, cchar))) { + return L_IN_CHARACTER; + } + /*FALLTHRU*/ + case L_IN_CONTINUE: + case L_IN_PREPROC: + if (begin < end) { + const unsigned char lchar = st->linecont_char; + + if (0 != lchar) { + if (lchar == end[-1]) { + return lsyntax; /* last character is continuation */ + + } else if (SYNF_LINECONT_WS & flags) { + const LINECHAR *back = end; /* scan backward consuming white-space */ + + while (back > begin) { /* MCHAR??? */ + const unsigned char ch = (unsigned char) *--back; + if (lchar == ch) { + return lsyntax; /* trailing continuation */ + } + if (' ' == ch || '\t' == ch) { + continue; + } + break; + } + } + } + } + break; + default: + assert(0 == lsyntaxin); + break; + } + } + + /* outside string/comment */ + while (cursor < end) { /* MCHAR??? */ + const unsigned char ch = (unsigned char) *cursor; + + if (0 == ch) { /* NULs, ignore */ + ++cursor; + continue; + } + + if (ch == quote) { /* quotes */ + if ((cursor + 1) < end) { + cursor += 2; + continue; + } + break; + } + + if (ch == schar || ch == cchar) { /* string/character */ + const LINECHAR *ocursor = cursor; + + if (callback) { + callback(cursor, udata); + cursor = syntax_string_end(st, ocursor + 1, end, quote, ch); + if (cursor) callback(cursor - 1, udata); + } else { + cursor = syntax_string_end(st, ocursor + 1, end, quote, ch); + } + + if (NULL == cursor) { + if (0 == (st->st_flags & SYNF_STRING_MATCHED)) { + return (ch == schar ? L_IN_STRING : L_IN_CHARACTER); + } + cursor = ocursor + 1; /* normal */ + } + continue; + } + + if (ch == ichar) { /* literals, optional quoting */ + const LINECHAR *ocursor = cursor; + + if (callback) { + callback(cursor, udata); + cursor = syntax_string_end(st, ocursor + 1, end, (char)(SYNF_LITERAL_NOQUOTES & flags ? 0 : quote), ch); + if (cursor) callback(cursor - 1, udata); + } else { + cursor = syntax_string_end(st, ocursor + 1, end, (char)(SYNF_LITERAL_NOQUOTES & flags ? 0 : quote), ch); + } + + if (NULL == cursor) { + return L_IN_LITERAL; + } + continue; + } + + if (charmap[ch] & SYNC_COMMENT) { /* comments */ + const LINECHAR *t_end = NULL; + + switch (syntax_comment(st, cursor, begin, end, &t_end)) { + case COMMENT_NORMAL: + cursor = t_end; + continue; //next character + case COMMENT_EOL: + return L_HAS_EOL_COMMENT; + case COMMENT_OPEN: + return L_IN_COMMENT; + case COMMENT_OPEN2: + return L_IN_COMMENT2; + case COMMENT_NONE: + default: + break; + } + } + + if (callback) callback(cursor, udata); + ++cursor; + } + + if (begin < end) { + unsigned char lchar; + + if (0 != (lchar = st->linecont_char)) { + int iscont = FALSE; + + if (lchar == end[-1]) { + iscont = TRUE; /* last character is continuation */ + + } else if (SYNF_LINECONT_WS & flags) { + cursor = end; /* scan backward consuming white-space */ + while (cursor > begin) { /* MCHAR??? */ + const unsigned char ch = (unsigned char) *--cursor; + + if (ch == lchar) { + iscont = TRUE; /* trailing continuation */ + break; + } + if (' ' == ch || '\t' == ch) { + continue; + } + break; + } + } + + if (iscont) { + unsigned char pchar; + + if (0 != (pchar = st->preprocessor_char)) { + cursor = begin; + while (cursor < end) { /* MCHAR??? */ + const unsigned char ch = (unsigned char) *cursor++; + + if (0 == charmap[ch]) { + continue; /* normal character */ + } + if (ch == pchar) { + return L_IN_PREPROC; + } + break; + } + } + return L_IN_CONTINUE; /* continuation */ + } + } + } + return 0; +} + +/*end*/ diff --git a/macsrc/grief.h b/macsrc/grief.h index 1645ce00..cf4fb592 100644 --- a/macsrc/grief.h +++ b/macsrc/grief.h @@ -446,6 +446,7 @@ #define BF2_HIWHITESPACE 0x00200000 /* Hilite whitespace */ #define BF2_HIMODIFIED 0x00400000 /* Hilite modified lines */ #define BF2_HIADDITIONAL 0x00800000 /* Hilite added lines */ +#define BF2_HISTATUSLINE 0x01000000 /* Hilite status line */ /* * BF3_XXXX values --- @@ -1112,6 +1113,33 @@ /* * Syntax rules/types + * + * Flag Description + * ---------------------------------------------------------------------------- + * SYNT_COMMENT , [, -string>] + * SYNT_CSTYLE , | + * SYNT_PREPROCESSOR , + * + * SYNT_STRING , + * SYNT_LITERAL , + * + * SYNT_LINECONT , + * SYNT_LINEJOIN , + * + * SYNT_QUOTE , + * SYNT_CHARACTER , + * + * SYNT_BRACKET , [, ] + * SYNT_HTML , , + * SYNT_TAG , , + * + * SYNT_WORD , + * SYNT_KEYWORD , + * + * SYNT_NUMERIC , [, ] + * SYNT_OPERATOR , + * SYNT_DELIMITER , + * SYNT_FORTRAN , , <[left-margin], code [, comment-margin]> */ #define SYNT_COMMENT 1 #define SYNT_PREPROCESSOR 2 @@ -1123,6 +1151,7 @@ #define SYNT_HTML 20 #define SYNT_BRACKET 21 +#define SYNT_TAG 22 #define SYNT_OPERATOR 30 #define SYNT_DELIMITER 31 @@ -1146,14 +1175,15 @@ * SYNF_LITERAL_NOQUOTES Literal strings don't translate quoted characters. * SYNF_STRING_MATCHED String open/close must be matched; otherwise ignored. * - * SYNF_COMMENTS_LEADINGWS xxx - * SYNF_COMMENTS_TRAILINGWS xxx - * SYNF_COMMENTS_QUOTE xxx + * SYNF_COMMENTS_LEADINGWS Dont hilite leading white-space. + * SYNF_COMMENTS_TRAILINGWS Dont hilite trailing white-space. + * SYNF_COMMENTS_QUOTE Allow comment character to be quoted. * SYNF_COMMENTS_CSTYLE C-style comments. * - * SYNF_PREPROCESSOR_WS xxx - * SYNF_LINECONT_WS xxx - * SYNF_MANDOC xxx + * SYNF_PREPROCESSOR_WS Dont hilite leading white-space. + * SYNF_LINECONT_WS Allow white-space after cont token. + * + * SYNF_MANDOC MANDOC hiliting. * * SYNF_HILITE_WS Hilite white-space. * SYNF_HILITE_LINECONT Hilite line continuations. @@ -1162,28 +1192,34 @@ * SYNF_SPELL_WORD Enable word spell check. * SYNF_SPELL_COMMENT Enable comment spell check. * + * SYNF_HTMLTAGS HTML tags. + * SYNF_XMLTAGS XML tags. */ -#define SYNF_CASEINSENSITIVE 0x0001 -#define SYNF_FORTRAN 0x0002 -#define SYNF_STRING_ONELINE 0x0004 -#define SYNF_LITERAL_NOQUOTES 0x0008 -#define SYNF_STRING_MATCHED 0x4000 - -#define SYNF_COMMENTS_LEADINGWS 0x0010 -#define SYNF_COMMENTS_TRAILINGWS 0x0020 -#define SYNF_COMMENTS_QUOTE 0x0040 -#define SYNF_COMMENTS_CSTYLE 0x0080 - -#define SYNF_PREPROCESSOR_WS 0x0100 -#define SYNF_LINECONT_WS 0x0200 -#define SYNF_MANDOC 0x0400 - -#define SYNF_HILITE_WS 0x1000 -#define SYNF_HILITE_LINECONT 0x2000 -#define SYNF_HILITE_PREPROCESSOR 0x0400 - -#define SYNF_SPELL_WORD 0x1000 -#define SYNF_SPELL_COMMENT 0x2000 +#define SYNF_CASEINSENSITIVE 0x000001 +#define SYNF_FORTRAN 0x000002 +#define SYNF_STRING_ONELINE 0x000004 +#define SYNF_LITERAL_NOQUOTES 0x000008 +#define SYNF_STRING_MATCHED 0x000800 + +#define SYNF_COMMENTS_LEADINGWS 0x000010 +#define SYNF_COMMENTS_TRAILINGWS 0x000020 +#define SYNF_COMMENTS_QUOTE 0x000040 +#define SYNF_COMMENTS_CSTYLE 0x000080 + +#define SYNF_PREPROCESSOR_WS 0x000100 +#define SYNF_LINECONT_WS 0x000200 + +#define SYNF_MANDOC 0x000400 + +#define SYNF_HILITE_WS 0x001000 +#define SYNF_HILITE_LINECONT 0x002000 +#define SYNF_HILITE_PREPROCESSOR 0x004000 + +#define SYNF_SPELL_WORD 0x010000 +#define SYNF_SPELL_COMMENT 0x020000 + +#define SYNF_HTMLTAG 0x040000 +#define SYNF_XMLTAG 0x080000 /* * Keywords, standard table usage diff --git a/macsrc/modes/html.cr b/macsrc/modes/html.cr index 80fadf8d..aa27c4fc 100644 --- a/macsrc/modes/html.cr +++ b/macsrc/modes/html.cr @@ -1,5 +1,5 @@ /* -*- mode: cr; indent-width: 4; -*- */ -/* $Id: html.cr,v 1.11 2014/10/22 02:34:33 ayoung Exp $ +/* $Id: html.cr,v 1.12 2022/08/28 12:27:01 cvsuser Exp $ * HTML support and indenting mode. * * @@ -9,9 +9,9 @@ #define MIN_ABBREV 1 -int _html_min_abbrev, - _html_keyboard, - _sgml_keyboard; +int _html_min_abbrev, + _html_keyboard, + _sgml_keyboard; #define MODENAME "html" @@ -21,32 +21,65 @@ main() { create_syntax(MODENAME); - syntax_token(SYNT_COMMENT, ""); + /* + * Syntax lexer/ + * Utilised during basic line preprocessing. + */ + syntax_token(SYNT_COMMENT, ""); // open/close, attr=comment + syntax_token(SYNT_COMMENT, ""); syntax_token(SYNT_PREPROCESSOR, "#"); syntax_token(SYNT_HTML, "<", ">"); - syntax_token(SYNT_BRACKET, "<", ">"); + syntax_token(SYNT_BRACKET, "<", ">"); // attr=delimiter syntax_token(SYNT_WORD, "A-Za-z&"); - - /* keywords */ - define_keywords(0, - "><", 3); - - define_keywords(0, - "Ð&ð", 4); - - define_keywords(0, - "ÄËÏÖÜäëï ö""+ - "üÿ", 5); - - define_keywords(0, - "ÆÂÅÊÎÔÞÛâ"+ - "æåêîôßþû", 6); - - define_keywords(0, - "ÁÀÃÇÉÈÍÌ"+ - "ÑÓÒØÕÚÙÝ"+ - "áàãçéèíì"+ - "ñóòøõúùý", 7); + syntax_token(SYNT_TAG, "ivoid", // void tag elements, HTML5 [case insensitive] + "area,base,br,col,command,embed,hr,img,input,keygen,link,meta,param,source,track,wbr,!DOCTYPE"); + + /* + * Options/ + * SYNF_HTMLTAG + * HTML tag processing. + * + * TAG rules, from the W3C specification for HTML: + * + * o The following is a complete list of the void elements in HTML: + * + * area, base, br, col, command, embed, hr, img, input, keygen, link, meta, param, source, track, wbr + * + * o Void elements only have a start tag; end tags must not be specified for void elements. + * + * o Start tags consist of the following parts, in exactly the following order: + * + * - Opening '<' character. + * - Elements tag name. + * - Optionally, one or more attributes, each of which must be preceded by one or more space characters. + * - Optionally, one or more space characters. + * - Optionally, a / character, which may be present only if the element is a void element. + * - Closing '>' character. + */ + set_syntax_flags(SYNF_HTMLTAG); + + /* + * Keywords + */ + define_keywords(SYNK_PRIMARY, + ">,<", -3); + + define_keywords(SYNK_PRIMARY, + "Ð,&,ð", -4); + + define_keywords(SYNK_PRIMARY, + "Ä,Ë,Ï,Ö,Ü,ä,ë,ï, ,ö,","+ + "ü,ÿ", -5); + + define_keywords(SYNK_PRIMARY, + "Æ,Â,Å,Ê,Î,Ô,Þ,Û,â,"+ + "æ,å,ê,î,ô,ß,þ,û", -6); + + define_keywords(SYNK_PRIMARY, + "Á,À,Ã,Ç,É,È,Í,Ì,"+ + "Ñ,Ó,Ò,Ø,Õ,Ú,Ù,Ý,"+ + "á,à,ã,ç,é,è,í,ì,"+ + "ñ,ó,ò,ø,õ,ú,ù,ý", -7); /* Template editor keyboard */ load_indent(); @@ -264,3 +297,4 @@ _html_abbrev() self_insert(); } + diff --git a/macsrc/modes/xml.cr b/macsrc/modes/xml.cr index 17141f57..0157ea60 100644 --- a/macsrc/modes/xml.cr +++ b/macsrc/modes/xml.cr @@ -1,5 +1,5 @@ /* -*- mode: cr; indent-width: 4; -*- - * $Id: xml.cr,v 1.1 2022/08/10 13:06:32 cvsuser Exp $ + * $Id: xml.cr,v 1.2 2022/08/28 12:27:01 cvsuser Exp $ * xml mode. * * @@ -14,9 +14,10 @@ main() { create_syntax(MODENAME); - // Syntax lexer/ - // utilised during basic line preprocessing. - // + /* + * Syntax lexer/ + * Utilised during basic line preprocessing. + */ syntax_token(SYNT_COMMENT, ""); // open/close, attr=comment syntax_token(SYNT_STRING, "\""); syntax_token(SYNT_LITERAL, "\'"); @@ -24,16 +25,24 @@ main() syntax_token(SYNT_BRACKET, "<", ">"); // attr=delimiter syntax_token(SYNT_WORD, "&A-Za-z"); - // Special Characters in XML/ - // - // < <, less than - // > >, greater than - // & &, ampersand - // ' ', apostrophe - // " ", quotation mark - // - // Plus html specials. - // + /* + * Options/ + * SYNF_XMLTAG + * XML tag processing. + */ + set_syntax_flags(SYNF_XMLTAG); + + /* + * Special Characters in XML/ + * + * < <, less than + * > >, greater than + * & &, ampersand + * ' ', apostrophe + * " ", quotation mark + * + * Plus html specials. + */ define_keywords(SYNK_PRIMARY, ">,<"); @@ -50,12 +59,13 @@ main() "Á,À,Ã,Ç,É,È,Í,Ì,Ñ,Ó,Ò,Ø,Õ,Ú,Ù,Ý,"+ "á,à,ã,ç,é,è,í,ì,ñ,ó,ò,ø,õ,ú,ù,ý"); - // TODO/DFA - // - // <\?xml \?> attr=constant - // <\? \?> attr=code - // < > attr=tag - // + /* + * TODO/DFA + * + * <\?xml \?> attr=constant + * <\? \?> attr=code + * < > attr=tag + */ }