Mercurial > vim
comparison src/highlight.c @ 26089:c544eacaf066 v8.2.3578
patch 8.2.3578: manipulating highlighting is complicated
Commit: https://github.com/vim/vim/commit/d1a8d658e1b16cf8579fc72cf7aa6a29a57ff5ef
Author: Yegappan Lakshmanan <yegappan@yahoo.com>
Date: Wed Nov 3 21:56:45 2021 +0000
patch 8.2.3578: manipulating highlighting is complicated
Problem: Manipulating highlighting is complicated.
Solution: Add the hlget() and hlset() functions. (Yegappan Lakshmanan,
closes #9039)
author | Bram Moolenaar <Bram@vim.org> |
---|---|
date | Wed, 03 Nov 2021 23:00:08 +0100 |
parents | c7e09c069ece |
children | bb87ce13e7d6 |
comparison
equal
deleted
inserted
replaced
26088:37d400a117f7 | 26089:c544eacaf066 |
---|---|
4079 gui_mch_free_font(gui.ital_font); | 4079 gui_mch_free_font(gui.ital_font); |
4080 gui_mch_free_font(gui.boldital_font); | 4080 gui_mch_free_font(gui.boldital_font); |
4081 # endif | 4081 # endif |
4082 } | 4082 } |
4083 #endif | 4083 #endif |
4084 | |
4085 #if defined(FEAT_EVAL) || defined(PROTO) | |
4086 /* | |
4087 * Convert each of the highlight attribute bits (bold, standout, underline, | |
4088 * etc.) set in 'hlattr' into a separate boolean item in a Dictionary with | |
4089 * the attribute name as the key. | |
4090 */ | |
4091 static dict_T * | |
4092 highlight_get_attr_dict(int hlattr) | |
4093 { | |
4094 dict_T *dict; | |
4095 int i; | |
4096 | |
4097 dict = dict_alloc(); | |
4098 if (dict == NULL) | |
4099 return NULL; | |
4100 | |
4101 for (i = 0; hl_attr_table[i] != 0; ++i) | |
4102 { | |
4103 if (hlattr & hl_attr_table[i]) | |
4104 { | |
4105 dict_add_bool(dict, hl_name_table[i], VVAL_TRUE); | |
4106 hlattr &= ~hl_attr_table[i]; // don't want "inverse" | |
4107 } | |
4108 } | |
4109 | |
4110 return dict; | |
4111 } | |
4112 | |
4113 /* | |
4114 * Return the attributes of the highlight group at index 'hl_idx' as a | |
4115 * Dictionary. If 'resolve_link' is TRUE, then resolves the highlight group | |
4116 * links recursively. | |
4117 */ | |
4118 static dict_T * | |
4119 highlight_get_info(int hl_idx, int resolve_link) | |
4120 { | |
4121 dict_T *dict; | |
4122 hl_group_T *sgp; | |
4123 dict_T *attr_dict; | |
4124 int hlgid; | |
4125 | |
4126 dict = dict_alloc(); | |
4127 if (dict == NULL) | |
4128 return dict; | |
4129 | |
4130 sgp = &HL_TABLE()[hl_idx]; | |
4131 // highlight group id is 1-based | |
4132 hlgid = hl_idx + 1; | |
4133 | |
4134 if (dict_add_string(dict, "name", sgp->sg_name) == FAIL) | |
4135 goto error; | |
4136 if (dict_add_number(dict, "id", hlgid) == FAIL) | |
4137 goto error; | |
4138 | |
4139 if (sgp->sg_link && resolve_link) | |
4140 { | |
4141 // resolve the highlight group link recursively | |
4142 while (sgp->sg_link) | |
4143 { | |
4144 hlgid = sgp->sg_link; | |
4145 sgp = &HL_TABLE()[sgp->sg_link - 1]; | |
4146 } | |
4147 } | |
4148 | |
4149 if (sgp->sg_term != 0) | |
4150 { | |
4151 attr_dict = highlight_get_attr_dict(sgp->sg_term); | |
4152 if (attr_dict != NULL) | |
4153 if (dict_add_dict(dict, "term", attr_dict) == FAIL) | |
4154 goto error; | |
4155 } | |
4156 if (sgp->sg_start != NULL) | |
4157 if (dict_add_string(dict, "start", sgp->sg_start) == FAIL) | |
4158 goto error; | |
4159 if (sgp->sg_stop != NULL) | |
4160 if (dict_add_string(dict, "stop", sgp->sg_stop) == FAIL) | |
4161 goto error; | |
4162 if (sgp->sg_cterm != 0) | |
4163 { | |
4164 attr_dict = highlight_get_attr_dict(sgp->sg_cterm); | |
4165 if (attr_dict != NULL) | |
4166 if (dict_add_dict(dict, "cterm", attr_dict) == FAIL) | |
4167 goto error; | |
4168 } | |
4169 if (sgp->sg_cterm_fg != 0) | |
4170 if (dict_add_string(dict, "ctermfg", | |
4171 highlight_color(hlgid, (char_u *)"fg", 'c')) == FAIL) | |
4172 goto error; | |
4173 if (sgp->sg_cterm_bg != 0) | |
4174 if (dict_add_string(dict, "ctermbg", | |
4175 highlight_color(hlgid, (char_u *)"bg", 'c')) == FAIL) | |
4176 goto error; | |
4177 if (sgp->sg_cterm_ul != 0) | |
4178 if (dict_add_string(dict, "ctermul", | |
4179 highlight_color(hlgid, (char_u *)"ul", 'c')) == FAIL) | |
4180 goto error; | |
4181 if (sgp->sg_gui != 0) | |
4182 { | |
4183 attr_dict = highlight_get_attr_dict(sgp->sg_gui); | |
4184 if (attr_dict != NULL) | |
4185 if (dict_add_dict(dict, "gui", attr_dict) == FAIL) | |
4186 goto error; | |
4187 } | |
4188 if (sgp->sg_gui_fg_name != NULL) | |
4189 if (dict_add_string(dict, "guifg", | |
4190 highlight_color(hlgid, (char_u *)"fg", 'g')) == FAIL) | |
4191 goto error; | |
4192 if (sgp->sg_gui_bg_name != NULL) | |
4193 if (dict_add_string(dict, "guibg", | |
4194 highlight_color(hlgid, (char_u *)"bg", 'g')) == FAIL) | |
4195 goto error; | |
4196 if (sgp->sg_gui_sp_name != NULL) | |
4197 if (dict_add_string(dict, "guisp", | |
4198 highlight_color(hlgid, (char_u *)"sp", 'g')) == FAIL) | |
4199 goto error; | |
4200 # ifdef FEAT_GUI | |
4201 if (sgp->sg_font_name != NULL) | |
4202 if (dict_add_string(dict, "font", sgp->sg_font_name) == FAIL) | |
4203 goto error; | |
4204 # endif | |
4205 if (sgp->sg_link) | |
4206 { | |
4207 char_u *link; | |
4208 | |
4209 link = HL_TABLE()[sgp->sg_link - 1].sg_name; | |
4210 if (link != NULL && dict_add_string(dict, "linksto", link) == FAIL) | |
4211 goto error; | |
4212 } | |
4213 if (dict_len(dict) == 2) | |
4214 // If only 'name' is present, then the highlight group is cleared. | |
4215 dict_add_bool(dict, "cleared", VVAL_TRUE); | |
4216 | |
4217 return dict; | |
4218 | |
4219 error: | |
4220 vim_free(dict); | |
4221 return NULL; | |
4222 } | |
4223 | |
4224 /* | |
4225 * "hlget([name])" function | |
4226 * Return the attributes of a specific highlight group (if specified) or all | |
4227 * the highlight groups. | |
4228 */ | |
4229 void | |
4230 f_hlget(typval_T *argvars, typval_T *rettv) | |
4231 { | |
4232 list_T *list; | |
4233 dict_T *dict; | |
4234 int i; | |
4235 char_u *hlarg = NULL; | |
4236 int resolve_link = FALSE; | |
4237 | |
4238 if (rettv_list_alloc(rettv) == FAIL) | |
4239 return; | |
4240 | |
4241 if (check_for_opt_string_arg(argvars, 0) == FAIL | |
4242 || (argvars[0].v_type != VAR_UNKNOWN | |
4243 && check_for_opt_bool_arg(argvars, 1) == FAIL)) | |
4244 return; | |
4245 | |
4246 if (argvars[0].v_type != VAR_UNKNOWN) | |
4247 { | |
4248 // highlight group name supplied | |
4249 hlarg = tv_get_string_chk(&argvars[0]); | |
4250 if (hlarg == NULL) | |
4251 return; | |
4252 | |
4253 if (argvars[1].v_type != VAR_UNKNOWN) | |
4254 { | |
4255 int error = FALSE; | |
4256 | |
4257 resolve_link = tv_get_bool_chk(&argvars[1], &error); | |
4258 if (error) | |
4259 return; | |
4260 } | |
4261 } | |
4262 | |
4263 list = rettv->vval.v_list; | |
4264 for (i = 0; i < highlight_ga.ga_len && !got_int; ++i) | |
4265 { | |
4266 if (hlarg == NULL || STRICMP(hlarg, HL_TABLE()[i].sg_name) == 0) | |
4267 { | |
4268 dict = highlight_get_info(i, resolve_link); | |
4269 if (dict != NULL) | |
4270 list_append_dict(list, dict); | |
4271 } | |
4272 } | |
4273 } | |
4274 | |
4275 /* | |
4276 * Returns the string value at 'dict[key]'. Returns NULL, if 'key' is not in | |
4277 * 'dict' or the value is not a string type. If the value is not a string type | |
4278 * or is NULL, then 'error' is set to TRUE. | |
4279 */ | |
4280 static char_u * | |
4281 hldict_get_string(dict_T *dict, char_u *key, int *error) | |
4282 { | |
4283 dictitem_T *di; | |
4284 | |
4285 *error = FALSE; | |
4286 di = dict_find(dict, key, -1); | |
4287 if (di == NULL) | |
4288 return NULL; | |
4289 | |
4290 if (di->di_tv.v_type != VAR_STRING || di->di_tv.vval.v_string == NULL) | |
4291 { | |
4292 emsg(_(e_stringreq)); | |
4293 *error = TRUE; | |
4294 return NULL; | |
4295 } | |
4296 | |
4297 return di->di_tv.vval.v_string; | |
4298 } | |
4299 | |
4300 /* | |
4301 * Convert the highlight attribute Dictionary at 'dict[key]' into a string | |
4302 * value in 'attr_str' of length 'len'. Returns FALSE if 'dict[key]' is not a | |
4303 * Dictionary or is NULL. | |
4304 */ | |
4305 static int | |
4306 hldict_attr_to_str( | |
4307 dict_T *dict, | |
4308 char_u *key, | |
4309 char_u *attr_str, | |
4310 int len) | |
4311 { | |
4312 dictitem_T *di; | |
4313 dict_T *attrdict; | |
4314 int i; | |
4315 | |
4316 attr_str[0] = NUL; | |
4317 di = dict_find(dict, key, -1); | |
4318 if (di == NULL) | |
4319 return TRUE; | |
4320 | |
4321 if (di->di_tv.v_type != VAR_DICT || di->di_tv.vval.v_dict == NULL) | |
4322 { | |
4323 emsg(_(e_dictreq)); | |
4324 return FALSE; | |
4325 } | |
4326 | |
4327 attrdict = di->di_tv.vval.v_dict; | |
4328 | |
4329 // If the attribute dict is empty, then return NONE to clear the attributes | |
4330 if (dict_len(attrdict) == 0) | |
4331 { | |
4332 vim_strcat(attr_str, (char_u *)"NONE", len); | |
4333 return TRUE; | |
4334 } | |
4335 | |
4336 for (i = 0; i < (int)ARRAY_LENGTH(hl_name_table); i++) | |
4337 { | |
4338 if (dict_get_bool(attrdict, (char_u *)hl_name_table[i], | |
4339 VVAL_FALSE) == VVAL_TRUE) | |
4340 { | |
4341 if (attr_str[0] != NUL) | |
4342 vim_strcat(attr_str, (char_u *)",", len); | |
4343 vim_strcat(attr_str, (char_u *)hl_name_table[i], len); | |
4344 } | |
4345 } | |
4346 | |
4347 return TRUE; | |
4348 } | |
4349 | |
4350 /* | |
4351 * Add or update a highlight group using 'dict' items. Returns TRUE if | |
4352 * successfully updated the highlight group. | |
4353 */ | |
4354 static int | |
4355 hlg_add_or_update(dict_T *dict) | |
4356 { | |
4357 char_u *name; | |
4358 int error; | |
4359 char_u term_attr[80]; | |
4360 char_u cterm_attr[80]; | |
4361 char_u gui_attr[80]; | |
4362 char_u *start; | |
4363 char_u *stop; | |
4364 char_u *ctermfg; | |
4365 char_u *ctermbg; | |
4366 char_u *ctermul; | |
4367 char_u *guifg; | |
4368 char_u *guibg; | |
4369 char_u *guisp; | |
4370 # ifdef FEAT_GUI | |
4371 char_u *font; | |
4372 # endif | |
4373 | |
4374 name = hldict_get_string(dict, (char_u *)"name", &error); | |
4375 if (name == NULL || error) | |
4376 return FALSE; | |
4377 | |
4378 if (dict_find(dict, (char_u *)"linksto", -1) != NULL) | |
4379 { | |
4380 char_u *linksto; | |
4381 | |
4382 // link highlight groups | |
4383 linksto = hldict_get_string(dict, (char_u *)"linksto", &error); | |
4384 if (linksto == NULL || error) | |
4385 return FALSE; | |
4386 | |
4387 vim_snprintf((char *)IObuff, IOSIZE, "link %s %s", name, linksto); | |
4388 do_highlight(IObuff, FALSE, FALSE); | |
4389 | |
4390 return TRUE; | |
4391 } | |
4392 | |
4393 if (dict_find(dict, (char_u *)"cleared", -1) != NULL) | |
4394 { | |
4395 varnumber_T cleared; | |
4396 | |
4397 // clear a highlight group | |
4398 cleared = dict_get_bool(dict, (char_u *)"cleared", FALSE); | |
4399 if (cleared == TRUE) | |
4400 { | |
4401 vim_snprintf((char *)IObuff, IOSIZE, "clear %s", name); | |
4402 do_highlight(IObuff, FALSE, FALSE); | |
4403 } | |
4404 | |
4405 return TRUE; | |
4406 } | |
4407 | |
4408 start = hldict_get_string(dict, (char_u *)"start", &error); | |
4409 if (error) | |
4410 return FALSE; | |
4411 | |
4412 stop = hldict_get_string(dict, (char_u *)"stop", &error); | |
4413 if (error) | |
4414 return FALSE; | |
4415 | |
4416 if (!hldict_attr_to_str(dict, (char_u *)"term", term_attr, | |
4417 sizeof(term_attr))) | |
4418 return FALSE; | |
4419 | |
4420 if (!hldict_attr_to_str(dict, (char_u *)"cterm", cterm_attr, | |
4421 sizeof(cterm_attr))) | |
4422 return FALSE; | |
4423 | |
4424 ctermfg = hldict_get_string(dict, (char_u *)"ctermfg", &error); | |
4425 if (error) | |
4426 return FALSE; | |
4427 | |
4428 ctermbg = hldict_get_string(dict, (char_u *)"ctermbg", &error); | |
4429 if (error) | |
4430 return FALSE; | |
4431 | |
4432 ctermul = hldict_get_string(dict, (char_u *)"ctermul", &error); | |
4433 if (error) | |
4434 return FALSE; | |
4435 | |
4436 if (!hldict_attr_to_str(dict, (char_u *)"gui", gui_attr, | |
4437 sizeof(gui_attr))) | |
4438 return FALSE; | |
4439 | |
4440 guifg = hldict_get_string(dict, (char_u *)"guifg", &error); | |
4441 if (error) | |
4442 return FALSE; | |
4443 | |
4444 guibg = hldict_get_string(dict, (char_u *)"guibg", &error); | |
4445 if (error) | |
4446 return FALSE; | |
4447 | |
4448 guisp = hldict_get_string(dict, (char_u *)"guisp", &error); | |
4449 if (error) | |
4450 return FALSE; | |
4451 | |
4452 # ifdef FEAT_GUI | |
4453 font = hldict_get_string(dict, (char_u *)"font", &error); | |
4454 if (error) | |
4455 return FALSE; | |
4456 # endif | |
4457 | |
4458 // If none of the attributes are specified, then do nothing. | |
4459 if (term_attr[0] == NUL && start == NULL && stop == NULL | |
4460 && cterm_attr[0] == NUL && ctermfg == NULL && ctermbg == NULL | |
4461 && ctermul == NULL && gui_attr[0] == NUL | |
4462 # ifdef FEAT_GUI | |
4463 && font == NULL | |
4464 # endif | |
4465 && guifg == NULL && guibg == NULL && guisp == NULL | |
4466 ) | |
4467 return TRUE; | |
4468 | |
4469 vim_snprintf((char *)IObuff, IOSIZE, | |
4470 "%s %s%s %s%s %s%s %s%s %s%s %s%s %s%s %s%s %s%s %s%s %s%s %s%s", | |
4471 name, | |
4472 term_attr[0] != NUL ? "term=" : "", | |
4473 term_attr[0] != NUL ? term_attr : (char_u *)"", | |
4474 start != NULL ? "start=" : "", | |
4475 start != NULL ? start : (char_u *)"", | |
4476 stop != NULL ? "stop=" : "", | |
4477 stop != NULL ? stop : (char_u *)"", | |
4478 cterm_attr[0] != NUL ? "cterm=" : "", | |
4479 cterm_attr[0] != NUL ? cterm_attr : (char_u *)"", | |
4480 ctermfg != NULL ? "ctermfg=" : "", | |
4481 ctermfg != NULL ? ctermfg : (char_u *)"", | |
4482 ctermbg != NULL ? "ctermbg=" : "", | |
4483 ctermbg != NULL ? ctermbg : (char_u *)"", | |
4484 ctermul != NULL ? "ctermul=" : "", | |
4485 ctermul != NULL ? ctermul : (char_u *)"", | |
4486 gui_attr[0] != NUL ? "gui=" : "", | |
4487 gui_attr[0] != NUL ? gui_attr : (char_u *)"", | |
4488 # ifdef FEAT_GUI | |
4489 font != NULL ? "font=" : "", | |
4490 font != NULL ? font : (char_u *)"", | |
4491 # else | |
4492 "", "", | |
4493 # endif | |
4494 guifg != NULL ? "guifg=" : "", | |
4495 guifg != NULL ? guifg : (char_u *)"", | |
4496 guibg != NULL ? "guibg=" : "", | |
4497 guibg != NULL ? guibg : (char_u *)"", | |
4498 guisp != NULL ? "guisp=" : "", | |
4499 guisp != NULL ? guisp : (char_u *)"" | |
4500 ); | |
4501 | |
4502 do_highlight(IObuff, FALSE, FALSE); | |
4503 | |
4504 return TRUE; | |
4505 } | |
4506 | |
4507 /* | |
4508 * "hlset([{highlight_attr}])" function | |
4509 * Add or modify highlight groups | |
4510 */ | |
4511 void | |
4512 f_hlset(typval_T *argvars, typval_T *rettv) | |
4513 { | |
4514 listitem_T *li; | |
4515 dict_T *dict; | |
4516 | |
4517 rettv->vval.v_number = -1; | |
4518 | |
4519 if (check_for_list_arg(argvars, 0) == FAIL) | |
4520 return; | |
4521 | |
4522 FOR_ALL_LIST_ITEMS(argvars->vval.v_list, li) | |
4523 { | |
4524 if (li->li_tv.v_type != VAR_DICT) | |
4525 { | |
4526 emsg(_(e_dictreq)); | |
4527 return; | |
4528 } | |
4529 | |
4530 dict = li->li_tv.vval.v_dict; | |
4531 if (!hlg_add_or_update(dict)) | |
4532 return; | |
4533 } | |
4534 | |
4535 rettv->vval.v_number = 0; | |
4536 } | |
4537 #endif |