📄 syntax.c
字号:
/* editor syntax highlighting. Copyright (C) 1996-2000 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.*/#include <config.h>#if defined(MIDNIGHT) || defined(GTK)#include "edit.h"#else#include "coolwidget.h"#endif#if defined (HAVE_MAD) && ! defined (MIDNIGHT) && ! defined (GTK)#include "mad.h"#endif/* bytes */#define SYNTAX_MARKER_DENSITY 512/* Mispelled words are flushed from the syntax highlighting rules when they have been around longer than TRANSIENT_WORD_TIME_OUT seconds. At a cursor rate of 30 chars per second and say 3 chars + a space per word, we can accumulate 450 words absolute max with a value of 60. This is below this limit of 1024 words in a context. */#define TRANSIENT_WORD_TIME_OUT 60#define UNKNOWN_FORMAT "unknown"#if !defined(MIDNIGHT) || defined(HAVE_SYNTAXH)int option_syntax_highlighting = 1;int option_auto_spellcheck = 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);#ifdef HAVE_MADstatic void *mad_syntax_malloc (size_t x, char *file, int line)#define syntax_malloc(x) mad_syntax_malloc (x, __FILE__, __LINE__)#elsestatic void *syntax_malloc (size_t x)#endif{ void *p;#ifdef HAVE_MAD p = mad_alloc (x, file, line);#else p = malloc (x);#endif memset (p, 0, x); return p;}#define syntax_free(x) {if(x){free(x);(x)=0;}}static long compare_word_to_right (WEdit * edit, long i, char *text, char *whole_left, char *whole_right, int line_start){ unsigned char *p, *q; int c, d, j; if (!*text) return -1; c = edit_get_byte (edit, i - 1); if (line_start) if (c != '\n') return -1; if (whole_left) if (strchr (whole_left, c)) return -1; for (p = (unsigned char *) text, q = p + strlen ((char *) p); (unsigned long) p < (unsigned long) q; p++, i++) { switch (*p) { case '\001': p++; for (;;) { c = edit_get_byte (edit, i); if (!*p) if (whole_right) if (!strchr (whole_right, c)) break; if (c == *p) break; if (c == '\n') return -1; i++; } break; case '\002': p++; j = 0; for (;;) { c = edit_get_byte (edit, i); if (c == *p) { j = i; if (*p == *text && !p[1]) /* handle eg '+' and @+@ keywords properly */ break; } if (j && strchr ((char *) p + 1, c)) /* c exists further down, so it will get matched later */ break; if (c == '\n' || c == '\t' || c == ' ') { if (!*p) { i--; break; } if (!j) return -1; i = j; break; } if (whole_right) if (!strchr (whole_right, c)) { if (!*p) { i--; break; } if (!j) return -1; i = j; break; } i++; } break; case '\003': p++; c = -1; for (;; i++) { d = c; c = edit_get_byte (edit, i); for (j = 0; p[j] != '\003'; j++) if (c == p[j]) goto found_char2; break; found_char2: j = c; /* dummy command */ } i--; while (*p != '\003') p++; if (p[1] == d) i--; break; case '\004': p++; c = edit_get_byte (edit, i); for (; *p != '\004'; p++) if (c == *p) goto found_char3; return -1; found_char3: for (; *p != '\004'; p++); break;#if 0/* especially for LaTeX */ case '\005': { int b = 0; p++; for (;;) { c = edit_get_byte (edit, i); if (c == '\\') { i += 2; continue; } if (c == '{') { } if (c == *p) break; if (c == '\n') return -1; i++; } break; }#endif default: if (*p != edit_get_byte (edit, i)) return -1; } } if (whole_right) if (strchr (whole_right, edit_get_byte (edit, i))) return -1; return i;}#define XXX \ if (*s < '\005' || *s == (unsigned char) c) \ goto done; \ s++;static inline char *xx_strchr (const unsigned char *s, int c){ repeat: XXX XXX XXX XXX XXX XXX XXX XXX; XXX XXX XXX XXX XXX XXX XXX XXX; goto repeat; done: return (char *) s;}static inline struct syntax_rule apply_rules_going_right (WEdit * edit, long i, struct syntax_rule rule){ struct context_rule *r; int contextchanged = 0, c; int found_right = 0, found_left = 0, keyword_foundleft = 0, keyword_foundright = 0; int is_end; long end = 0; struct syntax_rule _rule = rule; if (!(c = edit_get_byte (edit, i))) return rule; is_end = (rule.end == (unsigned char) i);/* check to turn off a keyword */ if (_rule.keyword) { struct key_word *k; k = edit->rules[_rule.context]->keyword[_rule.keyword]; if (edit_get_byte (edit, i - 1) == '\n') _rule.keyword = 0; if (is_end) { _rule.keyword = 0; keyword_foundleft = 1; } }/* check to turn off a context */ if (_rule.context && !_rule.keyword) { long e; r = edit->rules[_rule.context]; if (r->first_right == c && !(rule.border & RULE_ON_RIGHT_BORDER) && (e = compare_word_to_right (edit, i, r->right, r->whole_word_chars_left, r->whole_word_chars_right, r->line_start_right)) > 0) { _rule.end = e; found_right = 1; _rule.border = RULE_ON_RIGHT_BORDER; if (r->between_delimiters) _rule.context = 0; } else if (is_end && rule.border & RULE_ON_RIGHT_BORDER) {/* always turn off a context at 4 */ found_left = 1; _rule.border = 0; if (!keyword_foundleft) _rule.context = 0; } else if (is_end && rule.border & RULE_ON_LEFT_BORDER) {/* never turn off a context at 2 */ found_left = 1; _rule.border = 0; } }/* check to turn on a keyword */ if (!_rule.keyword) { char *p; p = (r = edit->rules[_rule.context])->keyword_first_chars; while (*(p = xx_strchr ((unsigned char *) p + 1, c))) { struct key_word *k; int count; long e; count = (unsigned long) p - (unsigned long) r->keyword_first_chars; k = r->keyword[count]; e = compare_word_to_right (edit, i, k->keyword, k->whole_word_chars_left, k->whole_word_chars_right, k->line_start); if (e > 0) { end = e; _rule.end = e; _rule.keyword = count; keyword_foundright = 1; break; } } }/* check to turn on a context */ if (!_rule.context) { if (!found_left && is_end) { if (rule.border & RULE_ON_RIGHT_BORDER) { _rule.border = 0; _rule.context = 0; contextchanged = 1; _rule.keyword = 0; } else if (rule.border & RULE_ON_LEFT_BORDER) { r = edit->rules[_rule._context]; _rule.border = 0; if (r->between_delimiters) { long e; _rule.context = _rule._context; contextchanged = 1; _rule.keyword = 0; if (r->first_right == c && (e = compare_word_to_right (edit, i, r->right, r->whole_word_chars_left, r->whole_word_chars_right, r->line_start_right)) >= end) { _rule.end = e; found_right = 1; _rule.border = RULE_ON_RIGHT_BORDER; _rule.context = 0; } } } } if (!found_right) { int count; struct context_rule **rules = edit->rules; for (count = 1; rules[count]; count++) { r = rules[count]; if (r->first_left == c) { long e; e = compare_word_to_right (edit, i, r->left, r->whole_word_chars_left, r->whole_word_chars_right, r->line_start_left); if (e >= end && (!_rule.keyword || keyword_foundright)) { _rule.end = e; found_right = 1; _rule.border = RULE_ON_LEFT_BORDER; _rule._context = count; if (!r->between_delimiters) if (!_rule.keyword) _rule.context = count; break; } } } } }/* check again to turn on a keyword if the context switched */ if (contextchanged && !_rule.keyword) { char *p; p = (r = edit->rules[_rule.context])->keyword_first_chars; while (*(p = xx_strchr ((unsigned char *) p + 1, c))) { struct key_word *k; int count; long e; count = (unsigned long) p - (unsigned long) r->keyword_first_chars; k = r->keyword[count]; e = compare_word_to_right (edit, i, k->keyword, k->whole_word_chars_left, k->whole_word_chars_right, k->line_start); if (e > 0) { _rule.end = e; _rule.keyword = count; break; } } } return _rule;}static struct syntax_rule edit_get_rule (WEdit * edit, long byte_index){ long i; if (edit->syntax_invalidate) { struct _syntax_marker *s; while (edit->syntax_marker && edit->syntax_marker->offset >= edit->last_get_rule) { s = edit->syntax_marker->next; syntax_free (edit->syntax_marker); edit->syntax_marker = s; } if (edit->syntax_marker) { edit->last_get_rule = edit->syntax_marker->offset; edit->rule = edit->syntax_marker->rule; } else { edit->last_get_rule = -1; memset (&edit->rule, 0, sizeof (edit->rule)); } edit->syntax_invalidate = 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); if (i > (edit->syntax_marker ? edit->syntax_marker->offset + SYNTAX_MARKER_DENSITY : SYNTAX_MARKER_DENSITY)) { struct _syntax_marker *s; s = edit->syntax_marker; edit->syntax_marker = syntax_malloc (sizeof (struct _syntax_marker)); edit->syntax_marker->next = s; edit->syntax_marker->offset = i; edit->syntax_marker->rule = edit->rule; } } } else if (byte_index < edit->last_get_rule) { struct _syntax_marker *s; for (;;) { if (!edit->syntax_marker) { memset (&edit->rule, 0, sizeof (edit->rule)); for (i = -1; i <= byte_index; i++) edit->rule = apply_rules_going_right (edit, i, edit->rule); break; } if (byte_index >= edit->syntax_marker->offset) { edit->rule = edit->syntax_marker->rule; for (i = edit->syntax_marker->offset + 1; i <= byte_index; i++) edit->rule = apply_rules_going_right (edit, i, edit->rule); break; } s = edit->syntax_marker->next; syntax_free (edit->syntax_marker); edit->syntax_marker = s; } } edit->last_get_rule = byte_index; return edit->rule;}static void translate_rule_to_color (WEdit * edit, struct syntax_rule rule, int *fg, int *bg){ struct key_word *k; k = edit->rules[rule.context]->keyword[rule.keyword]; *bg = k->bg; *fg = k->fg;}void edit_get_syntax_color (WEdit * edit, long byte_index, int *fg, int *bg){ if (edit->rules && byte_index < edit->last_byte && option_syntax_highlighting) { translate_rule_to_color (edit, edit_get_rule (edit, byte_index), fg, bg); } else {#ifdef MIDNIGHT *fg = EDITOR_NORMAL_COLOR;#else *fg = NO_COLOR; *bg = NO_COLOR;#endif }}/* Returns 0 on error/eof or a count of the number of bytes read including the newline. Result must be free'd. */#ifdef HAVE_MADstatic int mad_read_one_line (char **line, FILE * f, char *file, int line_)#define read_one_line(a,b) mad_read_one_line(a,b,__FILE__,__LINE__)#elsestatic int read_one_line (char **line, FILE * f)#endif{ char *p; int len = 256, c, r = 0, i = 0;#ifdef HAVE_MAD p = mad_syntax_malloc (len, file, line_);#else p = syntax_malloc (len);#endif for (;;) { c = fgetc (f); if (c == -1) { if (errno == EINTR) continue; 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 = (char *) strdup (s); while (*s) { switch (*s) { case '\\': s++; switch (*s) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -