9106 lines · 235.0 KB · C
RawDownload
/* 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(&current_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.