@@ -207,6 +207,21 @@ static int hl_flags[HLF_COUNT] = HL_FLAGS;
207207static garray_T highlight_ga ;
208208#define HL_TABLE () ((hl_group_T *)((highlight_ga.ga_data)))
209209
210+ // Wrapper struct for hashtable entries: stores the highlight group ID alongside
211+ // the uppercase name used as a hash key. Uses the same offsetof pattern as
212+ // signgroup_T / HI2SG.
213+ typedef struct {
214+ int hn_id ; // highlight group ID (1-based)
215+ char_u hn_key [1 ]; // uppercase name (stretchable array)
216+ } hlname_T ;
217+
218+ #define HLNAME_KEY_OFF offsetof(hlname_T, hn_key)
219+ #define HI2HLNAME (hi ) ((hlname_T *)((hi)->hi_key - HLNAME_KEY_OFF))
220+
221+ // hashtable for quick highlight group name lookup
222+ static hashtab_T highlight_ht ;
223+ static bool highlight_ht_inited = false;
224+
210225/*
211226 * An attribute number is the index in attr_table plus ATTR_OFF.
212227 */
@@ -217,6 +232,7 @@ static void set_hl_attr(int idx);
217232static void highlight_list_one (int id );
218233static int highlight_list_arg (int id , int didh , int type , int iarg , char_u * sarg , char * name );
219234static int syn_add_group (char_u * name );
235+ static int syn_name2id_len (char_u * name , int len );
220236static int hl_has_settings (int idx , int check_link );
221237static void highlight_clear (int idx );
222238
@@ -2034,9 +2050,11 @@ free_highlight(void)
20342050 {
20352051 highlight_clear (i );
20362052 vim_free (HL_TABLE ()[i ].sg_name );
2037- vim_free (HL_TABLE ()[i ].sg_name_u );
2053+ vim_free (HL_TABLE ()[i ].sg_name_u - HLNAME_KEY_OFF );
20382054 }
20392055 ga_clear (& highlight_ga );
2056+ hash_clear (& highlight_ht );
2057+ highlight_ht_inited = false;
20402058}
20412059#endif
20422060
@@ -3810,25 +3828,37 @@ syn_override(int id)
38103828}
38113829
38123830/*
3813- * Lookup a highlight group name and return its ID .
3831+ * Lookup a highlight group name by pointer and length .
38143832 * If it is not found, 0 is returned.
38153833 */
3816- int
3817- syn_name2id (char_u * name )
3834+ static int
3835+ syn_name2id_len (char_u * name , int len )
38183836{
3819- int i ;
38203837 char_u name_u [MAX_SYN_NAME + 1 ];
3838+ hashitem_T * hi ;
38213839
3822- // Avoid using stricmp() too much, it's slow on some systems
3823- // Avoid alloc()/free(), these are slow too. ID names over 200 chars
3824- // don't deserve to be found!
3825- vim_strncpy ( name_u , name , MAX_SYN_NAME ) ;
3840+ if ( len > MAX_SYN_NAME )
3841+ len = MAX_SYN_NAME ;
3842+ mch_memmove ( name_u , name , len );
3843+ name_u [ len ] = NUL ;
38263844 vim_strup (name_u );
3827- for (i = highlight_ga .ga_len ; -- i >= 0 ; )
3828- if (HL_TABLE ()[i ].sg_name_u != NULL
3829- && STRCMP (name_u , HL_TABLE ()[i ].sg_name_u ) == 0 )
3830- break ;
3831- return i + 1 ;
3845+ if (!highlight_ht_inited )
3846+ return 0 ;
3847+ hi = hash_find (& highlight_ht , name_u );
3848+ if (HASHITEM_EMPTY (hi ))
3849+ return 0 ;
3850+ return HI2HLNAME (hi )-> hn_id ;
3851+ }
3852+
3853+ /*
3854+ * Lookup a highlight group name and return its ID.
3855+ * If it is not found, 0 is returned.
3856+ */
3857+ int
3858+ syn_name2id (char_u * name )
3859+ {
3860+ // Avoid using stricmp() too much, it's slow on some systems.
3861+ return syn_name2id_len (name , (int )STRLEN (name ));
38323862}
38333863
38343864/*
@@ -3876,16 +3906,7 @@ syn_id2name(int id)
38763906 int
38773907syn_namen2id (char_u * linep , int len )
38783908{
3879- char_u * name ;
3880- int id = 0 ;
3881-
3882- name = vim_strnsave (linep , len );
3883- if (name == NULL )
3884- return 0 ;
3885-
3886- id = syn_name2id (name );
3887- vim_free (name );
3888- return id ;
3909+ return syn_name2id_len (linep , len );
38893910}
38903911
38913912/*
@@ -3905,15 +3926,14 @@ syn_check_group(char_u *pp, int len)
39053926 emsg (_ (e_highlight_group_name_too_long ));
39063927 return 0 ;
39073928 }
3908- name = vim_strnsave (pp , len );
3909- if (name == NULL )
3910- return 0 ;
3911-
3912- id = syn_name2id (name );
3929+ id = syn_name2id_len (pp , len );
39133930 if (id == 0 ) // doesn't exist yet
3931+ {
3932+ name = vim_strnsave (pp , len );
3933+ if (name == NULL )
3934+ return 0 ;
39143935 id = syn_add_group (name );
3915- else
3916- vim_free (name );
3936+ }
39173937 return id ;
39183938}
39193939
@@ -3952,6 +3972,8 @@ syn_add_group(char_u *name)
39523972 {
39533973 highlight_ga .ga_itemsize = sizeof (hl_group_T );
39543974 highlight_ga .ga_growsize = 10 ;
3975+ hash_init (& highlight_ht );
3976+ highlight_ht_inited = true;
39553977 }
39563978
39573979 if (highlight_ga .ga_len >= MAX_HL_ID )
@@ -3968,11 +3990,20 @@ syn_add_group(char_u *name)
39683990 return 0 ;
39693991 }
39703992
3971- name_up = vim_strsave_up (name );
3972- if (name_up == NULL )
39733993 {
3974- vim_free (name );
3975- return 0 ;
3994+ hlname_T * hn ;
3995+ int len = (int )STRLEN (name );
3996+
3997+ hn = alloc (offsetof(hlname_T , hn_key ) + len + 1 );
3998+ if (hn == NULL )
3999+ {
4000+ vim_free (name );
4001+ return 0 ;
4002+ }
4003+ vim_strncpy (hn -> hn_key , name , len );
4004+ vim_strup (hn -> hn_key );
4005+ hn -> hn_id = highlight_ga .ga_len + 1 ; // ID is index plus one
4006+ name_up = hn -> hn_key ;
39764007 }
39774008
39784009 CLEAR_POINTER (& (HL_TABLE ()[highlight_ga .ga_len ]));
@@ -3983,6 +4014,7 @@ syn_add_group(char_u *name)
39834014 HL_TABLE ()[highlight_ga .ga_len ].sg_gui_fg = INVALCOLOR ;
39844015 HL_TABLE ()[highlight_ga .ga_len ].sg_gui_sp = INVALCOLOR ;
39854016#endif
4017+ hash_add (& highlight_ht , name_up , "highlight" );
39864018 ++ highlight_ga .ga_len ;
39874019
39884020 return highlight_ga .ga_len ; // ID is index plus one
@@ -3995,9 +4027,14 @@ syn_add_group(char_u *name)
39954027 static void
39964028syn_unadd_group (void )
39974029{
4030+ hashitem_T * hi ;
4031+
39984032 -- highlight_ga .ga_len ;
4033+ hi = hash_find (& highlight_ht , HL_TABLE ()[highlight_ga .ga_len ].sg_name_u );
4034+ if (!HASHITEM_EMPTY (hi ))
4035+ hash_remove (& highlight_ht , hi , "highlight" );
39994036 vim_free (HL_TABLE ()[highlight_ga .ga_len ].sg_name );
4000- vim_free (HL_TABLE ()[highlight_ga .ga_len ].sg_name_u );
4037+ vim_free (HL_TABLE ()[highlight_ga .ga_len ].sg_name_u - HLNAME_KEY_OFF );
40014038}
40024039
40034040/*
@@ -4246,6 +4283,7 @@ highlight_changed(void)
42464283 int hlf ;
42474284 int i ;
42484285 char_u * p ;
4286+ char_u * default_hl ;
42494287 int attr ;
42504288 char_u * end ;
42514289 int id ;
@@ -4278,14 +4316,22 @@ highlight_changed(void)
42784316 highlight_ids [hlf ] = 0 ;
42794317 }
42804318
4319+ default_hl = get_highlight_default ();
4320+
42814321 // First set all attributes to their default value.
4282- // Then use the attributes from the 'highlight' option.
4322+ // Then use the attributes from the 'highlight' option, unless it already
4323+ // matches the default and would repeat the same work.
42834324 for (i = 0 ; i < 2 ; ++ i )
42844325 {
42854326 if (i )
4327+ {
4328+ if (default_hl != NULL && p_hl != NULL
4329+ && STRCMP (default_hl , p_hl ) == 0 )
4330+ continue ;
42864331 p = p_hl ;
4332+ }
42874333 else
4288- p = get_highlight_default () ;
4334+ p = default_hl ;
42894335 if (p == NULL ) // just in case
42904336 continue ;
42914337
0 commit comments