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)) #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 */ #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 current_syn_inc_tag = 0;
static int running_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 * 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 * 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 syn_list_cluster __ARGS((int id));
static void put_id_list __ARGS((char_u *name, short *list, int attr)); 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 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 int syn_list_keywords __ARGS((int id, hashtab_T *ht, int did_header, int attr));
static void syn_clear_keyword __ARGS((int id, keyentry_T **ktabp)); static void syn_clear_keyword __ARGS((int id, hashtab_T *ht));
static void free_keywtab __ARGS((keyentry_T **ktabp)); 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 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_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 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)); 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. */ /* Only check for keywords when not syncing and there are some. */
do_keywords = !syncing do_keywords = !syncing
&& (syn_buf->b_keywtab != NULL && (syn_buf->b_keywtab.ht_used > 0
|| syn_buf->b_keywtab_ic != NULL); || syn_buf->b_keywtab_ic.ht_used > 0);
/* Init the list of zero-width matches with a nextlist. This is used to /* Init the list of zero-width matches with a nextlist. This is used to
* avoid matching the same item in the same position twice. */ * 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 */ short **next_listp; /* return: next_list of matching keyword */
stateitem_T *cur_si; /* item at the top of the stack */ stateitem_T *cur_si; /* item at the top of the stack */
{ {
keyentry_T *ktab; keyentry_T *kp;
char_u *p; char_u *kwp;
int round; int round;
int len; int kwlen;
char_u keyword[MAXKEYWLEN + 1]; /* assume max. keyword len is 80 */ 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 /* Find first character after the keyword. First character was already
* checked. */ * checked. */
p = line + startcol; kwp = line + startcol;
len = 0; kwlen = 0;
do do
{ {
#ifdef FEAT_MBYTE #ifdef FEAT_MBYTE
if (has_mbyte) if (has_mbyte)
len += (*mb_ptr2len_check)(p + len); kwlen += (*mb_ptr2len_check)(kwp + kwlen);
else else
#endif #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; return 0;
/* /*
* Must make a copy of the keyword, so we can add a NUL and make it * Must make a copy of the keyword, so we can add a NUL and make it
* lowercase. * lowercase.
*/ */
STRNCPY(keyword, p, len); STRNCPY(keyword, kwp, kwlen);
keyword[len] = NUL; keyword[kwlen] = NUL;
/* /*
* Try twice: * Try twice:
@ -2988,41 +2995,35 @@ check_keyword_id(line, startcol, endcolp, flagsp, next_listp, cur_si)
*/ */
for (round = 1; round <= 2; ++round) 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; continue;
if (round == 1) /* match case */ if (round == 2) /* ignore case */
ktab = syn_buf->b_keywtab[syn_khash(keyword)]; (void)str_foldcase(kwp, kwlen, keyword, MAXKEYWLEN + 1);
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)];
}
/* /*
* 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: * When current_next_list is non-zero accept only that group, otherwise:
* Accept a not-contained keyword at toplevel. * Accept a not-contained keyword at toplevel.
* Accept a keyword at other levels only if it is in the contains list. * Accept a keyword at other levels only if it is in the contains list.
*/ */
for ( ; ktab != NULL; ktab = ktab->next) hi = hash_find(ht, keyword);
if ( STRCMP(keyword, ktab->keyword) == 0 if (!HASHITEM_EMPTY(hi))
&& (current_next_list != 0 for (kp = HI2KE(hi); kp != NULL; kp = kp->ke_next)
? 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))))
{ {
*endcolp = startcol + len; if (current_next_list != 0
*flagsp = ktab->flags; ? in_id_list(NULL, current_next_list, &kp->k_syn, 0)
*next_listp = ktab->next_list; : (cur_si == NULL
return ktab->k_syn.id; ? !(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; return 0;
@ -3066,10 +3067,8 @@ syntax_clear(buf)
curbuf->b_syn_containedin = FALSE; curbuf->b_syn_containedin = FALSE;
/* free the keywords */ /* free the keywords */
free_keywtab(buf->b_keywtab); clear_keywtab(&buf->b_keywtab);
buf->b_keywtab = NULL; clear_keywtab(&buf->b_keywtab_ic);
free_keywtab(buf->b_keywtab_ic);
buf->b_keywtab_ic = NULL;
/* free the syntax patterns */ /* free the syntax patterns */
for (i = buf->b_syn_patterns.ga_len; --i >= 0; ) 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" */ /* Clear keywords only when not ":syn sync clear group-name" */
if (!syncing) if (!syncing)
{ {
(void)syn_clear_keyword(id, curbuf->b_keywtab); (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_ic);
} }
/* clear the patterns for "id" */ /* clear the patterns for "id" */
@ -3552,8 +3551,8 @@ syn_list_one(id, syncing, link_only)
/* list the keywords for "id" */ /* list the keywords for "id" */
if (!syncing) if (!syncing)
{ {
did_header = syn_list_keywords(id, curbuf->b_keywtab, FALSE, attr); 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_ic,
did_header, attr); did_header, attr);
} }
@ -3787,15 +3786,16 @@ put_pattern(s, c, spp, attr)
* Return TRUE if the header has been printed. * Return TRUE if the header has been printed.
*/ */
static int static int
syn_list_keywords(id, ktabp, did_header, attr) syn_list_keywords(id, ht, did_header, attr)
int id; int id;
keyentry_T **ktabp; hashtab_T *ht;
int did_header; /* header has already been printed */ int did_header; /* header has already been printed */
int attr; int attr;
{ {
int i;
int outlen; int outlen;
keyentry_T *ktab; hashitem_T *hi;
keyentry_T *kp;
int todo;
int prev_contained = 0; int prev_contained = 0;
short *prev_next_list = NULL; short *prev_next_list = NULL;
short *prev_cont_in_list = NULL; short *prev_cont_in_list = NULL;
@ -3803,28 +3803,29 @@ syn_list_keywords(id, ktabp, did_header, attr)
int prev_skipwhite = 0; int prev_skipwhite = 0;
int prev_skipempty = 0; int prev_skipempty = 0;
if (ktabp == NULL)
return did_header;
/* /*
* Unfortunately, this list of keywords is not sorted on alphabet but on * Unfortunately, this list of keywords is not sorted on alphabet but on
* hash value... * 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) if (kp->k_syn.id == id)
|| prev_skipnl != (ktab->flags & HL_SKIPNL) {
|| prev_skipwhite != (ktab->flags & HL_SKIPWHITE) if (prev_contained != (kp->flags & HL_CONTAINED)
|| prev_skipempty != (ktab->flags & HL_SKIPEMPTY) || prev_skipnl != (kp->flags & HL_SKIPNL)
|| prev_cont_in_list != ktab->k_syn.cont_in_list || prev_skipwhite != (kp->flags & HL_SKIPWHITE)
|| prev_next_list != ktab->next_list) || prev_skipempty != (kp->flags & HL_SKIPEMPTY)
|| prev_cont_in_list != kp->k_syn.cont_in_list
|| prev_next_list != kp->next_list)
outlen = 9999; outlen = 9999;
else else
outlen = (int)STRLEN(ktab->keyword); outlen = (int)STRLEN(kp->keyword);
/* output "contained" and "nextgroup" on each line */ /* output "contained" and "nextgroup" on each line */
if (syn_list_header(did_header, outlen, id)) if (syn_list_header(did_header, outlen, id))
{ {
@ -3836,44 +3837,45 @@ syn_list_keywords(id, ktabp, did_header, attr)
prev_skipempty = 0; prev_skipempty = 0;
} }
did_header = TRUE; did_header = TRUE;
if (prev_contained != (ktab->flags & HL_CONTAINED)) if (prev_contained != (kp->flags & HL_CONTAINED))
{ {
msg_puts_attr((char_u *)"contained", attr); msg_puts_attr((char_u *)"contained", attr);
msg_putchar(' '); msg_putchar(' ');
prev_contained = (ktab->flags & HL_CONTAINED); prev_contained = (kp->flags & HL_CONTAINED);
} }
if (ktab->k_syn.cont_in_list != prev_cont_in_list) if (kp->k_syn.cont_in_list != prev_cont_in_list)
{ {
put_id_list((char_u *)"containedin", put_id_list((char_u *)"containedin",
ktab->k_syn.cont_in_list, attr); kp->k_syn.cont_in_list, attr);
msg_putchar(' '); msg_putchar(' ');
prev_cont_in_list = ktab->k_syn.cont_in_list; prev_cont_in_list = kp->k_syn.cont_in_list;
} }
if (ktab->next_list != prev_next_list) if (kp->next_list != prev_next_list)
{ {
put_id_list((char_u *)"nextgroup", ktab->next_list, attr); put_id_list((char_u *)"nextgroup", kp->next_list, attr);
msg_putchar(' '); msg_putchar(' ');
prev_next_list = ktab->next_list; prev_next_list = kp->next_list;
if (ktab->flags & HL_SKIPNL) if (kp->flags & HL_SKIPNL)
{ {
msg_puts_attr((char_u *)"skipnl", attr); msg_puts_attr((char_u *)"skipnl", attr);
msg_putchar(' '); msg_putchar(' ');
prev_skipnl = (ktab->flags & HL_SKIPNL); prev_skipnl = (kp->flags & HL_SKIPNL);
} }
if (ktab->flags & HL_SKIPWHITE) if (kp->flags & HL_SKIPWHITE)
{ {
msg_puts_attr((char_u *)"skipwhite", attr); msg_puts_attr((char_u *)"skipwhite", attr);
msg_putchar(' '); msg_putchar(' ');
prev_skipwhite = (ktab->flags & HL_SKIPWHITE); prev_skipwhite = (kp->flags & HL_SKIPWHITE);
} }
if (ktab->flags & HL_SKIPEMPTY) if (kp->flags & HL_SKIPEMPTY)
{ {
msg_puts_attr((char_u *)"skipempty", attr); msg_puts_attr((char_u *)"skipempty", attr);
msg_putchar(' '); msg_putchar(' ');
prev_skipempty = (ktab->flags & HL_SKIPEMPTY); prev_skipempty = (kp->flags & HL_SKIPEMPTY);
} }
} }
msg_outtrans(ktab->keyword); msg_outtrans(kp->keyword);
}
} }
} }
} }
@ -3882,65 +3884,84 @@ syn_list_keywords(id, ktabp, did_header, attr)
} }
static void static void
syn_clear_keyword(id, ktabp) syn_clear_keyword(id, ht)
int id; int id;
keyentry_T **ktabp; hashtab_T *ht;
{ {
int i; hashitem_T *hi;
keyentry_T *ktab; keyentry_T *kp;
keyentry_T *ktab_prev; keyentry_T *kp_prev;
keyentry_T *ktab_next; keyentry_T *kp_next;
int todo;
if (ktabp == NULL) /* no keywords present */ hash_lock(ht);
return; todo = ht->ht_used;
for (hi = ht->ht_array; todo > 0; ++hi)
for (i = 0; i < KHASH_SIZE; ++i)
{ {
ktab_prev = NULL; if (!HASHITEM_EMPTY(hi))
for (ktab = ktabp[i]; ktab != NULL; )
{ {
if (ktab->k_syn.id == id) --todo;
kp_prev = NULL;
for (kp = HI2KE(hi); kp != NULL; )
{ {
ktab_next = ktab->next; if (kp->k_syn.id == id)
if (ktab_prev == NULL) {
ktabp[i] = ktab_next; kp_next = kp->ke_next;
if (kp_prev == NULL)
{
if (kp_next == NULL)
hash_remove(ht, hi);
else else
ktab_prev->next = ktab_next; hi->hi_key = KE2HIKEY(kp_next);
vim_free(ktab); }
ktab = ktab_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 else
{ {
ktab_prev = ktab; kp_prev = kp;
ktab = ktab->next; kp = kp->ke_next;
} }
} }
} }
}
hash_unlock(ht);
} }
/* /*
* Recursive function to free() a branch of a kwordtab. * Clear a whole keyword table.
*/ */
static void static void
free_keywtab(ktabp) clear_keywtab(ht)
keyentry_T **ktabp; hashtab_T *ht;
{ {
int i; hashitem_T *hi;
keyentry_T *ktab; int todo;
keyentry_T *ktab_next; 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) if (!HASHITEM_EMPTY(hi))
for (ktab = ktabp[i]; ktab != NULL; ktab = ktab_next)
{ {
ktab_next = ktab->next; --todo;
vim_free(ktab->next_list); kp = HI2KE(hi);
vim_free(ktab->k_syn.cont_in_list); for (kp = HI2KE(hi); kp != NULL; kp = kp_next)
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 *cont_in_list; /* containedin for this keyword */
short *next_list; /* nextgroup for this keyword */ short *next_list; /* nextgroup for this keyword */
{ {
keyentry_T *ktab; keyentry_T *kp;
keyentry_T ***ktabpp; hashtab_T *ht;
int hash; hashitem_T *hi;
char_u *name_ic = name; char_u *name_ic = name;
long_u hash;
if (curbuf->b_syn_ic) 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) if (name_ic == NULL)
name_ic = name; name_ic = name;
} }
ktab = (keyentry_T *)alloc((int)(sizeof(keyentry_T) + STRLEN(name_ic))); kp = (keyentry_T *)alloc((int)(sizeof(keyentry_T) + STRLEN(name_ic)));
if (ktab == NULL) if (kp == NULL)
return; return;
STRCPY(ktab->keyword, name_ic); STRCPY(kp->keyword, name_ic);
if (name_ic != name) if (name_ic != name)
vim_free(name_ic); vim_free(name_ic);
ktab->k_syn.id = id; kp->k_syn.id = id;
ktab->k_syn.inc_tag = current_syn_inc_tag; kp->k_syn.inc_tag = current_syn_inc_tag;
ktab->flags = flags; kp->flags = flags;
ktab->k_syn.cont_in_list = copy_id_list(cont_in_list); kp->k_syn.cont_in_list = copy_id_list(cont_in_list);
if (cont_in_list != NULL) if (cont_in_list != NULL)
curbuf->b_syn_containedin = TRUE; 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) if (curbuf->b_syn_ic)
ktabpp = &curbuf->b_keywtab_ic; ht = &curbuf->b_keywtab_ic;
else 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( /* new keyword, add to hashtable */
(int)(sizeof(keyentry_T *) * KHASH_SIZE)); kp->ke_next = NULL;
if (*ktabpp == NULL) hash_add_item(ht, hi, kp->keyword, hash);
return;
} }
else
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)
{ {
hash = (hash << 4) + *p++; /* clear low 4 bits of hash, add char */ /* keyword already exists, prepend to list */
g = hash & 0xf0000000L; /* g has high 4 bits of hash only */ kp->ke_next = HI2KE(hi);
if (g != 0) hi->hi_key = KE2HIKEY(kp);
hash ^= g >> 24; /* xor g's high 4 bits into hash */
} }
return (int)(hash & KHASH_MASK);
} }
/* /*
@ -5774,8 +5777,8 @@ syntax_present(buf)
{ {
return (buf->b_syn_patterns.ga_len != 0 return (buf->b_syn_patterns.ga_len != 0
|| buf->b_syn_clusters.ga_len != 0 || buf->b_syn_clusters.ga_len != 0
|| curbuf->b_keywtab != NULL || curbuf->b_keywtab.ht_used > 0
|| curbuf->b_keywtab_ic != NULL); || curbuf->b_keywtab_ic.ht_used > 0);
} }
#if defined(FEAT_CMDL_COMPL) || defined(PROTO) #if defined(FEAT_CMDL_COMPL) || defined(PROTO)