/* htmlmode.c
*
* Copyright (c) 1999 Chris Smith
*
* Author:
* Eckehard Berns
*
* This file is distributed under the GPL, version 2 or at your option any
* later version. See COPYING for details.
*/
#include
#include
#include "lpecomm.h"
#include "highlight.h"
#include "mode-utils.h"
enum _states
{
STATE_BEGIN = 0,
STATE_TAG,
STATE_ARGUMENT,
STATE_QUOTE,
STATE_VALUE,
STATE_COMMENT,
STATE_SSI
};
#define COLOR_TEXT 70
#define COLOR_TAG 71
#define COLOR_SPECIAL 72
#define COLOR_ARGUMENT 73
#define COLOR_VALUE 74
#define COLOR_SSI 75
static int is_ssi = 0;
int mode_accept(buffer *buf)
{
char *suffix;
suffix = strrchr(buf->name, '.');
if (suffix == NULL)
return 0;
return mode_util_accept_extensions ( suffix, 0, 4, ".html", ".htm", ".shtml", ".dhtml" );
}
void mode_init(buffer *buf)
{
if (buf->mode_name == NULL)
{
buf->hardtab = mode_util_get_option_with_default ( "htmlmode", "hardtab", 1 );
buf->autoindent = mode_util_get_option_with_default ( "htmlmode", "autoindent", 0 );
buf->offerhelp = mode_util_get_option_with_default ( "htmlmode", "offerhelp", 1 );
buf->highlight = mode_util_get_option_with_default ( "htmlmode", "highlight", 1 );
buf->flashbrace = mode_util_get_option_with_default ( "htmlmode", "flashbrace", 1 );
}
buf->mode_name = "htmlmode";
buf->state_valid = buf->text;
buf->state_valid_num = 0;
buf->text->start_state = STATE_BEGIN;
}
void mode_enter(buffer *buf)
{
mode_util_set_slang_color("htmlmode", "text", COLOR_TEXT, "lightgray", "black" );
mode_util_set_slang_color("htmlmode", "tag", COLOR_TAG, "cyan", "black" );
mode_util_set_slang_color("htmlmode", "comment", COLOR_COMMENT, COLOR_COMMENT_FG, COLOR_COMMENT_BG );
mode_util_set_slang_color("htmlmode", "argument", COLOR_ARGUMENT, "blue", "black" );
mode_util_set_slang_color("htmlmode", "special", COLOR_SPECIAL, "brown", "black" );
mode_util_set_slang_color("htmlmode", "value", COLOR_VALUE, "brightblue", "black" );
mode_util_set_slang_color("htmlmode", "ssi", COLOR_SSI, "magenta", "black" );
mode_util_set_slang_color("htmlmode", "symbol", COLOR_SYMBOL, COLOR_SYMBOL_FG, COLOR_SYMBOL_BG );
mode_util_set_slang_color("htmlmode", "brace", COLOR_BRACE, COLOR_BRACE_FG, COLOR_BRACE_BG );
mode_util_set_slang_color("htmlmode", "illegal", COLOR_ILLEGAL, COLOR_ILLEGAL_FG, COLOR_ILLEGAL_BG );
}
/* SGML implementation of brace flashing
*
* Rules:
* 1. Braces are <>, and they cannot be nested
* 2. Ignore anything inside quotation marks (double)
*/
int mode_flashbrace(buffer * buf)
{
int found;
char ch, quote;
if (buf->pos.col == 0) return 0;
ch = buf->pos.line->txt[buf->pos.col - 1];
if (ch != '>') return 0;
buf->pos.col--;
quote = '\0';
found = 0;
do
{
while (buf->pos.col <= 0)
{
if (buf->pos.line == buf->scrollpos)
return 0;
buf->pos.line = buf->pos.line->prev;
buf->linenum--;
buf->pos.col = strlen(buf->pos.line->txt);
}
buf->pos.col--;
ch = buf->pos.line->txt[buf->pos.col];
if (quote != '\0')
{
if (ch == quote)
quote = '\0';
continue;
}
switch (ch)
{
case '<':
found = 1;
break;
case '\"':
quote = ch;
break;
}
}
while (!found);
set_scr_col(buf);
return 1;
}
#define IS_NAME(a) ((isalnum(a) || ((a) == '_') || \
((a) == '%') || ((a) == '&') || \
((a) == '.') || ((a) == '#')))
#define IS_WHITE(a) (isspace(a))
#define STATE (*state & 0x00ff)
#define EXCL (*state & 0xff00)
int mode_highlight(buffer * buf, buf_line * ln, int lnum, int *idx, int *state)
{
int color;
int i, ch;
char *p;
if (*state == -1)
{
*state = buf->state_valid->start_state;
while (buf->state_valid_num < lnum)
{
i = 0;
while (buf->state_valid->txt[i])
mode_highlight(buf, buf->state_valid,
buf->state_valid_num,
&i, state);
buf->state_valid = buf->state_valid->next;
buf->state_valid_num++;
buf->state_valid->start_state = *state;
}
i = 0;
color = -1;
*state = ln->start_state;
while (i < *idx)
color = mode_highlight(buf, ln, lnum, &i, state);
if ((i > *idx) && (color != -1))
{
*idx = i;
return color;
}
}
ch = ln->txt[*idx];
if (ch == 0)
return COLOR_TEXT;
if (ch == '>')
{
(*idx)++;
if (STATE == STATE_BEGIN)
return COLOR_ILLEGAL;
*state = STATE_BEGIN | EXCL;
return COLOR_TAG;
}
if ((*state == (STATE_TAG | 0x100)) &&
(ch == '-') && (ln->txt[*idx + 1] == '-') && (ln->txt[*idx + 2] == '#'))
{
*state = STATE_SSI | EXCL;
(*idx) += 3;
is_ssi = 1;
}
if ((*state == (STATE_TAG | 0x100)) &&
(ch == '-') && (ln->txt[*idx + 1] == '-'))
{
*state = STATE_COMMENT | EXCL;
(*idx) += 2;
}
if ((STATE == STATE_TAG) && (IS_WHITE(ch)))
{
do
{
(*idx)++;
}
while (IS_WHITE(ln->txt[*idx]));
return COLOR_TAG;
}
if (((STATE == STATE_TAG) || (STATE == STATE_ARGUMENT)) &&
(strchr("-;|+*?,", ch)))
{
(*idx)++;
*state = STATE_TAG | EXCL;
return COLOR_SYMBOL;
}
if (((STATE == STATE_TAG) || (STATE == STATE_ARGUMENT)) &&
(strchr("()[]", ch)))
{
(*idx)++;
*state = STATE_TAG | EXCL;
return COLOR_BRACE;
}
if ((STATE == STATE_TAG) && (IS_NAME(ch)))
{
do
{
(*idx)++;
}
while (IS_NAME(ln->txt[*idx]));
*state = STATE_ARGUMENT | EXCL;
return COLOR_ARGUMENT;
}
if ((STATE == STATE_TAG) && (ch == '"'))
{
(*idx)++;
*state = STATE_QUOTE | EXCL;
}
if (STATE == STATE_TAG)
{
(*idx)++;
return COLOR_ILLEGAL;
}
if ((STATE == STATE_ARGUMENT) && (ch == '='))
{
(*idx)++;
if (ln->txt[*idx] == '"')
{
*state = STATE_TAG | EXCL;
}
else
{
*state = STATE_VALUE | EXCL;
}
return COLOR_TAG;
}
if (STATE == STATE_ARGUMENT)
{
if (IS_WHITE(ch))
{
(*idx)++;
*state = STATE_TAG | EXCL;
return COLOR_TAG;
}
(*idx)++;
return COLOR_ILLEGAL;
}
if (STATE == STATE_VALUE)
{
while ((!IS_WHITE(ln->txt[*idx])) && (ln->txt[*idx]) &&
(ln->txt[*idx] != '>'))
(*idx)++;
*state = STATE_TAG | EXCL;
return COLOR_VALUE;
}
if (STATE == STATE_QUOTE)
{
while ((ln->txt[*idx]) && (ln->txt[*idx] != '"'))
(*idx)++;
if (ln->txt[*idx] == '"')
{
(*idx)++;
*state = STATE_TAG | EXCL;
}
return COLOR_VALUE;
}
if ((STATE == STATE_COMMENT) || (STATE == STATE_SSI))
{
p = strstr(&(ln->txt[*idx]), "--");
if (p == NULL)
{
*idx = strlen(ln->txt);
}
else
{
*state = STATE_TAG | EXCL;
*idx = p + 2 - ln->txt;
}
if (is_ssi)
{
is_ssi = 0;
return COLOR_SSI;
}
else
return COLOR_COMMENT;
}
if (ch == '<')
{
*state = STATE_TAG;
(*idx)++;
if (ln->txt[*idx] == '!')
{
*state = STATE_TAG | 0x100;
(*idx)++;
}
else if (ln->txt[*idx] == '/')
{
(*idx)++;
}
ch = ln->txt[*idx];
while (IS_NAME(ch))
{
(*idx)++;
ch = ln->txt[*idx];
}
return COLOR_TAG;
}
if (ch == '&')
{
do
{
(*idx)++;
ch = ln->txt[*idx];
}
while ((IS_NAME(ch)) || (ch == '#'));
if (ch == ';')
{
(*idx)++;
return COLOR_SPECIAL;
}
return COLOR_ILLEGAL;
}
*idx += strcspn(&(ln->txt[*idx]), "<&");
return COLOR_TEXT;
}