diff --git a/doc/mc.sgml b/doc/mc.sgml
index aa5fb1780..85cdf2a41 100644
--- a/doc/mc.sgml
+++ b/doc/mc.sgml
@@ -1932,7 +1932,7 @@ menus; file insertion; macro definition; regular expression
search and replace (and our own scanf-printf search and
replace); shift-arrow MSW-MAC text highlighting (for the
linux console only); insert-overwrite toggle; word-wrap; a variety of
-tabbing options; and an option
+tabbing options; syntax highlighting for various file types; and an option
to pipe text blocks through shell commands like indent and ispell.
@@ -1940,9 +1940,9 @@ The editor is very easy to use and requires no tutoring.
To see what keys do what, just consult the appropriate
pull-down menu. Other keys are: Shift movement
keys do text highlighting. Ctrl-Ins copies to the file
-cedit/cooledit.clip and Shift-Ins
-pastes from cedit/cooledit.clip.
-Shift-Del cuts to cedit/cooledit.clip, and
+.cedit/cooledit.clip and Shift-Ins
+pastes from .cedit/cooledit.clip.
+Shift-Del cuts to .cedit/cooledit.clip, and
Ctrl-Del deletes highlighted text (all Linux console only).
The completion key also does a Return
without an automatic indent. Mouse highlighting also works, and you
@@ -1968,7 +1968,7 @@ press Ctrl-A and then the assigned key. The macro is also
executed if you press Meta, Ctrl, or Esc and the assigned
key, provided that the key is not used for any other
function. Once defined, the macro commands go into the
-file cedit/cooledit.macros in your home directory.
+file .cedit/cooledit.macros in your home directory.
You can delete a macro by deleting the appropriate line in
this file.
@@ -2019,7 +2019,8 @@ binary files, you should set display bits to 7 bits in the
options menu to keep the spacing clean.
-See also the mcedit.1 man page for lots more information.
+See also the mcedit.1 man page for lots more information,
+including details on creating syntax highlighting rules.
A variety of tabbing and indenting options are available which
are described in this man page.
diff --git a/doc/mcedit.1.in b/doc/mcedit.1.in
index e781973fc..3654fe98a 100644
--- a/doc/mcedit.1.in
+++ b/doc/mcedit.1.in
@@ -72,7 +72,8 @@ menus; file insertion; macro definition; regular expression
search and replace (and our own scanf-printf search and
replace); shift-arrow MSW-MAC text highlighting (for the
linux console only); insert-overwrite toggle; word-wrap;
-a variety of tabbing options; and an option
+a variety of tabbing options; syntax highlighting for
+various file types; and an option
to pipe text blocks through shell commands like indent and
ispell.
.PP
@@ -83,14 +84,14 @@ pull-down menu. Other keys are: Shift movement
keys do text highlighting (Linux console only).
.B Ctrl-Ins
copies to the file
-.BR "~/cedit/cooledit.clip",
+.BR "~/.cedit/cooledit.clip",
and
.B Shift-Ins
pastes from
-.BR "~/cedit/cooledit.clip".
+.BR "~/.cedit/cooledit.clip".
.B Shift-Del
cuts to
-.BR "~/cedit/cooledit.clip",
+.BR "~/.cedit/cooledit.clip",
and
.B Ctrl-Del
deletes highlighted text - all linux console only.
@@ -114,7 +115,7 @@ and then the assigned key. The macro is also executed if
you press Meta, Ctrl, or Esc and the assigned key, provided that the
key is not used for any other function. Once defined, the macro
commands go into the file
-.BR "~/cedit/cooledit.macros".
+.BR "~/.cedit/cooledit.macros".
Do NOT edit this file unless you are not going to use macros again
in the same editing session, because
.B Mcedit
@@ -127,7 +128,7 @@ other running editors for macros to take effect.
.B F19
will format C code when it is highlighted. For this
to work, make an executable file called
-.B cedit/edit.indent.rc
+.B .cedit/edit.indent.rc
in your home directory containing the following:
.IP
@@ -136,44 +137,175 @@ in your home directory containing the following:
# Use $HOME instead of ~ if this doesn't work.
# You may also have to use a different redirection
# syntax for some machines.
-/usr/bin/indent -kr -pcs ~/cedit/cooledit.block >& /dev/null
-cat /dev/null > ~/cedit/cooledit.error
+/usr/bin/indent -kr -pcs ~/.cedit/cooledit.block >& /dev/null
+cat /dev/null > ~/.cedit/cooledit.error
.fi
.PP
.B C-p
will run ispell on a block of text in a similar way. The file
is
-.B cedit/edit.spell.rc
+.B .cedit/edit.spell.rc
.IP
.nf
#!/bin/sh
# Use $HOME instead of ~ if this doesn't work.
# You may also have to use a different redirection
# syntax for some machines.
-/usr/local/bin/ispell ~/cedit/cooledit.block >& /dev/null
-cat /dev/null > ~/cedit/cooledit.error
+/usr/local/bin/ispell ~/.cedit/cooledit.block >& /dev/null
+cat /dev/null > ~/.cedit/cooledit.error
.fi
.PP
.SH Redefining Keys
Keys may be redefined from the Midnight Commander options
menu.
.PP
+.SH SYNTAX HIGHLIGHTING
+As of version 3.6.0, \fBcooledit\fP has syntax highlighting. This means
+that keywords and contexts (like C comments, string constants, etc) are
+highlighted in different colours. The following section explains the
+format of the file \fB~/.cedit/syntax\fP.
+
+The file \fB~/.cedit/syntax\fP (\fB~/.cedit/mcsyntax\fP for mcedit) is
+rescanned on opening of a any new editor file. The file contains
+rules for highlighting, each of which is given on a seperate line,
+and define which keywords will be highlighted to what colour. The
+file is also divided into sections, each beginning with a line with
+the \fBfile\fP command, followed by a regular expression. The
+regular expression dictates the file name that that set of rules
+applies to.
+
+A section ends with the start of a new section. Each section is divided
+into contexts, and each context contains rules. A context is a scope
+within the text that a particular set of rules belongs to. For instance,
+the region within a C style comment (i.e. between \fB/*\fP and \fB*/\fP)
+has its own colour. This is a context, although it will have no further
+rules inside it because there is probably nothing that we want
+highlighted within a C comment.
+
+A trivial C programming section might look like this:
+.PP
+.nf
+file .\\*\\\\.c
+
+wholechars abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_
+
+# default colors
+context default
+ keyword whole if yellow
+ keyword whole else yellow
+ keyword whole for yellow
+ keyword whole while yellow
+ keyword whole do yellow
+ keyword whole switch yellow
+ keyword whole case yellow
+ keyword whole static yellow
+ keyword whole extern yellow
+ keyword { yellow
+ keyword } yellow
+ keyword '*' green
+
+# C comments
+context /\\* \\*/ brown
+
+# C preprocessor directives
+context linestart # \\n red
+ keyword \\\\\\n yellow
+
+# C string constants
+context " " green
+ keyword %d brightgreen
+ keyword %s brightgreen
+ keyword %c brightgreen
+ keyword \\\\" brightgreen
+.fi
+.PP
+Each context starts with a line of the form:
+.br
+\fBcontext\fP [\fBexclusive\fP] [\fBwhole\fP|\fBwholeright\fP|\fBwholeleft\fP]
+[\fBlinestart\fP] \fIdelim\fP [\fBlinestart\fP] \fIdelim\fP [\fIforeground\fP] [\fIbackground\fP]
+.br
+
+One exception is the first context. It must start with the command
+.br
+\fBcontext\fP \fBdefault\fP [\fIforeground\fP] [\fIbackground\fP]
+.br
+or else \fBcooledit\fP will return an error.
+
+The \fBlinestart\fP option dictates that \fIdelim\fP must start at
+the beginning of a line.
+
+The \fBwhole\fP option tells that delim must be a whole word. What
+constitutes a whole word are a set of characters that can be
+changed at any point in the file with the \fBwholechars\fP
+command. The \fBwholechars\fP command at the top just sets the
+set exactly to its default and could therefore have been omitted. To
+specify that a word must be whole on the left only, you can use
+the \fBwholeleft\fP option, and similarly on the right. The left and
+right set of characters can be set seperately with,
+.br
+\fBwholechars\fP [\fBleft\fP|\fBright\fP] \fIcharacters\fP
+
+The \fBexclusive\fP option causes the text between the delimiters to be
+highlighted, but not the delimiters themselves.
+
+Each rule is a line of the form:
+.br
+\fBkeyword\fP [\fBwhole\fP|\fBwholeright\fP|\fBwholeleft\fP] [\fBlinestart\fP]
+\fIstring\fP \fIforeground\fP [\fIbackground\fP]
+.br
+
+Context or keyword strings are interpreted so that you can include tabs
+and spaces with the sequences \\t and \\s. Newlines and the \\ are
+specified with \\n and \\\\ respectively. Since whitespace is used as a
+seperator, it may not be used explicitedly. Also, \\* must be used to
+specify a *. The * itself is a wildcard that matches any length of
+characters. For example,
+.nf
+ keyword '*' green
+.fi
+colours all C single character constants green. You could also have
+used
+.nf
+ keyword "*" green
+.fi
+to colour string constants, except that the matched string may not cross
+newlines. \fIThe wildcard may be used within context delimiters as
+well\fP, but you cannot have a wildcard as the last or first character.
+
+Important to note is the line
+.nf
+ keyword \\\\\\n yellow
+.fi
+This line defines a keyword containing the \\ and newline characters.
+Because keywords have a higher precedence than context delimiters, this
+keyword prevents the context from ending at the end of a line if the
+line ends in a \\ thus allowing C preprocessor directive to continue
+across multiple lines.
+
+Comment may be included on a line of there own and begin with
+a #.
+
+Because of the simplicity of the implementation, there are a few
+intricacies that will not be coped with correctly, but these are a minor
+irritation. On the whole, a broad spectrum of quite complicated
+situations are handled with these simple rules. It is a good idea to
+take a look at the syntax file to see some of the nifty tricks you can
+do with a little imagination. If you can't get by with the rules I have
+coded, and you think you have rule that would be useful, please email
+me with your request.
+.PP
.SH OPTIONS
-The following options are defined in
-.B ".mc.ini".
+Most options can now be set from the editors options dialog
+box. See the \fBOptions\fP menu. The following options are defined in
+\fB.mc.ini\fP, and have obvious correspondences in the dialog box.
You can modifiy them to change the editor behaviour, by editing the file.
-An options dialog box is presently not supported, but will be in the
-future. Unless specified, a 1 sets the option to on, and a 0 sets it to
+Unless specified, a 1 sets the option to on, and a 0 sets it to
off, as is usual.
.TP
.I use_internal_edit
This option is ignored when envoking
.B mcedit.
.TP
-.I editor_word_wrap_line_length
-Sets the maximum length of the line before a newline
-is inserted automatically; 0 means off.
-.TP
.I editor_key_emulation
1 for
.B Emacs
@@ -278,7 +410,7 @@ spacing clean.
.PP
.SH FILES
-@prefix@/lib/mc.hlp
+@prefix@/mc.hlp
.IP
The help file for the program.
.PP
@@ -300,7 +432,7 @@ $HOME/.mc.ini
User's own setup. If this file is present then the setup is loaded
from here instead of the system-wide startup file.
.PP
-$HOME/cedit/
+$HOME/.cedit/
.IP
User's own temporary directory where block commands are processed
and saved.
diff --git a/edit/Makefile.in b/edit/Makefile.in
index af21c7864..ccff9f174 100644
--- a/edit/Makefile.in
+++ b/edit/Makefile.in
@@ -19,10 +19,10 @@ AR = @AR@
#
EDITSRC = edit.c editcmd.c editwidget.c edit_key_translator.c editdraw.c \
- edit.h editmenu.c editcmddef.h wordproc.c editoptions.c
+ edit.h editmenu.c editcmddef.h wordproc.c syntax.c editoptions.c
EDITOBJS = edit.o editcmd.o editwidget.o editdraw.o editmenu.o wordproc.o \
- editoptions.o
+ syntax.o editoptions.o
DIST = Makefile.in README.edit $(EDITSRC)
diff --git a/edit/edit.h b/edit/edit.h
index 2946bf75e..da2185600 100644
--- a/edit/edit.h
+++ b/edit/edit.h
@@ -3,6 +3,10 @@
#ifdef MIDNIGHT
+#ifdef HAVE_SLANG
+#define HAVE_SYNTAXH 1
+#endif
+
# include
# include
# include
@@ -21,7 +25,7 @@
# include
# include
-#else
+#else /* ! MIDNIGHT */
# include "global.h"
# include
@@ -98,6 +102,11 @@
#define SEARCH_DIALOG_OPTION_NO_CASE 4
#define SEARCH_DIALOG_OPTION_BACKWARDS 8
+#ifdef MIDNIGHT
+#define SYNTAX_FILE "/.cedit/mcsyntax"
+#else
+#define SYNTAX_FILE "/.cedit/syntax"
+#endif
#define CLIP_FILE "/.cedit/cooledit.clip"
#define MACRO_FILE "/.cedit/cooledit.macros"
#define BLOCK_FILE "/.cedit/cooledit.block"
@@ -191,6 +200,47 @@ struct selection {
int len;
};
+
+#define RULE_CONTEXT 0x00FFF000UL
+#define RULE_CONTEXT_SHIFT 12
+#define RULE_WORD 0x00000FFFUL
+#define RULE_WORD_SHIFT 0
+#define RULE_ON_LEFT_BORDER 0x02000000UL
+#define RULE_ON_RIGHT_BORDER 0x01000000UL
+
+struct key_word {
+ char *keyword;
+ char first;
+ char last;
+ char *whole_word_chars_left;
+ char *whole_word_chars_right;
+#define NO_COLOR ((unsigned long) -1);
+ int line_start;
+ int bg;
+ int fg;
+};
+
+struct context_rule {
+ int rule_number;
+ char *left;
+ char first_left;
+ char last_left;
+ char line_start_left;
+ char *right;
+ char first_right;
+ char last_right;
+ char line_start_right;
+ int single_char;
+ int between_delimiters;
+ char *whole_word_chars_left;
+ char *whole_word_chars_right;
+ unsigned char *conflicts;
+/* first word is word[1] */
+ struct key_word **keyword;
+};
+
+
+
struct editor_widget {
#ifdef MIDNIGHT
Widget widget;
@@ -225,6 +275,7 @@ struct editor_widget {
long last_byte; /* Last byte of file */
long start_display; /* First char displayed */
long start_col; /* First displayed column, negative */
+ long max_column; /* The maximum cursor position ever reached used to calc hori scroll bar */
long curs_row; /*row position of curser on the screen */
long curs_col; /*column position on screen */
int force; /* how much of the screen do we redraw? */
@@ -258,8 +309,16 @@ struct editor_widget {
unsigned long stack_bottom;
struct stat stat;
+/* syntax higlighting */
+ struct context_rule **rules;
+ long last_get_rule;
+ unsigned long rule;
+ char *syntax_type; /* description of syntax highlighting type being used */
+ int explicit_syntax; /* have we forced the syntax hi. type in spite of the filename? */
+
int to_here; /* dummy marker */
+
/* macro stuff */
int macro_i; /* -1 if not recording index to macro[] otherwise */
struct macro macro[MAX_MACRO_LENGTH];
@@ -385,6 +444,17 @@ void edit_paste_from_history (WEdit *edit);
void edit_split_filename (WEdit * edit, char *name);
+#ifdef MIDNIGHT
+#define CWidget Widget
+#endif
+void edit_set_syntax_change_callback (void (*callback) (CWidget *));
+void edit_load_syntax (WEdit * edit, char **names, char *type);
+void edit_free_syntax_rules (WEdit * edit);
+void edit_get_syntax_color (WEdit * edit, long byte_index, int *fg, int *bg);
+
+
+#ifdef MIDNIGHT
+
/* put OS2/NT/WIN95 defines here */
# ifdef OS2_NT
@@ -562,4 +632,4 @@ extern char *option_backup_ext;
extern int edit_confirm_save;
#endif /* ! _EDIT_C */
-
+#endif /* __EDIT_H */
diff --git a/edit/editcmd.c b/edit/editcmd.c
index b72b44138..6da7f8826 100644
--- a/edit/editcmd.c
+++ b/edit/editcmd.c
@@ -392,6 +392,7 @@ int edit_save_as_cmd (WEdit * edit)
{
/* This heads the 'Save As' dialog box */
char *exp = edit_get_save_file (edit->dir, edit->filename, _(" Save As "));
+ int different_filename = 0;
edit_push_action (edit, KEY_PRESS + edit->start_display);
edit->force |= REDRAW_COMPLETELY;
@@ -402,6 +403,7 @@ int edit_save_as_cmd (WEdit * edit)
} else {
if (strcmp(catstrs (edit->dir, edit->filename, 0), exp)) {
int file;
+ different_filename = 1;
if ((file = open ((char *) exp, O_RDONLY)) != -1) { /* the file exists */
close (file);
if (edit_query_dialog2 (_(" Warning "),
@@ -418,6 +420,8 @@ int edit_save_as_cmd (WEdit * edit)
#ifdef MIDNIGHT
edit->delete_file = 0;
#endif
+ if (different_filename && !edit->explicit_syntax)
+ edit_load_syntax (edit, 0, 0);
return 1;
} else {
free (exp);
@@ -963,7 +967,7 @@ int edit_replace_prompt (WEdit * edit, char *replace_text, int xpos, int ypos)
{
QuickDialog Quick_input =
- {66, 6, 0, 0, N_(" Replace "),
+ {66, 6, 0, 0, _(" Replace "),
"[Input Line Keys]", "quick_input", 0 /*quick_widgets */ };
Quick_input.widgets = quick_widgets;
@@ -1040,7 +1044,7 @@ void edit_replace_dialog (WEdit * edit, char **search_text, char **replace_text,
quick_widgets[13].text = *search_text;
{
QuickDialog Quick_input =
- {50, REPLACE_DLG_HEIGHT, -1, 0, N_(" Replace "),
+ {50, REPLACE_DLG_HEIGHT, -1, 0, _(" Replace "),
"[Input Line Keys]", "quick_input", 0 /*quick_widgets */ };
Quick_input.widgets = quick_widgets;
@@ -1108,7 +1112,7 @@ void edit_search_dialog (WEdit * edit, char **search_text)
{
QuickDialog Quick_input =
- {50, SEARCH_DLG_HEIGHT, -1, 0, N_(" Search "),
+ {50, SEARCH_DLG_HEIGHT, -1, 0, _(" Search "),
"[Input Line Keys]", "quick_input", 0 /*quick_widgets */ };
Quick_input.widgets = quick_widgets;
@@ -2479,7 +2483,7 @@ void edit_mail_dialog (WEdit * edit)
static char *mail_to_last = 0;
QuickDialog Quick_input =
- {50, MAIL_DLG_HEIGHT, -1, 0, N_(" Mail "),
+ {50, MAIL_DLG_HEIGHT, -1, 0, _(" Mail "),
/* NLS ? */
"[Input Line Keys]", "quick_input", 0};
diff --git a/edit/editdraw.c b/edit/editdraw.c
index 9f09e3a38..295d71e7e 100644
--- a/edit/editdraw.c
+++ b/edit/editdraw.c
@@ -263,7 +263,7 @@ static void set_color (int font)
#define edit_move(x,y) widget_move(edit, y, x);
-static void print_to_widget (WEdit * edit, long row, int start_col, float start_col_real, long end_col, unsigned short line[])
+static void print_to_widget (WEdit * edit, long row, int start_col, float start_col_real, long end_col, unsigned int line[])
{
int x = (float) start_col_real + EDIT_TEXT_HORIZONTAL_OFFSET;
int x1 = start_col + EDIT_TEXT_HORIZONTAL_OFFSET;
@@ -275,15 +275,15 @@ static void print_to_widget (WEdit * edit, long row, int start_col, float start_
edit_move (x + FONT_OFFSET_X, y + FONT_OFFSET_Y);
{
- unsigned short *p = line;
+ unsigned int *p = line;
int textchar = ' ';
long style;
while (*p) {
- style = (*p) >> 8;
- textchar = (*p) & 255;
- if (!style || style & MOD_ABNORMAL || style & MOD_CURSOR)
- set_color (DEF_COLOR);
+ style = *p >> 8;
+ textchar = *p & 0xFF;
+ if (!(style & (0xFF - MOD_ABNORMAL - MOD_CURSOR)))
+ SLsmg_set_color ((*p & 0x007F0000) >> 16);
if (style & MOD_ABNORMAL)
textchar = '.';
if (style & MOD_HIGHLIGHTED) {
@@ -306,13 +306,15 @@ static void print_to_widget (WEdit * edit, long row, int start_col, float start_
/* b pointer to begining of line */
static void edit_draw_this_line (WEdit * edit, long b, long row, long start_col, long end_col)
{
- static unsigned short line[MAX_LINE_LEN];
- unsigned short *p = line;
+ static unsigned int line[MAX_LINE_LEN];
+ unsigned int *p = line;
long m1 = 0, m2 = 0, q;
int col, start_col_real;
unsigned int c;
+ int fg, bg;
int i;
+ edit_get_syntax_color (edit, b - 1, &fg, &bg);
q = edit_move_forward3 (edit, b, start_col - edit->start_col, 0);
start_col_real = (col = (int) edit_move_forward3 (edit, b, 0, q)) + edit->start_col;
@@ -330,7 +332,12 @@ static void edit_draw_this_line (WEdit * edit, long b, long row, long start_col,
*p |= MOD_BOLD * 256;
if (q >= edit->found_start && q < edit->found_start + edit->found_len)
*p |= MOD_HIGHLIGHTED * 256;
- switch (c = edit_get_byte (edit, q++)) {
+ c = edit_get_byte (edit, q);
+ edit_get_syntax_color (edit, q, &fg, &bg);
+/* we don't use bg for mc - fg contains both */
+ *p |= fg << 16;
+ q++;
+ switch (c) {
case '\n':
col = end_col - edit->start_col + 1; /* quit */
*(p++) |= ' ';
@@ -338,7 +345,7 @@ static void edit_draw_this_line (WEdit * edit, long b, long row, long start_col,
case '\t':
i = TAB_SIZE - ((int) col % TAB_SIZE);
*p |= ' ';
- c = *(p++) & (0xFFFF - MOD_CURSOR * 256);
+ c = *(p++) & (0xFFFFFFFF - MOD_CURSOR * 256);
col += i;
while (--i)
*(p++) = c;
@@ -391,8 +398,7 @@ static void edit_draw_this_char (WEdit * edit, long curs, long row)
{
int b = edit_bol (edit, curs);
#ifdef MIDNIGHT
- long start_col = edit_move_forward3 (edit, b, 0, curs) + edit->start_col;
- edit_draw_this_line (edit, b, row, start_col, start_col);
+ edit_draw_this_line (edit, b, row, 0, edit->num_widget_columns - 1);
#else
edit_draw_this_line (edit, b, row, 0, edit->widget->width);
#endif
@@ -410,6 +416,7 @@ void render_edit_text (WEdit * edit, long start_row, long start_column, long end
#ifndef MIDNIGHT
static Window prev_win = 0;
#endif
+ int fg, bg;
int force = edit->force;
long b;
@@ -438,7 +445,7 @@ void render_edit_text (WEdit * edit, long start_row, long start_column, long end
b = edit_move_forward (edit, edit->start_display, start_row, 0);
while (row <= end_row) {
if (key_pending (edit))
- return;
+ goto exit_render;
edit_draw_this_line (edit, b, row, start_column, end_column);
b = edit_move_forward (edit, b, 1, 0);
row++;
@@ -453,17 +460,17 @@ void render_edit_text (WEdit * edit, long start_row, long start_column, long end
b = edit->start_display;
while (row <= upto) {
if (key_pending (edit))
- return;
+ goto exit_render;
edit_draw_this_line (edit, b, row, start_column, end_column);
b = edit_move_forward (edit, b, 1, 0);
}
}
}
-/* if (force & REDRAW_LINE) { ---> default */
+/* if (force & REDRAW_LINE) { ---> default */
b = edit_bol (edit, edit->curs1);
if (curs_row >= start_row && curs_row <= end_row) {
if (key_pending (edit))
- return;
+ goto exit_render;
edit_draw_this_line (edit, b, curs_row, start_column, end_column);
}
if (force & REDRAW_AFTER_CURSOR) {
@@ -472,7 +479,7 @@ void render_edit_text (WEdit * edit, long start_row, long start_column, long end
b = edit_move_forward (edit, b, 1, 0);
while (row <= end_row) {
if (key_pending (edit))
- return;
+ goto exit_render;
edit_draw_this_line (edit, b, row, start_column, end_column);
b = edit_move_forward (edit, b, 1, 0);
row++;
@@ -484,7 +491,7 @@ void render_edit_text (WEdit * edit, long start_row, long start_column, long end
b = edit_move_backward (edit, edit_bol (edit, edit->curs1), 1);
if (row >= start_row && row <= end_row) {
if (key_pending (edit))
- return;
+ goto exit_render;
edit_draw_this_line (edit, b, row, start_column, end_column);
}
}
@@ -494,14 +501,19 @@ void render_edit_text (WEdit * edit, long start_row, long start_column, long end
b = edit_move_forward (edit, b, 1, 0);
if (row >= start_row && row <= end_row) {
if (key_pending (edit))
- return;
+ goto exit_render;
edit_draw_this_line (edit, b, row, start_column, end_column);
}
}
}
} else {
- edit_draw_this_char (edit, prev_curs, prev_curs_row);
- edit_draw_this_char (edit, edit->curs1, edit->curs_row);
+ if (prev_curs_row < edit->curs_row) { /* with the new text highlighting, we must draw from the top down */
+ edit_draw_this_char (edit, prev_curs, prev_curs_row);
+ edit_draw_this_char (edit, edit->curs1, edit->curs_row);
+ } else {
+ edit_draw_this_char (edit, edit->curs1, edit->curs_row);
+ edit_draw_this_char (edit, prev_curs, prev_curs_row);
+ }
}
edit->force = 0;
@@ -513,7 +525,8 @@ void render_edit_text (WEdit * edit, long start_row, long start_column, long end
#ifndef MIDNIGHT
prev_win = edit->widget->winid;
#endif
-
+ exit_render:
+ edit_get_syntax_color (edit, edit->start_display - 1, &fg, &bg);
}
diff --git a/edit/editoptions.c b/edit/editoptions.c
index 336f2f848..ca20eaabe 100644
--- a/edit/editoptions.c
+++ b/edit/editoptions.c
@@ -21,7 +21,7 @@
#include
#include "edit.h"
-#define OPT_DLG_H 13
+#define OPT_DLG_H 15
#define OPT_DLG_W 72
#ifndef USE_INTERNAL_EDIT
@@ -36,6 +36,8 @@ char *key_emu_str[] =
char *wrap_str[] =
{N_("None"), N_("Dynamic paragraphing"), N_("Type writer wrap")};
+extern int option_syntax_highlighting;
+
void edit_options_dialog (void)
{
char wrap_length[32], tab_spacing[32], *p, *q;
@@ -43,6 +45,7 @@ void edit_options_dialog (void)
int tedit_key_emulation = edit_key_emulation;
int toption_fill_tabs_with_spaces = option_fill_tabs_with_spaces;
int tedit_confirm_save = edit_confirm_save;
+ int tedit_syntax_highlighting = option_syntax_highlighting;
int toption_return_does_auto_indent = option_return_does_auto_indent;
int toption_backspace_through_tabs = option_backspace_through_tabs;
int toption_fake_half_tabs = option_fake_half_tabs;
@@ -68,31 +71,39 @@ void edit_options_dialog (void)
{quick_input, OPT_DLG_W / 2 + 24, OPT_DLG_W, OPT_DLG_H - 5, OPT_DLG_H, "", OPT_DLG_W / 2 - 4 - 24, 0,
0, 0, XV_WLAY_DONTCARE, "i"},
/*6 */
- {quick_checkbox, OPT_DLG_W / 2 + 1, OPT_DLG_W, OPT_DLG_H - 7, OPT_DLG_H, "confir&M before saving", 6, 0,
+#if !defined(MIDNIGHT) || defined(HAVE_SYNTAXH)
+#define OA 1
+ {quick_checkbox, OPT_DLG_W / 2 + 1, OPT_DLG_W, OPT_DLG_H - 7, OPT_DLG_H, "syntax h&Ighlighting", 8, 0,
0, 0, XV_WLAY_DONTCARE, NULL},
+#else
+#define OA 0
+#endif
/*7 */
- {quick_checkbox, OPT_DLG_W / 2 + 1, OPT_DLG_W, OPT_DLG_H - 8, OPT_DLG_H, "&Fill tabs with spaces", 0, 0,
+ {quick_checkbox, OPT_DLG_W / 2 + 1, OPT_DLG_W, OPT_DLG_H - 8, OPT_DLG_H, "confir&M before saving", 6, 0,
0, 0, XV_WLAY_DONTCARE, NULL},
/*8 */
- {quick_checkbox, OPT_DLG_W / 2 + 1, OPT_DLG_W, OPT_DLG_H - 9, OPT_DLG_H, "&Return does auto indent", 0, 0,
+ {quick_checkbox, OPT_DLG_W / 2 + 1, OPT_DLG_W, OPT_DLG_H - 9, OPT_DLG_H, "&Fill tabs with spaces", 0, 0,
0, 0, XV_WLAY_DONTCARE, NULL},
/*9 */
- {quick_checkbox, OPT_DLG_W / 2 + 1, OPT_DLG_W, OPT_DLG_H - 10, OPT_DLG_H, "&Backspace through tabs", 0, 0,
+ {quick_checkbox, OPT_DLG_W / 2 + 1, OPT_DLG_W, OPT_DLG_H - 10, OPT_DLG_H, "&Return does auto indent", 0, 0,
0, 0, XV_WLAY_DONTCARE, NULL},
/*10 */
- {quick_checkbox, OPT_DLG_W / 2 + 1, OPT_DLG_W, OPT_DLG_H - 11, OPT_DLG_H, "&Fake half tabs", 0, 0,
+ {quick_checkbox, OPT_DLG_W / 2 + 1, OPT_DLG_W, OPT_DLG_H - 11, OPT_DLG_H, "&Backspace through tabs", 0, 0,
0, 0, XV_WLAY_DONTCARE, NULL},
/*11 */
+ {quick_checkbox, OPT_DLG_W / 2 + 1, OPT_DLG_W, OPT_DLG_H - 12, OPT_DLG_H, "&Fake half tabs", 0, 0,
+ 0, 0, XV_WLAY_DONTCARE, NULL},
+/*12 */
{quick_radio, 5, OPT_DLG_W, OPT_DLG_H - 6, OPT_DLG_H, "", 3, 0,
0, wrap_str, XV_WLAY_DONTCARE, "wrapm"},
-/*12 */
- {quick_label, 4, OPT_DLG_W, OPT_DLG_H - 7, OPT_DLG_H, N_("Wrap mode"), 0, 0,
- 0, 0, XV_WLAY_DONTCARE, NULL},
/*13 */
- {quick_radio, 5, OPT_DLG_W, OPT_DLG_H - 10, OPT_DLG_H, "", 2, 0,
- 0, key_emu_str, XV_WLAY_DONTCARE, "keyemu"},
+ {quick_label, 4, OPT_DLG_W, OPT_DLG_H - 7, OPT_DLG_H, _("Wrap mode"), 0, 0,
+ 0, 0, XV_WLAY_DONTCARE, NULL},
/*14 */
- {quick_label, 4, OPT_DLG_W, OPT_DLG_H - 11, OPT_DLG_H, N_("Key emulation"), 0, 0,
+ {quick_radio, 5, OPT_DLG_W, OPT_DLG_H - 11, OPT_DLG_H, "", 2, 0,
+ 0, key_emu_str, XV_WLAY_DONTCARE, "keyemu"},
+/*15 */
+ {quick_label, 4, OPT_DLG_W, OPT_DLG_H - 12, OPT_DLG_H, _("Key emulation"), 0, 0,
0, 0, XV_WLAY_DONTCARE, NULL},
{0}};
@@ -103,11 +114,12 @@ void edit_options_dialog (void)
quick_widgets[3].str_result = &p;
quick_widgets[5].text = tab_spacing;
quick_widgets[5].str_result = &q;
- quick_widgets[6].result = &tedit_confirm_save;
- quick_widgets[7].result = &toption_fill_tabs_with_spaces;
- quick_widgets[8].result = &toption_return_does_auto_indent;
- quick_widgets[9].result = &toption_backspace_through_tabs;
- quick_widgets[10].result = &toption_fake_half_tabs;
+ quick_widgets[5 + OA].result = &tedit_syntax_highlighting;
+ quick_widgets[6 + OA].result = &tedit_confirm_save;
+ quick_widgets[7 + OA].result = &toption_fill_tabs_with_spaces;
+ quick_widgets[8 + OA].result = &toption_return_does_auto_indent;
+ quick_widgets[9 + OA].result = &toption_backspace_through_tabs;
+ quick_widgets[10 + OA].result = &toption_fake_half_tabs;
if (option_auto_para_formatting)
wrap_mode = 1;
@@ -116,11 +128,11 @@ void edit_options_dialog (void)
else
wrap_mode = 0;
- quick_widgets[11].result = &wrap_mode;
- quick_widgets[11].value = wrap_mode;
+ quick_widgets[11 + OA].result = &wrap_mode;
+ quick_widgets[11 + OA].value = wrap_mode;
- quick_widgets[13].result = &tedit_key_emulation;
- quick_widgets[13].value = tedit_key_emulation;
+ quick_widgets[13 + OA].result = &tedit_key_emulation;
+ quick_widgets[13 + OA].value = tedit_key_emulation;
{
QuickDialog Quick_options =
@@ -141,16 +153,17 @@ void edit_options_dialog (void)
option_tab_spacing += option_tab_spacing & 1;
free (q);
}
- edit_confirm_save = *quick_widgets[6].result;
- option_fill_tabs_with_spaces = *quick_widgets[7].result;
- option_return_does_auto_indent = *quick_widgets[8].result;
- option_backspace_through_tabs = *quick_widgets[9].result;
- option_fake_half_tabs = *quick_widgets[10].result;
+ option_syntax_highlighting = *quick_widgets[5 + OA].result;
+ edit_confirm_save = *quick_widgets[6 + OA].result;
+ option_fill_tabs_with_spaces = *quick_widgets[7 + OA].result;
+ option_return_does_auto_indent = *quick_widgets[8 + OA].result;
+ option_backspace_through_tabs = *quick_widgets[9 + OA].result;
+ option_fake_half_tabs = *quick_widgets[10 + OA].result;
- if (*quick_widgets[11].result == 1) {
+ if (*quick_widgets[11 + OA].result == 1) {
option_auto_para_formatting = 1;
option_typewriter_wrap = 0;
- } else if (*quick_widgets[11].result == 2) {
+ } else if (*quick_widgets[11 + OA].result == 2) {
option_auto_para_formatting = 0;
option_typewriter_wrap = 1;
} else {
@@ -158,7 +171,7 @@ void edit_options_dialog (void)
option_typewriter_wrap = 0;
}
- edit_key_emulation = *quick_widgets[13].result;
+ edit_key_emulation = *quick_widgets[13 + OA].result;
return;
} else {
diff --git a/edit/editwidget.c b/edit/editwidget.c
index ca2f981c0..e6dc19375 100644
--- a/edit/editwidget.c
+++ b/edit/editwidget.c
@@ -31,6 +31,7 @@
#include "mousemark.h"
#endif
+
#ifndef MIDNIGHT
extern int EditExposeRedraw;
@@ -48,17 +49,23 @@ void edit_destroy_callback (CWidget * w)
CError ("Trying to destroy non-existing editor widget.\n");
}
+void link_hscrollbar_to_editor (CWidget * scrollbar, CWidget * editor, XEvent * xevent, CEvent * cwevent, int whichscrbutton);
+
extern int option_editor_bg_normal;
void edit_tri_cursor (Window win);
-
/* starting_directory is for the filebrowser */
CWidget *CDrawEditor (const char *identifier, Window parent, int x, int y,
int width, int height, const char *text, const char *filename,
const char *starting_directory, unsigned int options, unsigned long text_size)
{
static made_directory = 0;
+ int extra_space_for_hscroll = 0;
CWidget *w;
WEdit *e;
+
+ if (options & EDITOR_HORIZ_SCROLL)
+ extra_space_for_hscroll = 8;
+
wedit = w = CSetupWidget (identifier, parent, x, y,
width + 7, height + 6, C_EDITOR_WIDGET,
ExposureMask | ButtonPressMask | ButtonReleaseMask | \
@@ -93,9 +100,14 @@ CWidget *CDrawEditor (const char *identifier, Window parent, int x, int y,
e->macro_i = -1;
e->widget = w;
- set_hint_pos (x + width + 7 + WIDGET_SPACING, y + height + 6 + WIDGET_SPACING);
+ set_hint_pos (x + width + 7 + WIDGET_SPACING, y + height + 6 + WIDGET_SPACING + extra_space_for_hscroll);
+ if (extra_space_for_hscroll) {
+ w->hori_scrollbar = CDrawHorizontalScrollbar (catstrs (identifier, ".hsc", 0), parent,
+ x, y + height + 6, width + 6, 12, 0, 0);
+ CSetScrollbarCallback (w->hori_scrollbar->ident, w->ident, link_hscrollbar_to_editor);
+ }
if (!(options & EDITOR_NO_TEXT))
- CDrawText (catstrs (identifier, ".text", 0), parent, x, y + height + 6 + WIDGET_SPACING, "%s", e->filename);
+ CDrawText (catstrs (identifier, ".text", 0), parent, x, y + height + 6 + WIDGET_SPACING + extra_space_for_hscroll, "%s", e->filename);
if (!(options & EDITOR_NO_SCROLL)) {
w->vert_scrollbar = CDrawVerticalScrollbar (catstrs (identifier, ".vsc", 0), parent,
x + width + 7 + WIDGET_SPACING, y, height + 6, 20, 0, 0);
@@ -104,30 +116,44 @@ CWidget *CDrawEditor (const char *identifier, Window parent, int x, int y,
return w;
}
-void update_scroll_bar (WEdit * e)
+void update_scroll_bars (WEdit * e)
{
int i, x1, x2;
CWidget *scroll;
scroll = e->widget->vert_scrollbar;
- if (!scroll)
- return;
-
- i = e->total_lines - e->start_line + 1;
- if (i > e->num_widget_lines)
- i = e->num_widget_lines;
- if (e->total_lines) {
- x1 = (double) 65535.0 *e->start_line / (e->total_lines + 1);
- x2 = (double) 65535.0 *i / (e->total_lines + 1);
- } else {
- x1 = 0;
- x2 = 65535;
+ if (scroll) {
+ i = e->total_lines - e->start_line + 1;
+ if (i > e->num_widget_lines)
+ i = e->num_widget_lines;
+ if (e->total_lines) {
+ x1 = (double) 65535.0 *e->start_line / (e->total_lines + 1);
+ x2 = (double) 65535.0 *i / (e->total_lines + 1);
+ } else {
+ x1 = 0;
+ x2 = 65535;
+ }
+ if (x1 != scroll->firstline || x2 != scroll->numlines) {
+ scroll->firstline = x1;
+ scroll->numlines = x2;
+ EditExposeRedraw = 1;
+ render_scrollbar (scroll);
+ EditExposeRedraw = 0;
+ }
}
- if (x1 != scroll->firstline || x2 != scroll->numlines) {
- scroll->firstline = x1;
- scroll->numlines = x2;
- EditExposeRedraw = 1;
- render_scrollbar (scroll);
- EditExposeRedraw = 0;
+ scroll = e->widget->hori_scrollbar;
+ if (scroll) {
+ i = e->max_column - (-e->start_col) + 1;
+ if (i > e->num_widget_columns * FONT_MEAN_WIDTH)
+ i = e->num_widget_columns * FONT_MEAN_WIDTH;
+ x1 = (double) 65535.0 *(-e->start_col) / (e->max_column + 1);
+ x2 = (double) 65535.0 *i / (e->max_column + 1);
+ if (x1 != scroll->firstline || x2 != scroll->numlines) {
+ scroll->firstline = x1;
+ scroll->numlines = x2;
+ EditExposeRedraw = 1;
+ render_scrollbar (scroll);
+ EditExposeRedraw = 0;
+ }
}
}
@@ -336,6 +362,55 @@ void link_scrollbar_to_editor (CWidget * scrollbar, CWidget * editor, XEvent * x
}
}
+void link_hscrollbar_to_editor (CWidget * scrollbar, CWidget * editor, XEvent * xevent, CEvent * cwevent, int whichscrbutton)
+{
+ int i, start_col;
+ WEdit *e;
+ e = editor->editor;
+ if (!e)
+ return;
+ if (!e->widget->hori_scrollbar)
+ return;
+ start_col = (-e->start_col);
+ if ((xevent->type == ButtonRelease || xevent->type == MotionNotify) && whichscrbutton == 3) {
+ e->start_col = (double) scrollbar->firstline * e->max_column / 65535.0 + 1;
+ e->start_col -= e->start_col % FONT_MEAN_WIDTH;
+ if (e->start_col < 0)
+ e->start_col = 0;
+ e->start_col = (-e->start_col);
+ } else if (xevent->type == ButtonPress && (cwevent->button == Button1 || cwevent->button == Button2)) {
+ switch (whichscrbutton) {
+ case 1:
+ edit_scroll_left (e, (e->num_widget_columns - 1) * FONT_MEAN_WIDTH);
+ break;
+ case 2:
+ edit_scroll_left (e, FONT_MEAN_WIDTH);
+ break;
+ case 5:
+ edit_scroll_right (e, FONT_MEAN_WIDTH);
+ break;
+ case 4:
+ edit_scroll_right (e, (e->num_widget_columns - 1) * FONT_MEAN_WIDTH);
+ break;
+ }
+ }
+ scrollbar->firstline = (double) 65535.0 *(-e->start_col) / (e->max_column + 1);
+ i = e->max_column - (-e->start_col) + 1;
+ if (i > e->num_widget_columns * FONT_MEAN_WIDTH)
+ i = e->num_widget_columns * FONT_MEAN_WIDTH;
+ scrollbar->numlines = (double) 65535.0 *i / (e->max_column + 1);
+ if (start_col != (-e->start_col)) {
+ e->force |= REDRAW_PAGE | REDRAW_LINE;
+ set_cursor_position (0, 0, 0, 0, 0, 0, 0, 0, 0);
+ if (CCheckWindowEvent (xevent->xany.window, ButtonReleaseMask | ButtonMotionMask, 0))
+ return;
+ }
+ if (e->force) {
+ edit_render_keypress (e);
+ edit_status (e);
+ }
+}
+
/*
This section comes from rxvt-2.21b1/src/screen.c by
Robert Nation &
@@ -449,7 +524,7 @@ void edit_update_screen (WEdit * e)
edit_scroll_screen_over_cursor (e);
edit_update_curs_row (e);
edit_update_curs_col (e);
- update_scroll_bar (e);
+ update_scroll_bars (e);
edit_status (e);
if (e->force & REDRAW_COMPLETELY)
@@ -488,7 +563,7 @@ static void edit_insert_column_of_text (WEdit * edit, unsigned char *data, int s
}
for (p = edit->curs1;; p++) {
if (p == edit->last_byte)
- goto insert;
+ edit_insert_ahead (edit, '\n');
if (edit_get_byte (edit, p) == '\n') {
p++;
break;
@@ -502,7 +577,6 @@ static void edit_insert_column_of_text (WEdit * edit, unsigned char *data, int s
}
continue;
}
- insert:
edit_insert (edit, data[i]);
}
edit_cursor_move (edit, cursor - edit->curs1);
@@ -517,6 +591,7 @@ void handle_client_message (CWidget * w, XEvent * xevent, CEvent * cwevent)
unsigned char *data;
unsigned long size;
int xs, ys;
+ long start_line;
int x, y, r, deleted = 0;
long click;
unsigned int state;
@@ -557,12 +632,14 @@ void handle_client_message (CWidget * w, XEvent * xevent, CEvent * cwevent)
edit_push_action (e, KEY_PRESS + e->start_display);
/* drops to the same window moving to the left: */
+ start_line = e->start_line;
if (xevent->xclient.data.l[2] == xevent->xclient.window && !(xevent->xclient.data.l[1] & Button1Mask))
if ((column_highlighting && x < max (e->column1, e->column2)) || !column_highlighting) {
edit_block_delete_cmd (e);
deleted = 1;
}
edit_update_curs_row (e);
+ edit_move_display (e, start_line);
click = edit_get_click_pos (e, x, y); /* click pos changes with edit_block_delete_cmd() */
edit_cursor_move (e, click - e->curs1);
if (data_type == DndFile) {
@@ -661,6 +738,8 @@ int eh_editor (CWidget * w, XEvent * xevent, CEvent * cwevent)
case FocusOut:
edit_render_tidbits (w);
e->force |= REDRAW_CHAR_ONLY | REDRAW_LINE;
+ edit_render_keypress (e);
+ return 1;
break;
case KeyRelease:
if (column_highlighting) {
@@ -683,6 +762,9 @@ int eh_editor (CWidget * w, XEvent * xevent, CEvent * cwevent)
}
}
r = edit_execute_key_command (e, cwevent->command, cwevent->insert);
+ if (r)
+ edit_update_screen (e);
+ return r;
break;
case EditorCommand:
cwevent->ident = w->ident;
@@ -938,7 +1020,7 @@ void edit_adjust_size (Dlg_head * h)
widget_set_size (&edit->widget, 0, 0, LINES - 1, COLS);
widget_set_size (&edit_bar->widget, LINES - 1, 0, 1, COLS);
widget_set_size (&edit_menubar->widget, 0, 0, 1, COLS);
- menubar_arrange(edit_menubar);
+ menubar_arrange(edit_menubar);
}
void edit_update_screen (WEdit * e)
diff --git a/edit/syntax.c b/edit/syntax.c
new file mode 100644
index 000000000..66119742b
--- /dev/null
+++ b/edit/syntax.c
@@ -0,0 +1,1040 @@
+/* editor syntax highlighting.
+
+ Copyright (C) 1996, 1997, 1998 the Free Software Foundation
+
+ Authors: 1998 Paul Sheer
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include
+#ifdef MIDNIGHT
+#include "edit.h"
+#else
+#include "coolwidget.h"
+#endif
+
+#if !defined(MIDNIGHT) || defined(HAVE_SYNTAXH)
+
+int option_syntax_highlighting = 1;
+
+/* these three functions are called from the outside */
+void edit_load_syntax (WEdit * edit, char **names, char *type);
+void edit_free_syntax_rules (WEdit * edit);
+void edit_get_syntax_color (WEdit * edit, long byte_index, int *fg, int *bg);
+
+static void *syntax_malloc (size_t x)
+{
+ void *p;
+ p = malloc (x);
+ memset (p, 0, x);
+ return p;
+}
+
+#define syntax_free(x) {if(x){free(x);(x)=0;}}
+
+static int compare_word_to_right (WEdit * edit, long i, char *text, char *whole_left, char *whole_right, int line_start)
+{
+ char *p;
+ int c;
+ if (!*text)
+ return 0;
+ c = edit_get_byte (edit, i - 1);
+ if (line_start)
+ if (c != '\n')
+ return 0;
+ if (whole_left)
+ if (strchr (whole_left, c))
+ return 0;
+ for (p = text; *p; p++, i++) {
+ if (*p == '\001') {
+ p++;
+ for (;;) {
+ c = edit_get_byte (edit, i);
+ if (c == '\n')
+ return 0;
+ if (c == *p)
+ break;
+ i++;
+ }
+ } else {
+ if (*p != edit_get_byte (edit, i))
+ return 0;
+ }
+ }
+ if (whole_right)
+ if (strchr (whole_right, edit_get_byte (edit, i)))
+ return 0;
+ return 1;
+}
+
+static int compare_word_to_left (WEdit * edit, long i, char *text, char *whole_left, char *whole_right, int line_start)
+{
+ char *p;
+ int c;
+ if (!*text)
+ return 0;
+ if (whole_right)
+ if (strchr (whole_right, edit_get_byte (edit, i + 1)))
+ return 0;
+ for (p = text + strlen (text) - 1; (unsigned long) p >= (unsigned long) text; p--, i--) {
+ if (*p == '\001') {
+ p--;
+ for (;;) {
+ c = edit_get_byte (edit, i);
+ if (c == '\n')
+ return 0;
+ if (c == *p)
+ break;
+ i--;
+ }
+ } else {
+ if (*p != edit_get_byte (edit, i))
+ return 0;
+ }
+ }
+ c = edit_get_byte (edit, i);
+ if (line_start)
+ if (c != '\n')
+ return 0;
+ if (whole_left)
+ if (strchr (whole_left, c))
+ return 0;
+ return 1;
+}
+
+
+#if 0
+#define debug_printf(x,y) printf(x,y)
+#else
+#define debug_printf(x,y)
+#endif
+
+static unsigned long apply_rules_going_right (WEdit * edit, long i, unsigned long rule)
+{
+ struct context_rule *r;
+ int context, keyword, c1, c2;
+ unsigned long border;
+ context = (rule & RULE_CONTEXT) >> RULE_CONTEXT_SHIFT;
+ keyword = (rule & RULE_WORD) >> RULE_WORD_SHIFT;
+ border = rule & (RULE_ON_LEFT_BORDER | RULE_ON_RIGHT_BORDER);
+ c1 = edit_get_byte (edit, i - 1);
+ c2 = edit_get_byte (edit, i);
+
+ debug_printf ("%c->", c1);
+ debug_printf ("%c ", c2);
+/* check to turn off a context */
+ if (context && !keyword) {
+ r = edit->rules[context];
+ if (r->first_right == c2 && compare_word_to_right (edit, i, r->right, r->whole_word_chars_left, r->whole_word_chars_right, r->line_start_right)) {
+ debug_printf ("3 ", 0);
+ border = RULE_ON_RIGHT_BORDER;
+ if (r->between_delimiters) {
+ context = 0;
+ debug_printf ("context=off ", 0);
+ keyword = 0;
+ }
+ } else if (!r->between_delimiters && r->last_right == c1 && compare_word_to_left (edit, i - 1, r->right, r->whole_word_chars_left, r->whole_word_chars_right, r->line_start_right)) {
+ debug_printf ("4 ", 0);
+ border = 0;
+ if (!(rule & RULE_ON_LEFT_BORDER)) {
+ context = 0;
+ debug_printf ("context=off ", 0);
+ keyword = 0;
+ }
+ } else if (r->last_left == c1 && compare_word_to_left (edit, i - 1, r->left, r->whole_word_chars_left, r->whole_word_chars_right, r->line_start_left)) {
+ debug_printf ("2 ", 0);
+ border = 0;
+ keyword = 0;
+ }
+ }
+ debug_printf ("border=%s ", border ? ((border & RULE_ON_LEFT_BORDER) ? "left" : "right") : "off");
+
+ debug_printf ("\n", 0);
+
+/* check to turn off a keyword */
+ if (keyword) {
+ struct key_word *k;
+ k = edit->rules[context]->keyword[keyword];
+ if (k->last == c1 && compare_word_to_left (edit, i - 1, k->keyword, k->whole_word_chars_left, k->whole_word_chars_right, k->line_start)) {
+ keyword = 0;
+ debug_printf ("keyword=%d ", keyword);
+ }
+ }
+/* check to turn on a context */
+ if (!context && !keyword) {
+ int count;
+ for (count = 1; edit->rules[count]; count++) {
+ r = edit->rules[count];
+ if (r->between_delimiters && r->last_right == c1 && compare_word_to_left (edit, i - 1, r->right, r->whole_word_chars_left, r->whole_word_chars_right, r->line_start_right)) {
+ debug_printf ("4 count=%d", count);
+ border = 0;
+ break;
+ } else if (r->first_left == c2 && compare_word_to_right (edit, i, r->left, r->whole_word_chars_left, r->whole_word_chars_right, r->line_start_left)) {
+ debug_printf ("1 ", 0);
+ border = RULE_ON_LEFT_BORDER;
+ if (!r->between_delimiters) {
+ context = count;
+ debug_printf ("context=%d ", context);
+ keyword = 0;
+ }
+ break;
+ } else if (r->between_delimiters && r->last_left == c1 && compare_word_to_left (edit, i - 1, r->left, r->whole_word_chars_left, r->whole_word_chars_right, r->line_start_left)) {
+ debug_printf ("2 ", 0);
+ border = 0;
+ if (!(rule & RULE_ON_RIGHT_BORDER)) {
+ if (r->between_delimiters) {
+ context = count;
+ debug_printf ("context=%d ", context);
+ keyword = 0;
+ }
+ break;
+ }
+ }
+ }
+ }
+/* check to turn on a keyword */
+ if (!keyword) {
+ int count;
+ r = edit->rules[context];
+ for (count = 1; r->keyword[count]; count++) {
+ struct key_word *k;
+ k = r->keyword[count];
+ if (k->first == c2)
+ if (compare_word_to_right (edit, i, k->keyword, k->whole_word_chars_left, k->whole_word_chars_right, k->line_start)) {
+ keyword = count;
+ debug_printf ("keyword=%d ", keyword);
+ break;
+ }
+ }
+ }
+ debug_printf ("border=%s ", border ? ((border & RULE_ON_LEFT_BORDER) ? "left" : "right") : "off");
+ debug_printf ("keyword=%d ", keyword);
+
+ debug_printf (" %d#\n", context);
+
+ return (context << RULE_CONTEXT_SHIFT) | (keyword << RULE_WORD_SHIFT) | border;
+}
+
+static inline int resolve_left_delim (WEdit * edit, long i, struct context_rule *r, int s)
+{
+ int c, count;
+ if (!r->conflicts)
+ return s;
+ for (;;) {
+ c = edit_get_byte (edit, i);
+ if (c == '\n')
+ break;
+ for (count = 1; r->conflicts[count]; count++) {
+ struct context_rule *p;
+ p = edit->rules[r->conflicts[count]];
+ if (!p)
+ break;
+ if (p->first_left == c && r->between_delimiters == p->between_delimiters && compare_word_to_right (edit, i, p->left, p->whole_word_chars_left, r->whole_word_chars_right, p->line_start_left))
+ return r->conflicts[count];
+ }
+ i--;
+ }
+ return 0;
+}
+
+/* we don't concern ourselves with single words here, 'cos we will always
+ start at the beginning of a line and then go right */
+static unsigned long apply_rules_going_left (WEdit * edit, long i, unsigned long rule)
+{
+ struct context_rule *r;
+ int context, keyword, c1, c2;
+ unsigned long border;
+ context = (rule & RULE_CONTEXT) >> RULE_CONTEXT_SHIFT;
+ keyword = (rule & RULE_WORD) >> RULE_WORD_SHIFT;
+ border = rule & (RULE_ON_LEFT_BORDER | RULE_ON_RIGHT_BORDER);
+ c1 = edit_get_byte (edit, i);
+ c2 = edit_get_byte (edit, i + 1);
+
+ debug_printf ("%c<-", c1);
+ debug_printf ("%c ", c2);
+
+/* check to turn off a context */
+ if (context && !keyword) {
+ r = edit->rules[context];
+ if (r->first_left == c2 && compare_word_to_right (edit, i + 1, r->left, r->whole_word_chars_left, r->whole_word_chars_right, r->line_start_left)) {
+ debug_printf ("1 ", 0);
+ border = 0;
+ if (!(rule & RULE_ON_RIGHT_BORDER)) {
+ context = 0;
+ keyword = 0;
+ debug_printf ("context=off ", 0);
+ }
+ } else if (!r->between_delimiters && r->first_right == c2 && compare_word_to_right (edit, i + 1, r->right, r->whole_word_chars_left, r->whole_word_chars_right, r->line_start_right)) {
+ debug_printf ("3 ", 0);
+ border = 0;
+ keyword = 0;
+ } else if (r->last_left == c1 && compare_word_to_left (edit, i, r->left, r->whole_word_chars_left, r->whole_word_chars_right, r->line_start_left)) {
+ debug_printf ("2 ", 0);
+ border = RULE_ON_LEFT_BORDER;
+ if (r->between_delimiters) {
+ context = 0;
+ keyword = 0;
+ debug_printf ("context=off ", 0);
+ }
+ }
+ }
+/* check to turn off a keyword */
+ if (keyword) {
+ struct key_word *k;
+ k = edit->rules[context]->keyword[keyword];
+ if (k->first == c2)
+ if (compare_word_to_right (edit, i + 1, k->keyword, k->whole_word_chars_left, k->whole_word_chars_right, k->line_start)) {
+ keyword = 0;
+ debug_printf ("keyword=%d ", keyword);
+ }
+ }
+ debug_printf ("border=%s ", border ? ((border & RULE_ON_LEFT_BORDER) ? "left" : "right") : "off");
+
+ debug_printf ("\n", 0);
+
+/* check to turn on a context */
+ if (!context && !keyword) {
+
+ int count;
+ for (count = 1; edit->rules[count]; count++) {
+ r = edit->rules[count];
+ if (r->first_left == c2 && compare_word_to_right (edit, i + 1, r->left, r->whole_word_chars_left, r->whole_word_chars_right, r->line_start_left)) {
+ debug_printf ("1 ", 0);
+ border = 0;
+ keyword = 0;
+ break;
+ } else if (r->last_right == c1 && compare_word_to_left (edit, i, r->right, r->whole_word_chars_left, r->whole_word_chars_right, r->line_start_right)) {
+ debug_printf ("4 count=%d", count);
+ if (!r->between_delimiters && !(c1 == '\n' && r->single_char)) {
+ border = RULE_ON_RIGHT_BORDER;
+ context = resolve_left_delim (edit, i - 1, r, count);
+ debug_printf ("context=%d ", context);
+ }
+ break;
+ } else if (r->between_delimiters && r->first_right == c2 && compare_word_to_right (edit, i + 1, r->right, r->whole_word_chars_left, r->whole_word_chars_right, r->line_start_right)) {
+ debug_printf ("3 ", 0);
+ border = 0;
+ if (!(rule & RULE_ON_LEFT_BORDER))
+ if (r->between_delimiters && !(c2 == '\n' && r->single_char)) {
+ context = resolve_left_delim (edit, i, r, count);
+ keyword = 0;
+ debug_printf ("context=%d ", context);
+ }
+ break;
+ }
+ }
+ }
+/* check to turn on a keyword */
+ if (!keyword) {
+ int count;
+ r = edit->rules[context];
+ for (count = 1; r->keyword[count]; count++) {
+ struct key_word *k;
+ k = r->keyword[count];
+ if (k->last == c1 && compare_word_to_left (edit, i, k->keyword, k->whole_word_chars_left, k->whole_word_chars_right, k->line_start)) {
+ keyword = count;
+ debug_printf ("keyword=%d ", keyword);
+ break;
+ }
+ }
+ }
+ debug_printf ("border=%s ", border ? ((border & RULE_ON_LEFT_BORDER) ? "left" : "right") : "off");
+
+ debug_printf (" %d#\n", context);
+
+ return (context << RULE_CONTEXT_SHIFT) | (keyword << RULE_WORD_SHIFT) | border;
+}
+
+static unsigned long edit_get_rule (WEdit * edit, long byte_index)
+{
+ long i;
+ if (byte_index < 0) {
+ edit->last_get_rule = -1;
+ edit->rule = 0;
+ return 0;
+ }
+ if (byte_index > edit->last_get_rule) {
+ for (i = edit->last_get_rule + 1; i <= byte_index; i++)
+ edit->rule = apply_rules_going_right (edit, i, edit->rule);
+ } else if (byte_index < edit->last_get_rule) {
+ for (i = edit->last_get_rule - 1; i >= byte_index; i--)
+ edit->rule = apply_rules_going_left (edit, i, edit->rule);
+ }
+ edit->last_get_rule = byte_index;
+ return edit->rule;
+}
+
+static void translate_rule_to_color (WEdit * edit, unsigned long rule, int *fg, int *bg)
+{
+ struct key_word *k;
+ k = edit->rules[(rule & RULE_CONTEXT) >> RULE_CONTEXT_SHIFT]->keyword[(rule & RULE_WORD) >> RULE_WORD_SHIFT];
+ *bg = k->bg;
+ *fg = k->fg;
+}
+
+void edit_get_syntax_color (WEdit * edit, long byte_index, int *fg, int *bg)
+{
+ unsigned long rule;
+ if (!edit->rules || byte_index >= edit->last_byte || !option_syntax_highlighting) {
+#ifdef MIDNIGHT
+ *fg = NORMAL_COLOR;
+#else
+ *fg = NO_COLOR;
+ *bg = NO_COLOR;
+#endif
+ } else {
+ rule = edit_get_rule (edit, byte_index);
+ translate_rule_to_color (edit, rule, fg, bg);
+ }
+}
+
+
+/*
+ Returns 0 on error/eof or a count of the number of bytes read
+ including the newline. Result must be free'd.
+ */
+static int read_one_line (char **line, FILE * f)
+{
+ char *p;
+ int len = 256, c, r = 0, i = 0;
+ p = syntax_malloc (len);
+ for (;;) {
+ c = fgetc (f);
+ if (c == -1) {
+ r = 0;
+ break;
+ } else if (c == '\n') {
+ r = i + 1; /* extra 1 for the newline just read */
+ break;
+ } else {
+ if (i >= len - 1) {
+ char *q;
+ q = syntax_malloc (len * 2);
+ memcpy (q, p, len);
+ syntax_free (p);
+ p = q;
+ len *= 2;
+ }
+ p[i++] = c;
+ }
+ }
+ p[i] = 0;
+ *line = p;
+ return r;
+}
+
+static char *strdup_convert (char *s)
+{
+ char *r, *p;
+ p = r = strdup (s);
+ while (*s) {
+ switch (*s) {
+ case '\\':
+ s++;
+ switch (*s) {
+ case 'n':
+ *p = '\n';
+ break;
+ case 'r':
+ *p = '\r';
+ break;
+ case 't':
+ *p = '\t';
+ break;
+ case 's':
+ *p = ' ';
+ break;
+ case '*':
+ *p = '*';
+ break;
+ case '\\':
+ *p = '\\';
+ break;
+ default:
+ *p = *s;
+ break;
+ }
+ break;
+ case '*':
+/* a * at the beginning or end of the line must be interpreted literally */
+ if ((unsigned long) p == (unsigned long) r || strlen (s) == 1)
+ *p = '*';
+ else
+ *p = '\001';
+ break;
+ default:
+ *p = *s;
+ break;
+ }
+ s++;
+ p++;
+ }
+ *p = 0;
+ return r;
+}
+
+#define whiteness(x) ((x) == '\t' || (x) == '\n' || (x) == ' ')
+
+static void get_args (char *l, char **args, int *argc)
+{
+ *argc = 0;
+ l--;
+ for (;;) {
+ char *p;
+ for (p = l + 1; *p && whiteness (*p); p++);
+ if (!*p)
+ break;
+ for (l = p + 1; *l && !whiteness (*l); l++);
+ *l = '\0';
+ *args = strdup_convert (p);
+ (*argc)++;
+ args++;
+ }
+ *args = 0;
+}
+
+static void free_args (char **args)
+{
+ while (*args) {
+ syntax_free (*args);
+ *args = 0;
+ args++;
+ }
+}
+
+#define check_a {if(!*a){result=line;break;}}
+#define check_not_a {if(*a){result=line;break;}}
+
+#ifdef MIDNIGHT
+int try_alloc_color_pair (char *fg, char *bg);
+#endif
+
+/* returns line number on error */
+static int edit_read_syntax_rules (WEdit * edit, FILE * f)
+{
+ char *fg, *bg;
+ char whole_right[256];
+ char whole_left[256];
+ char *args[1024], *l = 0;
+ int line = 0;
+ struct context_rule **r, *c;
+ int num_words = -1, num_contexts = -1;
+ int argc, result = 0;
+ int i, j;
+
+ args[0] = 0;
+
+ strcpy (whole_left, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_");
+ strcpy (whole_right, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_");
+
+ r = edit->rules = syntax_malloc (256 * sizeof (struct context_rule *));
+
+ for (;;) {
+ char **a;
+ line++;
+ if (!read_one_line (&l, f))
+ break;
+ get_args (l, args, &argc);
+ a = args + 1;
+ if (!args[0]) {
+ /* do nothing */
+ } else if (!strcmp (args[0], "wholechars")) {
+ check_a;
+ if (!strcmp (*a, "left")) {
+ a++;
+ strcpy (whole_left, *a);
+ } else if (!strcmp (*a, "right")) {
+ a++;
+ strcpy (whole_right, *a);
+ } else {
+ strcpy (whole_left, *a);
+ strcpy (whole_right, *a);
+ }
+ a++;
+ check_not_a;
+ } else if (!strcmp (args[0], "context")) {
+ check_a;
+ if (num_contexts == -1) {
+ if (strcmp (*a, "default")) { /* first context is the default */
+ *a = 0;
+ check_a;
+ }
+ a++;
+ c = r[0] = syntax_malloc (sizeof (struct context_rule));
+ c->left = strdup (" ");
+ c->right = strdup (" ");
+ num_contexts = 0;
+ } else {
+ c = r[num_contexts] = syntax_malloc (sizeof (struct context_rule));
+ if (!strcmp (*a, "exclusive")) {
+ a++;
+ c->between_delimiters = 1;
+ }
+ check_a;
+ if (!strcmp (*a, "whole")) {
+ a++;
+ c->whole_word_chars_left = strdup (whole_left);
+ c->whole_word_chars_right = strdup (whole_right);
+ } else if (!strcmp (*a, "wholeleft")) {
+ a++;
+ c->whole_word_chars_left = strdup (whole_left);
+ } else if (!strcmp (*a, "wholeright")) {
+ a++;
+ c->whole_word_chars_right = strdup (whole_right);
+ }
+ check_a;
+ if (!strcmp (*a, "linestart")) {
+ a++;
+ c->line_start_left = 1;
+ }
+ check_a;
+ c->left = strdup (*a++);
+ check_a;
+ if (!strcmp (*a, "linestart")) {
+ a++;
+ c->line_start_right = 1;
+ }
+ check_a;
+ c->right = strdup (*a++);
+ c->last_left = c->left[strlen (c->left) - 1];
+ c->last_right = c->right[strlen (c->right) - 1];
+ c->first_left = *c->left;
+ c->first_right = *c->right;
+ c->single_char = (strlen (c->right) == 1);
+ }
+ c->keyword = syntax_malloc (1024 * sizeof (struct key_word *));
+ num_words = 1;
+ c->keyword[0] = syntax_malloc (sizeof (struct key_word));
+ fg = *a;
+ if (*a)
+ a++;
+ bg = *a;
+ if (*a)
+ a++;
+#ifdef MIDNIGHT
+ c->keyword[0]->fg = try_alloc_color_pair (fg, bg);
+#else
+ c->keyword[0]->fg = allocate_color (fg);
+ c->keyword[0]->bg = allocate_color (bg);
+#endif
+ c->keyword[0]->keyword = strdup (" ");
+ check_not_a;
+ num_contexts++;
+ } else if (!strcmp (args[0], "keyword")) {
+ struct key_word *k;
+ if (num_words == -1)
+ *a = 0;
+ check_a;
+ k = r[num_contexts - 1]->keyword[num_words] = syntax_malloc (sizeof (struct key_word));
+ if (!strcmp (*a, "whole")) {
+ a++;
+ k->whole_word_chars_left = strdup (whole_left);
+ k->whole_word_chars_right = strdup (whole_right);
+ } else if (!strcmp (*a, "wholeleft")) {
+ a++;
+ k->whole_word_chars_left = strdup (whole_left);
+ } else if (!strcmp (*a, "wholeright")) {
+ a++;
+ k->whole_word_chars_right = strdup (whole_right);
+ }
+ check_a;
+ if (!strcmp (*a, "linestart")) {
+ a++;
+ k->line_start = 1;
+ }
+ check_a;
+ if (!strcmp (*a, "whole")) {
+ *a = 0;
+ check_a;
+ }
+ k->keyword = strdup (*a++);
+ k->last = k->keyword[strlen (k->keyword) - 1];
+ k->first = *k->keyword;
+ fg = *a;
+ if (*a)
+ a++;
+ bg = *a;
+ if (*a)
+ a++;
+#ifdef MIDNIGHT
+ k->fg = try_alloc_color_pair (fg, bg);
+#else
+ k->fg = allocate_color (fg);
+ k->bg = allocate_color (bg);
+#endif
+ check_not_a;
+ num_words++;
+ } else if (!strncmp (args[0], "#", 1)) {
+ /* do nothing for comment */
+ } else if (!strcmp (args[0], "file")) {
+ break;
+ } else { /* anything else is an error */
+ *a = 0;
+ check_a;
+ }
+ free_args (args);
+ syntax_free (l);
+ }
+ free_args (args);
+ syntax_free (l);
+
+ if (result)
+ return result;
+
+ if (num_contexts == -1) {
+ result = line;
+ return result;
+ }
+
+ for (i = 1; edit->rules[i]; i++) {
+ for (j = i + 1; edit->rules[j]; j++) {
+ if (strstr (edit->rules[j]->right, edit->rules[i]->right) && strcmp (edit->rules[i]->right, "\n")) {
+ unsigned char *s;
+ if (!edit->rules[i]->conflicts)
+ edit->rules[i]->conflicts = syntax_malloc (sizeof (unsigned char) * 260);
+ s = edit->rules[i]->conflicts;
+ s[strlen ((char *) s)] = (unsigned char) j;
+ }
+ }
+ }
+
+ return result;
+}
+
+void (*syntax_change_callback) (CWidget *) = 0;
+
+void edit_set_syntax_change_callback (void (*callback) (CWidget *))
+{
+ syntax_change_callback = callback;
+}
+
+void edit_free_syntax_rules (WEdit * edit)
+{
+ int i, j;
+ if (!edit)
+ return;
+ if (!edit->rules)
+ return;
+ syntax_free (edit->syntax_type);
+ if (syntax_change_callback)
+#ifdef MIDNIGHT
+ (*syntax_change_callback) (&edit->widget);
+#else
+ (*syntax_change_callback) (edit->widget);
+#endif
+ for (i = 0; edit->rules[i]; i++) {
+ if (edit->rules[i]->keyword) {
+ for (j = 0; edit->rules[i]->keyword[j]; j++) {
+ syntax_free (edit->rules[i]->keyword[j]->keyword);
+ syntax_free (edit->rules[i]->keyword[j]->whole_word_chars_left);
+ syntax_free (edit->rules[i]->keyword[j]->whole_word_chars_right);
+ syntax_free (edit->rules[i]->keyword[j]);
+ }
+ }
+ syntax_free (edit->rules[i]->conflicts);
+ syntax_free (edit->rules[i]->left);
+ syntax_free (edit->rules[i]->right);
+ syntax_free (edit->rules[i]->whole_word_chars_left);
+ syntax_free (edit->rules[i]->whole_word_chars_right);
+ syntax_free (edit->rules[i]->keyword);
+ syntax_free (edit->rules[i]);
+ }
+ syntax_free (edit->rules);
+}
+
+
+#ifdef MIDNIGHT
+
+char *syntax_text =
+"# Allowable colors for mc are\n"
+"# black\n"
+"# red\n"
+"# green\n"
+"# brown\n"
+"# blue\n"
+"# magenta\n"
+"# cyan\n"
+"# lightgray\n"
+"# gray\n"
+"# brightred\n"
+"# brightgreen\n"
+"# yellow\n"
+"# brightblue\n"
+"# brightmagenta\n"
+"# brightcyan\n"
+"# white\n"
+"\n"
+"file ..\\*\\\\.([chC]|CC|cxx|cc|cpp|CPP|CXX)$ C/C++\\sProgram\n"
+"context default\n"
+" keyword whole void yellow\n"
+" keyword whole int yellow\n"
+" keyword whole unsigned yellow\n"
+" keyword whole char yellow\n"
+" keyword whole long yellow\n"
+" keyword whole if yellow\n"
+" keyword whole for yellow\n"
+" keyword whole while yellow\n"
+" keyword whole do yellow\n"
+" keyword whole else yellow\n"
+" keyword whole double yellow\n"
+" keyword whole switch yellow\n"
+" keyword whole case yellow\n"
+" keyword whole default yellow\n"
+" keyword whole static yellow\n"
+" keyword whole extern yellow\n"
+" keyword whole struct yellow\n"
+" keyword whole typedef yellow\n"
+" keyword whole ... yellow\n"
+" keyword whole inline yellow\n"
+" keyword whole return yellow\n"
+" keyword '*' yellow\n"
+" keyword > yellow\n"
+" keyword < yellow\n"
+" keyword + yellow\n"
+" keyword - yellow\n"
+" keyword \\* yellow\n"
+" keyword / yellow\n"
+" keyword % yellow\n"
+" keyword = yellow\n"
+" keyword != yellow\n"
+" keyword == yellow\n"
+" keyword { brightcyan\n"
+" keyword } brightcyan\n"
+" keyword ( brightcyan\n"
+" keyword ) brightcyan\n"
+" keyword [ brightcyan\n"
+" keyword ] brightcyan\n"
+" keyword , brightcyan\n"
+" keyword : brightcyan\n"
+" keyword ; brightmagenta\n"
+"context /\\* \\*/ brown\n"
+"context linestart # \\n brightred\n"
+" keyword \\\\\\n yellow\n"
+" keyword /\\**\\*/ brown\n"
+" keyword \"*\" red\n"
+" keyword <*> red\n"
+"context \" \" green\n"
+" keyword %d yellow\n"
+" keyword %s yellow\n"
+" keyword %c yellow\n"
+" keyword %lu yellow\n"
+" keyword \\\\\" yellow\n";
+
+#else
+
+char *syntax_text =
+"file ..\\*\\\\.([chC]|CC|cxx|cc|cpp|CPP|CXX)$ C/C++\\sProgram\n"
+"context default\n"
+" keyword whole void 24\n"
+" keyword whole int 24\n"
+" keyword whole unsigned 24\n"
+" keyword whole char 24\n"
+" keyword whole long 24\n"
+" keyword whole if 24\n"
+" keyword whole for 24\n"
+" keyword whole while 24\n"
+" keyword whole do 24\n"
+" keyword whole else 24\n"
+" keyword whole double 24\n"
+" keyword whole switch 24\n"
+" keyword whole case 24\n"
+" keyword whole default 24\n"
+" keyword whole static 24\n"
+" keyword whole extern 24\n"
+" keyword whole struct 24\n"
+" keyword whole typedef 24\n"
+" keyword whole ... 24\n"
+" keyword whole inline 24\n"
+" keyword whole return 24\n"
+" keyword '*' 6\n"
+" keyword > 24\n"
+" keyword < 24\n"
+" keyword + 24\n"
+" keyword - 24\n"
+" keyword \\* 24\n"
+" keyword / 24\n"
+" keyword % 24\n"
+" keyword = 24\n"
+" keyword != 24\n"
+" keyword == 24\n"
+" keyword { 14\n"
+" keyword } 14\n"
+" keyword ( 15\n"
+" keyword ) 15\n"
+" keyword [ 14\n"
+" keyword ] 14\n"
+" keyword , 14\n"
+" keyword : 14\n"
+" keyword ; 19\n"
+"context /\\* \\*/ 22\n"
+"context linestart # \\n 18\n"
+" keyword \\\\\\n 24\n"
+" keyword /\\**\\*/ 22\n"
+" keyword \"*\" 19\n"
+" keyword <*> 19\n"
+"context \" \" 6\n"
+" keyword %d 24\n"
+" keyword %s 24\n"
+" keyword %c 24\n"
+" keyword %lu 24\n"
+" keyword \\\\\" 24\n"
+"file \\.\\* Help\\ssupport\\sother\\sfile\\stypes\n"
+"context default\n"
+"file \\.\\* by\\scoding\\srules\\sin\\s~/.cedit/syntax.\n"
+"context default\n"
+"file \\.\\* See\\sman/syntax\\sin\\sthe\\ssource\\sdistribution\n"
+"context default\n"
+"file \\.\\* and\\sconsult\\sthe\\sman\\spage.\n"
+"context default\n";
+
+#endif
+
+/* returns -1 on file error, line number on error in file syntax */
+static int edit_read_syntax_file (WEdit * edit, char **names, char *syntax_file, char *editor_file, char *type)
+{
+ FILE *f;
+ regex_t r;
+ regmatch_t pmatch[1];
+ char *args[1024], *l;
+ int line = 0;
+ int argc;
+ int result = 0;
+ int count = 0;
+
+ f = fopen (syntax_file, "r");
+ if (!f) {
+ f = fopen (syntax_file, "w");
+ if (!f)
+ return -1;
+ fprintf (f, "%s", syntax_text);
+ fclose (f);
+ f = fopen (syntax_file, "r");
+ if (!f)
+ return -1;
+ }
+ args[0] = 0;
+
+ for (;;) {
+ line++;
+ if (!read_one_line (&l, f))
+ break;
+ get_args (l, args, &argc);
+ if (!args[0]) {
+ } else if (!strcmp (args[0], "file")) {
+ if (!args[1] || !args[2]) {
+ result = line;
+ break;
+ }
+ if (regcomp (&r, args[1], REG_EXTENDED)) {
+ result = line;
+ break;
+ }
+ if (names) {
+ names[count++] = strdup (args[2]);
+ names[count] = 0;
+ } else if (type) {
+ if (!strcmp (type, args[2]))
+ goto found_type;
+ } else if (editor_file && edit) {
+ if (!regexec (&r, editor_file, 1, pmatch, 0)) {
+ int line_error;
+ found_type:
+ line_error = edit_read_syntax_rules (edit, f);
+ if (line_error)
+ result = line + line_error;
+ else {
+ syntax_free (edit->syntax_type);
+ edit->syntax_type = strdup (args[2]);
+ if (syntax_change_callback)
+#ifdef MIDNIGHT
+ (*syntax_change_callback) (&edit->widget);
+#else
+ (*syntax_change_callback) (edit->widget);
+#endif
+ }
+ break;
+ }
+ }
+ }
+ free_args (args);
+ syntax_free (l);
+ }
+ free_args (args);
+ syntax_free (l);
+
+ fclose (f);
+
+ return result;
+}
+
+/* loads rules into edit struct. one of edit or names must be zero. if
+ edit is zero, a list of types will be stored into name. type may be zero
+ in which case the type will be selected according to the filename. */
+void edit_load_syntax (WEdit * edit, char **names, char *type)
+{
+ int r;
+ char *f;
+
+ edit_free_syntax_rules (edit);
+
+#ifdef MIDNIGHT
+ if (!SLtt_Use_Ansi_Colors)
+ return;
+#endif
+
+ if (edit) {
+ if (!edit->filename)
+ return;
+ if (!*edit->filename)
+ return;
+ }
+ f = catstrs (home_dir, SYNTAX_FILE, 0);
+ r = edit_read_syntax_file (edit, names, f, edit ? edit->filename : 0, type);
+ if (r == -1) {
+ edit_free_syntax_rules (edit);
+ edit_error_dialog (_ (" Load syntax file "), _ (" File access error "));
+ return;
+ }
+ if (r) {
+ char s[80];
+ edit_free_syntax_rules (edit);
+ sprintf (s, _ (" Syntax error in file %s on line %d "), f, r);
+ edit_error_dialog (_ (" Load syntax file "), s);
+ return;
+ }
+}
+
+#else
+
+int option_syntax_highlighting = 0;
+
+void edit_load_syntax (WEdit * edit, char **names, char *type)
+{
+ return;
+}
+
+void edit_free_syntax_rules (WEdit * edit)
+{
+ return;
+}
+
+void edit_get_syntax_color (WEdit * edit, long byte_index, int *fg, int *bg)
+{
+ *fg = NORMAL_COLOR;
+}
+
+#endif /* !defined(MIDNIGHT) || defined(HAVE_SYNTAXH) */
+
+
diff --git a/src/ChangeLog b/src/ChangeLog
index a2b20c0b3..13f5ee438 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,32 @@
+Fri Apr 24 16:43:25 1998 Paul Sheer
+
+ * main.h, setup.c: editor_syntax_highlighting option added
+ for ini file.
+
+Fri Apr 24 14:54:06 1998 Paul Sheer
+
+ * syntax.c: added. this files reads ~/.cedit/mcsyntax and
+ processes generic rules for syntax highlighting of different
+ file types. Syntax highlighting does not store an attribute byte
+ for each byte of the edit buffer. Rather, it calculates colours
+ on the fly, with an optimised algorithm, as the text is being
+ rendered.
+
+ * edit.c, edit.h, editwidget.c, editdraw.c: changes to facilitate
+ syntax highlighting.
+
+ * editoptions.c: dialog box updated with a syntax highlighting
+ checkbox.
+
+ * slint.c: new function alloc_color_pair(). This allocates a new
+ color index. init_pair() itself now records the last colour index
+ so that colours can be added on to the end of the colour list
+ with alloc_color_pair().
+
+ * slint.c: new function try_alloc_color_pair() returns a new index
+ for a color with named fg and bg. Checks if that named colour
+ already exists before setting a new index.
+
1998-04-23 Miguel de Icaza
* user.c (execute_menu_command): Create temporary file exclusively
diff --git a/src/color.c b/src/color.c
index 5a5d56269..efd55cfec 100644
--- a/src/color.c
+++ b/src/color.c
@@ -58,13 +58,7 @@ void init_pair (int, CTYPE, CTYPE);
# define color_map_bg(n) color_map[n].bg
#endif
-struct colorpair {
- char *name; /* Name of the entry */
- CTYPE fg; /* foreground color */
- CTYPE bg; /* background color */
-};
-
-static struct colorpair color_map [] = {
+struct colorpair color_map [] = {
{ "normal=", 0, 0 }, /* normal */
{ "selected=", 0, 0 }, /* selected */
{ "marked=", 0, 0 }, /* marked */
diff --git a/src/color.h b/src/color.h
index 56a3b8dc0..249fb4816 100644
--- a/src/color.h
+++ b/src/color.h
@@ -11,6 +11,12 @@ extern int disable_colors;
extern int attr_pairs [];
+struct colorpair {
+ char *name; /* Name of the entry */
+ char *fg; /* foreground color */
+ char *bg; /* background color */
+};
+
#ifdef HAVE_GNOME
# define MY_COLOR_PAIR(x) x
# define PORT_COLOR(co,bw) co
diff --git a/src/main.h b/src/main.h
index ac07e05d5..2d919c337 100644
--- a/src/main.h
+++ b/src/main.h
@@ -58,6 +58,7 @@ extern int option_backup_ext_int;
extern int option_auto_para_formatting;
extern int option_typewriter_wrap;
extern int edit_confirm_save;
+extern int option_syntax_highlighting;
#endif /* ! USE_INTERNAL_EDIT */
extern int fast_reload_w;
extern int clear_before_exec;
diff --git a/src/setup.c b/src/setup.c
index 2a25fdf95..51958ea70 100644
--- a/src/setup.c
+++ b/src/setup.c
@@ -222,6 +222,7 @@ static struct {
{ "editor_option_auto_para_formatting", &option_auto_para_formatting },
{ "editor_option_typewriter_wrap", &option_typewriter_wrap },
{ "editor_edit_confirm_save", &edit_confirm_save },
+ { "editor_syntax_highlighting", &option_syntax_highlighting },
#endif
#ifdef HAVE_GNOME
diff --git a/src/slint.c b/src/slint.c
index 78d02d0ab..e983d0129 100644
--- a/src/slint.c
+++ b/src/slint.c
@@ -335,10 +335,57 @@ vline (int character, int len)
}
}
+int max_index = 0;
+
void
init_pair (int index, char *foreground, char *background)
{
+
SLtt_set_color (index, "", foreground, background);
+ if (index > max_index)
+ max_index = index;
+}
+
+int
+alloc_color_pair (char *foreground, char *background)
+{
+ init_pair (++max_index, foreground, background);
+ return max_index;
+}
+
+int
+try_alloc_color_pair (char *fg, char *bg)
+{
+ static struct colors_avail {
+ struct colors_avail *next;
+ char *fg, *bg;
+ int index;
+ } *p, c =
+ {
+ 0, 0, 0, 0
+ };
+
+ c.index = NORMAL_COLOR;
+ p = &c;
+ for (;;) {
+ if (((fg && p->fg) ? !strcmp (fg, p->fg) : fg == p->fg) != 0
+ && ((bg && p->bg) ? !strcmp (bg, p->bg) : bg == p->bg) != 0)
+ return p->index;
+ if (!p->next)
+ break;
+ p = p->next;
+ }
+ p->next = malloc (sizeof (c));
+ p = p->next;
+ p->next = 0;
+ p->fg = fg ? strdup (fg) : 0;
+ p->bg = bg ? strdup (bg) : 0;
+ if (!fg)
+ fg = "white";
+ if (!bg)
+ bg = "blue";
+ p->index = alloc_color_pair (fg, bg);
+ return p->index;
}
char *color_terminals [] = {