0
0
mirror of https://github.com/vim/vim.git synced 2025-07-26 11:04:33 -04:00

updated for version 7.0044

This commit is contained in:
Bram Moolenaar 2005-01-25 22:14:34 +00:00
parent 8f999f1999
commit dad6b69c00

View File

@ -190,12 +190,6 @@ typedef struct syn_pattern
#define SYN_STATE_P(ssp) ((bufstate_T *)((ssp)->ga_data))
/*
* Settings for keyword hash table. It uses a simplistic hash function: add
* all characters together, modulo KHASH_SIZE.
*/
#define KHASH_SIZE 512
#define KHASH_MASK (KHASH_SIZE - 1)
#define MAXKEYWLEN 80 /* maximum length of a keyword */
/*
@ -251,6 +245,18 @@ static char_u **syn_cmdlinep;
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
@ -390,11 +396,10 @@ 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, keyentry_T **ktabp, int did_header, int attr));
static void syn_clear_keyword __ARGS((int id, keyentry_T **ktabp));
static void free_keywtab __ARGS((keyentry_T **ktabp));
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 int syn_khash __ARGS((char_u *p));
static char_u *get_group_name __ARGS((char_u *arg, char_u **name_end));
static char_u *get_syn_options __ARGS((char_u *arg, int *flagsp, int keyword, int *sync_idx, short **cont_list, short **cont_in_list, short **next_list));
static void syn_cmd_include __ARGS((exarg_T *eap, int syncing));
@ -1775,8 +1780,8 @@ syn_current_attr(syncing, displaying)
/* Only check for keywords when not syncing and there are some. */
do_keywords = !syncing
&& (syn_buf->b_keywtab != NULL
|| syn_buf->b_keywtab_ic != NULL);
&& (syn_buf->b_keywtab.ht_used > 0
|| syn_buf->b_keywtab_ic.ht_used > 0);
/* Init the list of zero-width matches with a nextlist. This is used to
* avoid matching the same item in the same position twice. */
@ -2950,36 +2955,38 @@ check_keyword_id(line, startcol, endcolp, flagsp, next_listp, cur_si)
short **next_listp; /* return: next_list of matching keyword */
stateitem_T *cur_si; /* item at the top of the stack */
{
keyentry_T *ktab;
char_u *p;
keyentry_T *kp;
char_u *kwp;
int round;
int len;
int kwlen;
char_u keyword[MAXKEYWLEN + 1]; /* assume max. keyword len is 80 */
hashtab_T *ht;
hashitem_T *hi;
/* Find first character after the keyword. First character was already
* checked. */
p = line + startcol;
len = 0;
kwp = line + startcol;
kwlen = 0;
do
{
#ifdef FEAT_MBYTE
if (has_mbyte)
len += (*mb_ptr2len_check)(p + len);
kwlen += (*mb_ptr2len_check)(kwp + kwlen);
else
#endif
++len;
++kwlen;
}
while (vim_iswordc_buf(p + len, syn_buf));
while (vim_iswordc_buf(kwp + kwlen, syn_buf));
if (len > MAXKEYWLEN)
if (kwlen > MAXKEYWLEN)
return 0;
/*
* Must make a copy of the keyword, so we can add a NUL and make it
* lowercase.
*/
STRNCPY(keyword, p, len);
keyword[len] = NUL;
STRNCPY(keyword, kwp, kwlen);
keyword[kwlen] = NUL;
/*
* Try twice:
@ -2988,41 +2995,35 @@ check_keyword_id(line, startcol, endcolp, flagsp, next_listp, cur_si)
*/
for (round = 1; round <= 2; ++round)
{
if ((round == 1 ? syn_buf->b_keywtab : syn_buf->b_keywtab_ic) == NULL)
ht = round == 1 ? &syn_buf->b_keywtab : &syn_buf->b_keywtab_ic;
if (ht->ht_used == 0)
continue;
if (round == 1) /* match case */
ktab = syn_buf->b_keywtab[syn_khash(keyword)];
else /* round == 2, ignore case */
{
p = str_foldcase(keyword, (int)STRLEN(keyword));
if (p != NULL)
{
STRNCPY(keyword, p, MAXKEYWLEN);
keyword[MAXKEYWLEN] = NUL;
vim_free(p);
}
ktab = syn_buf->b_keywtab_ic[syn_khash(keyword)];
}
if (round == 2) /* ignore case */
(void)str_foldcase(kwp, kwlen, keyword, MAXKEYWLEN + 1);
/*
* Find keywords that match.
* Find keywords that match. There can be several with different
* attributes.
* When current_next_list is non-zero accept only that group, otherwise:
* Accept a not-contained keyword at toplevel.
* Accept a keyword at other levels only if it is in the contains list.
*/
for ( ; ktab != NULL; ktab = ktab->next)
if ( STRCMP(keyword, ktab->keyword) == 0
&& (current_next_list != 0
? in_id_list(NULL, current_next_list, &ktab->k_syn, 0)
: (cur_si == NULL
? !(ktab->flags & HL_CONTAINED)
: in_id_list(cur_si, cur_si->si_cont_list,
&ktab->k_syn, ktab->flags & HL_CONTAINED))))
hi = hash_find(ht, keyword);
if (!HASHITEM_EMPTY(hi))
for (kp = HI2KE(hi); kp != NULL; kp = kp->ke_next)
{
*endcolp = startcol + len;
*flagsp = ktab->flags;
*next_listp = ktab->next_list;
return ktab->k_syn.id;
if (current_next_list != 0
? in_id_list(NULL, current_next_list, &kp->k_syn, 0)
: (cur_si == NULL
? !(kp->flags & HL_CONTAINED)
: in_id_list(cur_si, cur_si->si_cont_list,
&kp->k_syn, kp->flags & HL_CONTAINED)))
{
*endcolp = startcol + kwlen;
*flagsp = kp->flags;
*next_listp = kp->next_list;
return kp->k_syn.id;
}
}
}
return 0;
@ -3066,10 +3067,8 @@ syntax_clear(buf)
curbuf->b_syn_containedin = FALSE;
/* free the keywords */
free_keywtab(buf->b_keywtab);
buf->b_keywtab = NULL;
free_keywtab(buf->b_keywtab_ic);
buf->b_keywtab_ic = NULL;
clear_keywtab(&buf->b_keywtab);
clear_keywtab(&buf->b_keywtab_ic);
/* free the syntax patterns */
for (i = buf->b_syn_patterns.ga_len; --i >= 0; )
@ -3277,8 +3276,8 @@ syn_clear_one(id, syncing)
/* Clear keywords only when not ":syn sync clear group-name" */
if (!syncing)
{
(void)syn_clear_keyword(id, curbuf->b_keywtab);
(void)syn_clear_keyword(id, curbuf->b_keywtab_ic);
(void)syn_clear_keyword(id, &curbuf->b_keywtab);
(void)syn_clear_keyword(id, &curbuf->b_keywtab_ic);
}
/* clear the patterns for "id" */
@ -3552,8 +3551,8 @@ syn_list_one(id, syncing, link_only)
/* list the keywords for "id" */
if (!syncing)
{
did_header = syn_list_keywords(id, curbuf->b_keywtab, FALSE, attr);
did_header = syn_list_keywords(id, curbuf->b_keywtab_ic,
did_header = syn_list_keywords(id, &curbuf->b_keywtab, FALSE, attr);
did_header = syn_list_keywords(id, &curbuf->b_keywtab_ic,
did_header, attr);
}
@ -3787,15 +3786,16 @@ put_pattern(s, c, spp, attr)
* Return TRUE if the header has been printed.
*/
static int
syn_list_keywords(id, ktabp, did_header, attr)
syn_list_keywords(id, ht, did_header, attr)
int id;
keyentry_T **ktabp;
hashtab_T *ht;
int did_header; /* header has already been printed */
int attr;
{
int i;
int outlen;
keyentry_T *ktab;
hashitem_T *hi;
keyentry_T *kp;
int todo;
int prev_contained = 0;
short *prev_next_list = NULL;
short *prev_cont_in_list = NULL;
@ -3803,77 +3803,79 @@ syn_list_keywords(id, ktabp, did_header, attr)
int prev_skipwhite = 0;
int prev_skipempty = 0;
if (ktabp == NULL)
return did_header;
/*
* Unfortunately, this list of keywords is not sorted on alphabet but on
* hash value...
*/
for (i = 0; i < KHASH_SIZE; ++i)
todo = ht->ht_used;
for (hi = ht->ht_array; todo > 0 && !got_int; ++hi)
{
for (ktab = ktabp[i]; ktab != NULL && !got_int; ktab = ktab->next)
if (!HASHITEM_EMPTY(hi))
{
if (ktab->k_syn.id == id)
--todo;
for (kp = HI2KE(hi); kp != NULL && !got_int; kp = kp->ke_next)
{
if (prev_contained != (ktab->flags & HL_CONTAINED)
|| prev_skipnl != (ktab->flags & HL_SKIPNL)
|| prev_skipwhite != (ktab->flags & HL_SKIPWHITE)
|| prev_skipempty != (ktab->flags & HL_SKIPEMPTY)
|| prev_cont_in_list != ktab->k_syn.cont_in_list
|| prev_next_list != ktab->next_list)
outlen = 9999;
else
outlen = (int)STRLEN(ktab->keyword);
/* output "contained" and "nextgroup" on each line */
if (syn_list_header(did_header, outlen, id))
if (kp->k_syn.id == id)
{
prev_contained = 0;
prev_next_list = NULL;
prev_cont_in_list = NULL;
prev_skipnl = 0;
prev_skipwhite = 0;
prev_skipempty = 0;
}
did_header = TRUE;
if (prev_contained != (ktab->flags & HL_CONTAINED))
{
msg_puts_attr((char_u *)"contained", attr);
msg_putchar(' ');
prev_contained = (ktab->flags & HL_CONTAINED);
}
if (ktab->k_syn.cont_in_list != prev_cont_in_list)
{
put_id_list((char_u *)"containedin",
ktab->k_syn.cont_in_list, attr);
msg_putchar(' ');
prev_cont_in_list = ktab->k_syn.cont_in_list;
}
if (ktab->next_list != prev_next_list)
{
put_id_list((char_u *)"nextgroup", ktab->next_list, attr);
msg_putchar(' ');
prev_next_list = ktab->next_list;
if (ktab->flags & HL_SKIPNL)
if (prev_contained != (kp->flags & HL_CONTAINED)
|| prev_skipnl != (kp->flags & HL_SKIPNL)
|| prev_skipwhite != (kp->flags & HL_SKIPWHITE)
|| prev_skipempty != (kp->flags & HL_SKIPEMPTY)
|| prev_cont_in_list != kp->k_syn.cont_in_list
|| prev_next_list != kp->next_list)
outlen = 9999;
else
outlen = (int)STRLEN(kp->keyword);
/* output "contained" and "nextgroup" on each line */
if (syn_list_header(did_header, outlen, id))
{
msg_puts_attr((char_u *)"skipnl", attr);
msg_putchar(' ');
prev_skipnl = (ktab->flags & HL_SKIPNL);
prev_contained = 0;
prev_next_list = NULL;
prev_cont_in_list = NULL;
prev_skipnl = 0;
prev_skipwhite = 0;
prev_skipempty = 0;
}
if (ktab->flags & HL_SKIPWHITE)
did_header = TRUE;
if (prev_contained != (kp->flags & HL_CONTAINED))
{
msg_puts_attr((char_u *)"skipwhite", attr);
msg_puts_attr((char_u *)"contained", attr);
msg_putchar(' ');
prev_skipwhite = (ktab->flags & HL_SKIPWHITE);
prev_contained = (kp->flags & HL_CONTAINED);
}
if (ktab->flags & HL_SKIPEMPTY)
if (kp->k_syn.cont_in_list != prev_cont_in_list)
{
msg_puts_attr((char_u *)"skipempty", attr);
put_id_list((char_u *)"containedin",
kp->k_syn.cont_in_list, attr);
msg_putchar(' ');
prev_skipempty = (ktab->flags & HL_SKIPEMPTY);
prev_cont_in_list = kp->k_syn.cont_in_list;
}
if (kp->next_list != prev_next_list)
{
put_id_list((char_u *)"nextgroup", kp->next_list, attr);
msg_putchar(' ');
prev_next_list = kp->next_list;
if (kp->flags & HL_SKIPNL)
{
msg_puts_attr((char_u *)"skipnl", attr);
msg_putchar(' ');
prev_skipnl = (kp->flags & HL_SKIPNL);
}
if (kp->flags & HL_SKIPWHITE)
{
msg_puts_attr((char_u *)"skipwhite", attr);
msg_putchar(' ');
prev_skipwhite = (kp->flags & HL_SKIPWHITE);
}
if (kp->flags & HL_SKIPEMPTY)
{
msg_puts_attr((char_u *)"skipempty", attr);
msg_putchar(' ');
prev_skipempty = (kp->flags & HL_SKIPEMPTY);
}
}
msg_outtrans(kp->keyword);
}
msg_outtrans(ktab->keyword);
}
}
}
@ -3882,65 +3884,84 @@ syn_list_keywords(id, ktabp, did_header, attr)
}
static void
syn_clear_keyword(id, ktabp)
syn_clear_keyword(id, ht)
int id;
keyentry_T **ktabp;
hashtab_T *ht;
{
int i;
keyentry_T *ktab;
keyentry_T *ktab_prev;
keyentry_T *ktab_next;
hashitem_T *hi;
keyentry_T *kp;
keyentry_T *kp_prev;
keyentry_T *kp_next;
int todo;
if (ktabp == NULL) /* no keywords present */
return;
for (i = 0; i < KHASH_SIZE; ++i)
hash_lock(ht);
todo = ht->ht_used;
for (hi = ht->ht_array; todo > 0; ++hi)
{
ktab_prev = NULL;
for (ktab = ktabp[i]; ktab != NULL; )
if (!HASHITEM_EMPTY(hi))
{
if (ktab->k_syn.id == id)
--todo;
kp_prev = NULL;
for (kp = HI2KE(hi); kp != NULL; )
{
ktab_next = ktab->next;
if (ktab_prev == NULL)
ktabp[i] = ktab_next;
if (kp->k_syn.id == id)
{
kp_next = kp->ke_next;
if (kp_prev == NULL)
{
if (kp_next == NULL)
hash_remove(ht, hi);
else
hi->hi_key = KE2HIKEY(kp_next);
}
else
kp_prev->ke_next = kp_next;
vim_free(kp->next_list);
vim_free(kp->k_syn.cont_in_list);
vim_free(kp);
kp = kp_next;
}
else
ktab_prev->next = ktab_next;
vim_free(ktab);
ktab = ktab_next;
}
else
{
ktab_prev = ktab;
ktab = ktab->next;
{
kp_prev = kp;
kp = kp->ke_next;
}
}
}
}
hash_unlock(ht);
}
/*
* Recursive function to free() a branch of a kwordtab.
* Clear a whole keyword table.
*/
static void
free_keywtab(ktabp)
keyentry_T **ktabp;
clear_keywtab(ht)
hashtab_T *ht;
{
int i;
keyentry_T *ktab;
keyentry_T *ktab_next;
hashitem_T *hi;
int todo;
keyentry_T *kp;
keyentry_T *kp_next;
if (ktabp != NULL)
todo = ht->ht_used;
for (hi = ht->ht_array; todo > 0; ++hi)
{
for (i = 0; i < KHASH_SIZE; ++i)
for (ktab = ktabp[i]; ktab != NULL; ktab = ktab_next)
if (!HASHITEM_EMPTY(hi))
{
--todo;
kp = HI2KE(hi);
for (kp = HI2KE(hi); kp != NULL; kp = kp_next)
{
ktab_next = ktab->next;
vim_free(ktab->next_list);
vim_free(ktab->k_syn.cont_in_list);
vim_free(ktab);
kp_next = kp->ke_next;
vim_free(kp->next_list);
vim_free(kp->k_syn.cont_in_list);
vim_free(kp);
}
vim_free(ktabp);
}
}
hash_clear(ht);
hash_init(ht);
}
/*
@ -3954,69 +3975,51 @@ add_keyword(name, id, flags, cont_in_list, next_list)
short *cont_in_list; /* containedin for this keyword */
short *next_list; /* nextgroup for this keyword */
{
keyentry_T *ktab;
keyentry_T ***ktabpp;
int hash;
keyentry_T *kp;
hashtab_T *ht;
hashitem_T *hi;
char_u *name_ic = name;
long_u hash;
if (curbuf->b_syn_ic)
{
name_ic = str_foldcase(name, (int)STRLEN(name));
name_ic = str_foldcase(name, (int)STRLEN(name), NULL, 0);
if (name_ic == NULL)
name_ic = name;
}
ktab = (keyentry_T *)alloc((int)(sizeof(keyentry_T) + STRLEN(name_ic)));
if (ktab == NULL)
kp = (keyentry_T *)alloc((int)(sizeof(keyentry_T) + STRLEN(name_ic)));
if (kp == NULL)
return;
STRCPY(ktab->keyword, name_ic);
STRCPY(kp->keyword, name_ic);
if (name_ic != name)
vim_free(name_ic);
ktab->k_syn.id = id;
ktab->k_syn.inc_tag = current_syn_inc_tag;
ktab->flags = flags;
ktab->k_syn.cont_in_list = copy_id_list(cont_in_list);
kp->k_syn.id = id;
kp->k_syn.inc_tag = current_syn_inc_tag;
kp->flags = flags;
kp->k_syn.cont_in_list = copy_id_list(cont_in_list);
if (cont_in_list != NULL)
curbuf->b_syn_containedin = TRUE;
ktab->next_list = copy_id_list(next_list);
kp->next_list = copy_id_list(next_list);
if (curbuf->b_syn_ic)
ktabpp = &curbuf->b_keywtab_ic;
ht = &curbuf->b_keywtab_ic;
else
ktabpp = &curbuf->b_keywtab;
ht = &curbuf->b_keywtab;
if (*ktabpp == NULL)
hash = hash_hash(kp->keyword);
hi = hash_lookup(ht, kp->keyword, hash);
if (HASHITEM_EMPTY(hi))
{
*ktabpp = (keyentry_T **)alloc_clear(
(int)(sizeof(keyentry_T *) * KHASH_SIZE));
if (*ktabpp == NULL)
return;
/* new keyword, add to hashtable */
kp->ke_next = NULL;
hash_add_item(ht, hi, kp->keyword, hash);
}
hash = syn_khash(ktab->keyword);
ktab->next = (*ktabpp)[hash];
(*ktabpp)[hash] = ktab;
}
/*
* Compute a hash value for a keyword. Uses the ElfHash algorithm, which is
* supposed to have an even distribution (suggested by Charles Campbell).
*/
static int
syn_khash(p)
char_u *p;
{
long_u hash = 0;
long_u g;
while (*p != NUL)
else
{
hash = (hash << 4) + *p++; /* clear low 4 bits of hash, add char */
g = hash & 0xf0000000L; /* g has high 4 bits of hash only */
if (g != 0)
hash ^= g >> 24; /* xor g's high 4 bits into hash */
/* keyword already exists, prepend to list */
kp->ke_next = HI2KE(hi);
hi->hi_key = KE2HIKEY(kp);
}
return (int)(hash & KHASH_MASK);
}
/*
@ -5774,8 +5777,8 @@ syntax_present(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);
|| curbuf->b_keywtab.ht_used > 0
|| curbuf->b_keywtab_ic.ht_used > 0);
}
#if defined(FEAT_CMDL_COMPL) || defined(PROTO)