2 Editor syntax highlighting.
4 Copyright (C) 1996, 1997, 1998, 2001, 2002, 2003, 2004, 2005, 2006,
6 The Free Software Foundation, Inc.
10 Egmont Koblinger <egmont@gmail.com>, 2010
11 Slava Zanko <slavazanko@gmail.com>, 2013
12 Andrew Borodin <aborodin@vmail.ru>, 2013
14 This file is part of the Midnight Commander.
16 The Midnight Commander is free software: you can redistribute it
17 and/or modify it under the terms of the GNU General Public License as
18 published by the Free Software Foundation, either version 3 of the License,
19 or (at your option) any later version.
21 The Midnight Commander is distributed in the hope that it will be useful,
22 but WITHOUT ANY WARRANTY; without even the implied warranty of
23 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 GNU General Public License for more details.
26 You should have received a copy of the GNU General Public License
27 along with this program. If not, see <http://www.gnu.org/licenses/>.
31 * \brief Source: editor syntax highlighting
34 * \author Mikhail Pobolovets
37 * Mispelled words are flushed from the syntax highlighting rules
38 * when they have been around longer than
39 * TRANSIENT_WORD_TIME_OUT seconds. At a cursor rate of 30
40 * chars per second and say 3 chars + a space per word, we can
41 * accumulate 450 words absolute max with a value of 60. This is
42 * below this limit of 1024 words in a context.
49 #include <sys/types.h>
57 #include "lib/global.h"
58 #include "lib/search.h" /* search engine */
60 #include "lib/strutil.h" /* utf string functions */
62 #include "lib/widget.h" /* message() */
64 #include "edit-impl.h"
65 #include "editwidget.h"
67 /*** global variables ****************************************************************************/
69 int option_syntax_highlighting
= 1;
70 int option_auto_syntax
= 1;
72 /*** file scope macro definitions ****************************************************************/
75 #define SYNTAX_MARKER_DENSITY 512
77 #define TRANSIENT_WORD_TIME_OUT 60
79 #define UNKNOWN_FORMAT "unknown"
81 #define MAX_WORDS_PER_CONTEXT 1024
82 #define MAX_CONTEXTS 128
84 #define RULE_ON_LEFT_BORDER 1
85 #define RULE_ON_RIGHT_BORDER 2
87 #define SYNTAX_TOKEN_STAR '\001'
88 #define SYNTAX_TOKEN_PLUS '\002'
89 #define SYNTAX_TOKEN_BRACKET '\003'
90 #define SYNTAX_TOKEN_BRACE '\004'
92 #define whiteness(x) ((x) == '\t' || (x) == '\n' || (x) == ' ')
95 #define break_a {result=line;break;}
96 #define check_a {if(!*a){result=line;break;}}
97 #define check_not_a {if(*a){result=line;break;}}
99 /*** file scope type declarations ****************************************************************/
105 char *whole_word_chars_left
;
106 char *whole_word_chars_right
;
114 unsigned char first_left
;
116 unsigned char first_right
;
117 char line_start_left
;
118 char line_start_right
;
119 int between_delimiters
;
120 char *whole_word_chars_left
;
121 char *whole_word_chars_right
;
122 char *keyword_first_chars
;
124 /* first word is word[1] */
125 struct key_word
**keyword
;
131 edit_syntax_rule_t rule
;
134 /*** file scope variables ************************************************************************/
136 static char *error_file_name
= NULL
;
138 /*** file scope functions ************************************************************************/
139 /* --------------------------------------------------------------------------------------------- */
142 mc_defines_destroy (gpointer key
, gpointer value
, gpointer data
)
147 g_strfreev ((char **) value
);
152 /* --------------------------------------------------------------------------------------------- */
153 /** Completely destroys the defines tree */
156 destroy_defines (GTree
** defines
)
158 g_tree_foreach (*defines
, mc_defines_destroy
, NULL
);
159 g_tree_destroy (*defines
);
163 /* --------------------------------------------------------------------------------------------- */
165 /** Wrapper for case insensitive mode */
167 xx_tolower (const WEdit
* edit
, int c
)
169 return edit
->is_case_insensitive
? tolower (c
) : c
;
172 /* --------------------------------------------------------------------------------------------- */
175 subst_defines (GTree
* defines
, char **argv
, char **argv_end
)
180 while (*argv
!= NULL
&& argv
< argv_end
)
182 t
= g_tree_lookup (defines
, *argv
);
187 /* Count argv array members */
189 for (p
= &argv
[1]; *p
!= NULL
; p
++)
192 /* Count members of definition array */
193 for (p
= t
; *p
!= NULL
; p
++)
195 p
= &argv
[count
+ argc
];
197 /* Buffer overflow or infinitive loop in define */
201 /* Move rest of argv after definition members */
203 *p
-- = argv
[argc
-- + 1];
205 /* Copy definition members to argv */
206 for (p
= argv
; *t
!= NULL
; *p
++ = *t
++)
213 /* --------------------------------------------------------------------------------------------- */
216 compare_word_to_right (const WEdit
* edit
, off_t i
, const char *text
,
217 const char *whole_left
, const char *whole_right
, long line_start
)
219 const unsigned char *p
, *q
;
225 c
= xx_tolower (edit
, edit_buffer_get_byte (&edit
->buffer
, i
- 1));
226 if ((line_start
!= 0 && c
!= '\n') || (whole_left
!= NULL
&& strchr (whole_left
, c
) != NULL
))
229 for (p
= (unsigned char *) text
, q
= p
+ strlen ((char *) p
); p
< q
; p
++, i
++)
233 case SYNTAX_TOKEN_STAR
:
238 c
= xx_tolower (edit
, edit_buffer_get_byte (&edit
->buffer
, i
));
239 if (*p
== '\0' && whole_right
!= NULL
&& strchr (whole_right
, c
) == NULL
)
248 case SYNTAX_TOKEN_PLUS
:
254 c
= xx_tolower (edit
, edit_buffer_get_byte (&edit
->buffer
, i
));
258 if (*p
== *text
&& p
[1] == '\0') /* handle eg '+' and @+@ keywords properly */
261 if (j
!= 0 && strchr ((char *) p
+ 1, c
) != NULL
) /* c exists further down, so it will get matched later */
263 if (c
== '\n' || c
== '\t' || c
== ' ' ||
264 (whole_right
!= NULL
&& strchr (whole_right
, c
) == NULL
))
279 case SYNTAX_TOKEN_BRACKET
:
286 c
= xx_tolower (edit
, edit_buffer_get_byte (&edit
->buffer
, i
));
287 for (j
= 0; p
[j
] != SYNTAX_TOKEN_BRACKET
&& p
[j
]; j
++)
295 while (*p
!= SYNTAX_TOKEN_BRACKET
&& p
<= q
)
302 case SYNTAX_TOKEN_BRACE
:
305 c
= xx_tolower (edit
, edit_buffer_get_byte (&edit
->buffer
, i
));
306 for (; *p
!= SYNTAX_TOKEN_BRACE
&& *p
; p
++)
311 while (*p
!= SYNTAX_TOKEN_BRACE
&& p
< q
)
315 if (*p
!= xx_tolower (edit
, edit_buffer_get_byte (&edit
->buffer
, i
)))
319 return (whole_right
!= NULL
&&
321 xx_tolower (edit
, edit_buffer_get_byte (&edit
->buffer
, i
))) != NULL
) ? -1 : i
;
324 /* --------------------------------------------------------------------------------------------- */
327 xx_strchr (const WEdit
* edit
, const unsigned char *s
, int char_byte
)
329 while (*s
>= '\005' && xx_tolower (edit
, *s
) != char_byte
)
332 return (const char *) s
;
335 /* --------------------------------------------------------------------------------------------- */
338 apply_rules_going_right (WEdit
* edit
, off_t i
)
340 struct context_rule
*r
;
342 gboolean contextchanged
= FALSE
;
343 gboolean found_left
= FALSE
, found_right
= FALSE
;
344 gboolean keyword_foundleft
= FALSE
, keyword_foundright
= FALSE
;
347 edit_syntax_rule_t _rule
= edit
->rule
;
349 c
= xx_tolower (edit
, edit_buffer_get_byte (&edit
->buffer
, i
));
353 is_end
= (edit
->rule
.end
== i
);
355 /* check to turn off a keyword */
356 if (_rule
.keyword
!= 0)
358 if (edit_buffer_get_byte (&edit
->buffer
, i
- 1) == '\n')
363 keyword_foundleft
= TRUE
;
367 /* check to turn off a context */
368 if (_rule
.context
!= 0 && _rule
.keyword
== 0)
372 r
= edit
->rules
[_rule
.context
];
373 if (r
->first_right
== c
&& (edit
->rule
.border
& RULE_ON_RIGHT_BORDER
) == 0
375 compare_word_to_right (edit
, i
, r
->right
, r
->whole_word_chars_left
,
376 r
->whole_word_chars_right
, r
->line_start_right
)) > 0)
380 _rule
.border
= RULE_ON_RIGHT_BORDER
;
381 if (r
->between_delimiters
)
384 else if (is_end
&& (edit
->rule
.border
& RULE_ON_RIGHT_BORDER
) != 0)
386 /* always turn off a context at 4 */
389 if (!keyword_foundleft
)
392 else if (is_end
&& (edit
->rule
.border
& RULE_ON_LEFT_BORDER
) != 0)
394 /* never turn off a context at 2 */
400 /* check to turn on a keyword */
401 if (_rule
.keyword
== 0)
405 r
= edit
->rules
[_rule
.context
];
406 p
= r
->keyword_first_chars
;
409 while (*(p
= xx_strchr (edit
, (unsigned char *) p
+ 1, c
)) != '\0')
415 count
= p
- r
->keyword_first_chars
;
416 k
= r
->keyword
[count
];
417 e
= compare_word_to_right (edit
, i
, k
->keyword
, k
->whole_word_chars_left
,
418 k
->whole_word_chars_right
, k
->line_start
);
423 _rule
.keyword
= count
;
424 keyword_foundright
= TRUE
;
430 /* check to turn on a context */
431 if (_rule
.context
== 0)
433 if (!found_left
&& is_end
)
435 if ((edit
->rule
.border
& RULE_ON_RIGHT_BORDER
) != 0)
439 contextchanged
= TRUE
;
443 else if ((edit
->rule
.border
& RULE_ON_LEFT_BORDER
) != 0)
445 r
= edit
->rules
[_rule
._context
];
447 if (r
->between_delimiters
)
449 _rule
.context
= _rule
._context
;
450 contextchanged
= TRUE
;
453 if (r
->first_right
== c
)
457 e
= compare_word_to_right (edit
, i
, r
->right
, r
->whole_word_chars_left
,
458 r
->whole_word_chars_right
, r
->line_start_right
);
463 _rule
.border
= RULE_ON_RIGHT_BORDER
;
474 struct context_rule
**rules
= edit
->rules
;
476 for (count
= 1; rules
[count
] != NULL
; count
++)
479 if (r
->first_left
== c
)
483 e
= compare_word_to_right (edit
, i
, r
->left
, r
->whole_word_chars_left
,
484 r
->whole_word_chars_right
, r
->line_start_left
);
485 if (e
>= end
&& (_rule
.keyword
== 0 || keyword_foundright
))
489 _rule
.border
= RULE_ON_LEFT_BORDER
;
490 _rule
._context
= count
;
491 if (!r
->between_delimiters
&& _rule
.keyword
== 0)
493 _rule
.context
= count
;
494 contextchanged
= TRUE
;
503 /* check again to turn on a keyword if the context switched */
504 if (contextchanged
&& _rule
.keyword
== 0)
508 r
= edit
->rules
[_rule
.context
];
509 p
= r
->keyword_first_chars
;
511 while (*(p
= xx_strchr (edit
, (unsigned char *) p
+ 1, c
)) != '\0')
517 count
= p
- r
->keyword_first_chars
;
518 k
= r
->keyword
[count
];
519 e
= compare_word_to_right (edit
, i
, k
->keyword
, k
->whole_word_chars_left
,
520 k
->whole_word_chars_right
, k
->line_start
);
524 _rule
.keyword
= count
;
533 /* --------------------------------------------------------------------------------------------- */
536 edit_get_rule (WEdit
* edit
, off_t byte_index
)
540 if (byte_index
> edit
->last_get_rule
)
542 for (i
= edit
->last_get_rule
+ 1; i
<= byte_index
; i
++)
544 off_t d
= SYNTAX_MARKER_DENSITY
;
546 apply_rules_going_right (edit
, i
);
548 if (edit
->syntax_marker
!= NULL
)
549 d
+= ((syntax_marker_t
*) edit
->syntax_marker
->data
)->offset
;
555 s
= g_new (syntax_marker_t
, 1);
557 s
->rule
= edit
->rule
;
558 edit
->syntax_marker
= g_slist_prepend (edit
->syntax_marker
, s
);
562 else if (byte_index
< edit
->last_get_rule
)
568 if (edit
->syntax_marker
== NULL
)
570 memset (&edit
->rule
, 0, sizeof (edit
->rule
));
571 for (i
= -1; i
<= byte_index
; i
++)
572 apply_rules_going_right (edit
, i
);
576 s
= (syntax_marker_t
*) edit
->syntax_marker
->data
;
578 if (byte_index
>= s
->offset
)
580 edit
->rule
= s
->rule
;
581 for (i
= s
->offset
+ 1; i
<= byte_index
; i
++)
582 apply_rules_going_right (edit
, i
);
587 edit
->syntax_marker
= g_slist_delete_link (edit
->syntax_marker
, edit
->syntax_marker
);
590 edit
->last_get_rule
= byte_index
;
593 /* --------------------------------------------------------------------------------------------- */
596 translate_rule_to_color (const WEdit
* edit
, const edit_syntax_rule_t
* rule
)
598 return edit
->rules
[rule
->context
]->keyword
[rule
->keyword
]->color
;
601 /* --------------------------------------------------------------------------------------------- */
603 Returns 0 on error/eof or a count of the number of bytes read
604 including the newline. Result must be free'd.
605 In case of an error, *line will not be modified.
609 read_one_line (char **line
, FILE * f
)
614 /* not reallocate string too often */
615 p
= g_string_sized_new (64);
634 /* handle all of \r\n, \r, \n correctly. */
647 g_string_append_c (p
, c
);
650 *line
= g_string_free (p
, FALSE
);
652 g_string_free (p
, TRUE
);
657 /* --------------------------------------------------------------------------------------------- */
697 *p
= SYNTAX_TOKEN_BRACKET
;
701 *p
= SYNTAX_TOKEN_BRACE
;
712 *p
= SYNTAX_TOKEN_STAR
;
715 *p
= SYNTAX_TOKEN_PLUS
;
728 /* --------------------------------------------------------------------------------------------- */
731 get_args (char *l
, char **args
, int args_size
)
735 while (argc
< args_size
)
738 while (*p
!= '\0' && whiteness (*p
))
742 for (l
= p
+ 1; *l
!= '\0' && !whiteness (*l
); l
++)
746 args
[argc
++] = convert (p
);
748 args
[argc
] = (char *) NULL
;
752 /* --------------------------------------------------------------------------------------------- */
755 this_try_alloc_color_pair (const char *fg
, const char *bg
, const char *attrs
)
757 char f
[80], b
[80], a
[80], *p
;
759 if (bg
!= NULL
&& *bg
== '\0')
761 if (fg
!= NULL
&& *fg
== '\0')
763 if (attrs
!= NULL
&& *attrs
== '\0')
766 if ((fg
== NULL
) && (bg
== NULL
))
767 return EDITOR_NORMAL_COLOR
;
771 g_strlcpy (f
, fg
, sizeof (f
));
779 g_strlcpy (b
, bg
, sizeof (b
));
785 if ((fg
== NULL
) || (bg
== NULL
))
787 /* get colors from skin */
790 editnormal
= mc_skin_get ("editor", "_default_", "default;default");
794 g_strlcpy (f
, editnormal
, sizeof (f
));
799 g_strlcpy (f
, "default", sizeof (f
));
804 p
= strchr (editnormal
, ';');
805 if ((p
!= NULL
) && (*(++p
) != '\0'))
806 g_strlcpy (b
, p
, sizeof (b
));
808 g_strlcpy (b
, "default", sizeof (b
));
817 g_strlcpy (a
, attrs
, sizeof (a
));
821 /* get_args() mangles the + signs, unmangle 'em */
823 while ((p
= strchr (p
, SYNTAX_TOKEN_PLUS
)) != NULL
)
827 return tty_try_alloc_color_pair (fg
, bg
, attrs
);
830 /* --------------------------------------------------------------------------------------------- */
833 open_include_file (const char *filename
)
837 MC_PTR_FREE (error_file_name
);
838 error_file_name
= g_strdup (filename
);
839 if (g_path_is_absolute (filename
))
840 return fopen (filename
, "r");
842 g_free (error_file_name
);
844 g_build_filename (mc_config_get_data_path (), EDIT_DIR
, filename
, (char *) NULL
);
845 f
= fopen (error_file_name
, "r");
849 g_free (error_file_name
);
850 error_file_name
= g_build_filename (mc_global
.sysconfig_dir
, "syntax", filename
, (char *) NULL
);
851 f
= fopen (error_file_name
, "r");
855 g_free (error_file_name
);
857 g_build_filename (mc_global
.share_data_dir
, "syntax", filename
, (char *) NULL
);
859 return fopen (error_file_name
, "r");
862 /* --------------------------------------------------------------------------------------------- */
865 xx_lowerize_line (WEdit
* edit
, char *line
, size_t len
)
867 if (edit
->is_case_insensitive
)
870 for (i
= 0; i
< len
; ++i
)
871 line
[i
] = tolower (line
[i
]);
875 /* --------------------------------------------------------------------------------------------- */
876 /** returns line number on error */
879 edit_read_syntax_rules (WEdit
* edit
, FILE * f
, char **args
, int args_size
)
882 char *fg
, *bg
, *attrs
;
883 char last_fg
[32] = "", last_bg
[32] = "", last_attrs
[64] = "";
884 char whole_right
[512];
885 char whole_left
[512];
887 int save_line
= 0, line
= 0;
888 struct context_rule
**r
, *c
= NULL
;
889 int num_words
= -1, num_contexts
= -1;
891 int alloc_contexts
= MAX_CONTEXTS
,
892 alloc_words_per_context
= MAX_WORDS_PER_CONTEXT
,
893 max_alloc_words_per_context
= MAX_WORDS_PER_CONTEXT
;
896 edit
->is_case_insensitive
= FALSE
;
898 strcpy (whole_left
, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_01234567890");
899 strcpy (whole_right
, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_01234567890");
901 r
= edit
->rules
= g_malloc0 (alloc_contexts
* sizeof (struct context_rule
*));
904 edit
->defines
= g_tree_new ((GCompareFunc
) strcmp
);
915 len
= read_one_line (&l
, f
);
917 xx_lowerize_line (edit
, l
, len
);
926 line
= save_line
+ 1;
927 MC_PTR_FREE (error_file_name
);
929 len
= read_one_line (&l
, f
);
932 xx_lowerize_line (edit
, l
, len
);
935 argc
= get_args (l
, args
, args_size
);
941 else if (strcmp (args
[0], "include") == 0)
943 if (g
!= NULL
|| argc
!= 2)
949 f
= open_include_file (args
[1]);
952 MC_PTR_FREE (error_file_name
);
959 else if (strcmp (args
[0], "caseinsensitive") == 0)
961 edit
->is_case_insensitive
= TRUE
;
963 else if (strcmp (args
[0], "wholechars") == 0)
966 if (strcmp (*a
, "left") == 0)
969 g_strlcpy (whole_left
, *a
, sizeof (whole_left
));
971 else if (strcmp (*a
, "right") == 0)
974 g_strlcpy (whole_right
, *a
, sizeof (whole_right
));
978 g_strlcpy (whole_left
, *a
, sizeof (whole_left
));
979 g_strlcpy (whole_right
, *a
, sizeof (whole_right
));
984 else if (strcmp (args
[0], "context") == 0)
987 if (num_contexts
== -1)
989 if (strcmp (*a
, "default") != 0)
990 { /* first context is the default */
994 c
= r
[0] = g_malloc0 (sizeof (struct context_rule
));
995 c
->left
= g_strdup (" ");
996 c
->right
= g_strdup (" ");
1001 /* Terminate previous context. */
1002 r
[num_contexts
- 1]->keyword
[num_words
] = NULL
;
1003 c
= r
[num_contexts
] = g_malloc0 (sizeof (struct context_rule
));
1004 if (strcmp (*a
, "exclusive") == 0)
1007 c
->between_delimiters
= 1;
1010 if (strcmp (*a
, "whole") == 0)
1013 c
->whole_word_chars_left
= g_strdup (whole_left
);
1014 c
->whole_word_chars_right
= g_strdup (whole_right
);
1016 else if (strcmp (*a
, "wholeleft") == 0)
1019 c
->whole_word_chars_left
= g_strdup (whole_left
);
1021 else if (strcmp (*a
, "wholeright") == 0)
1024 c
->whole_word_chars_right
= g_strdup (whole_right
);
1027 if (strcmp (*a
, "linestart") == 0)
1030 c
->line_start_left
= 1;
1033 c
->left
= g_strdup (*a
++);
1035 if (strcmp (*a
, "linestart") == 0)
1038 c
->line_start_right
= 1;
1041 c
->right
= g_strdup (*a
++);
1042 c
->first_left
= *c
->left
;
1043 c
->first_right
= *c
->right
;
1045 c
->keyword
= g_malloc (alloc_words_per_context
* sizeof (struct key_word
*));
1047 c
->keyword
[0] = g_malloc0 (sizeof (struct key_word
));
1048 subst_defines (edit
->defines
, a
, &args
[1024]);
1058 g_strlcpy (last_fg
, fg
!= NULL
? fg
: "", sizeof (last_fg
));
1059 g_strlcpy (last_bg
, bg
!= NULL
? bg
: "", sizeof (last_bg
));
1060 g_strlcpy (last_attrs
, attrs
!= NULL
? attrs
: "", sizeof (last_attrs
));
1061 c
->keyword
[0]->color
= this_try_alloc_color_pair (fg
, bg
, attrs
);
1062 c
->keyword
[0]->keyword
= g_strdup (" ");
1065 alloc_words_per_context
= MAX_WORDS_PER_CONTEXT
;
1066 if (++num_contexts
>= alloc_contexts
)
1068 struct context_rule
**tmp
;
1070 alloc_contexts
+= 128;
1071 tmp
= g_realloc (r
, alloc_contexts
* sizeof (struct context_rule
*));
1075 else if (strcmp (args
[0], "spellcheck") == 0)
1084 else if (strcmp (args
[0], "keyword") == 0)
1088 if (num_words
== -1)
1091 k
= r
[num_contexts
- 1]->keyword
[num_words
] = g_malloc0 (sizeof (struct key_word
));
1092 if (strcmp (*a
, "whole") == 0)
1095 k
->whole_word_chars_left
= g_strdup (whole_left
);
1096 k
->whole_word_chars_right
= g_strdup (whole_right
);
1098 else if (strcmp (*a
, "wholeleft") == 0)
1101 k
->whole_word_chars_left
= g_strdup (whole_left
);
1103 else if (strcmp (*a
, "wholeright") == 0)
1106 k
->whole_word_chars_right
= g_strdup (whole_right
);
1109 if (strcmp (*a
, "linestart") == 0)
1115 if (strcmp (*a
, "whole") == 0)
1119 k
->keyword
= g_strdup (*a
++);
1120 k
->first
= *k
->keyword
;
1121 subst_defines (edit
->defines
, a
, &args
[1024]);
1137 k
->color
= this_try_alloc_color_pair (fg
, bg
, attrs
);
1140 if (++num_words
>= alloc_words_per_context
)
1142 struct key_word
**tmp
;
1144 alloc_words_per_context
+= 1024;
1146 if (alloc_words_per_context
> max_alloc_words_per_context
)
1147 max_alloc_words_per_context
= alloc_words_per_context
;
1149 tmp
= g_realloc (c
->keyword
, alloc_words_per_context
* sizeof (struct key_word
*));
1153 else if (*(args
[0]) == '#')
1155 /* do nothing for comment */
1157 else if (strcmp (args
[0], "file") == 0)
1161 else if (strcmp (args
[0], "define") == 0)
1168 argv
= g_tree_lookup (edit
->defines
, key
);
1170 mc_defines_destroy (NULL
, argv
, NULL
);
1172 key
= g_strdup (key
);
1174 argv
= g_new (char *, argc
- 1);
1175 g_tree_insert (edit
->defines
, key
, argv
);
1177 *argv
++ = g_strdup (*a
++);
1181 { /* anything else is an error */
1190 /* Terminate context array. */
1191 if (num_contexts
> 0)
1193 r
[num_contexts
- 1]->keyword
[num_words
] = NULL
;
1194 r
[num_contexts
] = NULL
;
1197 if (edit
->rules
[0] == NULL
)
1198 MC_PTR_FREE (edit
->rules
);
1205 if (num_contexts
== -1)
1208 first_chars
= g_malloc0 (max_alloc_words_per_context
+ 2);
1210 for (i
= 0; edit
->rules
[i
] != NULL
; i
++)
1218 for (j
= 1; c
->keyword
[j
] != NULL
; j
++)
1219 *p
++ = c
->keyword
[j
]->first
;
1221 c
->keyword_first_chars
= g_strdup (first_chars
);
1224 g_free (first_chars
);
1230 /* --------------------------------------------------------------------------------------------- */
1232 /* returns -1 on file error, line number on error in file syntax */
1234 edit_read_syntax_file (WEdit
* edit
, char ***pnames
, const char *syntax_file
,
1235 const char *editor_file
, const char *first_line
, const char *type
)
1239 char *args
[1024], *l
= NULL
;
1244 gboolean found
= FALSE
;
1245 char **tmpnames
= NULL
;
1247 f
= fopen (syntax_file
, "r");
1250 lib_file
= g_build_filename (mc_global
.share_data_dir
, "syntax", "Syntax", (char *) NULL
);
1251 f
= fopen (lib_file
, "r");
1262 if (read_one_line (&l
, f
) == 0)
1264 (void) get_args (l
, args
, 1023); /* Final NULL */
1265 if (args
[0] == NULL
)
1268 /* Looking for 'include ...' lines before first 'file ...' ones */
1269 if (!found
&& strcmp (args
[0], "include") == 0)
1274 if (!args
[1] || !(g
= open_include_file (args
[1])))
1282 /* looking for 'file ...' lines only */
1283 if (strcmp (args
[0], "file") != 0)
1288 /* must have two args or report error */
1289 if (!args
[1] || !args
[2])
1294 if (pnames
&& *pnames
)
1296 /* 1: just collecting a list of names of rule sets */
1297 /* Reallocate the list if required */
1298 if (count
% NENTRIES
== 0)
1301 (char **) g_try_realloc (*pnames
, (count
+ NENTRIES
+ 1) * sizeof (char *));
1302 if (tmpnames
== NULL
)
1306 (*pnames
)[count
++] = g_strdup (args
[2]);
1307 (*pnames
)[count
] = NULL
;
1311 /* 2: rule set was explicitly specified by the caller */
1312 if (strcmp (type
, args
[2]) == 0)
1315 else if (editor_file
&& edit
)
1317 /* 3: auto-detect rule set from regular expressions */
1320 q
= mc_search (args
[1], DEFAULT_CHARSET
, editor_file
, MC_SEARCH_T_REGEX
);
1321 /* does filename match arg 1 ? */
1324 /* does first line match arg 3 ? */
1325 q
= mc_search (args
[3], DEFAULT_CHARSET
, first_line
, MC_SEARCH_T_REGEX
);
1332 syntax_type
= args
[2];
1333 line_error
= edit_read_syntax_rules (edit
, g
? g
: f
, args
, 1023);
1336 if (!error_file_name
) /* an included file */
1337 result
= line
+ line_error
;
1339 result
= line_error
;
1343 g_free (edit
->syntax_type
);
1344 edit
->syntax_type
= g_strdup (syntax_type
);
1345 /* if there are no rules then turn off syntax highlighting for speed */
1346 if (!g
&& !edit
->rules
[1])
1347 if (!edit
->rules
[0]->keyword
[1] && !edit
->rules
[0]->spelling
)
1349 edit_free_syntax_rules (edit
);
1367 /* --------------------------------------------------------------------------------------------- */
1370 get_first_editor_line (WEdit
* edit
)
1380 for (i
= 0; i
< sizeof (s
) - 1; i
++)
1382 s
[i
] = edit_buffer_get_byte (&edit
->buffer
, i
);
1390 s
[sizeof (s
) - 1] = '\0';
1396 /* --------------------------------------------------------------------------------------------- */
1397 /*** public functions ****************************************************************************/
1398 /* --------------------------------------------------------------------------------------------- */
1401 edit_get_syntax_color (WEdit
* edit
, off_t byte_index
)
1403 if (!tty_use_colors ())
1406 if (edit
->rules
!= NULL
&& byte_index
< edit
->buffer
.size
&& option_syntax_highlighting
)
1408 edit_get_rule (edit
, byte_index
);
1409 return translate_rule_to_color (edit
, &edit
->rule
);
1412 return EDITOR_NORMAL_COLOR
;
1415 /* --------------------------------------------------------------------------------------------- */
1418 edit_free_syntax_rules (WEdit
* edit
)
1425 destroy_defines (&edit
->defines
);
1429 edit_get_rule (edit
, -1);
1430 MC_PTR_FREE (edit
->syntax_type
);
1432 for (i
= 0; edit
->rules
[i
]; i
++)
1434 if (edit
->rules
[i
]->keyword
)
1436 for (j
= 0; edit
->rules
[i
]->keyword
[j
]; j
++)
1438 MC_PTR_FREE (edit
->rules
[i
]->keyword
[j
]->keyword
);
1439 MC_PTR_FREE (edit
->rules
[i
]->keyword
[j
]->whole_word_chars_left
);
1440 MC_PTR_FREE (edit
->rules
[i
]->keyword
[j
]->whole_word_chars_right
);
1441 MC_PTR_FREE (edit
->rules
[i
]->keyword
[j
]);
1444 MC_PTR_FREE (edit
->rules
[i
]->left
);
1445 MC_PTR_FREE (edit
->rules
[i
]->right
);
1446 MC_PTR_FREE (edit
->rules
[i
]->whole_word_chars_left
);
1447 MC_PTR_FREE (edit
->rules
[i
]->whole_word_chars_right
);
1448 MC_PTR_FREE (edit
->rules
[i
]->keyword
);
1449 MC_PTR_FREE (edit
->rules
[i
]->keyword_first_chars
);
1450 MC_PTR_FREE (edit
->rules
[i
]);
1453 g_slist_foreach (edit
->syntax_marker
, (GFunc
) g_free
, NULL
);
1454 g_slist_free (edit
->syntax_marker
);
1455 edit
->syntax_marker
= NULL
;
1456 MC_PTR_FREE (edit
->rules
);
1457 tty_color_free_all_tmp ();
1460 /* --------------------------------------------------------------------------------------------- */
1462 * Load rules into edit struct. Either edit or *pnames must be NULL. If
1463 * edit is NULL, a list of types will be stored into names. If type is
1464 * NULL, then the type will be selected according to the filename.
1465 * type must be edit->syntax_type or NULL
1468 edit_load_syntax (WEdit
* edit
, char ***pnames
, const char *type
)
1473 if (option_auto_syntax
)
1480 saved_type
= g_strdup (type
); /* save edit->syntax_type */
1481 edit_free_syntax_rules (edit
);
1482 edit
->syntax_type
= saved_type
; /* restore edit->syntax_type */
1485 if (!tty_use_colors ())
1488 if (!option_syntax_highlighting
&& (!pnames
|| !*pnames
))
1491 if (edit
!= NULL
&& edit
->filename_vpath
== NULL
)
1494 f
= mc_config_get_full_path (EDIT_SYNTAX_FILE
);
1496 r
= edit_read_syntax_file (edit
, pnames
, f
, vfs_path_as_str (edit
->filename_vpath
),
1497 get_first_editor_line (edit
),
1498 option_auto_syntax
? NULL
: edit
->syntax_type
);
1500 r
= edit_read_syntax_file (NULL
, pnames
, f
, NULL
, "", NULL
);
1503 edit_free_syntax_rules (edit
);
1504 message (D_ERROR
, _("Load syntax file"),
1505 _("Cannot open file %s\n%s"), f
, unix_error_string (errno
));
1509 edit_free_syntax_rules (edit
);
1510 message (D_ERROR
, _("Load syntax file"),
1511 _("Error in file %s on line %d"), error_file_name
? error_file_name
: f
, r
);
1512 MC_PTR_FREE (error_file_name
);
1518 /* --------------------------------------------------------------------------------------------- */
1521 edit_get_syntax_type (const WEdit
* edit
)
1523 return edit
->syntax_type
;
1526 /* --------------------------------------------------------------------------------------------- */