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