/* vi:set ts=8 sts=4 sw=4: * * VIM - Vi IMproved by Bram Moolenaar * * Do ":help uganda" in Vim to read copying and usage conditions. * Do ":help credits" in Vim to see a list of people who contributed. * See README.txt for an overview of the Vim source code. */ /* * syntax.c: code for syntax highlighting */ #include "vim.h" /* * Structure that stores information about a highlight group. * The ID of a highlight group is also called group ID. It is the index in * the highlight_ga array PLUS ONE. */struct hl_group{ char_u *sg_name; /* highlight group name */ char_u *sg_name_u; /* uppercase of sg_name *//* for normal terminals */ int sg_term; /* "term=" highlighting attributes */ char_u *sg_start; /* terminal string for start highl */ char_u *sg_stop; /* terminal string for stop highl */ int sg_term_attr; /* Screen attr for term mode *//* for color terminals */ int sg_cterm; /* "cterm=" highlighting attr */ int sg_cterm_bold; /* bold attr was set for light color */ int sg_cterm_fg; /* terminal fg color number + 1 */ int sg_cterm_bg; /* terminal bg color number + 1 */ int sg_cterm_attr; /* Screen attr for color term mode */#ifdef FEAT_GUI/* for when using the GUI */ int sg_gui; /* "gui=" highlighting attributes */ guicolor_T sg_gui_fg; /* GUI foreground color handle */ char_u *sg_gui_fg_name;/* GUI foreground color name */ guicolor_T sg_gui_bg; /* GUI background color handle */ char_u *sg_gui_bg_name;/* GUI background color name */ guicolor_T sg_gui_sp; /* GUI special color handle */ char_u *sg_gui_sp_name;/* GUI special color name */ GuiFont sg_font; /* GUI font handle */#ifdef FEAT_XFONTSET GuiFontset sg_fontset; /* GUI fontset handle */#endif char_u *sg_font_name; /* GUI font or fontset name */ int sg_gui_attr; /* Screen attr for GUI mode */#endif int sg_link; /* link to this highlight group ID */ int sg_set; /* combination of SG_* flags */#ifdef FEAT_EVAL scid_T sg_scriptID; /* script in which the group was last set */#endif}; #define SG_TERM 1 /* term has been set */#define SG_CTERM 2 /* cterm has been set */#define SG_GUI 4 /* gui has been set */#define SG_LINK 8 /* link has been set */ static garray_T highlight_ga; /* highlight groups for 'highlight' option */ #define HL_TABLE() ((struct hl_group *)((highlight_ga.ga_data))) #ifdef FEAT_CMDL_COMPLstatic int include_default = FALSE; /* include "default" for expansion */static int include_link = FALSE; /* include "link" for expansion */#endif /* * The "term", "cterm" and "gui" arguments can be any combination of the * following names, separated by commas (but no spaces!). */static char *(hl_name_table[]) = {"bold", "standout", "underline", "undercurl", "italic", "reverse", "inverse", "NONE"};static int hl_attr_table[] = {HL_BOLD, HL_STANDOUT, HL_UNDERLINE, HL_UNDERCURL, HL_ITALIC, HL_INVERSE, HL_INVERSE, 0}; static int get_attr_entry __ARGS((garray_T *table, attrentry_T *aep));static void syn_unadd_group __ARGS((void));static void set_hl_attr __ARGS((int idx));static void highlight_list_one __ARGS((int id));static int highlight_list_arg __ARGS((int id, int didh, int type, int iarg, char_u *sarg, char *name));static int syn_add_group __ARGS((char_u *name));static int syn_list_header __ARGS((int did_header, int outlen, int id));static int hl_has_settings __ARGS((int idx, int check_link));static void highlight_clear __ARGS((int idx)); #ifdef FEAT_GUIstatic void gui_do_one_color __ARGS((int idx, int do_menu, int do_tooltip));static int set_group_colors __ARGS((char_u *name, guicolor_T *fgp, guicolor_T *bgp, int do_menu, int use_norm, int do_tooltip));static guicolor_T color_name2handle __ARGS((char_u *name));static GuiFont font_name2handle __ARGS((char_u *name));# ifdef FEAT_XFONTSETstatic GuiFontset fontset_name2handle __ARGS((char_u *name, int fixed_width));# endifstatic void hl_do_font __ARGS((int idx, char_u *arg, int do_normal, int do_menu, int do_tooltip));#endif /* * An attribute number is the index in attr_table plus ATTR_OFF. */#define ATTR_OFF (HL_ALL + 1) #if defined(FEAT_SYN_HL) || defined(PROTO) #define SYN_NAMELEN 50 /* maximum length of a syntax name */ /* different types of offsets that are possible */#define SPO_MS_OFF 0 /* match start offset */#define SPO_ME_OFF 1 /* match end offset */#define SPO_HS_OFF 2 /* highl. start offset */#define SPO_HE_OFF 3 /* highl. end offset */#define SPO_RS_OFF 4 /* region start offset */#define SPO_RE_OFF 5 /* region end offset */#define SPO_LC_OFF 6 /* leading context offset */#define SPO_COUNT 7 static char *(spo_name_tab[SPO_COUNT]) = {"ms=", "me=", "hs=", "he=", "rs=", "re=", "lc="}; /* * The patterns that are being searched for are stored in a syn_pattern. * A match item consists of one pattern. * A start/end item consists of n start patterns and m end patterns. * A start/skip/end item consists of n start patterns, one skip pattern and m * end patterns. * For the latter two, the patterns are always consecutive: start-skip-end. * * A character offset can be given for the matched text (_m_start and _m_end) * and for the actually highlighted text (_h_start and _h_end). */typedef struct syn_pattern{ char sp_type; /* see SPTYPE_ defines below */ char sp_syncing; /* this item used for syncing */ short sp_flags; /* see HL_ defines below */ struct sp_syn sp_syn; /* struct passed to in_id_list() */ short sp_syn_match_id; /* highlight group ID of pattern */ char_u *sp_pattern; /* regexp to match, pattern */ regprog_T *sp_prog; /* regexp to match, program */ int sp_ic; /* ignore-case flag for sp_prog */ short sp_off_flags; /* see below */ int sp_offsets[SPO_COUNT]; /* offsets */ short *sp_cont_list; /* cont. group IDs, if non-zero */ short *sp_next_list; /* next group IDs, if non-zero */ int sp_sync_idx; /* sync item index (syncing only) */ int sp_line_id; /* ID of last line where tried */ int sp_startcol; /* next match in sp_line_id line */} synpat_T; /* The sp_off_flags are computed like this: * offset from the start of the matched text: (1 << SPO_XX_OFF) * offset from the end of the matched text: (1 << (SPO_XX_OFF + SPO_COUNT)) * When both are present, only one is used. */ #define SPTYPE_MATCH 1 /* match keyword with this group ID */#define SPTYPE_START 2 /* match a regexp, start of item */#define SPTYPE_END 3 /* match a regexp, end of item */#define SPTYPE_SKIP 4 /* match a regexp, skip within item */ #define HL_CONTAINED 0x01 /* not used on toplevel */#define HL_TRANSP 0x02 /* has no highlighting */#define HL_ONELINE 0x04 /* match within one line only */#define HL_HAS_EOL 0x08 /* end pattern that matches with $ */#define HL_SYNC_HERE 0x10 /* sync point after this item (syncing only) */#define HL_SYNC_THERE 0x20 /* sync point at current line (syncing only) */#define HL_MATCH 0x40 /* use match ID instead of item ID */#define HL_SKIPNL 0x80 /* nextgroup can skip newlines */#define HL_SKIPWHITE 0x100 /* nextgroup can skip white space */#define HL_SKIPEMPTY 0x200 /* nextgroup can skip empty lines */#define HL_KEEPEND 0x400 /* end match always kept */#define HL_EXCLUDENL 0x800 /* exclude NL from match */#define HL_DISPLAY 0x1000 /* only used for displaying, not syncing */#define HL_FOLD 0x2000 /* define fold */#define HL_EXTEND 0x4000 /* ignore a keepend *//* These don't fit in a short, thus can't be used for syntax items, only for * si_flags and bs_flags. */#define HL_MATCHCONT 0x8000 /* match continued from previous line */#define HL_TRANS_CONT 0x10000L /* transparent item without contains arg */ #define SYN_ITEMS(buf) ((synpat_T *)((buf)->b_syn_patterns.ga_data)) #define NONE_IDX -2 /* value of sp_sync_idx for "NONE" */ /* * Flags for b_syn_sync_flags: */#define SF_CCOMMENT 0x01 /* sync on a C-style comment */#define SF_MATCH 0x02 /* sync by matching a pattern */ #define SYN_STATE_P(ssp) ((bufstate_T *)((ssp)->ga_data)) #define MAXKEYWLEN 80 /* maximum length of a keyword */ /* * The attributes of the syntax item that has been recognized. */static int current_attr = 0; /* attr of current syntax word */#ifdef FEAT_EVALstatic int current_id = 0; /* ID of current char for syn_get_id() */static int current_trans_id = 0; /* idem, transparancy removed */#endif typedef struct syn_cluster_S{ char_u *scl_name; /* syntax cluster name */ char_u *scl_name_u; /* uppercase of scl_name */ short *scl_list; /* IDs in this syntax cluster */} syn_cluster_T; /* * Methods of combining two clusters */#define CLUSTER_REPLACE 1 /* replace first list with second */#define CLUSTER_ADD 2 /* add second list to first */#define CLUSTER_SUBTRACT 3 /* subtract second list from first */ #define SYN_CLSTR(buf) ((syn_cluster_T *)((buf)->b_syn_clusters.ga_data)) /* * Syntax group IDs have different types: * 0 - 9999 normal syntax groups * 10000 - 14999 ALLBUT indicator (current_syn_inc_tag added) * 15000 - 19999 TOP indicator (current_syn_inc_tag added) * 20000 - 24999 CONTAINED indicator (current_syn_inc_tag added) * >= 25000 cluster IDs (subtract SYNID_CLUSTER for the cluster ID) */#define SYNID_ALLBUT 10000 /* syntax group ID for contains=ALLBUT */#define SYNID_TOP 15000 /* syntax group ID for contains=TOP */#define SYNID_CONTAINED 20000 /* syntax group ID for contains=CONTAINED */#define SYNID_CLUSTER 25000 /* first syntax group ID for clusters */ /* * Annoying Hack(TM): ":syn include" needs this pointer to pass to * expand_filename(). Most of the other syntax commands don't need it, so * instead of passing it to them, we stow it here. */static char_u **syn_cmdlinep; /* * Another Annoying Hack(TM): To prevent rules from other ":syn include"'d * files from from leaking into ALLBUT lists, we assign a unique ID to the * rules in each ":syn include"'d file. */static int current_syn_inc_tag = 0;static int running_syn_inc_tag = 0; /* * In a hashtable item "hi_key" points to "keyword" in a keyentry. * This avoids adding a pointer to the hashtable item. * KE2HIKEY() converts a var pointer to a hashitem key pointer. * HIKEY2KE() converts a hashitem key pointer to a var pointer. * HI2KE() converts a hashitem pointer to a var pointer. */static keyentry_T dumkey;#define KE2HIKEY(kp) ((kp)->keyword)#define HIKEY2KE(p) ((keyentry_T *)((p) - (dumkey.keyword - (char_u *)&dumkey)))#define HI2KE(hi) HIKEY2KE((hi)->hi_key) /* * To reduce the time spent in keepend(), remember at which level in the state * stack the first item with "keepend" is present. When "-1", there is no * "keepend" on the stack. */static int keepend_level = -1; /* * For the current state we need to remember more than just the idx. * When si_m_endpos.lnum is 0, the items other than si_idx are unknown. * (The end positions have the column number of the next char) */typedef struct state_item{ int si_idx; /* index of syntax pattern */ int si_id; /* highlight group ID for keywords */ int si_trans_id; /* idem, transparancy removed */ int si_m_lnum; /* lnum of the match */ int si_m_startcol; /* starting column of the match */ lpos_T si_m_endpos; /* just after end posn of the match */ lpos_T si_h_startpos; /* start position of the highlighting */ lpos_T si_h_endpos; /* end position of the highlighting */ lpos_T si_eoe_pos; /* end position of end pattern */ int si_end_idx; /* group ID for end pattern or zero */ int si_ends; /* if match ends before si_m_endpos */ int si_attr; /* attributes in this state */ long si_flags; /* HL_HAS_EOL flag in this state, and * HL_SKIP* for si_next_list */ short *si_cont_list; /* list of contained groups */ short *si_next_list; /* nextgroup IDs after this item ends */ reg_extmatch_T *si_extmatch; /* \z(...\) matches from start * pattern */} stateitem_T; #define KEYWORD_IDX -1 /* value of si_idx for keywords */#define ID_LIST_ALL (short *)-1 /* valid of si_cont_list for containing all but contained groups */ /* * Struct to reduce the number of arguments to get_syn_options(), it's used * very often. */typedef struct{ int flags; /* flags for contained and transparent */ int keyword; /* TRUE for ":syn keyword" */ int *sync_idx; /* syntax item for "grouphere" argument, NULL if not allowed */ char has_cont_list; /* TRUE if "cont_list" can be used */ short *cont_list; /* group IDs for "contains" argument */ short *cont_in_list; /* group IDs for "containedin" argument */ short *next_list; /* group IDs for "nextgroup" argument */} syn_opt_arg_T; /* * The next possible match in the current line for any pattern is remembered, * to avoid having to try for a match in each column. * If next_match_idx == -1, not tried (in this line) yet. * If next_match_col == MAXCOL, no match found in this line. * (All end positions have the column of the char after the end) */static int next_match_col; /* column for start of next match */static lpos_T next_match_m_endpos; /* position for end of next match */static lpos_T next_match_h_startpos; /* pos. for highl. start of next match */static lpos_T next_match_h_endpos; /* pos. for highl. end of next match */static int next_match_idx; /* index of matched item */static long next_match_flags; /* flags for next match */static lpos_T next_match_eos_pos; /* end of start pattn (start region) */static lpos_T next_match_eoe_pos; /* pos. for end of end pattern */static int next_match_end_idx; /* ID of group for end pattn or zero */static reg_extmatch_T *next_match_extmatch = NULL; /* * A state stack is an array of integers or stateitem_T, stored in a * garray_T. A state stack is invalid if it's itemsize entry is zero. */#define INVALID_STATE(ssp) ((ssp)->ga_itemsize == 0)#define VALID_STATE(ssp) ((ssp)->ga_itemsize != 0) /* * The current state (within the line) of the recognition engine. * When current_state.ga_itemsize is 0 the current state is invalid. */static win_T *syn_win; /* current window for highlighting */static buf_T *syn_buf; /* current buffer for highlighting */static linenr_T current_lnum = 0; /* lnum of current state */static colnr_T current_col = 0; /* column of current state */static int current_state_stored = 0; /* TRUE if stored current state * after setting current_finished */static int current_finished = 0; /* current line has been finished */static garray_T current_state /* current stack of state_items */ = {0, 0, 0, 0, NULL};static short *current_next_list = NULL; /* when non-zero, nextgroup list */static int current_next_flags = 0; /* flags for current_next_list */static int current_line_id = 0; /* unique number for current line */ #define CUR_STATE(idx) ((stateitem_T *)(current_state.ga_data))[idx] static void syn_sync __ARGS((win_T *wp, linenr_T lnum, synstate_T *last_valid));static int syn_match_linecont __ARGS((linenr_T lnum));static void syn_start_line __ARGS((void));static void syn_update_ends __ARGS((int startofline));static void syn_stack_alloc __ARGS((void));static int syn_stack_cleanup __ARGS((void));static void syn_stack_free_entry __ARGS((buf_T *buf, synstate_T *p));static synstate_T *syn_stack_find_entry __ARGS((linenr_T lnum));static synstate_T *store_current_state __ARGS((synstate_T *sp));static void load_current_state __ARGS((synstate_T *from));static void invalidate_current_state __ARGS((void));static int syn_stack_equal __ARGS((synstate_T *sp));static void validate_current_state __ARGS((void));static int syn_finish_line __ARGS((int syncing));static int syn_current_attr __ARGS((int syncing, int displaying, int *can_spell));static int did_match_already __ARGS((int idx, garray_T *gap));static stateitem_T *push_next_match __ARGS((stateitem_T *cur_si));static void check_state_ends __ARGS((void));static void update_si_attr __ARGS((int idx));static void check_keepend __ARGS((void));static void update_si_end __ARGS((stateitem_T *sip, int startcol, int force));static short *copy_id_list __ARGS((short *list));static int in_id_list __ARGS((stateitem_T *item, short *cont_list, struct sp_syn *ssp, int contained));static int push_current_state __ARGS((int idx));static void pop_current_state __ARGS((void)); static void find_endpos __ARGS((int idx, lpos_T *startpos, lpos_T *m_endpos, lpos_T *hl_endpos, long *flagsp, lpos_T *end_endpos, int *end_idx, reg_extmatch_T *start_ext));static void clear_syn_state __ARGS((synstate_T *p));static void clear_current_state __ARGS((void)); static void limit_pos __ARGS((lpos_T *pos, lpos_T *limit));static void limit_pos_zero __ARGS((lpos_T *pos, lpos_T *limit));static void syn_add_end_off __ARGS((lpos_T *result, regmmatch_T *regmatch, synpat_T *spp, int idx, int extra));static void syn_add_start_off __ARGS((lpos_T *result, regmmatch_T *regmatch, synpat_T *spp, int idx, int extra));static char_u *syn_getcurline __ARGS((void));static int syn_regexec __ARGS((regmmatch_T *rmp, linenr_T lnum, colnr_T col));static int check_keyword_id __ARGS((char_u *line, int startcol, int *endcol, long *flags, short **next_list, stateitem_T *cur_si));static void syn_cmd_case __ARGS((exarg_T *eap, int syncing));static void syn_cmd_spell __ARGS((exarg_T *eap, int syncing));static void syntax_sync_clear __ARGS((void));static void syn_remove_pattern __ARGS((buf_T *buf, int idx));static void syn_clear_pattern __ARGS((buf_T *buf, int i));static void syn_clear_cluster __ARGS((buf_T *buf, int i));static void syn_cmd_clear __ARGS((exarg_T *eap, int syncing));static void syn_clear_one __ARGS((int id, int syncing));static void syn_cmd_on __ARGS((exarg_T *eap, int syncing));static void syn_cmd_enable __ARGS((exarg_T *eap, int syncing));static void syn_cmd_reset __ARGS((exarg_T *eap, int syncing));static void syn_cmd_manual __ARGS((exarg_T *eap, int syncing));static void syn_cmd_off __ARGS((exarg_T *eap, int syncing));static void syn_cmd_onoff __ARGS((exarg_T *eap, char *name));static void syn_cmd_list __ARGS((exarg_T *eap, int syncing));static void syn_lines_msg __ARGS((void));static void syn_match_msg __ARGS((void));static void syn_list_one __ARGS((int id, int syncing, int link_only));static void syn_list_cluster __ARGS((int id));static void put_id_list __ARGS((char_u *name, short *list, int attr));static void put_pattern __ARGS((char *s, int c, synpat_T *spp, int attr));static int syn_list_keywords __ARGS((int id, hashtab_T *ht, int did_header, int attr));static void syn_clear_keyword __ARGS((int id, hashtab_T *ht));static void clear_keywtab __ARGS((hashtab_T *ht));static void add_keyword __ARGS((char_u *name, int id, int flags, short *cont_in_list, short *next_list));static char_u *get_group_name __ARGS((char_u *arg, char_u **name_end));static char_u *get_syn_options __ARGS((char_u *arg, syn_opt_arg_T *opt));static void syn_cmd_include __ARGS((exarg_T *eap, int syncing));static void syn_cmd_keyword __ARGS((exarg_T *eap, int syncing));static void syn_cmd_match __ARGS((exarg_T *eap, int syncing));static void syn_cmd_region __ARGS((exarg_T *eap, int syncing));#ifdef __BORLANDC__static int _RTLENTRYF syn_compare_stub __ARGS((const void *v1, const void *v2));#elsestatic int syn_compare_stub __ARGS((const void *v1, const void *v2));#endifstatic void syn_cmd_cluster __ARGS((exarg_T *eap, int syncing));static int syn_scl_name2id __ARGS((char_u *name));static int syn_scl_namen2id __ARGS((char_u *linep, int len));static int syn_check_cluster __ARGS((char_u *pp, int len));static int syn_add_cluster __ARGS((char_u *name));static void init_syn_patterns __ARGS((void));static char_u *get_syn_pattern __ARGS((char_u *arg, synpat_T *ci));static void syn_cmd_sync __ARGS((exarg_T *eap, int syncing));static int get_id_list __ARGS((char_u **arg, int keylen, short **list));static void syn_combine_list __ARGS((short **clstr1, short **clstr2, int list_op));static void syn_incl_toplevel __ARGS((int id, int *flagsp)); /* * Start the syntax recognition for a line. This function is normally called * from the screen updating, once for each displayed line. * The buffer is remembered in syn_buf, because get_syntax_attr() doesn't get * it. Careful: curbuf and curwin are likely to point to another buffer and * window. */ voidsyntax_start(wp, lnum) win_T *wp; linenr_T lnum;{ synstate_T *p; synstate_T *last_valid = NULL; synstate_T *last_min_valid = NULL; synstate_T *sp, *prev; linenr_T parsed_lnum; linenr_T first_stored; int dist; static int changedtick = 0; /* remember the last change ID */ /* * After switching buffers, invalidate current_state. * Also do this when a change was made, the current state may be invalid * then. */ if (syn_buf != wp->w_buffer || changedtick != syn_buf->b_changedtick) { invalidate_current_state(); syn_buf = wp->w_buffer; } changedtick = syn_buf->b_changedtick; syn_win = wp; /* * Allocate syntax stack when needed. */ syn_stack_alloc(); if (syn_buf->b_sst_array == NULL) return; /* out of memory */ syn_buf->b_sst_lasttick = display_tick; /* * If the state of the end of the previous line is useful, store it. */ if (VALID_STATE(¤t_state) && current_lnum < lnum && current_lnum < syn_buf->b_ml.ml_line_count) { (void)syn_finish_line(FALSE); if (!current_state_stored) {Lines 1–500 of 9106. Load more
/* vi:set ts=8 sts=4 sw=4: * * VIM - Vi IMproved by Bram Moolenaar * * Do ":help uganda" in Vim to read copying and usage conditions. * Do ":help credits" in Vim to see a list of people who contributed. * See README.txt for an overview of the Vim source code. */ /* * syntax.c: code for syntax highlighting */ #include "vim.h" /* * Structure that stores information about a highlight group. * The ID of a highlight group is also called group ID. It is the index in * the highlight_ga array PLUS ONE. */ struct hl_group { char_u *sg_name; /* highlight group name */ char_u *sg_name_u; /* uppercase of sg_name */ /* for normal terminals */ int sg_term; /* "term=" highlighting attributes */ char_u *sg_start; /* terminal string for start highl */ char_u *sg_stop; /* terminal string for stop highl */ int sg_term_attr; /* Screen attr for term mode */ /* for color terminals */ int sg_cterm; /* "cterm=" highlighting attr */ int sg_cterm_bold; /* bold attr was set for light color */ int sg_cterm_fg; /* terminal fg color number + 1 */ int sg_cterm_bg; /* terminal bg color number + 1 */ int sg_cterm_attr; /* Screen attr for color term mode */ #ifdef FEAT_GUI /* for when using the GUI */ int sg_gui; /* "gui=" highlighting attributes */ guicolor_T sg_gui_fg; /* GUI foreground color handle */ char_u *sg_gui_fg_name;/* GUI foreground color name */ guicolor_T sg_gui_bg; /* GUI background color handle */ char_u *sg_gui_bg_name;/* GUI background color name */ guicolor_T sg_gui_sp; /* GUI special color handle */ char_u *sg_gui_sp_name;/* GUI special color name */ GuiFont sg_font; /* GUI font handle */ #ifdef FEAT_XFONTSET GuiFontset sg_fontset; /* GUI fontset handle */ #endif char_u *sg_font_name; /* GUI font or fontset name */ int sg_gui_attr; /* Screen attr for GUI mode */ #endif int sg_link; /* link to this highlight group ID */ int sg_set; /* combination of SG_* flags */ #ifdef FEAT_EVAL scid_T sg_scriptID; /* script in which the group was last set */ #endif }; #define SG_TERM 1 /* term has been set */ #define SG_CTERM 2 /* cterm has been set */ #define SG_GUI 4 /* gui has been set */ #define SG_LINK 8 /* link has been set */ static garray_T highlight_ga; /* highlight groups for 'highlight' option */ #define HL_TABLE() ((struct hl_group *)((highlight_ga.ga_data))) #ifdef FEAT_CMDL_COMPL static int include_default = FALSE; /* include "default" for expansion */ static int include_link = FALSE; /* include "link" for expansion */ #endif /* * The "term", "cterm" and "gui" arguments can be any combination of the * following names, separated by commas (but no spaces!). */ static char *(hl_name_table[]) = {"bold", "standout", "underline", "undercurl", "italic", "reverse", "inverse", "NONE"}; static int hl_attr_table[] = {HL_BOLD, HL_STANDOUT, HL_UNDERLINE, HL_UNDERCURL, HL_ITALIC, HL_INVERSE, HL_INVERSE, 0}; static int get_attr_entry __ARGS((garray_T *table, attrentry_T *aep)); static void syn_unadd_group __ARGS((void)); static void set_hl_attr __ARGS((int idx)); static void highlight_list_one __ARGS((int id)); static int highlight_list_arg __ARGS((int id, int didh, int type, int iarg, char_u *sarg, char *name)); static int syn_add_group __ARGS((char_u *name)); static int syn_list_header __ARGS((int did_header, int outlen, int id)); static int hl_has_settings __ARGS((int idx, int check_link)); static void highlight_clear __ARGS((int idx)); #ifdef FEAT_GUI static void gui_do_one_color __ARGS((int idx, int do_menu, int do_tooltip)); static int set_group_colors __ARGS((char_u *name, guicolor_T *fgp, guicolor_T *bgp, int do_menu, int use_norm, int do_tooltip)); static guicolor_T color_name2handle __ARGS((char_u *name)); static GuiFont font_name2handle __ARGS((char_u *name)); # ifdef FEAT_XFONTSET static GuiFontset fontset_name2handle __ARGS((char_u *name, int fixed_width)); # endif static void hl_do_font __ARGS((int idx, char_u *arg, int do_normal, int do_menu, int do_tooltip)); #endif /* * An attribute number is the index in attr_table plus ATTR_OFF. */ #define ATTR_OFF (HL_ALL + 1) #if defined(FEAT_SYN_HL) || defined(PROTO) #define SYN_NAMELEN 50 /* maximum length of a syntax name */ /* different types of offsets that are possible */ #define SPO_MS_OFF 0 /* match start offset */ #define SPO_ME_OFF 1 /* match end offset */ #define SPO_HS_OFF 2 /* highl. start offset */ #define SPO_HE_OFF 3 /* highl. end offset */ #define SPO_RS_OFF 4 /* region start offset */ #define SPO_RE_OFF 5 /* region end offset */ #define SPO_LC_OFF 6 /* leading context offset */ #define SPO_COUNT 7 static char *(spo_name_tab[SPO_COUNT]) = {"ms=", "me=", "hs=", "he=", "rs=", "re=", "lc="}; /* * The patterns that are being searched for are stored in a syn_pattern. * A match item consists of one pattern. * A start/end item consists of n start patterns and m end patterns. * A start/skip/end item consists of n start patterns, one skip pattern and m * end patterns. * For the latter two, the patterns are always consecutive: start-skip-end. * * A character offset can be given for the matched text (_m_start and _m_end) * and for the actually highlighted text (_h_start and _h_end). */ typedef struct syn_pattern { char sp_type; /* see SPTYPE_ defines below */ char sp_syncing; /* this item used for syncing */ short sp_flags; /* see HL_ defines below */ struct sp_syn sp_syn; /* struct passed to in_id_list() */ short sp_syn_match_id; /* highlight group ID of pattern */ char_u *sp_pattern; /* regexp to match, pattern */ regprog_T *sp_prog; /* regexp to match, program */ int sp_ic; /* ignore-case flag for sp_prog */ short sp_off_flags; /* see below */ int sp_offsets[SPO_COUNT]; /* offsets */ short *sp_cont_list; /* cont. group IDs, if non-zero */ short *sp_next_list; /* next group IDs, if non-zero */ int sp_sync_idx; /* sync item index (syncing only) */ int sp_line_id; /* ID of last line where tried */ int sp_startcol; /* next match in sp_line_id line */ } synpat_T; /* The sp_off_flags are computed like this: * offset from the start of the matched text: (1 << SPO_XX_OFF) * offset from the end of the matched text: (1 << (SPO_XX_OFF + SPO_COUNT)) * When both are present, only one is used. */ #define SPTYPE_MATCH 1 /* match keyword with this group ID */ #define SPTYPE_START 2 /* match a regexp, start of item */ #define SPTYPE_END 3 /* match a regexp, end of item */ #define SPTYPE_SKIP 4 /* match a regexp, skip within item */ #define HL_CONTAINED 0x01 /* not used on toplevel */ #define HL_TRANSP 0x02 /* has no highlighting */ #define HL_ONELINE 0x04 /* match within one line only */ #define HL_HAS_EOL 0x08 /* end pattern that matches with $ */ #define HL_SYNC_HERE 0x10 /* sync point after this item (syncing only) */ #define HL_SYNC_THERE 0x20 /* sync point at current line (syncing only) */ #define HL_MATCH 0x40 /* use match ID instead of item ID */ #define HL_SKIPNL 0x80 /* nextgroup can skip newlines */ #define HL_SKIPWHITE 0x100 /* nextgroup can skip white space */ #define HL_SKIPEMPTY 0x200 /* nextgroup can skip empty lines */ #define HL_KEEPEND 0x400 /* end match always kept */ #define HL_EXCLUDENL 0x800 /* exclude NL from match */ #define HL_DISPLAY 0x1000 /* only used for displaying, not syncing */ #define HL_FOLD 0x2000 /* define fold */ #define HL_EXTEND 0x4000 /* ignore a keepend */ /* These don't fit in a short, thus can't be used for syntax items, only for * si_flags and bs_flags. */ #define HL_MATCHCONT 0x8000 /* match continued from previous line */ #define HL_TRANS_CONT 0x10000L /* transparent item without contains arg */ #define SYN_ITEMS(buf) ((synpat_T *)((buf)->b_syn_patterns.ga_data)) #define NONE_IDX -2 /* value of sp_sync_idx for "NONE" */ /* * Flags for b_syn_sync_flags: */ #define SF_CCOMMENT 0x01 /* sync on a C-style comment */ #define SF_MATCH 0x02 /* sync by matching a pattern */ #define SYN_STATE_P(ssp) ((bufstate_T *)((ssp)->ga_data)) #define MAXKEYWLEN 80 /* maximum length of a keyword */ /* * The attributes of the syntax item that has been recognized. */ static int current_attr = 0; /* attr of current syntax word */ #ifdef FEAT_EVAL static int current_id = 0; /* ID of current char for syn_get_id() */ static int current_trans_id = 0; /* idem, transparancy removed */ #endif typedef struct syn_cluster_S { char_u *scl_name; /* syntax cluster name */ char_u *scl_name_u; /* uppercase of scl_name */ short *scl_list; /* IDs in this syntax cluster */ } syn_cluster_T; /* * Methods of combining two clusters */ #define CLUSTER_REPLACE 1 /* replace first list with second */ #define CLUSTER_ADD 2 /* add second list to first */ #define CLUSTER_SUBTRACT 3 /* subtract second list from first */ #define SYN_CLSTR(buf) ((syn_cluster_T *)((buf)->b_syn_clusters.ga_data)) /* * Syntax group IDs have different types: * 0 - 9999 normal syntax groups * 10000 - 14999 ALLBUT indicator (current_syn_inc_tag added) * 15000 - 19999 TOP indicator (current_syn_inc_tag added) * 20000 - 24999 CONTAINED indicator (current_syn_inc_tag added) * >= 25000 cluster IDs (subtract SYNID_CLUSTER for the cluster ID) */ #define SYNID_ALLBUT 10000 /* syntax group ID for contains=ALLBUT */ #define SYNID_TOP 15000 /* syntax group ID for contains=TOP */ #define SYNID_CONTAINED 20000 /* syntax group ID for contains=CONTAINED */ #define SYNID_CLUSTER 25000 /* first syntax group ID for clusters */ /* * Annoying Hack(TM): ":syn include" needs this pointer to pass to * expand_filename(). Most of the other syntax commands don't need it, so * instead of passing it to them, we stow it here. */ static char_u **syn_cmdlinep; /* * Another Annoying Hack(TM): To prevent rules from other ":syn include"'d * files from from leaking into ALLBUT lists, we assign a unique ID to the * rules in each ":syn include"'d file. */ static int current_syn_inc_tag = 0; static int running_syn_inc_tag = 0; /* * In a hashtable item "hi_key" points to "keyword" in a keyentry. * This avoids adding a pointer to the hashtable item. * KE2HIKEY() converts a var pointer to a hashitem key pointer. * HIKEY2KE() converts a hashitem key pointer to a var pointer. * HI2KE() converts a hashitem pointer to a var pointer. */ static keyentry_T dumkey; #define KE2HIKEY(kp) ((kp)->keyword) #define HIKEY2KE(p) ((keyentry_T *)((p) - (dumkey.keyword - (char_u *)&dumkey))) #define HI2KE(hi) HIKEY2KE((hi)->hi_key) /* * To reduce the time spent in keepend(), remember at which level in the state * stack the first item with "keepend" is present. When "-1", there is no * "keepend" on the stack. */ static int keepend_level = -1; /* * For the current state we need to remember more than just the idx. * When si_m_endpos.lnum is 0, the items other than si_idx are unknown. * (The end positions have the column number of the next char) */ typedef struct state_item { int si_idx; /* index of syntax pattern */ int si_id; /* highlight group ID for keywords */ int si_trans_id; /* idem, transparancy removed */ int si_m_lnum; /* lnum of the match */ int si_m_startcol; /* starting column of the match */ lpos_T si_m_endpos; /* just after end posn of the match */ lpos_T si_h_startpos; /* start position of the highlighting */ lpos_T si_h_endpos; /* end position of the highlighting */ lpos_T si_eoe_pos; /* end position of end pattern */ int si_end_idx; /* group ID for end pattern or zero */ int si_ends; /* if match ends before si_m_endpos */ int si_attr; /* attributes in this state */ long si_flags; /* HL_HAS_EOL flag in this state, and * HL_SKIP* for si_next_list */ short *si_cont_list; /* list of contained groups */ short *si_next_list; /* nextgroup IDs after this item ends */ reg_extmatch_T *si_extmatch; /* \z(...\) matches from start * pattern */ } stateitem_T; #define KEYWORD_IDX -1 /* value of si_idx for keywords */ #define ID_LIST_ALL (short *)-1 /* valid of si_cont_list for containing all but contained groups */ /* * Struct to reduce the number of arguments to get_syn_options(), it's used * very often. */ typedef struct { int flags; /* flags for contained and transparent */ int keyword; /* TRUE for ":syn keyword" */ int *sync_idx; /* syntax item for "grouphere" argument, NULL if not allowed */ char has_cont_list; /* TRUE if "cont_list" can be used */ short *cont_list; /* group IDs for "contains" argument */ short *cont_in_list; /* group IDs for "containedin" argument */ short *next_list; /* group IDs for "nextgroup" argument */ } syn_opt_arg_T; /* * The next possible match in the current line for any pattern is remembered, * to avoid having to try for a match in each column. * If next_match_idx == -1, not tried (in this line) yet. * If next_match_col == MAXCOL, no match found in this line. * (All end positions have the column of the char after the end) */ static int next_match_col; /* column for start of next match */ static lpos_T next_match_m_endpos; /* position for end of next match */ static lpos_T next_match_h_startpos; /* pos. for highl. start of next match */ static lpos_T next_match_h_endpos; /* pos. for highl. end of next match */ static int next_match_idx; /* index of matched item */ static long next_match_flags; /* flags for next match */ static lpos_T next_match_eos_pos; /* end of start pattn (start region) */ static lpos_T next_match_eoe_pos; /* pos. for end of end pattern */ static int next_match_end_idx; /* ID of group for end pattn or zero */ static reg_extmatch_T *next_match_extmatch = NULL; /* * A state stack is an array of integers or stateitem_T, stored in a * garray_T. A state stack is invalid if it's itemsize entry is zero. */ #define INVALID_STATE(ssp) ((ssp)->ga_itemsize == 0) #define VALID_STATE(ssp) ((ssp)->ga_itemsize != 0) /* * The current state (within the line) of the recognition engine. * When current_state.ga_itemsize is 0 the current state is invalid. */ static win_T *syn_win; /* current window for highlighting */ static buf_T *syn_buf; /* current buffer for highlighting */ static linenr_T current_lnum = 0; /* lnum of current state */ static colnr_T current_col = 0; /* column of current state */ static int current_state_stored = 0; /* TRUE if stored current state * after setting current_finished */ static int current_finished = 0; /* current line has been finished */ static garray_T current_state /* current stack of state_items */ = {0, 0, 0, 0, NULL}; static short *current_next_list = NULL; /* when non-zero, nextgroup list */ static int current_next_flags = 0; /* flags for current_next_list */ static int current_line_id = 0; /* unique number for current line */ #define CUR_STATE(idx) ((stateitem_T *)(current_state.ga_data))[idx] static void syn_sync __ARGS((win_T *wp, linenr_T lnum, synstate_T *last_valid)); static int syn_match_linecont __ARGS((linenr_T lnum)); static void syn_start_line __ARGS((void)); static void syn_update_ends __ARGS((int startofline)); static void syn_stack_alloc __ARGS((void)); static int syn_stack_cleanup __ARGS((void)); static void syn_stack_free_entry __ARGS((buf_T *buf, synstate_T *p)); static synstate_T *syn_stack_find_entry __ARGS((linenr_T lnum)); static synstate_T *store_current_state __ARGS((synstate_T *sp)); static void load_current_state __ARGS((synstate_T *from)); static void invalidate_current_state __ARGS((void)); static int syn_stack_equal __ARGS((synstate_T *sp)); static void validate_current_state __ARGS((void)); static int syn_finish_line __ARGS((int syncing)); static int syn_current_attr __ARGS((int syncing, int displaying, int *can_spell)); static int did_match_already __ARGS((int idx, garray_T *gap)); static stateitem_T *push_next_match __ARGS((stateitem_T *cur_si)); static void check_state_ends __ARGS((void)); static void update_si_attr __ARGS((int idx)); static void check_keepend __ARGS((void)); static void update_si_end __ARGS((stateitem_T *sip, int startcol, int force)); static short *copy_id_list __ARGS((short *list)); static int in_id_list __ARGS((stateitem_T *item, short *cont_list, struct sp_syn *ssp, int contained)); static int push_current_state __ARGS((int idx)); static void pop_current_state __ARGS((void)); static void find_endpos __ARGS((int idx, lpos_T *startpos, lpos_T *m_endpos, lpos_T *hl_endpos, long *flagsp, lpos_T *end_endpos, int *end_idx, reg_extmatch_T *start_ext)); static void clear_syn_state __ARGS((synstate_T *p)); static void clear_current_state __ARGS((void)); static void limit_pos __ARGS((lpos_T *pos, lpos_T *limit)); static void limit_pos_zero __ARGS((lpos_T *pos, lpos_T *limit)); static void syn_add_end_off __ARGS((lpos_T *result, regmmatch_T *regmatch, synpat_T *spp, int idx, int extra)); static void syn_add_start_off __ARGS((lpos_T *result, regmmatch_T *regmatch, synpat_T *spp, int idx, int extra)); static char_u *syn_getcurline __ARGS((void)); static int syn_regexec __ARGS((regmmatch_T *rmp, linenr_T lnum, colnr_T col)); static int check_keyword_id __ARGS((char_u *line, int startcol, int *endcol, long *flags, short **next_list, stateitem_T *cur_si)); static void syn_cmd_case __ARGS((exarg_T *eap, int syncing)); static void syn_cmd_spell __ARGS((exarg_T *eap, int syncing)); static void syntax_sync_clear __ARGS((void)); static void syn_remove_pattern __ARGS((buf_T *buf, int idx)); static void syn_clear_pattern __ARGS((buf_T *buf, int i)); static void syn_clear_cluster __ARGS((buf_T *buf, int i)); static void syn_cmd_clear __ARGS((exarg_T *eap, int syncing)); static void syn_clear_one __ARGS((int id, int syncing)); static void syn_cmd_on __ARGS((exarg_T *eap, int syncing)); static void syn_cmd_enable __ARGS((exarg_T *eap, int syncing)); static void syn_cmd_reset __ARGS((exarg_T *eap, int syncing)); static void syn_cmd_manual __ARGS((exarg_T *eap, int syncing)); static void syn_cmd_off __ARGS((exarg_T *eap, int syncing)); static void syn_cmd_onoff __ARGS((exarg_T *eap, char *name)); static void syn_cmd_list __ARGS((exarg_T *eap, int syncing)); static void syn_lines_msg __ARGS((void)); static void syn_match_msg __ARGS((void)); static void syn_list_one __ARGS((int id, int syncing, int link_only)); static void syn_list_cluster __ARGS((int id)); static void put_id_list __ARGS((char_u *name, short *list, int attr)); static void put_pattern __ARGS((char *s, int c, synpat_T *spp, int attr)); static int syn_list_keywords __ARGS((int id, hashtab_T *ht, int did_header, int attr)); static void syn_clear_keyword __ARGS((int id, hashtab_T *ht)); static void clear_keywtab __ARGS((hashtab_T *ht)); static void add_keyword __ARGS((char_u *name, int id, int flags, short *cont_in_list, short *next_list)); static char_u *get_group_name __ARGS((char_u *arg, char_u **name_end)); static char_u *get_syn_options __ARGS((char_u *arg, syn_opt_arg_T *opt)); static void syn_cmd_include __ARGS((exarg_T *eap, int syncing)); static void syn_cmd_keyword __ARGS((exarg_T *eap, int syncing)); static void syn_cmd_match __ARGS((exarg_T *eap, int syncing)); static void syn_cmd_region __ARGS((exarg_T *eap, int syncing)); #ifdef __BORLANDC__ static int _RTLENTRYF syn_compare_stub __ARGS((const void *v1, const void *v2)); #else static int syn_compare_stub __ARGS((const void *v1, const void *v2)); #endif static void syn_cmd_cluster __ARGS((exarg_T *eap, int syncing)); static int syn_scl_name2id __ARGS((char_u *name)); static int syn_scl_namen2id __ARGS((char_u *linep, int len)); static int syn_check_cluster __ARGS((char_u *pp, int len)); static int syn_add_cluster __ARGS((char_u *name)); static void init_syn_patterns __ARGS((void)); static char_u *get_syn_pattern __ARGS((char_u *arg, synpat_T *ci)); static void syn_cmd_sync __ARGS((exarg_T *eap, int syncing)); static int get_id_list __ARGS((char_u **arg, int keylen, short **list)); static void syn_combine_list __ARGS((short **clstr1, short **clstr2, int list_op)); static void syn_incl_toplevel __ARGS((int id, int *flagsp)); /* * Start the syntax recognition for a line. This function is normally called * from the screen updating, once for each displayed line. * The buffer is remembered in syn_buf, because get_syntax_attr() doesn't get * it. Careful: curbuf and curwin are likely to point to another buffer and * window. */ void syntax_start(wp, lnum) win_T *wp; linenr_T lnum; { synstate_T *p; synstate_T *last_valid = NULL; synstate_T *last_min_valid = NULL; synstate_T *sp, *prev; linenr_T parsed_lnum; linenr_T first_stored; int dist; static int changedtick = 0; /* remember the last change ID */ /* * After switching buffers, invalidate current_state. * Also do this when a change was made, the current state may be invalid * then. */ if (syn_buf != wp->w_buffer || changedtick != syn_buf->b_changedtick) { invalidate_current_state(); syn_buf = wp->w_buffer; } changedtick = syn_buf->b_changedtick; syn_win = wp; /* * Allocate syntax stack when needed. */ syn_stack_alloc(); if (syn_buf->b_sst_array == NULL) return; /* out of memory */ syn_buf->b_sst_lasttick = display_tick; /* * If the state of the end of the previous line is useful, store it. */ if (VALID_STATE(¤t_state) && current_lnum < lnum && current_lnum < syn_buf->b_ml.ml_line_count) { (void)syn_finish_line(FALSE); if (!current_state_stored) {