syntax.c
资源名称:vim53src.zip [点击查看]
上传用户:gddssl
上传日期:2007-01-06
资源大小:1003k
文件大小:166k
源码类别:
编辑器/阅读器
开发平台:
DOS
- curbuf->b_syn_topgrp = sgl_id;
- if (do_source(eap->arg, FALSE, FALSE) == FAIL)
- emsg2(e_notopen, eap->arg);
- curbuf->b_syn_topgrp = prev_toplvl_grp;
- current_syn_inc_lvl--;
- }
- /*
- * Handle ":syntax keyword {group-name} [{option}] keyword .." command.
- */
- /* ARGSUSED */
- static void
- syn_cmd_keyword(eap, syncing)
- EXARG *eap;
- int syncing; /* not used */
- {
- char_u *arg = eap->arg;
- char_u *group_name_end;
- int syn_id;
- char_u *rest;
- char_u *keyword_copy;
- char_u *p;
- char_u *first_arg;
- int round;
- int flags = 0;
- short *next_list = NULL;
- rest = get_group_name(arg, &group_name_end);
- if (rest != NULL)
- {
- syn_id = syn_check_group(arg, (int)(group_name_end - arg));
- /* allocate a buffer, for removing the backslashes in the keyword */
- keyword_copy = alloc((unsigned)STRLEN(rest) + 1);
- if (keyword_copy != NULL)
- {
- /*
- * The options given apply to ALL keywords, so all options must be
- * found before keywords can be created.
- * round 1: collect the options.
- * round 2: create the keywords.
- */
- first_arg = rest;
- for (round = 1; round <= 2; ++round)
- {
- /*
- * Isolate each keyword and add an entry for it.
- */
- for (rest = first_arg; rest != NULL && !ends_excmd(*rest);
- rest = skipwhite(rest))
- {
- rest = get_syn_options(rest, &flags, NULL,
- NULL, &next_list);
- if (rest == NULL || ends_excmd(*rest))
- break;
- p = keyword_copy;
- while (*rest && !vim_iswhite(*rest))
- {
- if (*rest == '\' && rest[1] != NUL)
- ++rest;
- *p++ = *rest++;
- }
- *p = NUL;
- if (round == 2 && !eap->skip)
- {
- for (p = vim_strchr(keyword_copy, '['); ; ++p)
- {
- if (p != NULL)
- *p = NUL;
- add_keyword(keyword_copy, syn_id, flags, next_list);
- if (p == NULL || p[1] == NUL || p[1] == ']')
- break;
- p[0] = p[1];
- }
- }
- }
- if (round == 1)
- syn_incl_toplevel(syn_id, &flags);
- }
- vim_free(keyword_copy);
- }
- }
- if (rest != NULL)
- eap->nextcmd = check_nextcmd(rest);
- else
- EMSG2(e_invarg2, arg);
- vim_free(next_list);
- redraw_curbuf_later(NOT_VALID);
- }
- /*
- * Handle ":syntax match {name} [{options}] {pattern} [{options}]".
- *
- * Also ":syntax sync match {name} [[grouphere | groupthere] {group-name}] .."
- */
- static void
- syn_cmd_match(eap, syncing)
- EXARG *eap;
- int syncing; /* TRUE for ":syntax sync match .. " */
- {
- char_u *arg = eap->arg;
- char_u *group_name_end;
- char_u *rest;
- struct syn_pattern item; /* the item found in the line */
- int syn_id;
- int idx;
- int flags = 0;
- int sync_idx = 0;
- short *cont_list = NULL;
- short *next_list = NULL;
- /* Isolate the group name, check for validity */
- rest = get_group_name(arg, &group_name_end);
- /* Get options before the pattern */
- rest = get_syn_options(rest, &flags, syncing ? &sync_idx : NULL,
- &cont_list, &next_list);
- /* get the pattern. */
- init_syn_patterns();
- vim_memset(&item, 0, sizeof(item));
- rest = get_syn_pattern(rest, &item);
- if (vim_regcomp_had_eol())
- flags |= HL_HAS_EOL;
- /* Get options after the pattern */
- rest = get_syn_options(rest, &flags, syncing ? &sync_idx : NULL,
- &cont_list, &next_list);
- if (rest != NULL) /* all arguments are valid */
- {
- /*
- * Check for trailing command and illegal trailing arguments.
- */
- eap->nextcmd = check_nextcmd(rest);
- if (!ends_excmd(*rest) || eap->skip)
- rest = NULL;
- else if (ga_grow(&curbuf->b_syn_patterns, 1) != FAIL
- && (syn_id = syn_check_group(arg,
- (int)(group_name_end - arg))) != 0)
- {
- syn_incl_toplevel(syn_id, &flags);
- /*
- * Store the pattern in the syn_items list
- */
- idx = curbuf->b_syn_patterns.ga_len;
- SYN_ITEMS(curbuf)[idx] = item;
- SYN_ITEMS(curbuf)[idx].sp_syncing = syncing;
- SYN_ITEMS(curbuf)[idx].sp_type = SPTYPE_MATCH;
- SYN_ITEMS(curbuf)[idx].sp_syn_id = syn_id;
- SYN_ITEMS(curbuf)[idx].sp_syn_inc_lvl = current_syn_inc_lvl;
- SYN_ITEMS(curbuf)[idx].sp_flags = flags;
- SYN_ITEMS(curbuf)[idx].sp_sync_idx = sync_idx;
- SYN_ITEMS(curbuf)[idx].sp_cont_list = cont_list;
- SYN_ITEMS(curbuf)[idx].sp_next_list = next_list;
- ++curbuf->b_syn_patterns.ga_len;
- --curbuf->b_syn_patterns.ga_room;
- /* remember that we found a match for syncing on */
- if (flags & (HL_SYNC_HERE|HL_SYNC_THERE))
- curbuf->b_syn_sync_flags |= SF_MATCH;
- redraw_curbuf_later(NOT_VALID);
- return; /* don't free the progs and patterns now */
- }
- }
- /*
- * Something failed, free the allocated memory.
- */
- vim_free(item.sp_prog);
- vim_free(item.sp_pattern);
- vim_free(cont_list);
- vim_free(next_list);
- if (rest == NULL)
- EMSG2(e_invarg2, arg);
- }
- /*
- * Handle ":syntax region {group-name} [matchgroup={group-name}]
- * start {start} .. [skip {skip}] end {end} .. [{options}]".
- */
- static void
- syn_cmd_region(eap, syncing)
- EXARG *eap;
- int syncing; /* TRUE for ":syntax sync region .." */
- {
- char_u *arg = eap->arg;
- char_u *group_name_end;
- char_u *rest; /* next arg, NULL on error */
- char_u *key_end;
- char_u *key = NULL;
- char_u *p;
- int item;
- #define ITEM_START 0
- #define ITEM_SKIP 1
- #define ITEM_END 2
- #define ITEM_MATCHGROUP 3
- struct pat_ptr
- {
- struct syn_pattern *pp_synp; /* pointer to syn_pattern */
- int pp_matchgroup_id; /* matchgroup ID */
- struct pat_ptr *pp_next; /* pointer to next pat_ptr */
- } *(pat_ptrs[3]);
- /* patterns found in the line */
- struct pat_ptr *ppp;
- struct pat_ptr *ppp_next;
- int pat_count = 0; /* number of syn_patterns found */
- int syn_id;
- int matchgroup_id = 0;
- int not_enough = FALSE; /* not enough arguments */
- int illegal = FALSE; /* illegal arguments */
- int success = FALSE;
- int idx;
- int flags = 0;
- short *cont_list = NULL;
- short *next_list = NULL;
- /* Isolate the group name, check for validity */
- rest = get_group_name(arg, &group_name_end);
- pat_ptrs[0] = NULL;
- pat_ptrs[1] = NULL;
- pat_ptrs[2] = NULL;
- init_syn_patterns();
- /*
- * get the options, patterns and matchgroup.
- */
- while (rest != NULL && !ends_excmd(*rest))
- {
- /* Check for option arguments */
- rest = get_syn_options(rest, &flags, NULL, &cont_list, &next_list);
- if (rest == NULL || ends_excmd(*rest))
- break;
- /* must be a pattern or matchgroup then */
- key_end = rest;
- while (*key_end && !vim_iswhite(*key_end) && *key_end != '=')
- ++key_end;
- vim_free(key);
- key = vim_strnsave_up(rest, (int)(key_end - rest));
- if (key == NULL) /* out of memory */
- {
- rest = NULL;
- break;
- }
- if (STRCMP(key, "MATCHGROUP") == 0)
- item = ITEM_MATCHGROUP;
- else if (STRCMP(key, "START") == 0)
- item = ITEM_START;
- else if (STRCMP(key, "END") == 0)
- item = ITEM_END;
- else if (STRCMP(key, "SKIP") == 0)
- {
- if (pat_ptrs[ITEM_SKIP] != NULL) /* one skip pattern allowed */
- {
- illegal = TRUE;
- break;
- }
- item = ITEM_SKIP;
- }
- else
- break;
- rest = skipwhite(key_end);
- if (*rest != '=')
- {
- rest = NULL;
- EMSG2("Missing '=': %s", arg);
- break;
- }
- rest = skipwhite(rest + 1);
- if (*rest == NUL)
- {
- not_enough = TRUE;
- break;
- }
- if (item == ITEM_MATCHGROUP)
- {
- p = skiptowhite(rest);
- if ((p - rest == 4 && STRNCMP(rest, "NONE", 4) == 0) || eap->skip)
- matchgroup_id = 0;
- else
- {
- matchgroup_id = syn_check_group(rest, (int)(p - rest));
- if (matchgroup_id == 0)
- {
- illegal = TRUE;
- break;
- }
- }
- rest = skipwhite(p);
- }
- else
- {
- /*
- * Allocate room for a syn_pattern, and link it in the list of
- * syn_patterns for this item, at the start (because the list is
- * used from end to start).
- */
- ppp = (struct pat_ptr *)alloc((unsigned)sizeof(struct pat_ptr));
- if (ppp == NULL)
- {
- rest = NULL;
- break;
- }
- ppp->pp_next = pat_ptrs[item];
- pat_ptrs[item] = ppp;
- ppp->pp_synp = (struct syn_pattern *)alloc_clear(
- (unsigned)sizeof(struct syn_pattern));
- if (ppp->pp_synp == NULL)
- {
- rest = NULL;
- break;
- }
- /*
- * Get the syntax pattern and the following offset(s).
- */
- rest = get_syn_pattern(rest, ppp->pp_synp);
- if (item == ITEM_END && vim_regcomp_had_eol())
- ppp->pp_synp->sp_flags |= HL_HAS_EOL;
- ppp->pp_matchgroup_id = matchgroup_id;
- ++pat_count;
- }
- }
- vim_free(key);
- if (illegal || not_enough)
- rest = NULL;
- /*
- * Must have a "start" and "end" pattern.
- */
- if (rest != NULL && (pat_ptrs[ITEM_START] == NULL ||
- pat_ptrs[ITEM_END] == NULL))
- {
- not_enough = TRUE;
- rest = NULL;
- }
- if (rest != NULL)
- {
- /*
- * Check for trailing garbage or command.
- * If OK, add the item.
- */
- eap->nextcmd = check_nextcmd(rest);
- if (!ends_excmd(*rest) || eap->skip)
- rest = NULL;
- else if (ga_grow(&(curbuf->b_syn_patterns), pat_count) != FAIL
- && (syn_id = syn_check_group(arg,
- (int)(group_name_end - arg))) != 0)
- {
- syn_incl_toplevel(syn_id, &flags);
- /*
- * Store the start/skip/end in the syn_items list
- */
- idx = curbuf->b_syn_patterns.ga_len;
- for (item = ITEM_START; item <= ITEM_END; ++item)
- {
- for (ppp = pat_ptrs[item]; ppp != NULL; ppp = ppp->pp_next)
- {
- SYN_ITEMS(curbuf)[idx] = *(ppp->pp_synp);
- SYN_ITEMS(curbuf)[idx].sp_syncing = syncing;
- SYN_ITEMS(curbuf)[idx].sp_type =
- (item == ITEM_START) ? SPTYPE_START :
- (item == ITEM_SKIP) ? SPTYPE_SKIP : SPTYPE_END;
- SYN_ITEMS(curbuf)[idx].sp_flags |= flags;
- SYN_ITEMS(curbuf)[idx].sp_syn_id = syn_id;
- SYN_ITEMS(curbuf)[idx].sp_syn_inc_lvl = current_syn_inc_lvl;
- SYN_ITEMS(curbuf)[idx].sp_syn_match_id =
- ppp->pp_matchgroup_id;
- if (item == ITEM_START)
- {
- SYN_ITEMS(curbuf)[idx].sp_cont_list = cont_list;
- SYN_ITEMS(curbuf)[idx].sp_next_list = next_list;
- }
- ++curbuf->b_syn_patterns.ga_len;
- --curbuf->b_syn_patterns.ga_room;
- ++idx;
- }
- }
- redraw_curbuf_later(NOT_VALID);
- success = TRUE; /* don't free the progs and patterns now */
- }
- }
- /*
- * Free the allocated memory.
- */
- for (item = ITEM_START; item <= ITEM_END; ++item)
- for (ppp = pat_ptrs[item]; ppp != NULL; ppp = ppp_next)
- {
- if (!success)
- {
- vim_free(ppp->pp_synp->sp_prog);
- vim_free(ppp->pp_synp->sp_pattern);
- }
- vim_free(ppp->pp_synp);
- ppp_next = ppp->pp_next;
- vim_free(ppp);
- }
- if (!success)
- {
- vim_free(cont_list);
- vim_free(next_list);
- if (not_enough)
- EMSG2("Not enough arguments: syntax region %s", arg);
- else if (illegal || rest == NULL)
- EMSG2(e_invarg2, arg);
- }
- }
- /*
- * A simple syntax group ID comparison function suitable for use in qsort()
- */
- static int
- #ifdef __BORLANDC__
- _RTLENTRYF
- #endif
- syn_compare_stub(v1, v2)
- const void *v1;
- const void *v2;
- {
- const short *s1 = v1;
- const short *s2 = v2;
- return (*s1 > *s2 ? 1 : *s1 < *s2 ? -1 : 0);
- }
- /*
- * Combines lists of syntax clusters.
- * *clstr1 and *clstr2 must both be allocated memory; they will be consumed.
- */
- static void
- syn_combine_list(clstr1, clstr2, list_op)
- short **clstr1;
- short **clstr2;
- int list_op;
- {
- int count1 = 0;
- int count2 = 0;
- short *g1;
- short *g2;
- short *clstr = NULL;
- int count;
- int round;
- /*
- * Handle degenerate cases.
- */
- if (*clstr2 == NULL)
- return;
- if (*clstr1 == NULL || list_op == CLUSTER_REPLACE)
- {
- if (list_op == CLUSTER_REPLACE)
- vim_free(*clstr1);
- if (list_op == CLUSTER_REPLACE || list_op == CLUSTER_ADD)
- *clstr1 = *clstr2;
- else
- vim_free(*clstr2);
- return;
- }
- for (g1 = *clstr1; *g1; g1++)
- ++count1;
- for (g2 = *clstr2; *g2; g2++)
- ++count2;
- /*
- * For speed purposes, sort both lists.
- */
- qsort(*clstr1, (size_t)count1, sizeof(short), syn_compare_stub);
- qsort(*clstr2, (size_t)count2, sizeof(short), syn_compare_stub);
- /*
- * We proceed in two passes; in round 1, we count the elements to place
- * in the new list, and in round 2, we allocate and populate the new
- * list. For speed, we use a mergesort-like method, adding the smaller
- * of the current elements in each list to the new list.
- */
- for (round = 1; round <= 2; round++)
- {
- g1 = *clstr1;
- g2 = *clstr2;
- count = 0;
- /*
- * First, loop through the lists until one of them is empty.
- */
- while (*g1 && *g2)
- {
- /*
- * We always want to add from the first list.
- */
- if (*g1 < *g2)
- {
- if (round == 2)
- clstr[count] = *g1;
- count++;
- g1++;
- continue;
- }
- /*
- * We only want to add from the second list if we're adding the
- * lists.
- */
- if (list_op == CLUSTER_ADD)
- {
- if (round == 2)
- clstr[count] = *g2;
- count++;
- }
- if (*g1 == *g2)
- g1++;
- g2++;
- }
- /*
- * Now add the leftovers from whichever list didn't get finished
- * first. As before, we only want to add from the second list if
- * we're adding the lists.
- */
- for (; *g1; g1++, count++)
- if (round == 2)
- clstr[count] = *g1;
- if (list_op == CLUSTER_ADD)
- for (; *g2; g2++, count++)
- if (round == 2)
- clstr[count] = *g2;
- if (round == 1)
- {
- /*
- * If the group ended up empty, we don't need to allocate any
- * space for it.
- */
- if (count == 0)
- {
- clstr = NULL;
- break;
- }
- clstr = (short *)alloc((unsigned)((count + 1) * sizeof(short)));
- if (clstr == NULL)
- break;
- clstr[count] = 0;
- }
- }
- /*
- * Finally, put the new list in place.
- */
- vim_free(*clstr1);
- vim_free(*clstr2);
- *clstr1 = clstr;
- }
- /*
- * Lookup a syntax cluster name and return it's ID.
- * If it is not found, 0 is returned.
- */
- static int
- syn_scl_name2id(name)
- char_u *name;
- {
- int i;
- char_u *name_u;
- /* Avoid using stricmp() too much, it's slow on some systems */
- name_u = vim_strsave_up(name);
- if (name_u == NULL)
- return 0;
- for (i = curbuf->b_syn_clusters.ga_len; --i >= 0; )
- if (SYN_CLSTR(curbuf)[i].scl_name_u != NULL
- && STRCMP(name_u, SYN_CLSTR(curbuf)[i].scl_name_u) == 0)
- break;
- vim_free(name_u);
- return (i < 0 ? 0 : i + CLUSTER_ID_MIN);
- }
- /*
- * Like syn_scl_name2id(), but take a pointer + length argument.
- */
- static int
- syn_scl_namen2id(linep, len)
- char_u *linep;
- int len;
- {
- char_u *name;
- int id = 0;
- name = vim_strnsave(linep, len);
- if (name != NULL)
- {
- id = syn_scl_name2id(name);
- vim_free(name);
- }
- return id;
- }
- /*
- * Find syntax cluster name in the table and return it's ID.
- * The argument is a pointer to the name and the length of the name.
- * If it doesn't exist yet, a new entry is created.
- * Return 0 for failure.
- */
- static int
- syn_check_cluster(pp, len)
- char_u *pp;
- int len;
- {
- int id;
- char_u *name;
- name = vim_strnsave(pp, len);
- if (name == NULL)
- return 0;
- id = syn_scl_name2id(name);
- if (id == 0) /* doesn't exist yet */
- id = syn_add_cluster(name);
- else
- vim_free(name);
- return id;
- }
- /*
- * Add new syntax cluster and return it's ID.
- * "name" must be an allocated string, it will be consumed.
- * Return 0 for failure.
- */
- static int
- syn_add_cluster(name)
- char_u *name;
- {
- int len;
- /*
- * First call for this growarray: init growing array.
- */
- if (curbuf->b_syn_clusters.ga_data == NULL)
- {
- curbuf->b_syn_clusters.ga_itemsize = sizeof(struct syn_cluster);
- curbuf->b_syn_clusters.ga_growsize = 10;
- }
- /*
- * Make room for at least one other cluster entry.
- */
- if (ga_grow(&curbuf->b_syn_clusters, 1) == FAIL)
- {
- vim_free(name);
- return 0;
- }
- len = curbuf->b_syn_clusters.ga_len;
- vim_memset(&(SYN_CLSTR(curbuf)[len]), 0, sizeof(struct syn_cluster));
- SYN_CLSTR(curbuf)[len].scl_name = name;
- SYN_CLSTR(curbuf)[len].scl_name_u = vim_strsave_up(name);
- SYN_CLSTR(curbuf)[len].scl_list = NULL;
- ++curbuf->b_syn_clusters.ga_len;
- --curbuf->b_syn_clusters.ga_room;
- return len + CLUSTER_ID_MIN;
- }
- /*
- * Handle ":syntax cluster {cluster-name} [contains={groupname},..]
- * [add={groupname},..] [remove={groupname},..]".
- */
- /* ARGSUSED */
- static void
- syn_cmd_cluster(eap, syncing)
- EXARG *eap;
- int syncing; /* not used */
- {
- char_u *arg = eap->arg;
- char_u *group_name_end;
- char_u *rest;
- int scl_id;
- short *clstr_list;
- int got_clstr = FALSE;
- int opt_len;
- int list_op;
- eap->nextcmd = find_nextcmd(arg);
- if (eap->skip)
- return;
- rest = get_group_name(arg, &group_name_end);
- if (rest != NULL)
- {
- scl_id = syn_check_cluster(arg, (int)(group_name_end - arg))
- - CLUSTER_ID_MIN;
- for (;;)
- {
- if (STRNICMP(rest, "add", 3) == 0
- && (vim_iswhite(rest[3]) || rest[3] == '='))
- {
- opt_len = 3;
- list_op = CLUSTER_ADD;
- }
- else if (STRNICMP(rest, "remove", 6) == 0
- && (vim_iswhite(rest[6]) || rest[6] == '='))
- {
- opt_len = 6;
- list_op = CLUSTER_SUBTRACT;
- }
- else if (STRNICMP(rest, "contains", 8) == 0
- && (vim_iswhite(rest[8]) || rest[8] == '='))
- {
- opt_len = 8;
- list_op = CLUSTER_REPLACE;
- }
- else
- break;
- clstr_list = NULL;
- if (get_id_list(&rest, opt_len, &clstr_list) == FAIL)
- {
- EMSG2(e_invarg2, rest);
- break;
- }
- syn_combine_list(&SYN_CLSTR(curbuf)[scl_id].scl_list,
- &clstr_list, list_op);
- got_clstr = TRUE;
- }
- if (got_clstr)
- redraw_curbuf_later(NOT_VALID);
- }
- if (!got_clstr)
- EMSG("No cluster specified");
- if (rest == NULL || !ends_excmd(*rest))
- EMSG2(e_invarg2, arg);
- }
- /*
- * On first call for current buffer: Init growing array.
- */
- static void
- init_syn_patterns()
- {
- curbuf->b_syn_patterns.ga_itemsize = sizeof(struct syn_pattern);
- curbuf->b_syn_patterns.ga_growsize = 10;
- }
- /*
- * Get one pattern for a ":syntax match" or ":syntax region" command.
- * Stores the pattern and program in a struct syn_pattern.
- * Returns a pointer to the next argument, or NULL in case of an error.
- */
- static char_u *
- get_syn_pattern(arg, ci)
- char_u *arg;
- struct syn_pattern *ci;
- {
- char_u *end;
- int *p;
- int idx;
- char_u *cpo_save;
- /* need at least three chars */
- if (arg == NULL || arg[1] == NUL || arg[2] == NUL)
- return NULL;
- end = skip_regexp(arg + 1, *arg, TRUE);
- if (*end != *arg) /* end delimiter not found */
- {
- EMSG2("Pattern delimiter not found: %s", arg);
- return NULL;
- }
- /* store the pattern and compiled regexp program */
- if ((ci->sp_pattern = vim_strnsave(arg + 1, (int)(end - arg - 1))) == NULL)
- return NULL;
- /* Make 'cpoptions' empty, to avoid the 'l' flag */
- cpo_save = p_cpo;
- p_cpo = (char_u *)"";
- ci->sp_prog = vim_regcomp(ci->sp_pattern, TRUE);
- p_cpo = cpo_save;
- if (ci->sp_prog == NULL)
- return NULL;
- ci->sp_ic = curbuf->b_syn_ic;
- /*
- * Check for a match, highlight or region offset.
- */
- ++end;
- do
- {
- for (idx = SPO_COUNT; --idx >= 0; )
- if (STRNCMP(end, spo_name_tab[idx], 3) == 0)
- break;
- if (idx >= 0)
- {
- p = &(ci->sp_offsets[idx]);
- if (idx != SPO_LC_OFF)
- switch (end[3])
- {
- case 's': break;
- case 'b': break;
- case 'e': idx += SPO_COUNT; break;
- default: idx = -1; break;
- }
- if (idx >= 0)
- {
- ci->sp_off_flags |= (1 << idx);
- if (idx == SPO_LC_OFF) /* lc=99 */
- {
- end += 3;
- *p = getdigits(&end);
- /* "lc=" offset automatically sets "ms=" offset */
- if (!(ci->sp_off_flags & (1 << SPO_MS_OFF)))
- {
- ci->sp_off_flags |= (1 << SPO_MS_OFF);
- ci->sp_offsets[SPO_MS_OFF] = *p;
- }
- }
- else /* yy=x+99 */
- {
- end += 4;
- if (*end == '+')
- {
- ++end;
- *p = getdigits(&end); /* positive offset */
- }
- else if (*end == '-')
- {
- ++end;
- *p = -getdigits(&end); /* negative offset */
- }
- }
- if (*end != ',')
- break;
- ++end;
- }
- }
- } while (idx >= 0);
- if (!ends_excmd(*end) && !vim_iswhite(*end))
- {
- EMSG2("Garbage after pattern: %s", arg);
- return NULL;
- }
- return skipwhite(end);
- }
- /*
- * Handle ":syntax sync .." command.
- */
- /* ARGSUSED */
- static void
- syn_cmd_sync(eap, syncing)
- EXARG *eap;
- int syncing; /* not used */
- {
- char_u *arg_start = eap->arg;
- char_u *arg_end;
- char_u *key = NULL;
- char_u *next_arg;
- int illegal = FALSE;
- int finished = FALSE;
- long n;
- char_u *cpo_save;
- if (ends_excmd(*arg_start))
- {
- syn_cmd_list(eap, TRUE);
- return;
- }
- while (!ends_excmd(*arg_start))
- {
- arg_end = skiptowhite(arg_start);
- next_arg = skipwhite(arg_end);
- vim_free(key);
- key = vim_strnsave_up(arg_start, (int)(arg_end - arg_start));
- if (STRCMP(key, "CCOMMENT") == 0)
- {
- if (!eap->skip)
- curbuf->b_syn_sync_flags |= SF_CCOMMENT;
- if (!ends_excmd(*next_arg))
- {
- arg_end = skiptowhite(next_arg);
- if (!eap->skip)
- curbuf->b_syn_sync_id = syn_check_group(next_arg,
- (int)(arg_end - next_arg));
- next_arg = skipwhite(arg_end);
- }
- else if (!eap->skip)
- curbuf->b_syn_sync_id = syn_name2id((char_u *)"Comment");
- }
- else if ( STRNCMP(key, "LINES", 5) == 0
- || STRNCMP(key, "MINLINES", 8) == 0
- || STRNCMP(key, "MAXLINES", 8) == 0)
- {
- if (key[0] == 'L')
- arg_end = key + 6;
- else
- arg_end = key + 9;
- if (arg_end[-1] != '=' || !isdigit(*arg_end))
- {
- illegal = TRUE;
- break;
- }
- n = getdigits(&arg_end);
- if (!eap->skip)
- {
- if (key[1] == 'A')
- curbuf->b_syn_sync_maxlines = n;
- else
- curbuf->b_syn_sync_minlines = n;
- }
- }
- else if (STRCMP(key, "LINECONT") == 0)
- {
- if (curbuf->b_syn_linecont_pat != NULL)
- {
- EMSG("syntax sync: line continuations pattern specified twice");
- finished = TRUE;
- break;
- }
- arg_end = skip_regexp(next_arg + 1, *next_arg, TRUE);
- if (*arg_end != *next_arg) /* end delimiter not found */
- {
- illegal = TRUE;
- break;
- }
- if (!eap->skip)
- {
- /* store the pattern and compiled regexp program */
- if ((curbuf->b_syn_linecont_pat = vim_strnsave(next_arg + 1,
- (int)(arg_end - next_arg - 1))) == NULL)
- {
- finished = TRUE;
- break;
- }
- curbuf->b_syn_linecont_ic = curbuf->b_syn_ic;
- /* Make 'cpoptions' empty, to avoid the 'l' flag */
- cpo_save = p_cpo;
- p_cpo = (char_u *)"";
- curbuf->b_syn_linecont_prog =
- vim_regcomp(curbuf->b_syn_linecont_pat, TRUE);
- p_cpo = cpo_save;
- if (curbuf->b_syn_linecont_prog == NULL)
- {
- vim_free(curbuf->b_syn_linecont_pat);
- curbuf->b_syn_linecont_pat = NULL;
- finished = TRUE;
- break;
- }
- }
- next_arg = skipwhite(arg_end + 1);
- }
- else
- {
- eap->arg = next_arg;
- if (STRCMP(key, "MATCH") == 0)
- syn_cmd_match(eap, TRUE);
- else if (STRCMP(key, "REGION") == 0)
- syn_cmd_region(eap, TRUE);
- else if (STRCMP(key, "CLEAR") == 0)
- syn_cmd_clear(eap, TRUE);
- else
- illegal = TRUE;
- finished = TRUE;
- break;
- }
- arg_start = next_arg;
- }
- vim_free(key);
- if (illegal)
- EMSG2("Illegal arguments: %s", arg_start);
- else if (!finished)
- {
- eap->nextcmd = check_nextcmd(arg_start);
- redraw_curbuf_later(NOT_VALID);
- }
- }
- /*
- * Convert a line of highlight group names into a list of group ID numbers.
- * "arg" should point to the "contains" or "nextgroup" keyword.
- * "arg" is advanced to after the last group name.
- * Careful: the argument is modified (NULs added).
- * returns FAIL for some error, OK for success.
- */
- static int
- get_id_list(arg, keylen, list)
- char_u **arg;
- int keylen; /* length of keyword */
- short **list; /* where to store the resulting list, if not
- NULL, the list is silently skipped! */
- {
- char_u *p;
- char_u *end;
- int round;
- int count;
- short *retval = NULL;
- char_u *name;
- vim_regexp *prog;
- int id;
- int i;
- int failed = FALSE;
- /*
- * We parse the list twice:
- * round == 1: count the number of items, allocate the array.
- * round == 2: fill the array with the items.
- */
- for (round = 1; round <= 2; ++round)
- {
- /*
- * skip "contains"
- */
- p = skipwhite(*arg + keylen);
- if (*p != '=')
- {
- EMSG2("Missing equal sign: %s", *arg);
- break;
- }
- p = skipwhite(p + 1);
- if (ends_excmd(*p))
- {
- EMSG2("Empty argument: %s", *arg);
- break;
- }
- /*
- * parse the arguments after "contains"
- */
- count = 0;
- while (!ends_excmd(*p))
- {
- for (end = p; *end && !vim_iswhite(*end) && *end != ','; ++end)
- ;
- name = alloc((int)(end - p + 3)); /* leave room for "^$" */
- if (name == NULL)
- {
- failed = TRUE;
- break;
- }
- STRNCPY(name + 1, p, end - p);
- name[end - p + 1] = NUL;
- if ( STRCMP(name + 1, "ALLBUT") == 0
- || STRCMP(name + 1, "ALL") == 0)
- {
- if (TO_UPPER(**arg) != 'C')
- {
- EMSG2("%s not allowed here", name + 1);
- failed = TRUE;
- vim_free(name);
- break;
- }
- if (count != 0)
- {
- EMSG2("%s must be first in contains list", name + 1);
- failed = TRUE;
- vim_free(name);
- break;
- }
- id = CONTAINS_ALLBUT + current_syn_inc_lvl;
- }
- else if (name[1] == '@')
- {
- id = syn_check_cluster(name + 2, (int)(end - p - 1));
- }
- else
- {
- /*
- * Handle full group name.
- */
- if (vim_strpbrk(name + 1, (char_u *)"\.*^$~[") == NULL)
- id = syn_check_group(name + 1, (int)(end - p));
- else
- {
- /*
- * Handle match of regexp with group names.
- */
- *name = '^';
- STRCAT(name, "$");
- prog = vim_regcomp(name, TRUE);
- if (prog == NULL)
- {
- failed = TRUE;
- vim_free(name);
- break;
- }
- reg_ic = TRUE;
- id = 0;
- for (i = highlight_ga.ga_len; --i >= 0; )
- {
- if (vim_regexec(prog, HL_TABLE()[i].sg_name, TRUE))
- {
- if (round == 2)
- retval[count] = i + 1;
- ++count;
- id = -1; /* remember that we found one */
- }
- }
- vim_free(prog);
- }
- }
- vim_free(name);
- if (id == 0)
- {
- EMSG2("Unknown group name: %s", p);
- failed = TRUE;
- break;
- }
- if (id > 0)
- {
- if (round == 2)
- retval[count] = id;
- ++count;
- }
- p = skipwhite(end);
- if (*p != ',')
- break;
- p = skipwhite(p + 1); /* skip comma in between arguments */
- }
- if (failed)
- break;
- if (round == 1)
- {
- retval = (short *)alloc((unsigned)((count + 1) * sizeof(short)));
- if (retval == NULL)
- break;
- retval[count] = 0; /* zero means end of the list */
- }
- }
- *arg = p;
- if (failed || retval == NULL)
- {
- vim_free(retval);
- return FAIL;
- }
- if (*list == NULL)
- *list = retval;
- else
- vim_free(retval); /* list already found, don't overwrite it */
- return OK;
- }
- /*
- * Make a copy of an ID list.
- */
- static short *
- copy_id_list(list)
- short *list;
- {
- int len;
- int count;
- short *retval;
- if (list == NULL)
- return NULL;
- for (count = 0; list[count]; ++count)
- ;
- len = (count + 1) * sizeof(short);
- retval = (short *)alloc((unsigned)len);
- if (retval != NULL)
- mch_memmove(retval, list, (size_t)len);
- return retval;
- }
- /*
- * Check if "id" is in the "contains" or "nextgroup" list of pattern "idx".
- */
- static int
- in_id_list(list, id, inclvl, contained)
- short *list; /* id list */
- int id; /* group id */
- int inclvl; /* ":syn include" level of group id */
- int contained; /* group id is contained */
- {
- int retval;
- short scl_id;
- short *scl_list;
- /*
- * If list is ID_LIST_ALL, we are in a transparent item that isn't
- * inside anything. Only allow not-contained groups.
- */
- if (list == ID_LIST_ALL)
- return !contained;
- /*
- * If the first item is "ALLBUT", return TRUE if id is NOT in the contains
- * list. We also require that id is at the same ":syn include" level
- * as the list.
- */
- if (*list >= CONTAINS_ALLBUT && *list < CLUSTER_ID_MIN)
- {
- if (*list - CONTAINS_ALLBUT != inclvl)
- return FALSE;
- ++list;
- retval = FALSE;
- }
- else
- retval = TRUE;
- /*
- * Return "retval" if id is in the contains list.
- */
- for (; *list; ++list)
- {
- if (*list == id)
- return retval;
- scl_id = *list - CLUSTER_ID_MIN;
- if (scl_id >= 0)
- {
- scl_list = SYN_CLSTR(syn_buf)[scl_id].scl_list;
- if (scl_list != NULL && in_id_list(scl_list, id, inclvl, contained))
- return retval;
- }
- }
- return !retval;
- }
- struct subcommand
- {
- char *name; /* subcommand name */
- void (*func)__ARGS((EXARG *, int)); /* function to call */
- };
- static struct subcommand subcommands[] =
- {
- {"case", syn_cmd_case},
- {"clear", syn_cmd_clear},
- {"cluster", syn_cmd_cluster},
- {"include", syn_cmd_include},
- {"keyword", syn_cmd_keyword},
- {"list", syn_cmd_list},
- {"match", syn_cmd_match},
- {"on", syn_cmd_on},
- {"off", syn_cmd_off},
- {"region", syn_cmd_region},
- {"sync", syn_cmd_sync},
- {"", syn_cmd_list},
- {NULL, NULL}
- };
- /*
- * Handle the ":syntax" command.
- * This searches the subcommands[] table for the subcommand name, and calls a
- * syntax_subcommand() function to do the rest.
- */
- void
- do_syntax(eap, cmdlinep)
- EXARG *eap;
- char_u **cmdlinep;
- {
- char_u *arg = eap->arg;
- char_u *subcmd_end;
- char_u *subcmd_name;
- int i;
- syn_cmdlinep = cmdlinep;
- /* isolate subcommand name */
- for (subcmd_end = arg; isalpha(*subcmd_end); ++subcmd_end)
- ;
- subcmd_name = vim_strnsave(arg, (int)(subcmd_end - arg));
- if (subcmd_name != NULL)
- {
- if (eap->skip) /* skip error messages for all subcommands */
- ++emsg_off;
- for (i = 0; ; ++i)
- {
- if (subcommands[i].name == NULL)
- {
- EMSG2("Invalid :syntax subcommand: %s", subcmd_name);
- break;
- }
- if (STRCMP(subcmd_name, (char_u *)subcommands[i].name) == 0)
- {
- eap->arg = skipwhite(subcmd_end);
- (subcommands[i].func)(eap, FALSE);
- break;
- }
- }
- vim_free(subcmd_name);
- if (eap->skip)
- --emsg_off;
- }
- }
- int
- syntax_present(buf)
- BUF *buf;
- {
- return (buf->b_syn_patterns.ga_len != 0
- || buf->b_syn_clusters.ga_len != 0
- || curbuf->b_keywtab != NULL
- || curbuf->b_keywtab_ic != NULL);
- }
- static enum
- {
- EXP_SUBCMD, /* expand ":syn" sub-commands */
- EXP_CASE /* expand ":syn case" arguments */
- } expand_what;
- /*
- * Handle command line completion for :syntax command.
- */
- void
- set_context_in_syntax_cmd(arg)
- char_u *arg;
- {
- char_u *p;
- /* Default: expand subcommands */
- expand_context = EXPAND_SYNTAX;
- expand_what = EXP_SUBCMD;
- expand_pattern = arg;
- include_link = FALSE;
- /* (part of) subcommand already typed */
- if (*arg != NUL)
- {
- p = skiptowhite(arg);
- if (*p != NUL) /* past first word */
- {
- expand_pattern = skipwhite(p);
- if (*skiptowhite(expand_pattern) != NUL)
- expand_context = EXPAND_NOTHING;
- else if (STRNICMP(arg, "case", p - arg) == 0)
- expand_what = EXP_CASE;
- else if ( STRNICMP(arg, "keyword", p - arg) == 0
- || STRNICMP(arg, "region", p - arg) == 0
- || STRNICMP(arg, "match", p - arg) == 0
- || STRNICMP(arg, "list", p - arg) == 0)
- expand_context = EXPAND_HIGHLIGHT;
- else
- expand_context = EXPAND_NOTHING;
- }
- }
- }
- static char *(case_args[]) = {"match", "ignore", NULL};
- /*
- * Function given to ExpandGeneric() to obtain the list syntax names for
- * expansion.
- */
- char_u *
- get_syntax_name(idx)
- int idx;
- {
- if (expand_what == EXP_SUBCMD)
- return (char_u *)subcommands[idx].name;
- return (char_u *)case_args[idx];
- }
- #ifdef WANT_EVAL
- /*
- * Function called for expression evaluation: get syntax ID at file position.
- */
- int
- syn_get_id(line, col, trans)
- long line;
- long col;
- int trans; /* remove transparancy */
- {
- if (curwin->w_buffer != syn_buf
- || col < (long)current_col || line != current_lnum)
- syntax_start(curwin, line);
- (void)get_syntax_attr((colnr_t)col, ml_get((linenr_t)line));
- return (trans ? current_trans_id : current_id);
- }
- #endif
- /*
- * Call vim_regexec() with the current buffer set to syn_buf. Makes
- * vim_iswordc() work correctly.
- */
- static int
- syn_regexec(prog, string, at_bol)
- vim_regexp *prog;
- char_u *string;
- int at_bol;
- {
- int retval;
- BUF *save_curbuf;
- save_curbuf = curbuf;
- curbuf = syn_buf;
- retval = vim_regexec(prog, string, at_bol);
- curbuf = save_curbuf;
- return retval;
- }
- #endif /* SYNTAX_HL */
- /**************************************
- * Highlighting stuff *
- **************************************/
- /*
- * The default highlight groups. Used in the 'highlight' and 'guicursor'
- * options default. Depends on 'background' option.
- */
- static char *(highlight_init_both[]) =
- {
- #ifdef USE_GUI
- "Cursor guibg=fg guifg=bg",
- #endif
- "ErrorMsg term=standout ctermbg=DarkRed ctermfg=White guibg=Red guifg=White",
- "IncSearch term=reverse cterm=reverse gui=reverse",
- "ModeMsg term=bold cterm=bold gui=bold",
- "NonText term=bold ctermfg=Blue gui=bold guifg=Blue",
- "StatusLine term=reverse,bold cterm=reverse,bold gui=reverse,bold",
- "StatusLineNC term=reverse cterm=reverse gui=reverse",
- "Visual term=reverse cterm=reverse gui=reverse guifg=Grey guibg=fg",
- NULL
- };
- static char *(highlight_init_light[]) =
- {
- "Directory term=bold ctermfg=DarkBlue guifg=Blue",
- "LineNr term=underline ctermfg=Brown guifg=Brown",
- "MoreMsg term=bold ctermfg=DarkGreen gui=bold guifg=SeaGreen",
- "Normal gui=NONE",
- "Question term=standout ctermfg=DarkGreen gui=bold guifg=SeaGreen",
- "Search term=reverse ctermbg=Yellow ctermfg=NONE guibg=Yellow guifg=NONE",
- "SpecialKey term=bold ctermfg=DarkBlue guifg=Blue",
- "Title term=bold ctermfg=DarkMagenta gui=bold guifg=Magenta",
- "WarningMsg term=standout ctermfg=DarkRed guifg=Red",
- NULL
- };
- static char *(highlight_init_dark[]) =
- {
- "Directory term=bold ctermfg=LightCyan guifg=Cyan",
- "LineNr term=underline ctermfg=Yellow guifg=Yellow",
- "MoreMsg term=bold ctermfg=LightGreen gui=bold guifg=SeaGreen",
- "Normal gui=NONE",
- "Question term=standout ctermfg=LightGreen gui=bold guifg=Green",
- "Search term=reverse ctermbg=Yellow ctermfg=Black guibg=Yellow guifg=Black",
- "SpecialKey term=bold ctermfg=LightBlue guifg=Cyan",
- "Title term=bold ctermfg=LightMagenta gui=bold guifg=Magenta",
- "WarningMsg term=standout ctermfg=LightRed guifg=Red",
- NULL
- };
- void
- init_highlight(both)
- int both; /* include groups where 'bg' doesn't matter */
- {
- int i;
- char **pp;
- if (both)
- {
- pp = highlight_init_both;
- for (i = 0; pp[i] != NULL; ++i)
- do_highlight((char_u *)pp[i], FALSE, TRUE);
- }
- if (TO_LOWER(*p_bg) == 'l')
- pp = highlight_init_light;
- else
- pp = highlight_init_dark;
- for (i = 0; pp[i] != NULL; ++i)
- do_highlight((char_u *)pp[i], FALSE, TRUE);
- }
- /*
- * Handle the ":highlight .." command.
- */
- void
- do_highlight(line, forceit, init)
- char_u *line;
- int forceit;
- int init; /* TRUE when called for initializing */
- {
- char_u *name_end;
- char_u *p;
- char_u *linep;
- char_u *key_start;
- char_u *arg_start;
- char_u *key = NULL, *arg = NULL;
- int i;
- int off;
- int len;
- int attr;
- int id;
- int idx;
- int doclear = FALSE;
- int dolink = FALSE;
- int error = FALSE;
- int color;
- int is_normal_group = FALSE; /* "Normal" group */
- #ifdef USE_GUI_X11
- int is_menu_group = FALSE; /* "Menu" group */
- int is_scrollbar_group = FALSE; /* "Scrollbar" group */
- #endif
- /*
- * If no argument, list current highlighting.
- */
- if (ends_excmd(*line))
- {
- for (i = 1; i <= highlight_ga.ga_len && !got_int; ++i)
- /* TODO: only call when the group has attributes set */
- highlight_list_one(i);
- return;
- }
- /*
- * Isolate the name.
- */
- name_end = skiptowhite(line);
- linep = skipwhite(name_end);
- if (STRNCMP(line, "clear", name_end - line) == 0)
- doclear = TRUE;
- if (STRNCMP(line, "link", name_end - line) == 0)
- dolink = TRUE;
- /*
- * ":highlight {group-name}": list highlighting for one group.
- */
- if (!doclear && !dolink && ends_excmd(*linep))
- {
- id = syn_namen2id(line, (int)(name_end - line));
- if (id == 0)
- EMSG2("highlight group not found: %s", line);
- else
- highlight_list_one(id);
- return;
- }
- /*
- * Handle ":highlight link {from} {to}" command.
- */
- if (dolink)
- {
- char_u *from_start = linep;
- char_u *from_end;
- char_u *to_start;
- char_u *to_end;
- int from_id;
- int to_id;
- from_end = skiptowhite(from_start);
- to_start = skipwhite(from_end);
- to_end = skiptowhite(to_start);
- if (ends_excmd(*from_start) || ends_excmd(*to_start))
- {
- EMSG2("Not enough arguments: ":highlight link %s"", from_start);
- return;
- }
- if (!ends_excmd(*skipwhite(to_end)))
- {
- EMSG2("Too many arguments: ":highlight link %s"", from_start);
- return;
- }
- from_id = syn_check_group(from_start, (int)(from_end - from_start));
- if (STRNCMP(to_start, "NONE", 4) == 0)
- to_id = 0;
- else
- to_id = syn_check_group(to_start, (int)(to_end - to_start));
- if (from_id > 0 && (!init || HL_TABLE()[from_id - 1].sg_set == 0))
- {
- /*
- * Don't allow a link when there already is some highlighting
- * for the group, unless '!' is used
- */
- if (to_id > 0 && !forceit && !init
- && (HL_TABLE()[from_id - 1].sg_term_attr != 0
- || HL_TABLE()[from_id - 1].sg_cterm_attr != 0
- #ifdef USE_GUI
- || HL_TABLE()[from_id - 1].sg_gui_attr != 0
- #endif
- ))
- {
- if (sourcing_name == NULL)
- EMSG("group has settings, highlight link ignored");
- }
- else
- {
- if (!init)
- HL_TABLE()[from_id - 1].sg_set |= SG_LINK;
- HL_TABLE()[from_id - 1].sg_link = to_id;
- }
- }
- redraw_curbuf_later(NOT_VALID);
- return;
- }
- /*
- * Handle ":highlight clear {group}" command.
- */
- if (doclear)
- {
- line = linep;
- if (ends_excmd(*line))
- {
- EMSG("Cannot clear all highlight groups");
- return;
- }
- name_end = skiptowhite(line);
- linep = skipwhite(name_end);
- }
- /*
- * Find the group name in the table. If it does not exist yet, add it.
- */
- id = syn_check_group(line, (int)(name_end - line));
- if (id == 0) /* failed (out of memory) */
- return;
- idx = id - 1; /* index is ID minus one */
- if (STRCMP(HL_TABLE()[idx].sg_name_u, "NORMAL") == 0)
- is_normal_group = TRUE;
- #ifdef USE_GUI_X11
- else if (STRCMP(HL_TABLE()[idx].sg_name_u, "MENU") == 0)
- is_menu_group = TRUE;
- else if (STRCMP(HL_TABLE()[idx].sg_name_u, "SCROLLBAR") == 0)
- is_scrollbar_group = TRUE;
- #endif
- if (doclear)
- highlight_clear(idx);
- else
- while (!ends_excmd(*linep))
- {
- key_start = linep;
- if (*linep == '=')
- {
- EMSG2("unexpected equal sign: %s", key_start);
- error = TRUE;
- break;
- }
- /*
- * Isolate the key ("term", "ctermfg", "ctermbg", "font", "guifg" or
- * "guibg").
- */
- while (*linep && !vim_iswhite(*linep) && *linep != '=')
- ++linep;
- vim_free(key);
- key = vim_strnsave_up(key_start, (int)(linep - key_start));
- if (key == NULL)
- {
- error = TRUE;
- break;
- }
- linep = skipwhite(linep);
- if (STRCMP(key, "NONE") == 0)
- {
- if (!init || HL_TABLE()[idx].sg_set == 0)
- {
- if (!init)
- HL_TABLE()[idx].sg_set |= SG_TERM+SG_CTERM+SG_GUI;
- highlight_clear(idx);
- }
- continue;
- }
- /*
- * Check for the equal sign.
- */
- if (*linep != '=')
- {
- EMSG2("missing equal sign: %s", key_start);
- error = TRUE;
- break;
- }
- ++linep;
- /*
- * Isolate the argument.
- */
- linep = skipwhite(linep);
- if (*linep == ''') /* guifg='color name' */
- {
- arg_start = ++linep;
- linep = vim_strchr(linep, ''');
- }
- else
- {
- arg_start = linep;
- linep = skiptowhite(linep);
- }
- if (linep == arg_start)
- {
- EMSG2("missing argument: %s", key_start);
- error = TRUE;
- break;
- }
- vim_free(arg);
- arg = vim_strnsave(arg_start, (int)(linep - arg_start));
- if (arg == NULL)
- {
- error = TRUE;
- break;
- }
- if (*linep == ''')
- ++linep;
- /*
- * Store the argument.
- */
- if ( STRCMP(key, "TERM") == 0
- || STRCMP(key, "CTERM") == 0
- || STRCMP(key, "GUI") == 0)
- {
- attr = 0;
- off = 0;
- while (arg[off] != NUL)
- {
- for (i = sizeof(hl_attr_table) / sizeof(int); --i >= 0; )
- {
- len = STRLEN(hl_name_table[i]);
- if (STRNICMP(arg + off, hl_name_table[i], len) == 0)
- {
- attr |= hl_attr_table[i];
- off += len;
- break;
- }
- }
- if (i < 0)
- {
- EMSG2("Illegal value: %s", arg);
- error = TRUE;
- break;
- }
- if (arg[off] == ',') /* another one follows */
- ++off;
- }
- if (error)
- break;
- if (*key == 'T')
- {
- if (!init || !(HL_TABLE()[idx].sg_set & SG_TERM))
- {
- if (!init)
- HL_TABLE()[idx].sg_set |= SG_TERM;
- HL_TABLE()[idx].sg_term = attr;
- }
- }
- else if (*key == 'C')
- {
- if (!init || !(HL_TABLE()[idx].sg_set & SG_CTERM))
- {
- if (!init)
- HL_TABLE()[idx].sg_set |= SG_CTERM;
- HL_TABLE()[idx].sg_cterm = attr;
- HL_TABLE()[idx].sg_cterm_bold = FALSE;
- }
- }
- #ifdef USE_GUI
- else
- {
- if (!init || !(HL_TABLE()[idx].sg_set & SG_GUI))
- {
- if (!init)
- HL_TABLE()[idx].sg_set |= SG_GUI;
- HL_TABLE()[idx].sg_gui = attr;
- }
- }
- #endif
- }
- else if (STRCMP(key, "FONT") == 0)
- {
- #ifdef USE_GUI /* in non-GUI fonts are simply ignored */
- gui_mch_free_font(HL_TABLE()[idx].sg_font);
- HL_TABLE()[idx].sg_font = font_name2handle(arg);
- vim_free(HL_TABLE()[idx].sg_font_name);
- HL_TABLE()[idx].sg_font_name = vim_strsave(arg);
- if (is_normal_group)
- gui_init_font(arg);
- #endif
- }
- else if (STRCMP(key, "CTERMFG") == 0 || STRCMP(key, "CTERMBG") == 0)
- {
- if (!init || !(HL_TABLE()[idx].sg_set & SG_CTERM))
- {
- if (!init)
- HL_TABLE()[idx].sg_set |= SG_CTERM;
- /* When setting the foreground color, and previously the "bold"
- * flag was set for a light color, reset it now */
- if (key[5] == 'F' && HL_TABLE()[idx].sg_cterm_bold)
- {
- HL_TABLE()[idx].sg_cterm &= ~HL_BOLD;
- HL_TABLE()[idx].sg_cterm_bold = FALSE;
- }
- if (isdigit(*arg))
- color = atoi((char *)arg);
- else
- {
- static char *(color_names[26]) = {
- "Black", "DarkBlue", "DarkGreen", "DarkCyan",
- "DarkRed", "DarkMagenta", "Brown", "Gray", "Grey",
- "LightGray", "LightGrey", "DarkGray", "DarkGrey",
- "Blue", "LightBlue", "Green", "LightGreen",
- "Cyan", "LightCyan", "Red", "LightRed", "Magenta",
- "LightMagenta", "Yellow", "White", "NONE"};
- static int color_numbers_16[26] = {0, 1, 2, 3,
- 4, 5, 6, 7, 7,
- 7, 7, 8, 8,
- 9, 9, 10, 10,
- 11, 11, 12, 12, 13,
- 13, 14, 15, -1};
- /* for terminals with less than 16 colors... */
- static int color_numbers_8[26] = {0, 4, 2, 6,
- 1, 5, 3, 7, 7,
- 7, 7, 0+8, 0+8,
- 4+8, 4+8, 2+8, 2+8,
- 6+8, 6+8, 1+8, 1+8, 5+8,
- 5+8, 3+8, 7+8, -1};
- /* reduce calls to STRICMP a bit, it can be slow */
- off = TO_UPPER(*arg);
- for (i = (sizeof(color_names) / sizeof(char *)); --i >= 0; )
- if (off == color_names[i][0]
- && STRICMP(arg + 1, color_names[i] + 1) == 0)
- break;
- if (i < 0)
- {
- EMSG2("Color name or number not recognized: %s", key_start);
- error = TRUE;
- break;
- }
- color = color_numbers_16[i];
- if (color >= 0)
- {
- if (atoi((char *)T_CCO) == 8)
- {
- color = color_numbers_8[i];
- if (key[5] == 'F')
- {
- /* set/reset bold attribute to get light foreground
- * colors (on some terminals, e.g. "linux") */
- if (color & 8)
- {
- HL_TABLE()[idx].sg_cterm |= HL_BOLD;
- HL_TABLE()[idx].sg_cterm_bold = TRUE;
- }
- else
- HL_TABLE()[idx].sg_cterm &= ~HL_BOLD;
- }
- color &= 7;
- }
- else if (atoi((char *)T_CCO) == 16)
- {
- /*
- * Guess: if the termcap entry ends in 'm', it is
- * probably an xterm-like terminal. Use the changed
- * order for colors.
- */
- if (*T_CAF != NUL)
- p = T_CAF;
- else
- p = T_CSF;
- if (*p != NUL && *(p + STRLEN(p) - 1) == 'm')
- color = color_numbers_8[i];
- }
- }
- }
- /* Add one to the argument, to avoid zero */
- if (key[5] == 'F')
- {
- HL_TABLE()[idx].sg_cterm_fg = color + 1;
- if (is_normal_group)
- {
- cterm_normal_fg_color = color + 1;
- cterm_normal_fg_bold = (HL_TABLE()[idx].sg_cterm & HL_BOLD);
- must_redraw = CLEAR;
- term_fg_color(color);
- }
- }
- else
- {
- HL_TABLE()[idx].sg_cterm_bg = color + 1;
- if (is_normal_group)
- {
- cterm_normal_bg_color = color + 1;
- must_redraw = CLEAR;
- term_bg_color(color);
- if (atoi((char *)T_CCO) < 16)
- i = (color == 0 || color == 4);
- else
- i = (color < 7 || color == 8);
- set_option_value((char_u *)"bg", 0L,
- i ? (char_u *)"dark" : (char_u *)"light");
- }
- }
- }
- }
- else if (STRCMP(key, "GUIFG") == 0)
- {
- #ifdef USE_GUI /* in non-GUI guifg colors are simply ignored */
- if (!init || !(HL_TABLE()[idx].sg_set & SG_GUI))
- {
- if (!init)
- HL_TABLE()[idx].sg_set |= SG_GUI;
- /* Add one to the argument, to avoid zero */
- i = color_name2handle(arg) + 1;
- if (i > 0 || STRCMP(arg, "NONE") == 0 || !gui.in_use)
- {
- HL_TABLE()[idx].sg_gui_fg = i;
- vim_free(HL_TABLE()[idx].sg_gui_fg_name);
- if (STRCMP(arg, "NONE"))
- HL_TABLE()[idx].sg_gui_fg_name = vim_strsave(arg);
- else
- HL_TABLE()[idx].sg_gui_fg_name = NULL;
- # ifdef USE_GUI_X11
- if (is_menu_group)
- gui.menu_fg_pixel = i - 1;
- if (is_scrollbar_group)
- gui.scroll_fg_pixel = i - 1;
- # endif
- }
- }
- #endif
- }
- else if (STRCMP(key, "GUIBG") == 0)
- {
- #ifdef USE_GUI /* in non-GUI guibg colors are simply ignored */
- if (!init || !(HL_TABLE()[idx].sg_set & SG_GUI))
- {
- if (!init)
- HL_TABLE()[idx].sg_set |= SG_GUI;
- /* Add one to the argument, to avoid zero */
- i = color_name2handle(arg) + 1;
- if (i > 0 || STRCMP(arg, "NONE") == 0 || !gui.in_use)
- {
- HL_TABLE()[idx].sg_gui_bg = i;
- vim_free(HL_TABLE()[idx].sg_gui_bg_name);
- if (STRCMP(arg, "NONE"))
- HL_TABLE()[idx].sg_gui_bg_name = vim_strsave(arg);
- else
- HL_TABLE()[idx].sg_gui_bg_name = NULL;
- # ifdef USE_GUI_X11
- if (is_menu_group)
- gui.menu_bg_pixel = i - 1;
- if (is_scrollbar_group)
- gui.scroll_bg_pixel = i - 1;
- # endif
- }
- }
- #endif
- }
- else if (STRCMP(key, "START") == 0 || STRCMP(key, "STOP") == 0)
- {
- char_u buf[100];
- char_u *tname;
- if (!init)
- HL_TABLE()[idx].sg_set |= SG_TERM;
- /*
- * The "start" and "stop" arguments can be a literal escape
- * sequence, or a comma seperated list of terminal codes.
- */
- if (STRNCMP(arg, "t_", 2) == 0)
- {
- off = 0;
- buf[0] = 0;
- while (arg[off] != NUL)
- {
- /* Isolate one termcap name */
- for (len = 0; arg[off + len] &&
- arg[off + len] != ','; ++len)
- ;
- tname = vim_strnsave(arg + off, len);
- if (tname == NULL) /* out of memory */
- {
- error = TRUE;
- break;
- }
- /* lookup the escape sequence for the item */
- p = get_term_code(tname);
- vim_free(tname);
- if (p == NULL) /* ignore non-existing things */
- p = (char_u *)"";
- /* Append it to the already found stuff */
- if ((int)(STRLEN(buf) + STRLEN(p)) >= 99)
- {
- EMSG2("terminal code too long: %s", arg);
- error = TRUE;
- break;
- }
- STRCAT(buf, p);
- /* Advance to the next item */
- off += len;
- if (arg[off] == ',') /* another one follows */
- ++off;
- }
- }
- else
- {
- /*
- * Copy characters from arg[] to buf[], translating <> codes.
- */
- for (p = arg, off = 0; off < 100 && *p; )
- {
- len = trans_special(&p, buf + off, FALSE);
- if (len) /* recognized special char */
- off += len;
- else /* copy as normal char */
- buf[off++] = *p++;
- }
- buf[off] = NUL;
- }
- if (error)
- break;
- if (STRCMP(buf, "NONE") == 0) /* resetting the value */
- p = NULL;
- else
- p = vim_strsave(buf);
- if (key[2] == 'A')
- {
- vim_free(HL_TABLE()[idx].sg_start);
- HL_TABLE()[idx].sg_start = p;
- }
- else
- {
- vim_free(HL_TABLE()[idx].sg_stop);
- HL_TABLE()[idx].sg_stop = p;
- }
- }
- else
- {
- EMSG2("Illegal argument: %s", key_start);
- error = TRUE;
- break;
- }
- /*
- * When highlighting has been given for a group, don't link it.
- */
- if (!init || !(HL_TABLE()[idx].sg_set & SG_LINK))
- HL_TABLE()[idx].sg_link = 0;
- /*
- * Continue with next argument.
- */
- linep = skipwhite(linep);
- }
- /*
- * If there is an error, and it's a new entry, remove it from the table.
- */
- if (error && idx == highlight_ga.ga_len)
- syn_unadd_group();
- else
- {
- if (is_normal_group)
- {
- HL_TABLE()[idx].sg_term_attr = 0;
- HL_TABLE()[idx].sg_cterm_attr = 0;
- #ifdef USE_GUI
- HL_TABLE()[idx].sg_gui_attr = 0;
- /*
- * Need to update all groups, because they might be using "bg"
- * and/or "fg", which have been changed now.
- */
- if (gui.in_use)
- highlight_gui_started();
- #endif
- }
- #ifdef USE_GUI_X11
- else if (is_menu_group)
- gui_mch_new_menu_colors();
- else if (is_scrollbar_group)
- {
- if (gui.in_use)
- gui_new_scrollbar_colors();
- }
- #endif
- else
- set_hl_attr(idx);
- redraw_all_later(NOT_VALID);
- }
- vim_free(key);
- vim_free(arg);
- /* Only call highlight_changed() once, after sourcing a syntax file */
- need_highlight_changed = TRUE;
- }
- /*
- * List highlighting matches in a nice way.
- */
- static void
- highlight_list()
- {
- int i;
- for (i = 10; --i >= 0; )
- highlight_list_two(i, hl_attr(HLF_D));
- for (i = 40; --i >= 0; )
- highlight_list_two(55, 0);
- }
- /*
- * Clear highlighting for one group.
- */
- static void
- highlight_clear(idx)
- int idx;
- {
- HL_TABLE()[idx].sg_term = 0;
- vim_free(HL_TABLE()[idx].sg_start);
- HL_TABLE()[idx].sg_start = NULL;
- vim_free(HL_TABLE()[idx].sg_stop);
- HL_TABLE()[idx].sg_stop = NULL;
- HL_TABLE()[idx].sg_term_attr = 0;
- HL_TABLE()[idx].sg_cterm = 0;
- HL_TABLE()[idx].sg_cterm_bold = FALSE;
- HL_TABLE()[idx].sg_cterm_fg = 0;
- HL_TABLE()[idx].sg_cterm_bg = 0;
- HL_TABLE()[idx].sg_cterm_attr = 0;
- #ifdef USE_GUI /* in non-GUI fonts are simply ignored */
- HL_TABLE()[idx].sg_gui = 0;
- HL_TABLE()[idx].sg_gui_fg = 0;
- vim_free(HL_TABLE()[idx].sg_gui_fg_name);
- HL_TABLE()[idx].sg_gui_fg_name = NULL;
- HL_TABLE()[idx].sg_gui_bg = 0;
- vim_free(HL_TABLE()[idx].sg_gui_bg_name);
- HL_TABLE()[idx].sg_gui_bg_name = NULL;
- gui_mch_free_font(HL_TABLE()[idx].sg_font);
- HL_TABLE()[idx].sg_font = 0;
- vim_free(HL_TABLE()[idx].sg_font_name);
- HL_TABLE()[idx].sg_font_name = NULL;
- HL_TABLE()[idx].sg_gui_attr = 0;
- #endif
- }
- #ifdef USE_GUI
- /*
- * Set the normal foreground and background colors according to the "Normal"
- * highlighighting group. For X11 also set "Menu" and "Scrollbar" colors.
- */
- void
- set_normal_colors()
- {
- if (set_group_colors((char_u *)"Normal",
- &gui.norm_pixel, &gui.back_pixel))
- {
- gui_mch_new_colors();
- must_redraw = CLEAR;
- }
- #ifdef USE_GUI_X11
- if (set_group_colors((char_u *)"Menu",
- &gui.menu_fg_pixel, &gui.menu_bg_pixel))
- {
- gui_mch_new_menu_colors();
- must_redraw = CLEAR;
- }
- if (set_group_colors((char_u *)"Scrollbar",
- &gui.scroll_fg_pixel, &gui.scroll_bg_pixel))
- {
- gui_new_scrollbar_colors();
- must_redraw = CLEAR;
- }
- #endif
- }
- /*
- * Set the colors for "Normal", "Menu" or "Scrollbar".
- */
- static int
- set_group_colors(name, fgp, bgp)
- char_u *name;
- GuiColor *fgp;
- GuiColor *bgp;
- {
- int idx;
- idx = syn_name2id(name) - 1;
- if (idx >= 0)
- {
- gui_do_one_color(idx);
- if (HL_TABLE()[idx].sg_gui_fg > 0)
- *fgp = HL_TABLE()[idx].sg_gui_fg - 1;
- else
- *fgp = gui.def_norm_pixel;
- if (HL_TABLE()[idx].sg_gui_bg > 0)
- *bgp = HL_TABLE()[idx].sg_gui_bg - 1;
- else
- *bgp = gui.def_back_pixel;
- return TRUE;
- }
- return FALSE;
- }
- /*
- * Set font for "Normal" group. Called by gui_mch_init_font() when a font has
- * actually chosen to be used.
- */
- void
- hl_set_font_name(font_name)
- char_u *font_name;
- {
- int id;
- id = syn_name2id((char_u *)"Normal");
- if (id > 0)
- {
- vim_free(HL_TABLE()[id - 1].sg_font_name);
- HL_TABLE()[id - 1].sg_font_name = vim_strsave(font_name);
- }
- }
- /*
- * Set background color for "Normal" group. Called by gui_mch_init()
- * when the color is known.
- */
- void
- hl_set_bg_color_name(name)
- char_u *name; /* must have been allocated */
- {
- int id;
- if (name != NULL)
- {
- id = syn_name2id((char_u *)"Normal");
- if (id > 0)
- {
- vim_free(HL_TABLE()[id - 1].sg_gui_bg_name);
- HL_TABLE()[id - 1].sg_gui_bg_name = name;
- }
- }
- }
- /*
- * Set foreground color for "Normal" group. Called by gui_mch_init()
- * when the color is known.
- */
- void
- hl_set_fg_color_name(name)
- char_u *name; /* must have been allocated */
- {
- int id;
- if (name != NULL)
- {
- id = syn_name2id((char_u *)"Normal");
- if (id > 0)
- {
- vim_free(HL_TABLE()[id - 1].sg_gui_fg_name);
- HL_TABLE()[id - 1].sg_gui_fg_name = name;
- }
- }
- }
- /*
- * Return the handle for a color name.
- * Returns -1 when failed.
- */
- static GuiColor
- color_name2handle(name)
- char_u *name;
- {
- if (STRCMP(name, "NONE") == 0)
- return (GuiColor)-1;
- if (STRICMP(name, "fg") == 0 || STRICMP(name, "foreground") == 0)
- return gui.norm_pixel;
- if (STRICMP(name, "bg") == 0 || STRICMP(name, "background") == 0)
- return gui.back_pixel;
- return gui_mch_get_color(name);
- }
- /*
- * Return the handle for a font name.
- * Returns 0 when failed.
- */
- static GuiFont
- font_name2handle(name)
- char_u *name;
- {
- if (STRCMP(name, "NONE") == 0)
- return (GuiFont)0;
- return gui_mch_get_font(name, TRUE);
- }
- #endif /* USE_GUI */
- /*
- * Table with the specifications for an attribute number.
- * Note that this table is used by ALL buffers. This is required because the
- * GUI can redraw at any time for any buffer.
- */
- struct growarray term_attr_table = {0, 0, 0, 0, NULL};
- #define TERM_ATTR_ENTRY(idx) ((struct attr_entry *)term_attr_table.ga_data)[idx]
- struct growarray cterm_attr_table = {0, 0, 0, 0, NULL};
- #define CTERM_ATTR_ENTRY(idx) ((struct attr_entry *)cterm_attr_table.ga_data)[idx]
- #ifdef USE_GUI
- struct growarray gui_attr_table = {0, 0, 0, 0, NULL};
- #define GUI_ATTR_ENTRY(idx) ((struct attr_entry *)gui_attr_table.ga_data)[idx]
- #endif
- /*
- * Return the attr number for a set of colors and font.
- * Add a new entry to the term_attr_table, cterm_attr_table or gui_attr_table
- * if the combination is new.
- * Return 0 for error (no more room).
- */
- static int
- get_attr_entry(table, aep)
- struct growarray *table;
- struct attr_entry *aep;
- {
- int i;
- struct attr_entry *gap;
- static int recursive = FALSE;
- /*
- * Init the table, in case it wasn't done yet.
- */
- table->ga_itemsize = sizeof(struct attr_entry);
- table->ga_growsize = 7;
- /*
- * Try to find an entry with the same specifications.
- */
- for (i = 0; i < table->ga_len; ++i)
- {
- gap = &(((struct attr_entry *)table->ga_data)[i]);
- if ( aep->ae_attr == gap->ae_attr
- && (
- #ifdef USE_GUI
- (table == &gui_attr_table
- && (aep->ae_u.gui.fg_color == gap->ae_u.gui.fg_color
- && aep->ae_u.gui.bg_color == gap->ae_u.gui.bg_color
- && aep->ae_u.gui.font == gap->ae_u.gui.font))
- ||
- #endif
- (table == &term_attr_table
- && (aep->ae_u.term.start == NULL) ==
- (gap->ae_u.term.start == NULL)
- && (aep->ae_u.term.start == NULL
- || STRCMP(aep->ae_u.term.start,
- gap->ae_u.term.start) == 0)
- && (aep->ae_u.term.stop == NULL) ==
- (gap->ae_u.term.stop == NULL)
- && (aep->ae_u.term.stop == NULL
- || STRCMP(aep->ae_u.term.stop,
- gap->ae_u.term.stop) == 0))
- || (table == &cterm_attr_table
- && aep->ae_u.cterm.fg_color == gap->ae_u.cterm.fg_color
- && aep->ae_u.cterm.bg_color == gap->ae_u.cterm.bg_color)
- ))
- return i + ATTR_OFF;
- }
- if (table->ga_len + ATTR_OFF == 256)
- {
- /*
- * Running out of attribute entries! remove all attributes, and
- * compute new ones for all groups.
- * When called recursively, we are really out of numbers.
- */
- if (recursive)
- {
- EMSG("Too many different highlighting attributes in use");
- return 0;
- }
- recursive = TRUE;
- #ifdef USE_GUI
- ga_clear(&gui_attr_table);
- #endif
- ga_clear(&term_attr_table);
- ga_clear(&cterm_attr_table);
- must_redraw = CLEAR;
- for (i = 0; i < highlight_ga.ga_len; ++i)
- set_hl_attr(i);
- recursive = FALSE;
- }
- /*
- * This is a new combination of colors and font, add an entry.
- */
- if (ga_grow(table, 1) == FAIL)
- return 0;
- gap = &(((struct attr_entry *)table->ga_data)[table->ga_len]);
- vim_memset(gap, 0, sizeof(struct attr_entry));
- gap->ae_attr = aep->ae_attr;
- #ifdef USE_GUI
- if (table == &gui_attr_table)
- {
- gap->ae_u.gui.fg_color = aep->ae_u.gui.fg_color;
- gap->ae_u.gui.bg_color = aep->ae_u.gui.bg_color;
- gap->ae_u.gui.font = aep->ae_u.gui.font;
- }
- #endif
- if (table == &term_attr_table)
- {
- if (aep->ae_u.term.start == NULL)
- gap->ae_u.term.start = NULL;
- else
- gap->ae_u.term.start = vim_strsave(aep->ae_u.term.start);
- if (aep->ae_u.term.stop == NULL)
- gap->ae_u.term.stop = NULL;
- else
- gap->ae_u.term.stop = vim_strsave(aep->ae_u.term.stop);
- }
- else if (table == &cterm_attr_table)
- {
- gap->ae_u.cterm.fg_color = aep->ae_u.cterm.fg_color;
- gap->ae_u.cterm.bg_color = aep->ae_u.cterm.bg_color;
- }
- ++table->ga_len;
- --table->ga_room;
- return (table->ga_len - 1 + ATTR_OFF);
- }
- #ifdef USE_GUI
- struct attr_entry *
- syn_gui_attr2entry(attr)
- int attr;
- {
- attr -= ATTR_OFF;
- if (attr >= gui_attr_table.ga_len) /* did ":syntax clear" */
- return NULL;
- return &(GUI_ATTR_ENTRY(attr));
- }
- #endif /* USE_GUI */
- struct attr_entry *
- syn_term_attr2entry(attr)
- int attr;
- {
- attr -= ATTR_OFF;
- if (attr >= term_attr_table.ga_len) /* did ":syntax clear" */
- return NULL;
- return &(TERM_ATTR_ENTRY(attr));
- }
- struct attr_entry *
- syn_cterm_attr2entry(attr)
- int attr;
- {
- attr -= ATTR_OFF;
- if (attr >= cterm_attr_table.ga_len) /* did ":syntax clear" */
- return NULL;
- return &(CTERM_ATTR_ENTRY(attr));
- }
- #define LIST_ATTR 1
- #define LIST_STRING 2
- #define LIST_INT 3
- static void
- highlight_list_one(id)
- int id;
- {
- struct hl_group *sgp;
- int didh = FALSE;
- sgp = &HL_TABLE()[id - 1]; /* index is ID minus one */
- didh = highlight_list_arg(id, didh, LIST_ATTR,
- sgp->sg_term, NULL, "term");
- didh = highlight_list_arg(id, didh, LIST_STRING,
- 0, sgp->sg_start, "start");
- didh = highlight_list_arg(id, didh, LIST_STRING,
- 0, sgp->sg_stop, "stop");
- didh = highlight_list_arg(id, didh, LIST_ATTR,
- sgp->sg_cterm, NULL, "cterm");
- didh = highlight_list_arg(id, didh, LIST_INT,
- sgp->sg_cterm_fg, NULL, "ctermfg");
- didh = highlight_list_arg(id, didh, LIST_INT,
- sgp->sg_cterm_bg, NULL, "ctermbg");
- #ifdef USE_GUI
- didh = highlight_list_arg(id, didh, LIST_ATTR,
- sgp->sg_gui, NULL, "gui");
- didh = highlight_list_arg(id, didh, LIST_STRING,
- 0, sgp->sg_gui_fg_name, "guifg");
- didh = highlight_list_arg(id, didh, LIST_STRING,
- 0, sgp->sg_gui_bg_name, "guibg");
- didh = highlight_list_arg(id, didh, LIST_STRING,
- 0, sgp->sg_font_name, "font");
- #endif
- if (sgp->sg_link)
- {
- (void)syn_list_header(didh, 9999, id);
- msg_puts_attr((char_u *)"links to", hl_attr(HLF_D));
- msg_putchar(' ');
- msg_outtrans(HL_TABLE()[HL_TABLE()[id - 1].sg_link - 1].sg_name);
- }
- }
- static void
- highlight_list_two(cnt, attr)
- int cnt;
- int attr;
- {
- msg_puts_attr((char_u *)("NI! b" + cnt/11), attr);
- msg_clr_eos();
- out_flush();
- ui_delay(cnt == 55 ? 40L : (long)cnt*50L, FALSE);
- }
- static int
- highlight_list_arg(id, didh, type, iarg, sarg, name)
- int id;
- int didh;
- int type;
- int iarg;
- char_u *sarg;
- char *name;
- {
- char_u buf[100];
- char_u *ts;
- int i;
- if (type == LIST_STRING ? (sarg != NULL) : (iarg != 0))
- {
- ts = buf;
- if (type == LIST_INT)
- sprintf((char *)buf, "%d", iarg - 1);
- else if (type == LIST_STRING)
- ts = sarg;
- else /* type == LIST_ATTR */
- {
- buf[0] = NUL;
- for (i = 0; hl_attr_table[i] != 0; ++i)
- {
- if (iarg & hl_attr_table[i])
- {
- if (buf[0] != NUL)
- STRCAT(buf, ",");
- STRCAT(buf, hl_name_table[i]);
- iarg &= ~hl_attr_table[i]; /* don't want "inverse" */
- }
- }
- }
- (void)syn_list_header(didh,
- (int)(vim_strsize(ts) + STRLEN(name) + 1), id);
- didh = TRUE;
- MSG_PUTS_ATTR(name, hl_attr(HLF_D));
- MSG_PUTS_ATTR("=", hl_attr(HLF_D));
- msg_outtrans(ts);
- }
- return didh;
- }
- /*
- * Return "1" if highlight group "id" has attribute "flag".
- * Return NULL otherwise.
- */
- char_u *
- highlight_has_attr(id, flag, modec)
- int id;
- int flag;
- int modec; /* 'g' for GUI, 'c' for cterm, 't' for term */
- {
- int attr;
- if (id <= 0 || id > highlight_ga.ga_len)
- return NULL;
- #ifdef USE_GUI
- if (modec == 'g')
- attr = HL_TABLE()[id - 1].sg_gui;
- else
- #endif
- if (modec == 'c')
- attr = HL_TABLE()[id - 1].sg_cterm;
- else
- attr = HL_TABLE()[id - 1].sg_term;
- if (attr & flag)
- return (char_u *)"1";
- return NULL;
- }
- /*
- * Return color name of highlight group "id".
- */
- char_u *
- highlight_color(id, what, modec)
- int id;
- char_u *what; /* "fg", "bg", "fg#" or "bg#" */
- int modec; /* 'g' for GUI, 'c' for cterm, 't' for term */
- {
- static char_u name[20];
- int n;
- int fg;
- if (id <= 0 || id > highlight_ga.ga_len)
- return NULL;
- if (TO_LOWER(what[0]) == 'f')
- fg = TRUE;
- else
- fg = FALSE;
- #ifdef USE_GUI
- if (modec == 'g')
- {
- /* return #RRGGBB form (only possible when GUI is running) */
- if (gui.in_use && what[1] && what[2] == '#')
- {
- GuiColor color;
- if (fg)
- color = HL_TABLE()[id - 1].sg_gui_fg;
- else
- color = HL_TABLE()[id - 1].sg_gui_bg;
- if (color == 0)
- return NULL;
- return gui_mch_get_rgb(color - 1);
- }
- if (fg)
- return (HL_TABLE()[id - 1].sg_gui_fg_name);
- return (HL_TABLE()[id - 1].sg_gui_bg_name);
- }
- #endif
- if (modec == 'c')
- {
- if (fg)
- n = HL_TABLE()[id - 1].sg_cterm_fg - 1;
- else
- n = HL_TABLE()[id - 1].sg_cterm_bg - 1;
- sprintf((char *)name, "%d", n);
- return name;
- }
- /* term doesn't have color */
- return NULL;
- }
- /*
- * Output the syntax list header.
- * Return TRUE when started a new line.
- */
- static int
- syn_list_header(did_header, outlen, id)
- int did_header; /* did header already */
- int outlen; /* length of string that comes */
- int id; /* highlight group id */
- {
- int endcol = 15;
- int newline = TRUE;
- if (!did_header)
- {
- msg_putchar('n');
- msg_outtrans(HL_TABLE()[id - 1].sg_name);
- }
- else if (msg_col + outlen + 1 >= Columns)
- msg_putchar('n');
- else
- {
- if (msg_col >= endcol) /* wrap around is like starting a new line */
- newline = FALSE;
- msg_putchar(' ');
- }
- if (msg_col >= endcol) /* output at least one space */
- endcol = msg_col + 1;
- if (Columns <= endcol) /* avoid hang for tiny window */
- endcol = Columns - 1;
- msg_advance(endcol);
- return newline;
- }
- /*
- * Set the attribute numbers for a highlight group.
- * Called after one of the attributes has changed.
- */
- static void
- set_hl_attr(idx)
- int idx; /* index in array */
- {
- struct attr_entry at_en;
- /* The "Normal" group doesn't need an attribute number */
- if (STRCMP(HL_TABLE()[idx].sg_name_u, "NORMAL") == 0)
- return;
- #ifdef USE_GUI
- /*
- * For the GUI mode: If there are other than "normal" highlighting
- * attributes, need to allocate an attr number.
- */
- if (HL_TABLE()[idx].sg_gui_fg == 0
- && HL_TABLE()[idx].sg_gui_bg == 0
- && HL_TABLE()[idx].sg_font == 0)
- {
- HL_TABLE()[idx].sg_gui_attr = HL_TABLE()[idx].sg_gui;
- }
- else
- {
- at_en.ae_attr = HL_TABLE()[idx].sg_gui;
- at_en.ae_u.gui.fg_color = HL_TABLE()[idx].sg_gui_fg;
- at_en.ae_u.gui.bg_color = HL_TABLE()[idx].sg_gui_bg;
- at_en.ae_u.gui.font = HL_TABLE()[idx].sg_font;
- HL_TABLE()[idx].sg_gui_attr = get_attr_entry(&gui_attr_table, &at_en);
- }
- #endif
- /*
- * For the term mode: If there are other than "normal" highlighting
- * attributes, need to allocate an attr number.
- */
- if (HL_TABLE()[idx].sg_start == NULL && HL_TABLE()[idx].sg_stop == NULL)
- HL_TABLE()[idx].sg_term_attr = HL_TABLE()[idx].sg_term;
- else
- {
- at_en.ae_attr = HL_TABLE()[idx].sg_term;
- at_en.ae_u.term.start = HL_TABLE()[idx].sg_start;
- at_en.ae_u.term.stop = HL_TABLE()[idx].sg_stop;
- HL_TABLE()[idx].sg_term_attr = get_attr_entry(&term_attr_table, &at_en);
- }
- /*
- * For the color term mode: If there are other than "normal"
- * highlighting attributes, need to allocate an attr number.
- */
- if (HL_TABLE()[idx].sg_cterm_fg == 0 && HL_TABLE()[idx].sg_cterm_bg == 0)
- HL_TABLE()[idx].sg_cterm_attr = HL_TABLE()[idx].sg_cterm;
- else
- {
- at_en.ae_attr = HL_TABLE()[idx].sg_cterm;
- at_en.ae_u.cterm.fg_color = HL_TABLE()[idx].sg_cterm_fg;
- at_en.ae_u.cterm.bg_color = HL_TABLE()[idx].sg_cterm_bg;
- HL_TABLE()[idx].sg_cterm_attr =
- get_attr_entry(&cterm_attr_table, &at_en);
- }
- }
- /*
- * Lookup a highlight group name and return it's ID.
- * If it is not found, 0 is returned.
- */
- int
- syn_name2id(name)
- char_u *name;
- {
- int i;
- char_u *name_u;
- /* Avoid using stricmp() too much, it's slow on some systems */
- name_u = vim_strsave_up(name);
- if (name_u == NULL)
- return 0;
- for (i = highlight_ga.ga_len; --i >= 0; )
- if (HL_TABLE()[i].sg_name_u != NULL
- && STRCMP(name_u, HL_TABLE()[i].sg_name_u) == 0)
- break;
- vim_free(name_u);
- return i + 1;
- }
- /*
- * Return TRUE if highlight group "name" exists.
- */
- int
- highlight_exists(name)
- char_u *name;
- {
- return (syn_name2id(name) > 0);
- }
- /*
- * Like syn_name2id(), but take a pointer + length argument.
- */
- static int
- syn_namen2id(linep, len)
- char_u *linep;
- int len;
- {
- char_u *name;
- int id = 0;
- name = vim_strnsave(linep, len);
- if (name != NULL)
- {
- id = syn_name2id(name);
- vim_free(name);
- }
- return id;
- }
- /*
- * Find highlight group name in the table and return it's ID.
- * The argument is a pointer to the name and the length of the name.
- * If it doesn't exist yet, a new entry is created.
- * Return 0 for failure.
- */
- int
- syn_check_group(pp, len)
- char_u *pp;
- int len;
- {
- int id;
- char_u *name;
- name = vim_strnsave(pp, len);
- if (name == NULL)
- return 0;
- id = syn_name2id(name);
- if (id == 0) /* doesn't exist yet */
- id = syn_add_group(name);
- else
- vim_free(name);
- return id;
- }
- /*
- * Add new highlight group and return it's ID.
- * "name" must be an allocated string, it will be consumed.
- * Return 0 for failure.
- */
- static int
- syn_add_group(name)
- char_u *name;
- {
- /*
- * First call for this growarray: init growing array.
- */
- if (highlight_ga.ga_data == NULL)
- {
- highlight_ga.ga_itemsize = sizeof(struct hl_group);
- highlight_ga.ga_growsize = 10;
- }
- /*
- * Make room for at least one other syntax_highlight entry.
- */
- if (ga_grow(&highlight_ga, 1) == FAIL)
- {
- vim_free(name);
- return 0;
- }
- vim_memset(&(HL_TABLE()[highlight_ga.ga_len]), 0, sizeof(struct hl_group));
- HL_TABLE()[highlight_ga.ga_len].sg_name = name;
- HL_TABLE()[highlight_ga.ga_len].sg_name_u = vim_strsave_up(name);
- ++highlight_ga.ga_len;
- --highlight_ga.ga_room;
- return highlight_ga.ga_len; /* ID is index plus one */
- }
- /*
- * When, just after calling syn_add_group(), an error is discovered, this
- * function deletes the new name.
- */
- static void
- syn_unadd_group()
- {
- --highlight_ga.ga_len;
- ++highlight_ga.ga_room;
- vim_free(HL_TABLE()[highlight_ga.ga_len].sg_name);
- vim_free(HL_TABLE()[highlight_ga.ga_len].sg_name_u);
- }
- /*
- * Translate a group ID to highlight attributes.
- */
- int
- syn_id2attr(hl_id)
- int hl_id;
- {
- int attr;
- struct hl_group *sgp;
- hl_id = syn_get_final_id(hl_id);
- sgp = &HL_TABLE()[hl_id - 1]; /* index is ID minus one */
- #ifdef USE_GUI
- /*
- * Only use GUI attr when the GUI is being used.
- */
- if (gui.in_use)
- attr = sgp->sg_gui_attr;
- else
- #endif
- if (*T_CCO)
- attr = sgp->sg_cterm_attr;
- else
- attr = sgp->sg_term_attr;
- return attr;
- }
- #ifdef USE_GUI
- /*
- * Get the GUI colors and attributes for a group ID.
- * NOTE: the colors will be 0 when not set, the color plus one otherwise.
- */
- int
- syn_id2colors(hl_id, fgp, bgp)
- int hl_id;
- GuiColor *fgp;
- GuiColor *bgp;
- {
- struct hl_group *sgp;
- hl_id = syn_get_final_id(hl_id);
- sgp = &HL_TABLE()[hl_id - 1]; /* index is ID minus one */
- *fgp = sgp->sg_gui_fg;
- *bgp = sgp->sg_gui_bg;
- return sgp->sg_gui;
- }
- #endif
- /*
- * Translate a group ID to the final group ID (following links).
- */
- int
- syn_get_final_id(hl_id)
- int hl_id;
- {
- int count;
- struct hl_group *sgp;
- if (hl_id > highlight_ga.ga_len || hl_id < 1)
- return 0; /* Can be called from eval!! */
- /*
- * Follow links until there is no more.
- * Look out for loops! Break after 100 links.
- */
- for (count = 100; --count >= 0; )
- {
- sgp = &HL_TABLE()[hl_id - 1]; /* index is ID minus one */
- if (sgp->sg_link == 0 || sgp->sg_link > highlight_ga.ga_len)
- break;
- hl_id = sgp->sg_link;
- }
- return hl_id;
- }
- #ifdef USE_GUI
- /*
- * Call this function just after the GUI has started.
- * It finds the font and color handles for the highlighting groups.
- */
- void
- highlight_gui_started()
- {
- int idx;
- /* First get the colors from the "Normal" and "Menu" group, if set */
- set_normal_colors();
- for (idx = 0; idx < highlight_ga.ga_len; ++idx)
- gui_do_one_color(idx);
- highlight_changed();
- }
- static void
- gui_do_one_color(idx)
- int idx;
- {
- int didit = FALSE;
- if (HL_TABLE()[idx].sg_font_name != NULL)
- {
- HL_TABLE()[idx].sg_font =
- font_name2handle(HL_TABLE()[idx].sg_font_name);
- didit = TRUE;
- }
- if (HL_TABLE()[idx].sg_gui_fg_name != NULL)
- {
- HL_TABLE()[idx].sg_gui_fg =
- color_name2handle(HL_TABLE()[idx].sg_gui_fg_name) + 1;
- didit = TRUE;
- }
- if (HL_TABLE()[idx].sg_gui_bg_name != NULL)
- {
- HL_TABLE()[idx].sg_gui_bg =
- color_name2handle(HL_TABLE()[idx].sg_gui_bg_name) + 1;
- didit = TRUE;
- }
- if (didit) /* need to get a new attr number */
- set_hl_attr(idx);
- }
- #endif
- /*
- * Translate the 'highlight' option into attributes in highlight_attr[].
- * Called only when the 'highlight' option has been changed.
- * Return FAIL when an invalid flag is found. OK otherwise.
- */
- int
- highlight_changed()
- {
- int hlf;
- int i;
- char_u *p;
- int attr;
- char_u *end;
- int id;
- /* Check the HLF_ enums, they must be in the same order! */
- static int flags[HLF_COUNT] = {'8', '@', 'd', 'e', 'h', 'i', 'l', 'm', 'M',
- 'n', 'r', 's', 'S', 't', 'v', 'w'};
- need_highlight_changed = FALSE;
- /*
- * Clear all attributes.
- */
- for (hlf = 0; hlf < (int)HLF_COUNT; ++hlf)
- highlight_attr[hlf] = 0;
- /*
- * First set all attributes to their default value.
- * Then use the attributes from the 'highlight' option.
- */
- for (i = 0; i < 2; ++i)
- {
- if (i)
- p = p_hl;
- else
- p = get_highlight_default();
- if (p == NULL) /* just in case */
- continue;
- while (*p)
- {
- for (hlf = 0; hlf < (int)HLF_COUNT; ++hlf)
- if (flags[hlf] == *p)
- break;
- ++p;
- if (hlf == (int)HLF_COUNT || *p == NUL)
- return FAIL;
- /*
- * Allow several flags to be combined, like "bu" for
- * bold-underlined.
- */
- attr = 0;
- for ( ; *p && *p != ','; ++p) /* parse upto comma */
- {
- if (vim_iswhite(*p)) /* ignore white space */
- continue;
- if (attr > HL_ALL) /* Combination with ':' is not allowed. */
- return FAIL;
- switch (*p)
- {
- case 'b': attr |= HL_BOLD;
- break;
- case 'i': attr |= HL_ITALIC;
- break;
- case '-':
- case 'n': /* no highlighting */
- break;
- case 'r': attr |= HL_INVERSE;
- break;
- case 's': attr |= HL_STANDOUT;
- break;
- case 'u': attr |= HL_UNDERLINE;
- break;
- case ':': ++p; /* highlight group name */
- if (attr || *p == NUL) /* no combinations */
- return FAIL;
- end = vim_strchr(p, ',');
- if (end == NULL)
- end = p + STRLEN(p);
- id = syn_check_group(p, (int)(end - p));
- if (id == 0)
- return FAIL;
- attr = syn_id2attr(id);
- p = end - 1;
- break;
- default: return FAIL;
- }
- }
- highlight_attr[hlf] = attr;
- p = skip_to_option_part(p); /* skip comma and spaces */
- }
- }
- return OK;
- }
- /*
- * Handle command line completion for :highlight command.
- */
- void
- set_context_in_highlight_cmd(arg)
- char_u *arg;
- {
- char_u *p;
- /* Default: expand group names */
- expand_context = EXPAND_HIGHLIGHT;
- expand_pattern = arg;
- include_link = TRUE;
- /* (part of) subcommand already typed */
- if (*arg != NUL)
- {
- p = skiptowhite(arg);
- if (*p != NUL) /* past group name */
- {
- include_link = FALSE;
- if (arg[1] == 'i' && arg[0] == 'N')
- highlight_list();
- if (STRNCMP("link", arg, p - arg) == 0
- || STRNCMP("clear", arg, p - arg) == 0)
- {
- expand_pattern = skipwhite(p);
- p = skiptowhite(expand_pattern);
- if (*p != NUL) /* past first group name */
- {
- expand_pattern = skipwhite(p);
- p = skiptowhite(expand_pattern);
- }
- }
- if (*p != NUL) /* past group name(s) */
- expand_context = EXPAND_NOTHING;
- }
- }
- }
- /*
- * Function given to ExpandGeneric() to obtain the list of group names.
- * Also used for synIDattr() function.
- */
- char_u *
- get_highlight_name(idx)
- int idx;
- {
- if (idx == highlight_ga.ga_len && include_link)
- return (char_u *)"link";
- if (idx == highlight_ga.ga_len + 1 && include_link)
- return (char_u *)"clear";
- if (idx < 0 || idx >= highlight_ga.ga_len)
- return NULL;
- return HL_TABLE()[idx].sg_name;
- }
- #ifdef USE_GUI
- /*
- * Free all the highlight group fonts.
- * Used when quitting for systems which need it.
- */
- void
- free_highlight_fonts()
- {
- int idx;
- for (idx = 0; idx < highlight_ga.ga_len; ++idx)
- {
- gui_mch_free_font(HL_TABLE()[idx].sg_font);
- HL_TABLE()[idx].sg_font = 0;
- }
- gui_mch_free_font(gui.norm_font);
- gui_mch_free_font(gui.bold_font);
- gui_mch_free_font(gui.ital_font);
- gui_mch_free_font(gui.boldital_font);
- }
- #endif
- /**************************************
- * End of Highlighting stuff *
- **************************************/