Browse Source

editor updated to reflect cooledit-3.6.0
syntax highlighting added and doc files updated

Paul Sheer 27 years ago
parent
commit
38a912e1e2
10 changed files with 1497 additions and 113 deletions
  1. 7 6
      doc/mc.sgml
  2. 153 21
      doc/mcedit.1.in
  3. 2 2
      edit/Makefile.in
  4. 72 2
      edit/edit.h
  5. 8 4
      edit/editcmd.c
  6. 35 22
      edit/editdraw.c
  7. 43 30
      edit/editoptions.c
  8. 108 26
      edit/editwidget.c
  9. 1040 0
      edit/syntax.c
  10. 29 0
      src/ChangeLog

+ 7 - 6
doc/mc.sgml

@@ -1932,7 +1932,7 @@ menus; file insertion; <bf>macro definition</bf>; <bf>regular expression</bf>
 search and replace (and our own scanf-printf search and
 replace); <bf>shift-arrow MSW-MAC text highlighting</bf> (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.
 
 <p>
@@ -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. <bf>Ctrl-Ins</bf> copies to the file
-<bf>cedit/cooledit.clip</bf> and <bf>Shift-Ins</bf>
-pastes from <bf>cedit/cooledit.clip</bf>.
-<bf>Shift-Del</bf> cuts to <bf>cedit/cooledit.clip</bf>, and
+<bf>.cedit/cooledit.clip</bf> and <bf>Shift-Ins</bf>
+pastes from <bf>.cedit/cooledit.clip</bf>.
+<bf>Shift-Del</bf> cuts to <bf>.cedit/cooledit.clip</bf>, and
 <bf>Ctrl-Del</bf> 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 <bf>Ctrl-A</bf> 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 <bf>cedit/cooledit.macros</bf> in your home directory.
+file <bf>.cedit/cooledit.macros</bf> 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 <bf>display bits</bf> to 7 bits in the
 options menu to keep the spacing clean.
 
 <p>
-See also the <bf>mcedit.1</bf> man page for lots more information.
+See also the <bf>mcedit.1</bf> 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.
 

+ 153 - 21
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.

+ 2 - 2
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)
 

+ 72 - 2
edit/edit.h

@@ -3,6 +3,10 @@
 
 #ifdef MIDNIGHT
 
+#ifdef HAVE_SLANG
+#define HAVE_SYNTAXH 1
+#endif
+
 #    include <stdio.h>
 #    include <stdarg.h>
 #    include <sys/types.h>
@@ -21,7 +25,7 @@
 #    include <stdlib.h>
 #    include <malloc.h>
 
-#else
+#else       /* ! MIDNIGHT */
 
 #    include "global.h"
 #    include <stdio.h>
@@ -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 */

+ 8 - 4
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};
 

+ 35 - 22
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);
 }
 
 

+ 43 - 30
edit/editoptions.c

@@ -21,7 +21,7 @@
 #include <config.h>
 #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;
-
-	    if (*quick_widgets[11].result == 1) {
+	    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 + 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 {

+ 108 - 26
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 <nation@rocket.sanders.lockheed.com> &
@@ -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)

+ 1040 - 0
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 <config.h>
+#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) */
+
+

+ 29 - 0
src/ChangeLog

@@ -1,3 +1,32 @@
+Fri Apr 24 16:43:25 1998  Paul Sheer  <psheer@obsidian.co.za>
+
+	* main.h, setup.c: editor_syntax_highlighting option added
+	for ini file.
+
+Fri Apr 24 14:54:06 1998  Paul Sheer  <psheer@obsidian.co.za>
+
+	* 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  <miguel@nuclecu.unam.mx>
 
 	* user.c (execute_menu_command): Create temporary file exclusively

Some files were not shown because too many files changed in this diff