1 /* vi:set ts=8 sts=4 sw=4 noet: 2 * 3 * VIM - Vi IMproved by Bram Moolenaar 4 * 5 * Do ":help uganda" in Vim to read copying and usage conditions. 6 * Do ":help credits" in Vim to see a list of people who contributed. 7 * See README.txt for an overview of the Vim source code. 8 */ 9 10 /* 11 * syntax.c: code for syntax highlighting 12 */ 13 14 #include "vim.h" 15 16 #if defined(FEAT_SYN_HL) || defined(PROTO) 17 18 #define SYN_NAMELEN 50 // maximum length of a syntax name 19 20 // different types of offsets that are possible 21 #define SPO_MS_OFF 0 // match start offset 22 #define SPO_ME_OFF 1 // match end offset 23 #define SPO_HS_OFF 2 // highl. start offset 24 #define SPO_HE_OFF 3 // highl. end offset 25 #define SPO_RS_OFF 4 // region start offset 26 #define SPO_RE_OFF 5 // region end offset 27 #define SPO_LC_OFF 6 // leading context offset 28 #define SPO_COUNT 7 29 30 static char *(spo_name_tab[SPO_COUNT]) = 31 {"ms=", "me=", "hs=", "he=", "rs=", "re=", "lc="}; 32 33 /* 34 * The patterns that are being searched for are stored in a syn_pattern. 35 * A match item consists of one pattern. 36 * A start/end item consists of n start patterns and m end patterns. 37 * A start/skip/end item consists of n start patterns, one skip pattern and m 38 * end patterns. 39 * For the latter two, the patterns are always consecutive: start-skip-end. 40 * 41 * A character offset can be given for the matched text (_m_start and _m_end) 42 * and for the actually highlighted text (_h_start and _h_end). 43 * 44 * Note that ordering of members is optimized to reduce padding. 45 */ 46 typedef struct syn_pattern 47 { 48 char sp_type; // see SPTYPE_ defines below 49 char sp_syncing; // this item used for syncing 50 short sp_syn_match_id; // highlight group ID of pattern 51 short sp_off_flags; // see below 52 int sp_offsets[SPO_COUNT]; // offsets 53 int sp_flags; // see HL_ defines below 54 #ifdef FEAT_CONCEAL 55 int sp_cchar; // conceal substitute character 56 #endif 57 int sp_ic; // ignore-case flag for sp_prog 58 int sp_sync_idx; // sync item index (syncing only) 59 int sp_line_id; // ID of last line where tried 60 int sp_startcol; // next match in sp_line_id line 61 short *sp_cont_list; // cont. group IDs, if non-zero 62 short *sp_next_list; // next group IDs, if non-zero 63 struct sp_syn sp_syn; // struct passed to in_id_list() 64 char_u *sp_pattern; // regexp to match, pattern 65 regprog_T *sp_prog; // regexp to match, program 66 #ifdef FEAT_PROFILE 67 syn_time_T sp_time; 68 #endif 69 } synpat_T; 70 71 // The sp_off_flags are computed like this: 72 // offset from the start of the matched text: (1 << SPO_XX_OFF) 73 // offset from the end of the matched text: (1 << (SPO_XX_OFF + SPO_COUNT)) 74 // When both are present, only one is used. 75 76 #define SPTYPE_MATCH 1 // match keyword with this group ID 77 #define SPTYPE_START 2 // match a regexp, start of item 78 #define SPTYPE_END 3 // match a regexp, end of item 79 #define SPTYPE_SKIP 4 // match a regexp, skip within item 80 81 82 #define SYN_ITEMS(buf) ((synpat_T *)((buf)->b_syn_patterns.ga_data)) 83 84 #define NONE_IDX -2 // value of sp_sync_idx for "NONE" 85 86 /* 87 * Flags for b_syn_sync_flags: 88 */ 89 #define SF_CCOMMENT 0x01 // sync on a C-style comment 90 #define SF_MATCH 0x02 // sync by matching a pattern 91 92 #define SYN_STATE_P(ssp) ((bufstate_T *)((ssp)->ga_data)) 93 94 #define MAXKEYWLEN 80 // maximum length of a keyword 95 96 /* 97 * The attributes of the syntax item that has been recognized. 98 */ 99 static int current_attr = 0; // attr of current syntax word 100 #ifdef FEAT_EVAL 101 static int current_id = 0; // ID of current char for syn_get_id() 102 static int current_trans_id = 0; // idem, transparency removed 103 #endif 104 #ifdef FEAT_CONCEAL 105 static int current_flags = 0; 106 static int current_seqnr = 0; 107 static int current_sub_char = 0; 108 #endif 109 110 typedef struct syn_cluster_S 111 { 112 char_u *scl_name; // syntax cluster name 113 char_u *scl_name_u; // uppercase of scl_name 114 short *scl_list; // IDs in this syntax cluster 115 } syn_cluster_T; 116 117 /* 118 * Methods of combining two clusters 119 */ 120 #define CLUSTER_REPLACE 1 // replace first list with second 121 #define CLUSTER_ADD 2 // add second list to first 122 #define CLUSTER_SUBTRACT 3 // subtract second list from first 123 124 #define SYN_CLSTR(buf) ((syn_cluster_T *)((buf)->b_syn_clusters.ga_data)) 125 126 /* 127 * Syntax group IDs have different types: 128 * 0 - 19999 normal syntax groups 129 * 20000 - 20999 ALLBUT indicator (current_syn_inc_tag added) 130 * 21000 - 21999 TOP indicator (current_syn_inc_tag added) 131 * 22000 - 22999 CONTAINED indicator (current_syn_inc_tag added) 132 * 23000 - 32767 cluster IDs (subtract SYNID_CLUSTER for the cluster ID) 133 */ 134 #define SYNID_ALLBUT MAX_HL_ID // syntax group ID for contains=ALLBUT 135 #define SYNID_TOP 21000 // syntax group ID for contains=TOP 136 #define SYNID_CONTAINED 22000 // syntax group ID for contains=CONTAINED 137 #define SYNID_CLUSTER 23000 // first syntax group ID for clusters 138 139 #define MAX_SYN_INC_TAG 999 // maximum before the above overflow 140 #define MAX_CLUSTER_ID (32767 - SYNID_CLUSTER) 141 142 /* 143 * Annoying Hack(TM): ":syn include" needs this pointer to pass to 144 * expand_filename(). Most of the other syntax commands don't need it, so 145 * instead of passing it to them, we stow it here. 146 */ 147 static char_u **syn_cmdlinep; 148 149 /* 150 * Another Annoying Hack(TM): To prevent rules from other ":syn include"'d 151 * files from leaking into ALLBUT lists, we assign a unique ID to the 152 * rules in each ":syn include"'d file. 153 */ 154 static int current_syn_inc_tag = 0; 155 static int running_syn_inc_tag = 0; 156 157 /* 158 * In a hashtable item "hi_key" points to "keyword" in a keyentry. 159 * This avoids adding a pointer to the hashtable item. 160 * KE2HIKEY() converts a var pointer to a hashitem key pointer. 161 * HIKEY2KE() converts a hashitem key pointer to a var pointer. 162 * HI2KE() converts a hashitem pointer to a var pointer. 163 */ 164 static keyentry_T dumkey; 165 #define KE2HIKEY(kp) ((kp)->keyword) 166 #define HIKEY2KE(p) ((keyentry_T *)((p) - (dumkey.keyword - (char_u *)&dumkey))) 167 #define HI2KE(hi) HIKEY2KE((hi)->hi_key) 168 169 /* 170 * To reduce the time spent in keepend(), remember at which level in the state 171 * stack the first item with "keepend" is present. When "-1", there is no 172 * "keepend" on the stack. 173 */ 174 static int keepend_level = -1; 175 176 static char msg_no_items[] = N_("No Syntax items defined for this buffer"); 177 178 /* 179 * For the current state we need to remember more than just the idx. 180 * When si_m_endpos.lnum is 0, the items other than si_idx are unknown. 181 * (The end positions have the column number of the next char) 182 */ 183 typedef struct state_item 184 { 185 int si_idx; // index of syntax pattern or 186 // KEYWORD_IDX 187 int si_id; // highlight group ID for keywords 188 int si_trans_id; // idem, transparency removed 189 int si_m_lnum; // lnum of the match 190 int si_m_startcol; // starting column of the match 191 lpos_T si_m_endpos; // just after end posn of the match 192 lpos_T si_h_startpos; // start position of the highlighting 193 lpos_T si_h_endpos; // end position of the highlighting 194 lpos_T si_eoe_pos; // end position of end pattern 195 int si_end_idx; // group ID for end pattern or zero 196 int si_ends; // if match ends before si_m_endpos 197 int si_attr; // attributes in this state 198 long si_flags; // HL_HAS_EOL flag in this state, and 199 // HL_SKIP* for si_next_list 200 #ifdef FEAT_CONCEAL 201 int si_seqnr; // sequence number 202 int si_cchar; // substitution character for conceal 203 #endif 204 short *si_cont_list; // list of contained groups 205 short *si_next_list; // nextgroup IDs after this item ends 206 reg_extmatch_T *si_extmatch; // \z(...\) matches from start 207 // pattern 208 } stateitem_T; 209 210 #define KEYWORD_IDX -1 // value of si_idx for keywords 211 #define ID_LIST_ALL (short *)-1 // valid of si_cont_list for containing all 212 // but contained groups 213 214 #ifdef FEAT_CONCEAL 215 static int next_seqnr = 1; // value to use for si_seqnr 216 #endif 217 218 /* 219 * Struct to reduce the number of arguments to get_syn_options(), it's used 220 * very often. 221 */ 222 typedef struct 223 { 224 int flags; // flags for contained and transparent 225 int keyword; // TRUE for ":syn keyword" 226 int *sync_idx; // syntax item for "grouphere" argument, NULL 227 // if not allowed 228 char has_cont_list; // TRUE if "cont_list" can be used 229 short *cont_list; // group IDs for "contains" argument 230 short *cont_in_list; // group IDs for "containedin" argument 231 short *next_list; // group IDs for "nextgroup" argument 232 } syn_opt_arg_T; 233 234 /* 235 * The next possible match in the current line for any pattern is remembered, 236 * to avoid having to try for a match in each column. 237 * If next_match_idx == -1, not tried (in this line) yet. 238 * If next_match_col == MAXCOL, no match found in this line. 239 * (All end positions have the column of the char after the end) 240 */ 241 static int next_match_col; // column for start of next match 242 static lpos_T next_match_m_endpos; // position for end of next match 243 static lpos_T next_match_h_startpos; // pos. for highl. start of next match 244 static lpos_T next_match_h_endpos; // pos. for highl. end of next match 245 static int next_match_idx; // index of matched item 246 static long next_match_flags; // flags for next match 247 static lpos_T next_match_eos_pos; // end of start pattn (start region) 248 static lpos_T next_match_eoe_pos; // pos. for end of end pattern 249 static int next_match_end_idx; // ID of group for end pattn or zero 250 static reg_extmatch_T *next_match_extmatch = NULL; 251 252 /* 253 * A state stack is an array of integers or stateitem_T, stored in a 254 * garray_T. A state stack is invalid if its itemsize entry is zero. 255 */ 256 #define INVALID_STATE(ssp) ((ssp)->ga_itemsize == 0) 257 #define VALID_STATE(ssp) ((ssp)->ga_itemsize != 0) 258 259 #define FOR_ALL_SYNSTATES(sb, sst) \ 260 for ((sst) = (sb)->b_sst_first; (sst) != NULL; (sst) = (sst)->sst_next) 261 262 /* 263 * The current state (within the line) of the recognition engine. 264 * When current_state.ga_itemsize is 0 the current state is invalid. 265 */ 266 static win_T *syn_win; // current window for highlighting 267 static buf_T *syn_buf; // current buffer for highlighting 268 static synblock_T *syn_block; // current buffer for highlighting 269 #ifdef FEAT_RELTIME 270 static proftime_T *syn_tm; // timeout limit 271 #endif 272 static linenr_T current_lnum = 0; // lnum of current state 273 static colnr_T current_col = 0; // column of current state 274 static int current_state_stored = 0; // TRUE if stored current state 275 // after setting current_finished 276 static int current_finished = 0; // current line has been finished 277 static garray_T current_state // current stack of state_items 278 = {0, 0, 0, 0, NULL}; 279 static short *current_next_list = NULL; // when non-zero, nextgroup list 280 static int current_next_flags = 0; // flags for current_next_list 281 static int current_line_id = 0; // unique number for current line 282 283 #define CUR_STATE(idx) ((stateitem_T *)(current_state.ga_data))[idx] 284 285 static void syn_sync(win_T *wp, linenr_T lnum, synstate_T *last_valid); 286 static int syn_match_linecont(linenr_T lnum); 287 static void syn_start_line(void); 288 static void syn_update_ends(int startofline); 289 static void syn_stack_alloc(void); 290 static int syn_stack_cleanup(void); 291 static void syn_stack_free_entry(synblock_T *block, synstate_T *p); 292 static synstate_T *syn_stack_find_entry(linenr_T lnum); 293 static synstate_T *store_current_state(void); 294 static void load_current_state(synstate_T *from); 295 static void invalidate_current_state(void); 296 static int syn_stack_equal(synstate_T *sp); 297 static void validate_current_state(void); 298 static int syn_finish_line(int syncing); 299 static int syn_current_attr(int syncing, int displaying, int *can_spell, int keep_state); 300 static int did_match_already(int idx, garray_T *gap); 301 static stateitem_T *push_next_match(stateitem_T *cur_si); 302 static void check_state_ends(void); 303 static void update_si_attr(int idx); 304 static void check_keepend(void); 305 static void update_si_end(stateitem_T *sip, int startcol, int force); 306 static short *copy_id_list(short *list); 307 static int in_id_list(stateitem_T *item, short *cont_list, struct sp_syn *ssp, int contained); 308 static int push_current_state(int idx); 309 static void pop_current_state(void); 310 #ifdef FEAT_PROFILE 311 static void syn_clear_time(syn_time_T *tt); 312 static void syntime_clear(void); 313 static void syntime_report(void); 314 static int syn_time_on = FALSE; 315 # define IF_SYN_TIME(p) (p) 316 #else 317 # define IF_SYN_TIME(p) NULL 318 typedef int syn_time_T; 319 #endif 320 321 static void syn_stack_apply_changes_block(synblock_T *block, buf_T *buf); 322 static void find_endpos(int idx, lpos_T *startpos, lpos_T *m_endpos, lpos_T *hl_endpos, long *flagsp, lpos_T *end_endpos, int *end_idx, reg_extmatch_T *start_ext); 323 324 static void limit_pos(lpos_T *pos, lpos_T *limit); 325 static void limit_pos_zero(lpos_T *pos, lpos_T *limit); 326 static void syn_add_end_off(lpos_T *result, regmmatch_T *regmatch, synpat_T *spp, int idx, int extra); 327 static void syn_add_start_off(lpos_T *result, regmmatch_T *regmatch, synpat_T *spp, int idx, int extra); 328 static char_u *syn_getcurline(void); 329 static int syn_regexec(regmmatch_T *rmp, linenr_T lnum, colnr_T col, syn_time_T *st); 330 static int check_keyword_id(char_u *line, int startcol, int *endcol, long *flags, short **next_list, stateitem_T *cur_si, int *ccharp); 331 static void syn_remove_pattern(synblock_T *block, int idx); 332 static void syn_clear_pattern(synblock_T *block, int i); 333 static void syn_clear_cluster(synblock_T *block, int i); 334 static void syn_clear_one(int id, int syncing); 335 static void syn_cmd_onoff(exarg_T *eap, char *name); 336 static void syn_lines_msg(void); 337 static void syn_match_msg(void); 338 static void syn_list_one(int id, int syncing, int link_only); 339 static void syn_list_cluster(int id); 340 static void put_id_list(char_u *name, short *list, int attr); 341 static void put_pattern(char *s, int c, synpat_T *spp, int attr); 342 static int syn_list_keywords(int id, hashtab_T *ht, int did_header, int attr); 343 static void syn_clear_keyword(int id, hashtab_T *ht); 344 static void clear_keywtab(hashtab_T *ht); 345 static int syn_scl_namen2id(char_u *linep, int len); 346 static int syn_check_cluster(char_u *pp, int len); 347 static int syn_add_cluster(char_u *name); 348 static void init_syn_patterns(void); 349 static char_u *get_syn_pattern(char_u *arg, synpat_T *ci); 350 static int get_id_list(char_u **arg, int keylen, short **list, int skip); 351 static void syn_combine_list(short **clstr1, short **clstr2, int list_op); 352 353 #if defined(FEAT_RELTIME) || defined(PROTO) 354 /* 355 * Set the timeout used for syntax highlighting. 356 * Use NULL to reset, no timeout. 357 */ 358 void 359 syn_set_timeout(proftime_T *tm) 360 { 361 syn_tm = tm; 362 } 363 #endif 364 365 /* 366 * Start the syntax recognition for a line. This function is normally called 367 * from the screen updating, once for each displayed line. 368 * The buffer is remembered in syn_buf, because get_syntax_attr() doesn't get 369 * it. Careful: curbuf and curwin are likely to point to another buffer and 370 * window. 371 */ 372 void 373 syntax_start(win_T *wp, linenr_T lnum) 374 { 375 synstate_T *p; 376 synstate_T *last_valid = NULL; 377 synstate_T *last_min_valid = NULL; 378 synstate_T *sp, *prev = NULL; 379 linenr_T parsed_lnum; 380 linenr_T first_stored; 381 int dist; 382 static varnumber_T changedtick = 0; // remember the last change ID 383 384 #ifdef FEAT_CONCEAL 385 current_sub_char = NUL; 386 #endif 387 388 /* 389 * After switching buffers, invalidate current_state. 390 * Also do this when a change was made, the current state may be invalid 391 * then. 392 */ 393 if (syn_block != wp->w_s 394 || syn_buf != wp->w_buffer 395 || changedtick != CHANGEDTICK(syn_buf)) 396 { 397 invalidate_current_state(); 398 syn_buf = wp->w_buffer; 399 syn_block = wp->w_s; 400 } 401 changedtick = CHANGEDTICK(syn_buf); 402 syn_win = wp; 403 404 /* 405 * Allocate syntax stack when needed. 406 */ 407 syn_stack_alloc(); 408 if (syn_block->b_sst_array == NULL) 409 return; // out of memory 410 syn_block->b_sst_lasttick = display_tick; 411 412 /* 413 * If the state of the end of the previous line is useful, store it. 414 */ 415 if (VALID_STATE(¤t_state) 416 && current_lnum < lnum 417 && current_lnum < syn_buf->b_ml.ml_line_count) 418 { 419 (void)syn_finish_line(FALSE); 420 if (!current_state_stored) 421 { 422 ++current_lnum; 423 (void)store_current_state(); 424 } 425 426 /* 427 * If the current_lnum is now the same as "lnum", keep the current 428 * state (this happens very often!). Otherwise invalidate 429 * current_state and figure it out below. 430 */ 431 if (current_lnum != lnum) 432 invalidate_current_state(); 433 } 434 else 435 invalidate_current_state(); 436 437 /* 438 * Try to synchronize from a saved state in b_sst_array[]. 439 * Only do this if lnum is not before and not to far beyond a saved state. 440 */ 441 if (INVALID_STATE(¤t_state) && syn_block->b_sst_array != NULL) 442 { 443 // Find last valid saved state before start_lnum. 444 FOR_ALL_SYNSTATES(syn_block, p) 445 { 446 if (p->sst_lnum > lnum) 447 break; 448 if (p->sst_lnum <= lnum && p->sst_change_lnum == 0) 449 { 450 last_valid = p; 451 if (p->sst_lnum >= lnum - syn_block->b_syn_sync_minlines) 452 last_min_valid = p; 453 } 454 } 455 if (last_min_valid != NULL) 456 load_current_state(last_min_valid); 457 } 458 459 /* 460 * If "lnum" is before or far beyond a line with a saved state, need to 461 * re-synchronize. 462 */ 463 if (INVALID_STATE(¤t_state)) 464 { 465 syn_sync(wp, lnum, last_valid); 466 if (current_lnum == 1) 467 // First line is always valid, no matter "minlines". 468 first_stored = 1; 469 else 470 // Need to parse "minlines" lines before state can be considered 471 // valid to store. 472 first_stored = current_lnum + syn_block->b_syn_sync_minlines; 473 } 474 else 475 first_stored = current_lnum; 476 477 /* 478 * Advance from the sync point or saved state until the current line. 479 * Save some entries for syncing with later on. 480 */ 481 if (syn_block->b_sst_len <= Rows) 482 dist = 999999; 483 else 484 dist = syn_buf->b_ml.ml_line_count / (syn_block->b_sst_len - Rows) + 1; 485 while (current_lnum < lnum) 486 { 487 syn_start_line(); 488 (void)syn_finish_line(FALSE); 489 ++current_lnum; 490 491 // If we parsed at least "minlines" lines or started at a valid 492 // state, the current state is considered valid. 493 if (current_lnum >= first_stored) 494 { 495 // Check if the saved state entry is for the current line and is 496 // equal to the current state. If so, then validate all saved 497 // states that depended on a change before the parsed line. 498 if (prev == NULL) 499 prev = syn_stack_find_entry(current_lnum - 1); 500 if (prev == NULL) 501 sp = syn_block->b_sst_first; 502 else 503 sp = prev; 504 while (sp != NULL && sp->sst_lnum < current_lnum) 505 sp = sp->sst_next; 506 if (sp != NULL 507 && sp->sst_lnum == current_lnum 508 && syn_stack_equal(sp)) 509 { 510 parsed_lnum = current_lnum; 511 prev = sp; 512 while (sp != NULL && sp->sst_change_lnum <= parsed_lnum) 513 { 514 if (sp->sst_lnum <= lnum) 515 // valid state before desired line, use this one 516 prev = sp; 517 else if (sp->sst_change_lnum == 0) 518 // past saved states depending on change, break here. 519 break; 520 sp->sst_change_lnum = 0; 521 sp = sp->sst_next; 522 } 523 load_current_state(prev); 524 } 525 // Store the state at this line when it's the first one, the line 526 // where we start parsing, or some distance from the previously 527 // saved state. But only when parsed at least 'minlines'. 528 else if (prev == NULL 529 || current_lnum == lnum 530 || current_lnum >= prev->sst_lnum + dist) 531 prev = store_current_state(); 532 } 533 534 // This can take a long time: break when CTRL-C pressed. The current 535 // state will be wrong then. 536 line_breakcheck(); 537 if (got_int) 538 { 539 current_lnum = lnum; 540 break; 541 } 542 } 543 544 syn_start_line(); 545 } 546 547 /* 548 * We cannot simply discard growarrays full of state_items or buf_states; we 549 * have to manually release their extmatch pointers first. 550 */ 551 static void 552 clear_syn_state(synstate_T *p) 553 { 554 int i; 555 garray_T *gap; 556 557 if (p->sst_stacksize > SST_FIX_STATES) 558 { 559 gap = &(p->sst_union.sst_ga); 560 for (i = 0; i < gap->ga_len; i++) 561 unref_extmatch(SYN_STATE_P(gap)[i].bs_extmatch); 562 ga_clear(gap); 563 } 564 else 565 { 566 for (i = 0; i < p->sst_stacksize; i++) 567 unref_extmatch(p->sst_union.sst_stack[i].bs_extmatch); 568 } 569 } 570 571 /* 572 * Cleanup the current_state stack. 573 */ 574 static void 575 clear_current_state(void) 576 { 577 int i; 578 stateitem_T *sip; 579 580 sip = (stateitem_T *)(current_state.ga_data); 581 for (i = 0; i < current_state.ga_len; i++) 582 unref_extmatch(sip[i].si_extmatch); 583 ga_clear(¤t_state); 584 } 585 586 /* 587 * Try to find a synchronisation point for line "lnum". 588 * 589 * This sets current_lnum and the current state. One of three methods is 590 * used: 591 * 1. Search backwards for the end of a C-comment. 592 * 2. Search backwards for given sync patterns. 593 * 3. Simply start on a given number of lines above "lnum". 594 */ 595 static void 596 syn_sync( 597 win_T *wp, 598 linenr_T start_lnum, 599 synstate_T *last_valid) 600 { 601 buf_T *curbuf_save; 602 win_T *curwin_save; 603 pos_T cursor_save; 604 int idx; 605 linenr_T lnum; 606 linenr_T end_lnum; 607 linenr_T break_lnum; 608 int had_sync_point; 609 stateitem_T *cur_si; 610 synpat_T *spp; 611 char_u *line; 612 int found_flags = 0; 613 int found_match_idx = 0; 614 linenr_T found_current_lnum = 0; 615 int found_current_col= 0; 616 lpos_T found_m_endpos; 617 colnr_T prev_current_col; 618 619 /* 620 * Clear any current state that might be hanging around. 621 */ 622 invalidate_current_state(); 623 624 /* 625 * Start at least "minlines" back. Default starting point for parsing is 626 * there. 627 * Start further back, to avoid that scrolling backwards will result in 628 * resyncing for every line. Now it resyncs only one out of N lines, 629 * where N is minlines * 1.5, or minlines * 2 if minlines is small. 630 * Watch out for overflow when minlines is MAXLNUM. 631 */ 632 if (syn_block->b_syn_sync_minlines > start_lnum) 633 start_lnum = 1; 634 else 635 { 636 if (syn_block->b_syn_sync_minlines == 1) 637 lnum = 1; 638 else if (syn_block->b_syn_sync_minlines < 10) 639 lnum = syn_block->b_syn_sync_minlines * 2; 640 else 641 lnum = syn_block->b_syn_sync_minlines * 3 / 2; 642 if (syn_block->b_syn_sync_maxlines != 0 643 && lnum > syn_block->b_syn_sync_maxlines) 644 lnum = syn_block->b_syn_sync_maxlines; 645 if (lnum >= start_lnum) 646 start_lnum = 1; 647 else 648 start_lnum -= lnum; 649 } 650 current_lnum = start_lnum; 651 652 /* 653 * 1. Search backwards for the end of a C-style comment. 654 */ 655 if (syn_block->b_syn_sync_flags & SF_CCOMMENT) 656 { 657 // Need to make syn_buf the current buffer for a moment, to be able to 658 // use find_start_comment(). 659 curwin_save = curwin; 660 curwin = wp; 661 curbuf_save = curbuf; 662 curbuf = syn_buf; 663 664 /* 665 * Skip lines that end in a backslash. 666 */ 667 for ( ; start_lnum > 1; --start_lnum) 668 { 669 line = ml_get(start_lnum - 1); 670 if (*line == NUL || *(line + STRLEN(line) - 1) != '\\') 671 break; 672 } 673 current_lnum = start_lnum; 674 675 // set cursor to start of search 676 cursor_save = wp->w_cursor; 677 wp->w_cursor.lnum = start_lnum; 678 wp->w_cursor.col = 0; 679 680 /* 681 * If the line is inside a comment, need to find the syntax item that 682 * defines the comment. 683 * Restrict the search for the end of a comment to b_syn_sync_maxlines. 684 */ 685 if (find_start_comment((int)syn_block->b_syn_sync_maxlines) != NULL) 686 { 687 for (idx = syn_block->b_syn_patterns.ga_len; --idx >= 0; ) 688 if (SYN_ITEMS(syn_block)[idx].sp_syn.id 689 == syn_block->b_syn_sync_id 690 && SYN_ITEMS(syn_block)[idx].sp_type == SPTYPE_START) 691 { 692 validate_current_state(); 693 if (push_current_state(idx) == OK) 694 update_si_attr(current_state.ga_len - 1); 695 break; 696 } 697 } 698 699 // restore cursor and buffer 700 wp->w_cursor = cursor_save; 701 curwin = curwin_save; 702 curbuf = curbuf_save; 703 } 704 705 /* 706 * 2. Search backwards for given sync patterns. 707 */ 708 else if (syn_block->b_syn_sync_flags & SF_MATCH) 709 { 710 if (syn_block->b_syn_sync_maxlines != 0 711 && start_lnum > syn_block->b_syn_sync_maxlines) 712 break_lnum = start_lnum - syn_block->b_syn_sync_maxlines; 713 else 714 break_lnum = 0; 715 716 found_m_endpos.lnum = 0; 717 found_m_endpos.col = 0; 718 end_lnum = start_lnum; 719 lnum = start_lnum; 720 while (--lnum > break_lnum) 721 { 722 // This can take a long time: break when CTRL-C pressed. 723 line_breakcheck(); 724 if (got_int) 725 { 726 invalidate_current_state(); 727 current_lnum = start_lnum; 728 break; 729 } 730 731 // Check if we have run into a valid saved state stack now. 732 if (last_valid != NULL && lnum == last_valid->sst_lnum) 733 { 734 load_current_state(last_valid); 735 break; 736 } 737 738 /* 739 * Check if the previous line has the line-continuation pattern. 740 */ 741 if (lnum > 1 && syn_match_linecont(lnum - 1)) 742 continue; 743 744 /* 745 * Start with nothing on the state stack 746 */ 747 validate_current_state(); 748 749 for (current_lnum = lnum; current_lnum < end_lnum; ++current_lnum) 750 { 751 syn_start_line(); 752 for (;;) 753 { 754 had_sync_point = syn_finish_line(TRUE); 755 /* 756 * When a sync point has been found, remember where, and 757 * continue to look for another one, further on in the line. 758 */ 759 if (had_sync_point && current_state.ga_len) 760 { 761 cur_si = &CUR_STATE(current_state.ga_len - 1); 762 if (cur_si->si_m_endpos.lnum > start_lnum) 763 { 764 // ignore match that goes to after where started 765 current_lnum = end_lnum; 766 break; 767 } 768 if (cur_si->si_idx < 0) 769 { 770 // Cannot happen? 771 found_flags = 0; 772 found_match_idx = KEYWORD_IDX; 773 } 774 else 775 { 776 spp = &(SYN_ITEMS(syn_block)[cur_si->si_idx]); 777 found_flags = spp->sp_flags; 778 found_match_idx = spp->sp_sync_idx; 779 } 780 found_current_lnum = current_lnum; 781 found_current_col = current_col; 782 found_m_endpos = cur_si->si_m_endpos; 783 /* 784 * Continue after the match (be aware of a zero-length 785 * match). 786 */ 787 if (found_m_endpos.lnum > current_lnum) 788 { 789 current_lnum = found_m_endpos.lnum; 790 current_col = found_m_endpos.col; 791 if (current_lnum >= end_lnum) 792 break; 793 } 794 else if (found_m_endpos.col > current_col) 795 current_col = found_m_endpos.col; 796 else 797 ++current_col; 798 799 // syn_current_attr() will have skipped the check for 800 // an item that ends here, need to do that now. Be 801 // careful not to go past the NUL. 802 prev_current_col = current_col; 803 if (syn_getcurline()[current_col] != NUL) 804 ++current_col; 805 check_state_ends(); 806 current_col = prev_current_col; 807 } 808 else 809 break; 810 } 811 } 812 813 /* 814 * If a sync point was encountered, break here. 815 */ 816 if (found_flags) 817 { 818 /* 819 * Put the item that was specified by the sync point on the 820 * state stack. If there was no item specified, make the 821 * state stack empty. 822 */ 823 clear_current_state(); 824 if (found_match_idx >= 0 825 && push_current_state(found_match_idx) == OK) 826 update_si_attr(current_state.ga_len - 1); 827 828 /* 829 * When using "grouphere", continue from the sync point 830 * match, until the end of the line. Parsing starts at 831 * the next line. 832 * For "groupthere" the parsing starts at start_lnum. 833 */ 834 if (found_flags & HL_SYNC_HERE) 835 { 836 if (current_state.ga_len) 837 { 838 cur_si = &CUR_STATE(current_state.ga_len - 1); 839 cur_si->si_h_startpos.lnum = found_current_lnum; 840 cur_si->si_h_startpos.col = found_current_col; 841 update_si_end(cur_si, (int)current_col, TRUE); 842 check_keepend(); 843 } 844 current_col = found_m_endpos.col; 845 current_lnum = found_m_endpos.lnum; 846 (void)syn_finish_line(FALSE); 847 ++current_lnum; 848 } 849 else 850 current_lnum = start_lnum; 851 852 break; 853 } 854 855 end_lnum = lnum; 856 invalidate_current_state(); 857 } 858 859 // Ran into start of the file or exceeded maximum number of lines 860 if (lnum <= break_lnum) 861 { 862 invalidate_current_state(); 863 current_lnum = break_lnum + 1; 864 } 865 } 866 867 validate_current_state(); 868 } 869 870 static void 871 save_chartab(char_u *chartab) 872 { 873 if (syn_block->b_syn_isk != empty_option) 874 { 875 mch_memmove(chartab, syn_buf->b_chartab, (size_t)32); 876 mch_memmove(syn_buf->b_chartab, syn_win->w_s->b_syn_chartab, 877 (size_t)32); 878 } 879 } 880 881 static void 882 restore_chartab(char_u *chartab) 883 { 884 if (syn_win->w_s->b_syn_isk != empty_option) 885 mch_memmove(syn_buf->b_chartab, chartab, (size_t)32); 886 } 887 888 /* 889 * Return TRUE if the line-continuation pattern matches in line "lnum". 890 */ 891 static int 892 syn_match_linecont(linenr_T lnum) 893 { 894 regmmatch_T regmatch; 895 int r; 896 char_u buf_chartab[32]; // chartab array for syn iskyeyword 897 898 if (syn_block->b_syn_linecont_prog != NULL) 899 { 900 // use syntax iskeyword option 901 save_chartab(buf_chartab); 902 regmatch.rmm_ic = syn_block->b_syn_linecont_ic; 903 regmatch.regprog = syn_block->b_syn_linecont_prog; 904 r = syn_regexec(®match, lnum, (colnr_T)0, 905 IF_SYN_TIME(&syn_block->b_syn_linecont_time)); 906 syn_block->b_syn_linecont_prog = regmatch.regprog; 907 restore_chartab(buf_chartab); 908 return r; 909 } 910 return FALSE; 911 } 912 913 /* 914 * Prepare the current state for the start of a line. 915 */ 916 static void 917 syn_start_line(void) 918 { 919 current_finished = FALSE; 920 current_col = 0; 921 922 /* 923 * Need to update the end of a start/skip/end that continues from the 924 * previous line and regions that have "keepend". 925 */ 926 if (current_state.ga_len > 0) 927 { 928 syn_update_ends(TRUE); 929 check_state_ends(); 930 } 931 932 next_match_idx = -1; 933 ++current_line_id; 934 #ifdef FEAT_CONCEAL 935 next_seqnr = 1; 936 #endif 937 } 938 939 /* 940 * Check for items in the stack that need their end updated. 941 * When "startofline" is TRUE the last item is always updated. 942 * When "startofline" is FALSE the item with "keepend" is forcefully updated. 943 */ 944 static void 945 syn_update_ends(int startofline) 946 { 947 stateitem_T *cur_si; 948 int i; 949 int seen_keepend; 950 951 if (startofline) 952 { 953 // Check for a match carried over from a previous line with a 954 // contained region. The match ends as soon as the region ends. 955 for (i = 0; i < current_state.ga_len; ++i) 956 { 957 cur_si = &CUR_STATE(i); 958 if (cur_si->si_idx >= 0 959 && (SYN_ITEMS(syn_block)[cur_si->si_idx]).sp_type 960 == SPTYPE_MATCH 961 && cur_si->si_m_endpos.lnum < current_lnum) 962 { 963 cur_si->si_flags |= HL_MATCHCONT; 964 cur_si->si_m_endpos.lnum = 0; 965 cur_si->si_m_endpos.col = 0; 966 cur_si->si_h_endpos = cur_si->si_m_endpos; 967 cur_si->si_ends = TRUE; 968 } 969 } 970 } 971 972 /* 973 * Need to update the end of a start/skip/end that continues from the 974 * previous line. And regions that have "keepend", because they may 975 * influence contained items. If we've just removed "extend" 976 * (startofline == 0) then we should update ends of normal regions 977 * contained inside "keepend" because "extend" could have extended 978 * these "keepend" regions as well as contained normal regions. 979 * Then check for items ending in column 0. 980 */ 981 i = current_state.ga_len - 1; 982 if (keepend_level >= 0) 983 for ( ; i > keepend_level; --i) 984 if (CUR_STATE(i).si_flags & HL_EXTEND) 985 break; 986 987 seen_keepend = FALSE; 988 for ( ; i < current_state.ga_len; ++i) 989 { 990 cur_si = &CUR_STATE(i); 991 if ((cur_si->si_flags & HL_KEEPEND) 992 || (seen_keepend && !startofline) 993 || (i == current_state.ga_len - 1 && startofline)) 994 { 995 cur_si->si_h_startpos.col = 0; // start highl. in col 0 996 cur_si->si_h_startpos.lnum = current_lnum; 997 998 if (!(cur_si->si_flags & HL_MATCHCONT)) 999 update_si_end(cur_si, (int)current_col, !startofline); 1000 1001 if (!startofline && (cur_si->si_flags & HL_KEEPEND)) 1002 seen_keepend = TRUE; 1003 } 1004 } 1005 check_keepend(); 1006 } 1007 1008 ///////////////////////////////////////// 1009 // Handling of the state stack cache. 1010 1011 /* 1012 * EXPLANATION OF THE SYNTAX STATE STACK CACHE 1013 * 1014 * To speed up syntax highlighting, the state stack for the start of some 1015 * lines is cached. These entries can be used to start parsing at that point. 1016 * 1017 * The stack is kept in b_sst_array[] for each buffer. There is a list of 1018 * valid entries. b_sst_first points to the first one, then follow sst_next. 1019 * The entries are sorted on line number. The first entry is often for line 2 1020 * (line 1 always starts with an empty stack). 1021 * There is also a list for free entries. This construction is used to avoid 1022 * having to allocate and free memory blocks too often. 1023 * 1024 * When making changes to the buffer, this is logged in b_mod_*. When calling 1025 * update_screen() to update the display, it will call 1026 * syn_stack_apply_changes() for each displayed buffer to adjust the cached 1027 * entries. The entries which are inside the changed area are removed, 1028 * because they must be recomputed. Entries below the changed have their line 1029 * number adjusted for deleted/inserted lines, and have their sst_change_lnum 1030 * set to indicate that a check must be made if the changed lines would change 1031 * the cached entry. 1032 * 1033 * When later displaying lines, an entry is stored for each line. Displayed 1034 * lines are likely to be displayed again, in which case the state at the 1035 * start of the line is needed. 1036 * For not displayed lines, an entry is stored for every so many lines. These 1037 * entries will be used e.g., when scrolling backwards. The distance between 1038 * entries depends on the number of lines in the buffer. For small buffers 1039 * the distance is fixed at SST_DIST, for large buffers there is a fixed 1040 * number of entries SST_MAX_ENTRIES, and the distance is computed. 1041 */ 1042 1043 static void 1044 syn_stack_free_block(synblock_T *block) 1045 { 1046 synstate_T *p; 1047 1048 if (block->b_sst_array != NULL) 1049 { 1050 FOR_ALL_SYNSTATES(block, p) 1051 clear_syn_state(p); 1052 VIM_CLEAR(block->b_sst_array); 1053 block->b_sst_first = NULL; 1054 block->b_sst_len = 0; 1055 } 1056 } 1057 /* 1058 * Free b_sst_array[] for buffer "buf". 1059 * Used when syntax items changed to force resyncing everywhere. 1060 */ 1061 void 1062 syn_stack_free_all(synblock_T *block) 1063 { 1064 #ifdef FEAT_FOLDING 1065 win_T *wp; 1066 #endif 1067 1068 syn_stack_free_block(block); 1069 1070 #ifdef FEAT_FOLDING 1071 // When using "syntax" fold method, must update all folds. 1072 FOR_ALL_WINDOWS(wp) 1073 { 1074 if (wp->w_s == block && foldmethodIsSyntax(wp)) 1075 foldUpdateAll(wp); 1076 } 1077 #endif 1078 } 1079 1080 /* 1081 * Allocate the syntax state stack for syn_buf when needed. 1082 * If the number of entries in b_sst_array[] is much too big or a bit too 1083 * small, reallocate it. 1084 * Also used to allocate b_sst_array[] for the first time. 1085 */ 1086 static void 1087 syn_stack_alloc(void) 1088 { 1089 long len; 1090 synstate_T *to, *from; 1091 synstate_T *sstp; 1092 1093 len = syn_buf->b_ml.ml_line_count / SST_DIST + Rows * 2; 1094 if (len < SST_MIN_ENTRIES) 1095 len = SST_MIN_ENTRIES; 1096 else if (len > SST_MAX_ENTRIES) 1097 len = SST_MAX_ENTRIES; 1098 if (syn_block->b_sst_len > len * 2 || syn_block->b_sst_len < len) 1099 { 1100 // Allocate 50% too much, to avoid reallocating too often. 1101 len = syn_buf->b_ml.ml_line_count; 1102 len = (len + len / 2) / SST_DIST + Rows * 2; 1103 if (len < SST_MIN_ENTRIES) 1104 len = SST_MIN_ENTRIES; 1105 else if (len > SST_MAX_ENTRIES) 1106 len = SST_MAX_ENTRIES; 1107 1108 if (syn_block->b_sst_array != NULL) 1109 { 1110 // When shrinking the array, cleanup the existing stack. 1111 // Make sure that all valid entries fit in the new array. 1112 while (syn_block->b_sst_len - syn_block->b_sst_freecount + 2 > len 1113 && syn_stack_cleanup()) 1114 ; 1115 if (len < syn_block->b_sst_len - syn_block->b_sst_freecount + 2) 1116 len = syn_block->b_sst_len - syn_block->b_sst_freecount + 2; 1117 } 1118 1119 sstp = ALLOC_CLEAR_MULT(synstate_T, len); 1120 if (sstp == NULL) // out of memory! 1121 return; 1122 1123 to = sstp - 1; 1124 if (syn_block->b_sst_array != NULL) 1125 { 1126 // Move the states from the old array to the new one. 1127 for (from = syn_block->b_sst_first; from != NULL; 1128 from = from->sst_next) 1129 { 1130 ++to; 1131 *to = *from; 1132 to->sst_next = to + 1; 1133 } 1134 } 1135 if (to != sstp - 1) 1136 { 1137 to->sst_next = NULL; 1138 syn_block->b_sst_first = sstp; 1139 syn_block->b_sst_freecount = len - (int)(to - sstp) - 1; 1140 } 1141 else 1142 { 1143 syn_block->b_sst_first = NULL; 1144 syn_block->b_sst_freecount = len; 1145 } 1146 1147 // Create the list of free entries. 1148 syn_block->b_sst_firstfree = to + 1; 1149 while (++to < sstp + len) 1150 to->sst_next = to + 1; 1151 (sstp + len - 1)->sst_next = NULL; 1152 1153 vim_free(syn_block->b_sst_array); 1154 syn_block->b_sst_array = sstp; 1155 syn_block->b_sst_len = len; 1156 } 1157 } 1158 1159 /* 1160 * Check for changes in a buffer to affect stored syntax states. Uses the 1161 * b_mod_* fields. 1162 * Called from update_screen(), before screen is being updated, once for each 1163 * displayed buffer. 1164 */ 1165 void 1166 syn_stack_apply_changes(buf_T *buf) 1167 { 1168 win_T *wp; 1169 1170 syn_stack_apply_changes_block(&buf->b_s, buf); 1171 1172 FOR_ALL_WINDOWS(wp) 1173 { 1174 if ((wp->w_buffer == buf) && (wp->w_s != &buf->b_s)) 1175 syn_stack_apply_changes_block(wp->w_s, buf); 1176 } 1177 } 1178 1179 static void 1180 syn_stack_apply_changes_block(synblock_T *block, buf_T *buf) 1181 { 1182 synstate_T *p, *prev, *np; 1183 linenr_T n; 1184 1185 prev = NULL; 1186 for (p = block->b_sst_first; p != NULL; ) 1187 { 1188 if (p->sst_lnum + block->b_syn_sync_linebreaks > buf->b_mod_top) 1189 { 1190 n = p->sst_lnum + buf->b_mod_xlines; 1191 if (n <= buf->b_mod_bot) 1192 { 1193 // this state is inside the changed area, remove it 1194 np = p->sst_next; 1195 if (prev == NULL) 1196 block->b_sst_first = np; 1197 else 1198 prev->sst_next = np; 1199 syn_stack_free_entry(block, p); 1200 p = np; 1201 continue; 1202 } 1203 // This state is below the changed area. Remember the line 1204 // that needs to be parsed before this entry can be made valid 1205 // again. 1206 if (p->sst_change_lnum != 0 && p->sst_change_lnum > buf->b_mod_top) 1207 { 1208 if (p->sst_change_lnum + buf->b_mod_xlines > buf->b_mod_top) 1209 p->sst_change_lnum += buf->b_mod_xlines; 1210 else 1211 p->sst_change_lnum = buf->b_mod_top; 1212 } 1213 if (p->sst_change_lnum == 0 1214 || p->sst_change_lnum < buf->b_mod_bot) 1215 p->sst_change_lnum = buf->b_mod_bot; 1216 1217 p->sst_lnum = n; 1218 } 1219 prev = p; 1220 p = p->sst_next; 1221 } 1222 } 1223 1224 /* 1225 * Reduce the number of entries in the state stack for syn_buf. 1226 * Returns TRUE if at least one entry was freed. 1227 */ 1228 static int 1229 syn_stack_cleanup(void) 1230 { 1231 synstate_T *p, *prev; 1232 disptick_T tick; 1233 int above; 1234 int dist; 1235 int retval = FALSE; 1236 1237 if (syn_block->b_sst_first == NULL) 1238 return retval; 1239 1240 // Compute normal distance between non-displayed entries. 1241 if (syn_block->b_sst_len <= Rows) 1242 dist = 999999; 1243 else 1244 dist = syn_buf->b_ml.ml_line_count / (syn_block->b_sst_len - Rows) + 1; 1245 1246 /* 1247 * Go through the list to find the "tick" for the oldest entry that can 1248 * be removed. Set "above" when the "tick" for the oldest entry is above 1249 * "b_sst_lasttick" (the display tick wraps around). 1250 */ 1251 tick = syn_block->b_sst_lasttick; 1252 above = FALSE; 1253 prev = syn_block->b_sst_first; 1254 for (p = prev->sst_next; p != NULL; prev = p, p = p->sst_next) 1255 { 1256 if (prev->sst_lnum + dist > p->sst_lnum) 1257 { 1258 if (p->sst_tick > syn_block->b_sst_lasttick) 1259 { 1260 if (!above || p->sst_tick < tick) 1261 tick = p->sst_tick; 1262 above = TRUE; 1263 } 1264 else if (!above && p->sst_tick < tick) 1265 tick = p->sst_tick; 1266 } 1267 } 1268 1269 /* 1270 * Go through the list to make the entries for the oldest tick at an 1271 * interval of several lines. 1272 */ 1273 prev = syn_block->b_sst_first; 1274 for (p = prev->sst_next; p != NULL; prev = p, p = p->sst_next) 1275 { 1276 if (p->sst_tick == tick && prev->sst_lnum + dist > p->sst_lnum) 1277 { 1278 // Move this entry from used list to free list 1279 prev->sst_next = p->sst_next; 1280 syn_stack_free_entry(syn_block, p); 1281 p = prev; 1282 retval = TRUE; 1283 } 1284 } 1285 return retval; 1286 } 1287 1288 /* 1289 * Free the allocated memory for a syn_state item. 1290 * Move the entry into the free list. 1291 */ 1292 static void 1293 syn_stack_free_entry(synblock_T *block, synstate_T *p) 1294 { 1295 clear_syn_state(p); 1296 p->sst_next = block->b_sst_firstfree; 1297 block->b_sst_firstfree = p; 1298 ++block->b_sst_freecount; 1299 } 1300 1301 /* 1302 * Find an entry in the list of state stacks at or before "lnum". 1303 * Returns NULL when there is no entry or the first entry is after "lnum". 1304 */ 1305 static synstate_T * 1306 syn_stack_find_entry(linenr_T lnum) 1307 { 1308 synstate_T *p, *prev; 1309 1310 prev = NULL; 1311 for (p = syn_block->b_sst_first; p != NULL; prev = p, p = p->sst_next) 1312 { 1313 if (p->sst_lnum == lnum) 1314 return p; 1315 if (p->sst_lnum > lnum) 1316 break; 1317 } 1318 return prev; 1319 } 1320 1321 /* 1322 * Try saving the current state in b_sst_array[]. 1323 * The current state must be valid for the start of the current_lnum line! 1324 */ 1325 static synstate_T * 1326 store_current_state(void) 1327 { 1328 int i; 1329 synstate_T *p; 1330 bufstate_T *bp; 1331 stateitem_T *cur_si; 1332 synstate_T *sp = syn_stack_find_entry(current_lnum); 1333 1334 /* 1335 * If the current state contains a start or end pattern that continues 1336 * from the previous line, we can't use it. Don't store it then. 1337 */ 1338 for (i = current_state.ga_len - 1; i >= 0; --i) 1339 { 1340 cur_si = &CUR_STATE(i); 1341 if (cur_si->si_h_startpos.lnum >= current_lnum 1342 || cur_si->si_m_endpos.lnum >= current_lnum 1343 || cur_si->si_h_endpos.lnum >= current_lnum 1344 || (cur_si->si_end_idx 1345 && cur_si->si_eoe_pos.lnum >= current_lnum)) 1346 break; 1347 } 1348 if (i >= 0) 1349 { 1350 if (sp != NULL) 1351 { 1352 // find "sp" in the list and remove it 1353 if (syn_block->b_sst_first == sp) 1354 // it's the first entry 1355 syn_block->b_sst_first = sp->sst_next; 1356 else 1357 { 1358 // find the entry just before this one to adjust sst_next 1359 FOR_ALL_SYNSTATES(syn_block, p) 1360 if (p->sst_next == sp) 1361 break; 1362 if (p != NULL) // just in case 1363 p->sst_next = sp->sst_next; 1364 } 1365 syn_stack_free_entry(syn_block, sp); 1366 sp = NULL; 1367 } 1368 } 1369 else if (sp == NULL || sp->sst_lnum != current_lnum) 1370 { 1371 /* 1372 * Add a new entry 1373 */ 1374 // If no free items, cleanup the array first. 1375 if (syn_block->b_sst_freecount == 0) 1376 { 1377 (void)syn_stack_cleanup(); 1378 // "sp" may have been moved to the freelist now 1379 sp = syn_stack_find_entry(current_lnum); 1380 } 1381 // Still no free items? Must be a strange problem... 1382 if (syn_block->b_sst_freecount == 0) 1383 sp = NULL; 1384 else 1385 { 1386 // Take the first item from the free list and put it in the used 1387 // list, after *sp 1388 p = syn_block->b_sst_firstfree; 1389 syn_block->b_sst_firstfree = p->sst_next; 1390 --syn_block->b_sst_freecount; 1391 if (sp == NULL) 1392 { 1393 // Insert in front of the list 1394 p->sst_next = syn_block->b_sst_first; 1395 syn_block->b_sst_first = p; 1396 } 1397 else 1398 { 1399 // insert in list after *sp 1400 p->sst_next = sp->sst_next; 1401 sp->sst_next = p; 1402 } 1403 sp = p; 1404 sp->sst_stacksize = 0; 1405 sp->sst_lnum = current_lnum; 1406 } 1407 } 1408 if (sp != NULL) 1409 { 1410 // When overwriting an existing state stack, clear it first 1411 clear_syn_state(sp); 1412 sp->sst_stacksize = current_state.ga_len; 1413 if (current_state.ga_len > SST_FIX_STATES) 1414 { 1415 // Need to clear it, might be something remaining from when the 1416 // length was less than SST_FIX_STATES. 1417 ga_init2(&sp->sst_union.sst_ga, (int)sizeof(bufstate_T), 1); 1418 if (ga_grow(&sp->sst_union.sst_ga, current_state.ga_len) == FAIL) 1419 sp->sst_stacksize = 0; 1420 else 1421 sp->sst_union.sst_ga.ga_len = current_state.ga_len; 1422 bp = SYN_STATE_P(&(sp->sst_union.sst_ga)); 1423 } 1424 else 1425 bp = sp->sst_union.sst_stack; 1426 for (i = 0; i < sp->sst_stacksize; ++i) 1427 { 1428 bp[i].bs_idx = CUR_STATE(i).si_idx; 1429 bp[i].bs_flags = CUR_STATE(i).si_flags; 1430 #ifdef FEAT_CONCEAL 1431 bp[i].bs_seqnr = CUR_STATE(i).si_seqnr; 1432 bp[i].bs_cchar = CUR_STATE(i).si_cchar; 1433 #endif 1434 bp[i].bs_extmatch = ref_extmatch(CUR_STATE(i).si_extmatch); 1435 } 1436 sp->sst_next_flags = current_next_flags; 1437 sp->sst_next_list = current_next_list; 1438 sp->sst_tick = display_tick; 1439 sp->sst_change_lnum = 0; 1440 } 1441 current_state_stored = TRUE; 1442 return sp; 1443 } 1444 1445 /* 1446 * Copy a state stack from "from" in b_sst_array[] to current_state; 1447 */ 1448 static void 1449 load_current_state(synstate_T *from) 1450 { 1451 int i; 1452 bufstate_T *bp; 1453 1454 clear_current_state(); 1455 validate_current_state(); 1456 keepend_level = -1; 1457 if (from->sst_stacksize 1458 && ga_grow(¤t_state, from->sst_stacksize) != FAIL) 1459 { 1460 if (from->sst_stacksize > SST_FIX_STATES) 1461 bp = SYN_STATE_P(&(from->sst_union.sst_ga)); 1462 else 1463 bp = from->sst_union.sst_stack; 1464 for (i = 0; i < from->sst_stacksize; ++i) 1465 { 1466 CUR_STATE(i).si_idx = bp[i].bs_idx; 1467 CUR_STATE(i).si_flags = bp[i].bs_flags; 1468 #ifdef FEAT_CONCEAL 1469 CUR_STATE(i).si_seqnr = bp[i].bs_seqnr; 1470 CUR_STATE(i).si_cchar = bp[i].bs_cchar; 1471 #endif 1472 CUR_STATE(i).si_extmatch = ref_extmatch(bp[i].bs_extmatch); 1473 if (keepend_level < 0 && (CUR_STATE(i).si_flags & HL_KEEPEND)) 1474 keepend_level = i; 1475 CUR_STATE(i).si_ends = FALSE; 1476 CUR_STATE(i).si_m_lnum = 0; 1477 if (CUR_STATE(i).si_idx >= 0) 1478 CUR_STATE(i).si_next_list = 1479 (SYN_ITEMS(syn_block)[CUR_STATE(i).si_idx]).sp_next_list; 1480 else 1481 CUR_STATE(i).si_next_list = NULL; 1482 update_si_attr(i); 1483 } 1484 current_state.ga_len = from->sst_stacksize; 1485 } 1486 current_next_list = from->sst_next_list; 1487 current_next_flags = from->sst_next_flags; 1488 current_lnum = from->sst_lnum; 1489 } 1490 1491 /* 1492 * Compare saved state stack "*sp" with the current state. 1493 * Return TRUE when they are equal. 1494 */ 1495 static int 1496 syn_stack_equal(synstate_T *sp) 1497 { 1498 int i, j; 1499 bufstate_T *bp; 1500 reg_extmatch_T *six, *bsx; 1501 1502 // First a quick check if the stacks have the same size end nextlist. 1503 if (sp->sst_stacksize == current_state.ga_len 1504 && sp->sst_next_list == current_next_list) 1505 { 1506 // Need to compare all states on both stacks. 1507 if (sp->sst_stacksize > SST_FIX_STATES) 1508 bp = SYN_STATE_P(&(sp->sst_union.sst_ga)); 1509 else 1510 bp = sp->sst_union.sst_stack; 1511 1512 for (i = current_state.ga_len; --i >= 0; ) 1513 { 1514 // If the item has another index the state is different. 1515 if (bp[i].bs_idx != CUR_STATE(i).si_idx) 1516 break; 1517 if (bp[i].bs_extmatch != CUR_STATE(i).si_extmatch) 1518 { 1519 // When the extmatch pointers are different, the strings in 1520 // them can still be the same. Check if the extmatch 1521 // references are equal. 1522 bsx = bp[i].bs_extmatch; 1523 six = CUR_STATE(i).si_extmatch; 1524 // If one of the extmatch pointers is NULL the states are 1525 // different. 1526 if (bsx == NULL || six == NULL) 1527 break; 1528 for (j = 0; j < NSUBEXP; ++j) 1529 { 1530 // Check each referenced match string. They must all be 1531 // equal. 1532 if (bsx->matches[j] != six->matches[j]) 1533 { 1534 // If the pointer is different it can still be the 1535 // same text. Compare the strings, ignore case when 1536 // the start item has the sp_ic flag set. 1537 if (bsx->matches[j] == NULL 1538 || six->matches[j] == NULL) 1539 break; 1540 if ((SYN_ITEMS(syn_block)[CUR_STATE(i).si_idx]).sp_ic 1541 ? MB_STRICMP(bsx->matches[j], 1542 six->matches[j]) != 0 1543 : STRCMP(bsx->matches[j], six->matches[j]) != 0) 1544 break; 1545 } 1546 } 1547 if (j != NSUBEXP) 1548 break; 1549 } 1550 } 1551 if (i < 0) 1552 return TRUE; 1553 } 1554 return FALSE; 1555 } 1556 1557 /* 1558 * We stop parsing syntax above line "lnum". If the stored state at or below 1559 * this line depended on a change before it, it now depends on the line below 1560 * the last parsed line. 1561 * The window looks like this: 1562 * line which changed 1563 * displayed line 1564 * displayed line 1565 * lnum -> line below window 1566 */ 1567 void 1568 syntax_end_parsing(linenr_T lnum) 1569 { 1570 synstate_T *sp; 1571 1572 sp = syn_stack_find_entry(lnum); 1573 if (sp != NULL && sp->sst_lnum < lnum) 1574 sp = sp->sst_next; 1575 1576 if (sp != NULL && sp->sst_change_lnum != 0) 1577 sp->sst_change_lnum = lnum; 1578 } 1579 1580 /* 1581 * End of handling of the state stack. 1582 ****************************************/ 1583 1584 static void 1585 invalidate_current_state(void) 1586 { 1587 clear_current_state(); 1588 current_state.ga_itemsize = 0; // mark current_state invalid 1589 current_next_list = NULL; 1590 keepend_level = -1; 1591 } 1592 1593 static void 1594 validate_current_state(void) 1595 { 1596 current_state.ga_itemsize = sizeof(stateitem_T); 1597 current_state.ga_growsize = 3; 1598 } 1599 1600 /* 1601 * Return TRUE if the syntax at start of lnum changed since last time. 1602 * This will only be called just after get_syntax_attr() for the previous 1603 * line, to check if the next line needs to be redrawn too. 1604 */ 1605 int 1606 syntax_check_changed(linenr_T lnum) 1607 { 1608 int retval = TRUE; 1609 synstate_T *sp; 1610 1611 /* 1612 * Check the state stack when: 1613 * - lnum is just below the previously syntaxed line. 1614 * - lnum is not before the lines with saved states. 1615 * - lnum is not past the lines with saved states. 1616 * - lnum is at or before the last changed line. 1617 */ 1618 if (VALID_STATE(¤t_state) && lnum == current_lnum + 1) 1619 { 1620 sp = syn_stack_find_entry(lnum); 1621 if (sp != NULL && sp->sst_lnum == lnum) 1622 { 1623 /* 1624 * finish the previous line (needed when not all of the line was 1625 * drawn) 1626 */ 1627 (void)syn_finish_line(FALSE); 1628 1629 /* 1630 * Compare the current state with the previously saved state of 1631 * the line. 1632 */ 1633 if (syn_stack_equal(sp)) 1634 retval = FALSE; 1635 1636 /* 1637 * Store the current state in b_sst_array[] for later use. 1638 */ 1639 ++current_lnum; 1640 (void)store_current_state(); 1641 } 1642 } 1643 1644 return retval; 1645 } 1646 1647 /* 1648 * Finish the current line. 1649 * This doesn't return any attributes, it only gets the state at the end of 1650 * the line. It can start anywhere in the line, as long as the current state 1651 * is valid. 1652 */ 1653 static int 1654 syn_finish_line( 1655 int syncing) // called for syncing 1656 { 1657 stateitem_T *cur_si; 1658 colnr_T prev_current_col; 1659 1660 while (!current_finished) 1661 { 1662 (void)syn_current_attr(syncing, FALSE, NULL, FALSE); 1663 /* 1664 * When syncing, and found some item, need to check the item. 1665 */ 1666 if (syncing && current_state.ga_len) 1667 { 1668 /* 1669 * Check for match with sync item. 1670 */ 1671 cur_si = &CUR_STATE(current_state.ga_len - 1); 1672 if (cur_si->si_idx >= 0 1673 && (SYN_ITEMS(syn_block)[cur_si->si_idx].sp_flags 1674 & (HL_SYNC_HERE|HL_SYNC_THERE))) 1675 return TRUE; 1676 1677 // syn_current_attr() will have skipped the check for an item 1678 // that ends here, need to do that now. Be careful not to go 1679 // past the NUL. 1680 prev_current_col = current_col; 1681 if (syn_getcurline()[current_col] != NUL) 1682 ++current_col; 1683 check_state_ends(); 1684 current_col = prev_current_col; 1685 } 1686 ++current_col; 1687 } 1688 return FALSE; 1689 } 1690 1691 /* 1692 * Return highlight attributes for next character. 1693 * Must first call syntax_start() once for the line. 1694 * "col" is normally 0 for the first use in a line, and increments by one each 1695 * time. It's allowed to skip characters and to stop before the end of the 1696 * line. But only a "col" after a previously used column is allowed. 1697 * When "can_spell" is not NULL set it to TRUE when spell-checking should be 1698 * done. 1699 */ 1700 int 1701 get_syntax_attr( 1702 colnr_T col, 1703 int *can_spell, 1704 int keep_state) // keep state of char at "col" 1705 { 1706 int attr = 0; 1707 1708 if (can_spell != NULL) 1709 // Default: Only do spelling when there is no @Spell cluster or when 1710 // ":syn spell toplevel" was used. 1711 *can_spell = syn_block->b_syn_spell == SYNSPL_DEFAULT 1712 ? (syn_block->b_spell_cluster_id == 0) 1713 : (syn_block->b_syn_spell == SYNSPL_TOP); 1714 1715 // check for out of memory situation 1716 if (syn_block->b_sst_array == NULL) 1717 return 0; 1718 1719 // After 'synmaxcol' the attribute is always zero. 1720 if (syn_buf->b_p_smc > 0 && col >= (colnr_T)syn_buf->b_p_smc) 1721 { 1722 clear_current_state(); 1723 #ifdef FEAT_EVAL 1724 current_id = 0; 1725 current_trans_id = 0; 1726 #endif 1727 #ifdef FEAT_CONCEAL 1728 current_flags = 0; 1729 current_seqnr = 0; 1730 #endif 1731 return 0; 1732 } 1733 1734 // Make sure current_state is valid 1735 if (INVALID_STATE(¤t_state)) 1736 validate_current_state(); 1737 1738 /* 1739 * Skip from the current column to "col", get the attributes for "col". 1740 */ 1741 while (current_col <= col) 1742 { 1743 attr = syn_current_attr(FALSE, TRUE, can_spell, 1744 current_col == col ? keep_state : FALSE); 1745 ++current_col; 1746 } 1747 1748 return attr; 1749 } 1750 1751 /* 1752 * Get syntax attributes for current_lnum, current_col. 1753 */ 1754 static int 1755 syn_current_attr( 1756 int syncing, // When 1: called for syncing 1757 int displaying, // result will be displayed 1758 int *can_spell, // return: do spell checking 1759 int keep_state) // keep syntax stack afterwards 1760 { 1761 int syn_id; 1762 lpos_T endpos; // was: char_u *endp; 1763 lpos_T hl_startpos; // was: int hl_startcol; 1764 lpos_T hl_endpos; 1765 lpos_T eos_pos; // end-of-start match (start region) 1766 lpos_T eoe_pos; // end-of-end pattern 1767 int end_idx; // group ID for end pattern 1768 int idx; 1769 synpat_T *spp; 1770 stateitem_T *cur_si, *sip = NULL; 1771 int startcol; 1772 int endcol; 1773 long flags; 1774 int cchar; 1775 short *next_list; 1776 int found_match; // found usable match 1777 static int try_next_column = FALSE; // must try in next col 1778 int do_keywords; 1779 regmmatch_T regmatch; 1780 lpos_T pos; 1781 int lc_col; 1782 reg_extmatch_T *cur_extmatch = NULL; 1783 char_u buf_chartab[32]; // chartab array for syn iskyeyword 1784 char_u *line; // current line. NOTE: becomes invalid after 1785 // looking for a pattern match! 1786 1787 // variables for zero-width matches that have a "nextgroup" argument 1788 int keep_next_list; 1789 int zero_width_next_list = FALSE; 1790 garray_T zero_width_next_ga; 1791 1792 /* 1793 * No character, no attributes! Past end of line? 1794 * Do try matching with an empty line (could be the start of a region). 1795 */ 1796 line = syn_getcurline(); 1797 if (line[current_col] == NUL && current_col != 0) 1798 { 1799 /* 1800 * If we found a match after the last column, use it. 1801 */ 1802 if (next_match_idx >= 0 && next_match_col >= (int)current_col 1803 && next_match_col != MAXCOL) 1804 (void)push_next_match(NULL); 1805 1806 current_finished = TRUE; 1807 current_state_stored = FALSE; 1808 return 0; 1809 } 1810 1811 // if the current or next character is NUL, we will finish the line now 1812 if (line[current_col] == NUL || line[current_col + 1] == NUL) 1813 { 1814 current_finished = TRUE; 1815 current_state_stored = FALSE; 1816 } 1817 1818 /* 1819 * When in the previous column there was a match but it could not be used 1820 * (empty match or already matched in this column) need to try again in 1821 * the next column. 1822 */ 1823 if (try_next_column) 1824 { 1825 next_match_idx = -1; 1826 try_next_column = FALSE; 1827 } 1828 1829 // Only check for keywords when not syncing and there are some. 1830 do_keywords = !syncing 1831 && (syn_block->b_keywtab.ht_used > 0 1832 || syn_block->b_keywtab_ic.ht_used > 0); 1833 1834 // Init the list of zero-width matches with a nextlist. This is used to 1835 // avoid matching the same item in the same position twice. 1836 ga_init2(&zero_width_next_ga, (int)sizeof(int), 10); 1837 1838 // use syntax iskeyword option 1839 save_chartab(buf_chartab); 1840 1841 /* 1842 * Repeat matching keywords and patterns, to find contained items at the 1843 * same column. This stops when there are no extra matches at the current 1844 * column. 1845 */ 1846 do 1847 { 1848 found_match = FALSE; 1849 keep_next_list = FALSE; 1850 syn_id = 0; 1851 1852 1853 /* 1854 * 1. Check for a current state. 1855 * Only when there is no current state, or if the current state may 1856 * contain other things, we need to check for keywords and patterns. 1857 * Always need to check for contained items if some item has the 1858 * "containedin" argument (takes extra time!). 1859 */ 1860 if (current_state.ga_len) 1861 cur_si = &CUR_STATE(current_state.ga_len - 1); 1862 else 1863 cur_si = NULL; 1864 1865 if (syn_block->b_syn_containedin || cur_si == NULL 1866 || cur_si->si_cont_list != NULL) 1867 { 1868 /* 1869 * 2. Check for keywords, if on a keyword char after a non-keyword 1870 * char. Don't do this when syncing. 1871 */ 1872 if (do_keywords) 1873 { 1874 line = syn_getcurline(); 1875 if (vim_iswordp_buf(line + current_col, syn_buf) 1876 && (current_col == 0 1877 || !vim_iswordp_buf(line + current_col - 1 1878 - (has_mbyte 1879 ? (*mb_head_off)(line, line + current_col - 1) 1880 : 0) , syn_buf))) 1881 { 1882 syn_id = check_keyword_id(line, (int)current_col, 1883 &endcol, &flags, &next_list, cur_si, 1884 &cchar); 1885 if (syn_id != 0) 1886 { 1887 if (push_current_state(KEYWORD_IDX) == OK) 1888 { 1889 cur_si = &CUR_STATE(current_state.ga_len - 1); 1890 cur_si->si_m_startcol = current_col; 1891 cur_si->si_h_startpos.lnum = current_lnum; 1892 cur_si->si_h_startpos.col = 0; // starts right away 1893 cur_si->si_m_endpos.lnum = current_lnum; 1894 cur_si->si_m_endpos.col = endcol; 1895 cur_si->si_h_endpos.lnum = current_lnum; 1896 cur_si->si_h_endpos.col = endcol; 1897 cur_si->si_ends = TRUE; 1898 cur_si->si_end_idx = 0; 1899 cur_si->si_flags = flags; 1900 #ifdef FEAT_CONCEAL 1901 cur_si->si_seqnr = next_seqnr++; 1902 cur_si->si_cchar = cchar; 1903 if (current_state.ga_len > 1) 1904 cur_si->si_flags |= 1905 CUR_STATE(current_state.ga_len - 2).si_flags 1906 & HL_CONCEAL; 1907 #endif 1908 cur_si->si_id = syn_id; 1909 cur_si->si_trans_id = syn_id; 1910 if (flags & HL_TRANSP) 1911 { 1912 if (current_state.ga_len < 2) 1913 { 1914 cur_si->si_attr = 0; 1915 cur_si->si_trans_id = 0; 1916 } 1917 else 1918 { 1919 cur_si->si_attr = CUR_STATE( 1920 current_state.ga_len - 2).si_attr; 1921 cur_si->si_trans_id = CUR_STATE( 1922 current_state.ga_len - 2).si_trans_id; 1923 } 1924 } 1925 else 1926 cur_si->si_attr = syn_id2attr(syn_id); 1927 cur_si->si_cont_list = NULL; 1928 cur_si->si_next_list = next_list; 1929 check_keepend(); 1930 } 1931 else 1932 vim_free(next_list); 1933 } 1934 } 1935 } 1936 1937 /* 1938 * 3. Check for patterns (only if no keyword found). 1939 */ 1940 if (syn_id == 0 && syn_block->b_syn_patterns.ga_len) 1941 { 1942 /* 1943 * If we didn't check for a match yet, or we are past it, check 1944 * for any match with a pattern. 1945 */ 1946 if (next_match_idx < 0 || next_match_col < (int)current_col) 1947 { 1948 /* 1949 * Check all relevant patterns for a match at this 1950 * position. This is complicated, because matching with a 1951 * pattern takes quite a bit of time, thus we want to 1952 * avoid doing it when it's not needed. 1953 */ 1954 next_match_idx = 0; // no match in this line yet 1955 next_match_col = MAXCOL; 1956 for (idx = syn_block->b_syn_patterns.ga_len; --idx >= 0; ) 1957 { 1958 spp = &(SYN_ITEMS(syn_block)[idx]); 1959 if ( spp->sp_syncing == syncing 1960 && (displaying || !(spp->sp_flags & HL_DISPLAY)) 1961 && (spp->sp_type == SPTYPE_MATCH 1962 || spp->sp_type == SPTYPE_START) 1963 && (current_next_list != NULL 1964 ? in_id_list(NULL, current_next_list, 1965 &spp->sp_syn, 0) 1966 : (cur_si == NULL 1967 ? !(spp->sp_flags & HL_CONTAINED) 1968 : in_id_list(cur_si, 1969 cur_si->si_cont_list, &spp->sp_syn, 1970 spp->sp_flags & HL_CONTAINED)))) 1971 { 1972 int r; 1973 1974 // If we already tried matching in this line, and 1975 // there isn't a match before next_match_col, skip 1976 // this item. 1977 if (spp->sp_line_id == current_line_id 1978 && spp->sp_startcol >= next_match_col) 1979 continue; 1980 spp->sp_line_id = current_line_id; 1981 1982 lc_col = current_col - spp->sp_offsets[SPO_LC_OFF]; 1983 if (lc_col < 0) 1984 lc_col = 0; 1985 1986 regmatch.rmm_ic = spp->sp_ic; 1987 regmatch.regprog = spp->sp_prog; 1988 r = syn_regexec(®match, 1989 current_lnum, 1990 (colnr_T)lc_col, 1991 IF_SYN_TIME(&spp->sp_time)); 1992 spp->sp_prog = regmatch.regprog; 1993 if (!r) 1994 { 1995 // no match in this line, try another one 1996 spp->sp_startcol = MAXCOL; 1997 continue; 1998 } 1999 2000 /* 2001 * Compute the first column of the match. 2002 */ 2003 syn_add_start_off(&pos, ®match, 2004 spp, SPO_MS_OFF, -1); 2005 if (pos.lnum > current_lnum) 2006 { 2007 // must have used end of match in a next line, 2008 // we can't handle that 2009 spp->sp_startcol = MAXCOL; 2010 continue; 2011 } 2012 startcol = pos.col; 2013 2014 // remember the next column where this pattern 2015 // matches in the current line 2016 spp->sp_startcol = startcol; 2017 2018 /* 2019 * If a previously found match starts at a lower 2020 * column number, don't use this one. 2021 */ 2022 if (startcol >= next_match_col) 2023 continue; 2024 2025 /* 2026 * If we matched this pattern at this position 2027 * before, skip it. Must retry in the next 2028 * column, because it may match from there. 2029 */ 2030 if (did_match_already(idx, &zero_width_next_ga)) 2031 { 2032 try_next_column = TRUE; 2033 continue; 2034 } 2035 2036 endpos.lnum = regmatch.endpos[0].lnum; 2037 endpos.col = regmatch.endpos[0].col; 2038 2039 // Compute the highlight start. 2040 syn_add_start_off(&hl_startpos, ®match, 2041 spp, SPO_HS_OFF, -1); 2042 2043 // Compute the region start. 2044 // Default is to use the end of the match. 2045 syn_add_end_off(&eos_pos, ®match, 2046 spp, SPO_RS_OFF, 0); 2047 2048 /* 2049 * Grab the external submatches before they get 2050 * overwritten. Reference count doesn't change. 2051 */ 2052 unref_extmatch(cur_extmatch); 2053 cur_extmatch = re_extmatch_out; 2054 re_extmatch_out = NULL; 2055 2056 flags = 0; 2057 eoe_pos.lnum = 0; // avoid warning 2058 eoe_pos.col = 0; 2059 end_idx = 0; 2060 hl_endpos.lnum = 0; 2061 2062 /* 2063 * For a "oneline" the end must be found in the 2064 * same line too. Search for it after the end of 2065 * the match with the start pattern. Set the 2066 * resulting end positions at the same time. 2067 */ 2068 if (spp->sp_type == SPTYPE_START 2069 && (spp->sp_flags & HL_ONELINE)) 2070 { 2071 lpos_T startpos; 2072 2073 startpos = endpos; 2074 find_endpos(idx, &startpos, &endpos, &hl_endpos, 2075 &flags, &eoe_pos, &end_idx, cur_extmatch); 2076 if (endpos.lnum == 0) 2077 continue; // not found 2078 } 2079 2080 /* 2081 * For a "match" the size must be > 0 after the 2082 * end offset needs has been added. Except when 2083 * syncing. 2084 */ 2085 else if (spp->sp_type == SPTYPE_MATCH) 2086 { 2087 syn_add_end_off(&hl_endpos, ®match, spp, 2088 SPO_HE_OFF, 0); 2089 syn_add_end_off(&endpos, ®match, spp, 2090 SPO_ME_OFF, 0); 2091 if (endpos.lnum == current_lnum 2092 && (int)endpos.col + syncing < startcol) 2093 { 2094 /* 2095 * If an empty string is matched, may need 2096 * to try matching again at next column. 2097 */ 2098 if (regmatch.startpos[0].col 2099 == regmatch.endpos[0].col) 2100 try_next_column = TRUE; 2101 continue; 2102 } 2103 } 2104 2105 /* 2106 * keep the best match so far in next_match_* 2107 */ 2108 // Highlighting must start after startpos and end 2109 // before endpos. 2110 if (hl_startpos.lnum == current_lnum 2111 && (int)hl_startpos.col < startcol) 2112 hl_startpos.col = startcol; 2113 limit_pos_zero(&hl_endpos, &endpos); 2114 2115 next_match_idx = idx; 2116 next_match_col = startcol; 2117 next_match_m_endpos = endpos; 2118 next_match_h_endpos = hl_endpos; 2119 next_match_h_startpos = hl_startpos; 2120 next_match_flags = flags; 2121 next_match_eos_pos = eos_pos; 2122 next_match_eoe_pos = eoe_pos; 2123 next_match_end_idx = end_idx; 2124 unref_extmatch(next_match_extmatch); 2125 next_match_extmatch = cur_extmatch; 2126 cur_extmatch = NULL; 2127 } 2128 } 2129 } 2130 2131 /* 2132 * If we found a match at the current column, use it. 2133 */ 2134 if (next_match_idx >= 0 && next_match_col == (int)current_col) 2135 { 2136 synpat_T *lspp; 2137 2138 // When a zero-width item matched which has a nextgroup, 2139 // don't push the item but set nextgroup. 2140 lspp = &(SYN_ITEMS(syn_block)[next_match_idx]); 2141 if (next_match_m_endpos.lnum == current_lnum 2142 && next_match_m_endpos.col == current_col 2143 && lspp->sp_next_list != NULL) 2144 { 2145 current_next_list = lspp->sp_next_list; 2146 current_next_flags = lspp->sp_flags; 2147 keep_next_list = TRUE; 2148 zero_width_next_list = TRUE; 2149 2150 // Add the index to a list, so that we can check 2151 // later that we don't match it again (and cause an 2152 // endless loop). 2153 if (ga_grow(&zero_width_next_ga, 1) == OK) 2154 { 2155 ((int *)(zero_width_next_ga.ga_data)) 2156 [zero_width_next_ga.ga_len++] = next_match_idx; 2157 } 2158 next_match_idx = -1; 2159 } 2160 else 2161 cur_si = push_next_match(cur_si); 2162 found_match = TRUE; 2163 } 2164 } 2165 } 2166 2167 /* 2168 * Handle searching for nextgroup match. 2169 */ 2170 if (current_next_list != NULL && !keep_next_list) 2171 { 2172 /* 2173 * If a nextgroup was not found, continue looking for one if: 2174 * - this is an empty line and the "skipempty" option was given 2175 * - we are on white space and the "skipwhite" option was given 2176 */ 2177 if (!found_match) 2178 { 2179 line = syn_getcurline(); 2180 if (((current_next_flags & HL_SKIPWHITE) 2181 && VIM_ISWHITE(line[current_col])) 2182 || ((current_next_flags & HL_SKIPEMPTY) 2183 && *line == NUL)) 2184 break; 2185 } 2186 2187 /* 2188 * If a nextgroup was found: Use it, and continue looking for 2189 * contained matches. 2190 * If a nextgroup was not found: Continue looking for a normal 2191 * match. 2192 * When did set current_next_list for a zero-width item and no 2193 * match was found don't loop (would get stuck). 2194 */ 2195 current_next_list = NULL; 2196 next_match_idx = -1; 2197 if (!zero_width_next_list) 2198 found_match = TRUE; 2199 } 2200 2201 } while (found_match); 2202 2203 restore_chartab(buf_chartab); 2204 2205 /* 2206 * Use attributes from the current state, if within its highlighting. 2207 * If not, use attributes from the current-but-one state, etc. 2208 */ 2209 current_attr = 0; 2210 #ifdef FEAT_EVAL 2211 current_id = 0; 2212 current_trans_id = 0; 2213 #endif 2214 #ifdef FEAT_CONCEAL 2215 current_flags = 0; 2216 current_seqnr = 0; 2217 #endif 2218 if (cur_si != NULL) 2219 { 2220 #ifndef FEAT_EVAL 2221 int current_trans_id = 0; 2222 #endif 2223 for (idx = current_state.ga_len - 1; idx >= 0; --idx) 2224 { 2225 sip = &CUR_STATE(idx); 2226 if ((current_lnum > sip->si_h_startpos.lnum 2227 || (current_lnum == sip->si_h_startpos.lnum 2228 && current_col >= sip->si_h_startpos.col)) 2229 && (sip->si_h_endpos.lnum == 0 2230 || current_lnum < sip->si_h_endpos.lnum 2231 || (current_lnum == sip->si_h_endpos.lnum 2232 && current_col < sip->si_h_endpos.col))) 2233 { 2234 current_attr = sip->si_attr; 2235 #ifdef FEAT_EVAL 2236 current_id = sip->si_id; 2237 #endif 2238 current_trans_id = sip->si_trans_id; 2239 #ifdef FEAT_CONCEAL 2240 current_flags = sip->si_flags; 2241 current_seqnr = sip->si_seqnr; 2242 current_sub_char = sip->si_cchar; 2243 #endif 2244 break; 2245 } 2246 } 2247 2248 if (can_spell != NULL) 2249 { 2250 struct sp_syn sps; 2251 2252 /* 2253 * set "can_spell" to TRUE if spell checking is supposed to be 2254 * done in the current item. 2255 */ 2256 if (syn_block->b_spell_cluster_id == 0) 2257 { 2258 // There is no @Spell cluster: Do spelling for items without 2259 // @NoSpell cluster. 2260 if (syn_block->b_nospell_cluster_id == 0 2261 || current_trans_id == 0) 2262 *can_spell = (syn_block->b_syn_spell != SYNSPL_NOTOP); 2263 else 2264 { 2265 sps.inc_tag = 0; 2266 sps.id = syn_block->b_nospell_cluster_id; 2267 sps.cont_in_list = NULL; 2268 *can_spell = !in_id_list(sip, sip->si_cont_list, &sps, 0); 2269 } 2270 } 2271 else 2272 { 2273 // The @Spell cluster is defined: Do spelling in items with 2274 // the @Spell cluster. But not when @NoSpell is also there. 2275 // At the toplevel only spell check when ":syn spell toplevel" 2276 // was used. 2277 if (current_trans_id == 0) 2278 *can_spell = (syn_block->b_syn_spell == SYNSPL_TOP); 2279 else 2280 { 2281 sps.inc_tag = 0; 2282 sps.id = syn_block->b_spell_cluster_id; 2283 sps.cont_in_list = NULL; 2284 *can_spell = in_id_list(sip, sip->si_cont_list, &sps, 0); 2285 2286 if (syn_block->b_nospell_cluster_id != 0) 2287 { 2288 sps.id = syn_block->b_nospell_cluster_id; 2289 if (in_id_list(sip, sip->si_cont_list, &sps, 0)) 2290 *can_spell = FALSE; 2291 } 2292 } 2293 } 2294 } 2295 2296 2297 /* 2298 * Check for end of current state (and the states before it) at the 2299 * next column. Don't do this for syncing, because we would miss a 2300 * single character match. 2301 * First check if the current state ends at the current column. It 2302 * may be for an empty match and a containing item might end in the 2303 * current column. 2304 */ 2305 if (!syncing && !keep_state) 2306 { 2307 check_state_ends(); 2308 if (current_state.ga_len > 0 2309 && syn_getcurline()[current_col] != NUL) 2310 { 2311 ++current_col; 2312 check_state_ends(); 2313 --current_col; 2314 } 2315 } 2316 } 2317 else if (can_spell != NULL) 2318 // Default: Only do spelling when there is no @Spell cluster or when 2319 // ":syn spell toplevel" was used. 2320 *can_spell = syn_block->b_syn_spell == SYNSPL_DEFAULT 2321 ? (syn_block->b_spell_cluster_id == 0) 2322 : (syn_block->b_syn_spell == SYNSPL_TOP); 2323 2324 // nextgroup ends at end of line, unless "skipnl" or "skipempty" present 2325 if (current_next_list != NULL 2326 && (line = syn_getcurline())[current_col] != NUL 2327 && line[current_col + 1] == NUL 2328 && !(current_next_flags & (HL_SKIPNL | HL_SKIPEMPTY))) 2329 current_next_list = NULL; 2330 2331 if (zero_width_next_ga.ga_len > 0) 2332 ga_clear(&zero_width_next_ga); 2333 2334 // No longer need external matches. But keep next_match_extmatch. 2335 unref_extmatch(re_extmatch_out); 2336 re_extmatch_out = NULL; 2337 unref_extmatch(cur_extmatch); 2338 2339 return current_attr; 2340 } 2341 2342 2343 /* 2344 * Check if we already matched pattern "idx" at the current column. 2345 */ 2346 static int 2347 did_match_already(int idx, garray_T *gap) 2348 { 2349 int i; 2350 2351 for (i = current_state.ga_len; --i >= 0; ) 2352 if (CUR_STATE(i).si_m_startcol == (int)current_col 2353 && CUR_STATE(i).si_m_lnum == (int)current_lnum 2354 && CUR_STATE(i).si_idx == idx) 2355 return TRUE; 2356 2357 // Zero-width matches with a nextgroup argument are not put on the syntax 2358 // stack, and can only be matched once anyway. 2359 for (i = gap->ga_len; --i >= 0; ) 2360 if (((int *)(gap->ga_data))[i] == idx) 2361 return TRUE; 2362 2363 return FALSE; 2364 } 2365 2366 /* 2367 * Push the next match onto the stack. 2368 */ 2369 static stateitem_T * 2370 push_next_match(stateitem_T *cur_si) 2371 { 2372 synpat_T *spp; 2373 #ifdef FEAT_CONCEAL 2374 int save_flags; 2375 #endif 2376 2377 spp = &(SYN_ITEMS(syn_block)[next_match_idx]); 2378 2379 /* 2380 * Push the item in current_state stack; 2381 */ 2382 if (push_current_state(next_match_idx) == OK) 2383 { 2384 /* 2385 * If it's a start-skip-end type that crosses lines, figure out how 2386 * much it continues in this line. Otherwise just fill in the length. 2387 */ 2388 cur_si = &CUR_STATE(current_state.ga_len - 1); 2389 cur_si->si_h_startpos = next_match_h_startpos; 2390 cur_si->si_m_startcol = current_col; 2391 cur_si->si_m_lnum = current_lnum; 2392 cur_si->si_flags = spp->sp_flags; 2393 #ifdef FEAT_CONCEAL 2394 cur_si->si_seqnr = next_seqnr++; 2395 cur_si->si_cchar = spp->sp_cchar; 2396 if (current_state.ga_len > 1) 2397 cur_si->si_flags |= 2398 CUR_STATE(current_state.ga_len - 2).si_flags & HL_CONCEAL; 2399 #endif 2400 cur_si->si_next_list = spp->sp_next_list; 2401 cur_si->si_extmatch = ref_extmatch(next_match_extmatch); 2402 if (spp->sp_type == SPTYPE_START && !(spp->sp_flags & HL_ONELINE)) 2403 { 2404 // Try to find the end pattern in the current line 2405 update_si_end(cur_si, (int)(next_match_m_endpos.col), TRUE); 2406 check_keepend(); 2407 } 2408 else 2409 { 2410 cur_si->si_m_endpos = next_match_m_endpos; 2411 cur_si->si_h_endpos = next_match_h_endpos; 2412 cur_si->si_ends = TRUE; 2413 cur_si->si_flags |= next_match_flags; 2414 cur_si->si_eoe_pos = next_match_eoe_pos; 2415 cur_si->si_end_idx = next_match_end_idx; 2416 } 2417 if (keepend_level < 0 && (cur_si->si_flags & HL_KEEPEND)) 2418 keepend_level = current_state.ga_len - 1; 2419 check_keepend(); 2420 update_si_attr(current_state.ga_len - 1); 2421 2422 #ifdef FEAT_CONCEAL 2423 save_flags = cur_si->si_flags & (HL_CONCEAL | HL_CONCEALENDS); 2424 #endif 2425 /* 2426 * If the start pattern has another highlight group, push another item 2427 * on the stack for the start pattern. 2428 */ 2429 if ( spp->sp_type == SPTYPE_START 2430 && spp->sp_syn_match_id != 0 2431 && push_current_state(next_match_idx) == OK) 2432 { 2433 cur_si = &CUR_STATE(current_state.ga_len - 1); 2434 cur_si->si_h_startpos = next_match_h_startpos; 2435 cur_si->si_m_startcol = current_col; 2436 cur_si->si_m_lnum = current_lnum; 2437 cur_si->si_m_endpos = next_match_eos_pos; 2438 cur_si->si_h_endpos = next_match_eos_pos; 2439 cur_si->si_ends = TRUE; 2440 cur_si->si_end_idx = 0; 2441 cur_si->si_flags = HL_MATCH; 2442 #ifdef FEAT_CONCEAL 2443 cur_si->si_seqnr = next_seqnr++; 2444 cur_si->si_flags |= save_flags; 2445 if (cur_si->si_flags & HL_CONCEALENDS) 2446 cur_si->si_flags |= HL_CONCEAL; 2447 #endif 2448 cur_si->si_next_list = NULL; 2449 check_keepend(); 2450 update_si_attr(current_state.ga_len - 1); 2451 } 2452 } 2453 2454 next_match_idx = -1; // try other match next time 2455 2456 return cur_si; 2457 } 2458 2459 /* 2460 * Check for end of current state (and the states before it). 2461 */ 2462 static void 2463 check_state_ends(void) 2464 { 2465 stateitem_T *cur_si; 2466 int had_extend; 2467 2468 cur_si = &CUR_STATE(current_state.ga_len - 1); 2469 for (;;) 2470 { 2471 if (cur_si->si_ends 2472 && (cur_si->si_m_endpos.lnum < current_lnum 2473 || (cur_si->si_m_endpos.lnum == current_lnum 2474 && cur_si->si_m_endpos.col <= current_col))) 2475 { 2476 /* 2477 * If there is an end pattern group ID, highlight the end pattern 2478 * now. No need to pop the current item from the stack. 2479 * Only do this if the end pattern continues beyond the current 2480 * position. 2481 */ 2482 if (cur_si->si_end_idx 2483 && (cur_si->si_eoe_pos.lnum > current_lnum 2484 || (cur_si->si_eoe_pos.lnum == current_lnum 2485 && cur_si->si_eoe_pos.col > current_col))) 2486 { 2487 cur_si->si_idx = cur_si->si_end_idx; 2488 cur_si->si_end_idx = 0; 2489 cur_si->si_m_endpos = cur_si->si_eoe_pos; 2490 cur_si->si_h_endpos = cur_si->si_eoe_pos; 2491 cur_si->si_flags |= HL_MATCH; 2492 #ifdef FEAT_CONCEAL 2493 cur_si->si_seqnr = next_seqnr++; 2494 if (cur_si->si_flags & HL_CONCEALENDS) 2495 cur_si->si_flags |= HL_CONCEAL; 2496 #endif 2497 update_si_attr(current_state.ga_len - 1); 2498 2499 // nextgroup= should not match in the end pattern 2500 current_next_list = NULL; 2501 2502 // what matches next may be different now, clear it 2503 next_match_idx = 0; 2504 next_match_col = MAXCOL; 2505 break; 2506 } 2507 else 2508 { 2509 // handle next_list, unless at end of line and no "skipnl" or 2510 // "skipempty" 2511 current_next_list = cur_si->si_next_list; 2512 current_next_flags = cur_si->si_flags; 2513 if (!(current_next_flags & (HL_SKIPNL | HL_SKIPEMPTY)) 2514 && syn_getcurline()[current_col] == NUL) 2515 current_next_list = NULL; 2516 2517 // When the ended item has "extend", another item with 2518 // "keepend" now needs to check for its end. 2519 had_extend = (cur_si->si_flags & HL_EXTEND); 2520 2521 pop_current_state(); 2522 2523 if (current_state.ga_len == 0) 2524 break; 2525 2526 if (had_extend && keepend_level >= 0) 2527 { 2528 syn_update_ends(FALSE); 2529 if (current_state.ga_len == 0) 2530 break; 2531 } 2532 2533 cur_si = &CUR_STATE(current_state.ga_len - 1); 2534 2535 /* 2536 * Only for a region the search for the end continues after 2537 * the end of the contained item. If the contained match 2538 * included the end-of-line, break here, the region continues. 2539 * Don't do this when: 2540 * - "keepend" is used for the contained item 2541 * - not at the end of the line (could be end="x$"me=e-1). 2542 * - "excludenl" is used (HL_HAS_EOL won't be set) 2543 */ 2544 if (cur_si->si_idx >= 0 2545 && SYN_ITEMS(syn_block)[cur_si->si_idx].sp_type 2546 == SPTYPE_START 2547 && !(cur_si->si_flags & (HL_MATCH | HL_KEEPEND))) 2548 { 2549 update_si_end(cur_si, (int)current_col, TRUE); 2550 check_keepend(); 2551 if ((current_next_flags & HL_HAS_EOL) 2552 && keepend_level < 0 2553 && syn_getcurline()[current_col] == NUL) 2554 break; 2555 } 2556 } 2557 } 2558 else 2559 break; 2560 } 2561 } 2562 2563 /* 2564 * Update an entry in the current_state stack for a match or region. This 2565 * fills in si_attr, si_next_list and si_cont_list. 2566 */ 2567 static void 2568 update_si_attr(int idx) 2569 { 2570 stateitem_T *sip = &CUR_STATE(idx); 2571 synpat_T *spp; 2572 2573 // This should not happen... 2574 if (sip->si_idx < 0) 2575 return; 2576 2577 spp = &(SYN_ITEMS(syn_block)[sip->si_idx]); 2578 if (sip->si_flags & HL_MATCH) 2579 sip->si_id = spp->sp_syn_match_id; 2580 else 2581 sip->si_id = spp->sp_syn.id; 2582 sip->si_attr = syn_id2attr(sip->si_id); 2583 sip->si_trans_id = sip->si_id; 2584 if (sip->si_flags & HL_MATCH) 2585 sip->si_cont_list = NULL; 2586 else 2587 sip->si_cont_list = spp->sp_cont_list; 2588 2589 /* 2590 * For transparent items, take attr from outer item. 2591 * Also take cont_list, if there is none. 2592 * Don't do this for the matchgroup of a start or end pattern. 2593 */ 2594 if ((spp->sp_flags & HL_TRANSP) && !(sip->si_flags & HL_MATCH)) 2595 { 2596 if (idx == 0) 2597 { 2598 sip->si_attr = 0; 2599 sip->si_trans_id = 0; 2600 if (sip->si_cont_list == NULL) 2601 sip->si_cont_list = ID_LIST_ALL; 2602 } 2603 else 2604 { 2605 sip->si_attr = CUR_STATE(idx - 1).si_attr; 2606 sip->si_trans_id = CUR_STATE(idx - 1).si_trans_id; 2607 sip->si_h_startpos = CUR_STATE(idx - 1).si_h_startpos; 2608 sip->si_h_endpos = CUR_STATE(idx - 1).si_h_endpos; 2609 if (sip->si_cont_list == NULL) 2610 { 2611 sip->si_flags |= HL_TRANS_CONT; 2612 sip->si_cont_list = CUR_STATE(idx - 1).si_cont_list; 2613 } 2614 } 2615 } 2616 } 2617 2618 /* 2619 * Check the current stack for patterns with "keepend" flag. 2620 * Propagate the match-end to contained items, until a "skipend" item is found. 2621 */ 2622 static void 2623 check_keepend(void) 2624 { 2625 int i; 2626 lpos_T maxpos; 2627 lpos_T maxpos_h; 2628 stateitem_T *sip; 2629 2630 /* 2631 * This check can consume a lot of time; only do it from the level where 2632 * there really is a keepend. 2633 */ 2634 if (keepend_level < 0) 2635 return; 2636 2637 /* 2638 * Find the last index of an "extend" item. "keepend" items before that 2639 * won't do anything. If there is no "extend" item "i" will be 2640 * "keepend_level" and all "keepend" items will work normally. 2641 */ 2642 for (i = current_state.ga_len - 1; i > keepend_level; --i) 2643 if (CUR_STATE(i).si_flags & HL_EXTEND) 2644 break; 2645 2646 maxpos.lnum = 0; 2647 maxpos.col = 0; 2648 maxpos_h.lnum = 0; 2649 maxpos_h.col = 0; 2650 for ( ; i < current_state.ga_len; ++i) 2651 { 2652 sip = &CUR_STATE(i); 2653 if (maxpos.lnum != 0) 2654 { 2655 limit_pos_zero(&sip->si_m_endpos, &maxpos); 2656 limit_pos_zero(&sip->si_h_endpos, &maxpos_h); 2657 limit_pos_zero(&sip->si_eoe_pos, &maxpos); 2658 sip->si_ends = TRUE; 2659 } 2660 if (sip->si_ends && (sip->si_flags & HL_KEEPEND)) 2661 { 2662 if (maxpos.lnum == 0 2663 || maxpos.lnum > sip->si_m_endpos.lnum 2664 || (maxpos.lnum == sip->si_m_endpos.lnum 2665 && maxpos.col > sip->si_m_endpos.col)) 2666 maxpos = sip->si_m_endpos; 2667 if (maxpos_h.lnum == 0 2668 || maxpos_h.lnum > sip->si_h_endpos.lnum 2669 || (maxpos_h.lnum == sip->si_h_endpos.lnum 2670 && maxpos_h.col > sip->si_h_endpos.col)) 2671 maxpos_h = sip->si_h_endpos; 2672 } 2673 } 2674 } 2675 2676 /* 2677 * Update an entry in the current_state stack for a start-skip-end pattern. 2678 * This finds the end of the current item, if it's in the current line. 2679 * 2680 * Return the flags for the matched END. 2681 */ 2682 static void 2683 update_si_end( 2684 stateitem_T *sip, 2685 int startcol, // where to start searching for the end 2686 int force) // when TRUE overrule a previous end 2687 { 2688 lpos_T startpos; 2689 lpos_T endpos; 2690 lpos_T hl_endpos; 2691 lpos_T end_endpos; 2692 int end_idx; 2693 2694 // return quickly for a keyword 2695 if (sip->si_idx < 0) 2696 return; 2697 2698 // Don't update when it's already done. Can be a match of an end pattern 2699 // that started in a previous line. Watch out: can also be a "keepend" 2700 // from a containing item. 2701 if (!force && sip->si_m_endpos.lnum >= current_lnum) 2702 return; 2703 2704 /* 2705 * We need to find the end of the region. It may continue in the next 2706 * line. 2707 */ 2708 end_idx = 0; 2709 startpos.lnum = current_lnum; 2710 startpos.col = startcol; 2711 find_endpos(sip->si_idx, &startpos, &endpos, &hl_endpos, 2712 &(sip->si_flags), &end_endpos, &end_idx, sip->si_extmatch); 2713 2714 if (endpos.lnum == 0) 2715 { 2716 // No end pattern matched. 2717 if (SYN_ITEMS(syn_block)[sip->si_idx].sp_flags & HL_ONELINE) 2718 { 2719 // a "oneline" never continues in the next line 2720 sip->si_ends = TRUE; 2721 sip->si_m_endpos.lnum = current_lnum; 2722 sip->si_m_endpos.col = (colnr_T)STRLEN(syn_getcurline()); 2723 } 2724 else 2725 { 2726 // continues in the next line 2727 sip->si_ends = FALSE; 2728 sip->si_m_endpos.lnum = 0; 2729 } 2730 sip->si_h_endpos = sip->si_m_endpos; 2731 } 2732 else 2733 { 2734 // match within this line 2735 sip->si_m_endpos = endpos; 2736 sip->si_h_endpos = hl_endpos; 2737 sip->si_eoe_pos = end_endpos; 2738 sip->si_ends = TRUE; 2739 sip->si_end_idx = end_idx; 2740 } 2741 } 2742 2743 /* 2744 * Add a new state to the current state stack. 2745 * It is cleared and the index set to "idx". 2746 * Return FAIL if it's not possible (out of memory). 2747 */ 2748 static int 2749 push_current_state(int idx) 2750 { 2751 if (ga_grow(¤t_state, 1) == FAIL) 2752 return FAIL; 2753 CLEAR_POINTER(&CUR_STATE(current_state.ga_len)); 2754 CUR_STATE(current_state.ga_len).si_idx = idx; 2755 ++current_state.ga_len; 2756 return OK; 2757 } 2758 2759 /* 2760 * Remove a state from the current_state stack. 2761 */ 2762 static void 2763 pop_current_state(void) 2764 { 2765 if (current_state.ga_len) 2766 { 2767 unref_extmatch(CUR_STATE(current_state.ga_len - 1).si_extmatch); 2768 --current_state.ga_len; 2769 } 2770 // after the end of a pattern, try matching a keyword or pattern 2771 next_match_idx = -1; 2772 2773 // if first state with "keepend" is popped, reset keepend_level 2774 if (keepend_level >= current_state.ga_len) 2775 keepend_level = -1; 2776 } 2777 2778 /* 2779 * Find the end of a start/skip/end syntax region after "startpos". 2780 * Only checks one line. 2781 * Also handles a match item that continued from a previous line. 2782 * If not found, the syntax item continues in the next line. m_endpos->lnum 2783 * will be 0. 2784 * If found, the end of the region and the end of the highlighting is 2785 * computed. 2786 */ 2787 static void 2788 find_endpos( 2789 int idx, // index of the pattern 2790 lpos_T *startpos, // where to start looking for an END match 2791 lpos_T *m_endpos, // return: end of match 2792 lpos_T *hl_endpos, // return: end of highlighting 2793 long *flagsp, // return: flags of matching END 2794 lpos_T *end_endpos, // return: end of end pattern match 2795 int *end_idx, // return: group ID for end pat. match, or 0 2796 reg_extmatch_T *start_ext) // submatches from the start pattern 2797 { 2798 colnr_T matchcol; 2799 synpat_T *spp, *spp_skip; 2800 int start_idx; 2801 int best_idx; 2802 regmmatch_T regmatch; 2803 regmmatch_T best_regmatch; // startpos/endpos of best match 2804 lpos_T pos; 2805 char_u *line; 2806 int had_match = FALSE; 2807 char_u buf_chartab[32]; // chartab array for syn option iskyeyword 2808 2809 // just in case we are invoked for a keyword 2810 if (idx < 0) 2811 return; 2812 2813 /* 2814 * Check for being called with a START pattern. 2815 * Can happen with a match that continues to the next line, because it 2816 * contained a region. 2817 */ 2818 spp = &(SYN_ITEMS(syn_block)[idx]); 2819 if (spp->sp_type != SPTYPE_START) 2820 { 2821 *hl_endpos = *startpos; 2822 return; 2823 } 2824 2825 /* 2826 * Find the SKIP or first END pattern after the last START pattern. 2827 */ 2828 for (;;) 2829 { 2830 spp = &(SYN_ITEMS(syn_block)[idx]); 2831 if (spp->sp_type != SPTYPE_START) 2832 break; 2833 ++idx; 2834 } 2835 2836 /* 2837 * Lookup the SKIP pattern (if present) 2838 */ 2839 if (spp->sp_type == SPTYPE_SKIP) 2840 { 2841 spp_skip = spp; 2842 ++idx; 2843 } 2844 else 2845 spp_skip = NULL; 2846 2847 // Setup external matches for syn_regexec(). 2848 unref_extmatch(re_extmatch_in); 2849 re_extmatch_in = ref_extmatch(start_ext); 2850 2851 matchcol = startpos->col; // start looking for a match at sstart 2852 start_idx = idx; // remember the first END pattern. 2853 best_regmatch.startpos[0].col = 0; // avoid compiler warning 2854 2855 // use syntax iskeyword option 2856 save_chartab(buf_chartab); 2857 2858 for (;;) 2859 { 2860 /* 2861 * Find end pattern that matches first after "matchcol". 2862 */ 2863 best_idx = -1; 2864 for (idx = start_idx; idx < syn_block->b_syn_patterns.ga_len; ++idx) 2865 { 2866 int lc_col = matchcol; 2867 int r; 2868 2869 spp = &(SYN_ITEMS(syn_block)[idx]); 2870 if (spp->sp_type != SPTYPE_END) // past last END pattern 2871 break; 2872 lc_col -= spp->sp_offsets[SPO_LC_OFF]; 2873 if (lc_col < 0) 2874 lc_col = 0; 2875 2876 regmatch.rmm_ic = spp->sp_ic; 2877 regmatch.regprog = spp->sp_prog; 2878 r = syn_regexec(®match, startpos->lnum, lc_col, 2879 IF_SYN_TIME(&spp->sp_time)); 2880 spp->sp_prog = regmatch.regprog; 2881 if (r) 2882 { 2883 if (best_idx == -1 || regmatch.startpos[0].col 2884 < best_regmatch.startpos[0].col) 2885 { 2886 best_idx = idx; 2887 best_regmatch.startpos[0] = regmatch.startpos[0]; 2888 best_regmatch.endpos[0] = regmatch.endpos[0]; 2889 } 2890 } 2891 } 2892 2893 /* 2894 * If all end patterns have been tried, and there is no match, the 2895 * item continues until end-of-line. 2896 */ 2897 if (best_idx == -1) 2898 break; 2899 2900 /* 2901 * If the skip pattern matches before the end pattern, 2902 * continue searching after the skip pattern. 2903 */ 2904 if (spp_skip != NULL) 2905 { 2906 int lc_col = matchcol - spp_skip->sp_offsets[SPO_LC_OFF]; 2907 int r; 2908 2909 if (lc_col < 0) 2910 lc_col = 0; 2911 regmatch.rmm_ic = spp_skip->sp_ic; 2912 regmatch.regprog = spp_skip->sp_prog; 2913 r = syn_regexec(®match, startpos->lnum, lc_col, 2914 IF_SYN_TIME(&spp_skip->sp_time)); 2915 spp_skip->sp_prog = regmatch.regprog; 2916 if (r && regmatch.startpos[0].col 2917 <= best_regmatch.startpos[0].col) 2918 { 2919 int line_len; 2920 2921 // Add offset to skip pattern match 2922 syn_add_end_off(&pos, ®match, spp_skip, SPO_ME_OFF, 1); 2923 2924 // If the skip pattern goes on to the next line, there is no 2925 // match with an end pattern in this line. 2926 if (pos.lnum > startpos->lnum) 2927 break; 2928 2929 line = ml_get_buf(syn_buf, startpos->lnum, FALSE); 2930 line_len = (int)STRLEN(line); 2931 2932 // take care of an empty match or negative offset 2933 if (pos.col <= matchcol) 2934 ++matchcol; 2935 else if (pos.col <= regmatch.endpos[0].col) 2936 matchcol = pos.col; 2937 else 2938 // Be careful not to jump over the NUL at the end-of-line 2939 for (matchcol = regmatch.endpos[0].col; 2940 matchcol < line_len && matchcol < pos.col; 2941 ++matchcol) 2942 ; 2943 2944 // if the skip pattern includes end-of-line, break here 2945 if (matchcol >= line_len) 2946 break; 2947 2948 continue; // start with first end pattern again 2949 } 2950 } 2951 2952 /* 2953 * Match from start pattern to end pattern. 2954 * Correct for match and highlight offset of end pattern. 2955 */ 2956 spp = &(SYN_ITEMS(syn_block)[best_idx]); 2957 syn_add_end_off(m_endpos, &best_regmatch, spp, SPO_ME_OFF, 1); 2958 // can't end before the start 2959 if (m_endpos->lnum == startpos->lnum && m_endpos->col < startpos->col) 2960 m_endpos->col = startpos->col; 2961 2962 syn_add_end_off(end_endpos, &best_regmatch, spp, SPO_HE_OFF, 1); 2963 // can't end before the start 2964 if (end_endpos->lnum == startpos->lnum 2965 && end_endpos->col < startpos->col) 2966 end_endpos->col = startpos->col; 2967 // can't end after the match 2968 limit_pos(end_endpos, m_endpos); 2969 2970 /* 2971 * If the end group is highlighted differently, adjust the pointers. 2972 */ 2973 if (spp->sp_syn_match_id != spp->sp_syn.id && spp->sp_syn_match_id != 0) 2974 { 2975 *end_idx = best_idx; 2976 if (spp->sp_off_flags & (1 << (SPO_RE_OFF + SPO_COUNT))) 2977 { 2978 hl_endpos->lnum = best_regmatch.endpos[0].lnum; 2979 hl_endpos->col = best_regmatch.endpos[0].col; 2980 } 2981 else 2982 { 2983 hl_endpos->lnum = best_regmatch.startpos[0].lnum; 2984 hl_endpos->col = best_regmatch.startpos[0].col; 2985 } 2986 hl_endpos->col += spp->sp_offsets[SPO_RE_OFF]; 2987 2988 // can't end before the start 2989 if (hl_endpos->lnum == startpos->lnum 2990 && hl_endpos->col < startpos->col) 2991 hl_endpos->col = startpos->col; 2992 limit_pos(hl_endpos, m_endpos); 2993 2994 // now the match ends where the highlighting ends, it is turned 2995 // into the matchgroup for the end 2996 *m_endpos = *hl_endpos; 2997 } 2998 else 2999 { 3000 *end_idx = 0; 3001 *hl_endpos = *end_endpos; 3002 } 3003 3004 *flagsp = spp->sp_flags; 3005 3006 had_match = TRUE; 3007 break; 3008 } 3009 3010 // no match for an END pattern in this line 3011 if (!had_match) 3012 m_endpos->lnum = 0; 3013 3014 restore_chartab(buf_chartab); 3015 3016 // Remove external matches. 3017 unref_extmatch(re_extmatch_in); 3018 re_extmatch_in = NULL; 3019 } 3020 3021 /* 3022 * Limit "pos" not to be after "limit". 3023 */ 3024 static void 3025 limit_pos(lpos_T *pos, lpos_T *limit) 3026 { 3027 if (pos->lnum > limit->lnum) 3028 *pos = *limit; 3029 else if (pos->lnum == limit->lnum && pos->col > limit->col) 3030 pos->col = limit->col; 3031 } 3032 3033 /* 3034 * Limit "pos" not to be after "limit", unless pos->lnum is zero. 3035 */ 3036 static void 3037 limit_pos_zero( 3038 lpos_T *pos, 3039 lpos_T *limit) 3040 { 3041 if (pos->lnum == 0) 3042 *pos = *limit; 3043 else 3044 limit_pos(pos, limit); 3045 } 3046 3047 /* 3048 * Add offset to matched text for end of match or highlight. 3049 */ 3050 static void 3051 syn_add_end_off( 3052 lpos_T *result, // returned position 3053 regmmatch_T *regmatch, // start/end of match 3054 synpat_T *spp, // matched pattern 3055 int idx, // index of offset 3056 int extra) // extra chars for offset to start 3057 { 3058 int col; 3059 int off; 3060 char_u *base; 3061 char_u *p; 3062 3063 if (spp->sp_off_flags & (1 << idx)) 3064 { 3065 result->lnum = regmatch->startpos[0].lnum; 3066 col = regmatch->startpos[0].col; 3067 off = spp->sp_offsets[idx] + extra; 3068 } 3069 else 3070 { 3071 result->lnum = regmatch->endpos[0].lnum; 3072 col = regmatch->endpos[0].col; 3073 off = spp->sp_offsets[idx]; 3074 } 3075 // Don't go past the end of the line. Matters for "rs=e+2" when there 3076 // is a matchgroup. Watch out for match with last NL in the buffer. 3077 if (result->lnum > syn_buf->b_ml.ml_line_count) 3078 col = 0; 3079 else if (off != 0) 3080 { 3081 base = ml_get_buf(syn_buf, result->lnum, FALSE); 3082 p = base + col; 3083 if (off > 0) 3084 { 3085 while (off-- > 0 && *p != NUL) 3086 MB_PTR_ADV(p); 3087 } 3088 else if (off < 0) 3089 { 3090 while (off++ < 0 && base < p) 3091 MB_PTR_BACK(base, p); 3092 } 3093 col = (int)(p - base); 3094 } 3095 result->col = col; 3096 } 3097 3098 /* 3099 * Add offset to matched text for start of match or highlight. 3100 * Avoid resulting column to become negative. 3101 */ 3102 static void 3103 syn_add_start_off( 3104 lpos_T *result, // returned position 3105 regmmatch_T *regmatch, // start/end of match 3106 synpat_T *spp, 3107 int idx, 3108 int extra) // extra chars for offset to end 3109 { 3110 int col; 3111 int off; 3112 char_u *base; 3113 char_u *p; 3114 3115 if (spp->sp_off_flags & (1 << (idx + SPO_COUNT))) 3116 { 3117 result->lnum = regmatch->endpos[0].lnum; 3118 col = regmatch->endpos[0].col; 3119 off = spp->sp_offsets[idx] + extra; 3120 } 3121 else 3122 { 3123 result->lnum = regmatch->startpos[0].lnum; 3124 col = regmatch->startpos[0].col; 3125 off = spp->sp_offsets[idx]; 3126 } 3127 if (result->lnum > syn_buf->b_ml.ml_line_count) 3128 { 3129 // a "\n" at the end of the pattern may take us below the last line 3130 result->lnum = syn_buf->b_ml.ml_line_count; 3131 col = (int)STRLEN(ml_get_buf(syn_buf, result->lnum, FALSE)); 3132 } 3133 if (off != 0) 3134 { 3135 base = ml_get_buf(syn_buf, result->lnum, FALSE); 3136 p = base + col; 3137 if (off > 0) 3138 { 3139 while (off-- && *p != NUL) 3140 MB_PTR_ADV(p); 3141 } 3142 else if (off < 0) 3143 { 3144 while (off++ && base < p) 3145 MB_PTR_BACK(base, p); 3146 } 3147 col = (int)(p - base); 3148 } 3149 result->col = col; 3150 } 3151 3152 /* 3153 * Get current line in syntax buffer. 3154 */ 3155 static char_u * 3156 syn_getcurline(void) 3157 { 3158 return ml_get_buf(syn_buf, current_lnum, FALSE); 3159 } 3160 3161 /* 3162 * Call vim_regexec() to find a match with "rmp" in "syn_buf". 3163 * Returns TRUE when there is a match. 3164 */ 3165 static int 3166 syn_regexec( 3167 regmmatch_T *rmp, 3168 linenr_T lnum, 3169 colnr_T col, 3170 syn_time_T *st UNUSED) 3171 { 3172 int r; 3173 #ifdef FEAT_RELTIME 3174 int timed_out = FALSE; 3175 #endif 3176 #ifdef FEAT_PROFILE 3177 proftime_T pt; 3178 3179 if (syn_time_on) 3180 profile_start(&pt); 3181 #endif 3182 3183 if (rmp->regprog == NULL) 3184 // This can happen if a previous call to vim_regexec_multi() tried to 3185 // use the NFA engine, which resulted in NFA_TOO_EXPENSIVE, and 3186 // compiling the pattern with the other engine fails. 3187 return FALSE; 3188 3189 rmp->rmm_maxcol = syn_buf->b_p_smc; 3190 r = vim_regexec_multi(rmp, syn_win, syn_buf, lnum, col, 3191 #ifdef FEAT_RELTIME 3192 syn_tm, &timed_out 3193 #else 3194 NULL, NULL 3195 #endif 3196 ); 3197 3198 #ifdef FEAT_PROFILE 3199 if (syn_time_on) 3200 { 3201 profile_end(&pt); 3202 profile_add(&st->total, &pt); 3203 if (profile_cmp(&pt, &st->slowest) < 0) 3204 st->slowest = pt; 3205 ++st->count; 3206 if (r > 0) 3207 ++st->match; 3208 } 3209 #endif 3210 #ifdef FEAT_RELTIME 3211 if (timed_out && !syn_win->w_s->b_syn_slow) 3212 { 3213 syn_win->w_s->b_syn_slow = TRUE; 3214 msg(_("'redrawtime' exceeded, syntax highlighting disabled")); 3215 } 3216 #endif 3217 3218 if (r > 0) 3219 { 3220 rmp->startpos[0].lnum += lnum; 3221 rmp->endpos[0].lnum += lnum; 3222 return TRUE; 3223 } 3224 return FALSE; 3225 } 3226 3227 /* 3228 * Check one position in a line for a matching keyword. 3229 * The caller must check if a keyword can start at startcol. 3230 * Return its ID if found, 0 otherwise. 3231 */ 3232 static int 3233 check_keyword_id( 3234 char_u *line, 3235 int startcol, // position in line to check for keyword 3236 int *endcolp, // return: character after found keyword 3237 long *flagsp, // return: flags of matching keyword 3238 short **next_listp, // return: next_list of matching keyword 3239 stateitem_T *cur_si, // item at the top of the stack 3240 int *ccharp UNUSED) // conceal substitution char 3241 { 3242 keyentry_T *kp; 3243 char_u *kwp; 3244 int round; 3245 int kwlen; 3246 char_u keyword[MAXKEYWLEN + 1]; // assume max. keyword len is 80 3247 hashtab_T *ht; 3248 hashitem_T *hi; 3249 3250 // Find first character after the keyword. First character was already 3251 // checked. 3252 kwp = line + startcol; 3253 kwlen = 0; 3254 do 3255 { 3256 if (has_mbyte) 3257 kwlen += (*mb_ptr2len)(kwp + kwlen); 3258 else 3259 ++kwlen; 3260 } 3261 while (vim_iswordp_buf(kwp + kwlen, syn_buf)); 3262 3263 if (kwlen > MAXKEYWLEN) 3264 return 0; 3265 3266 /* 3267 * Must make a copy of the keyword, so we can add a NUL and make it 3268 * lowercase. 3269 */ 3270 vim_strncpy(keyword, kwp, kwlen); 3271 3272 /* 3273 * Try twice: 3274 * 1. matching case 3275 * 2. ignoring case 3276 */ 3277 for (round = 1; round <= 2; ++round) 3278 { 3279 ht = round == 1 ? &syn_block->b_keywtab : &syn_block->b_keywtab_ic; 3280 if (ht->ht_used == 0) 3281 continue; 3282 if (round == 2) // ignore case 3283 (void)str_foldcase(kwp, kwlen, keyword, MAXKEYWLEN + 1); 3284 3285 /* 3286 * Find keywords that match. There can be several with different 3287 * attributes. 3288 * When current_next_list is non-zero accept only that group, otherwise: 3289 * Accept a not-contained keyword at toplevel. 3290 * Accept a keyword at other levels only if it is in the contains list. 3291 */ 3292 hi = hash_find(ht, keyword); 3293 if (!HASHITEM_EMPTY(hi)) 3294 for (kp = HI2KE(hi); kp != NULL; kp = kp->ke_next) 3295 { 3296 if (current_next_list != 0 3297 ? in_id_list(NULL, current_next_list, &kp->k_syn, 0) 3298 : (cur_si == NULL 3299 ? !(kp->flags & HL_CONTAINED) 3300 : in_id_list(cur_si, cur_si->si_cont_list, 3301 &kp->k_syn, kp->flags & HL_CONTAINED))) 3302 { 3303 *endcolp = startcol + kwlen; 3304 *flagsp = kp->flags; 3305 *next_listp = kp->next_list; 3306 #ifdef FEAT_CONCEAL 3307 *ccharp = kp->k_char; 3308 #endif 3309 return kp->k_syn.id; 3310 } 3311 } 3312 } 3313 return 0; 3314 } 3315 3316 /* 3317 * Handle ":syntax conceal" command. 3318 */ 3319 static void 3320 syn_cmd_conceal(exarg_T *eap UNUSED, int syncing UNUSED) 3321 { 3322 #ifdef FEAT_CONCEAL 3323 char_u *arg = eap->arg; 3324 char_u *next; 3325 3326 eap->nextcmd = find_nextcmd(arg); 3327 if (eap->skip) 3328 return; 3329 3330 next = skiptowhite(arg); 3331 if (*arg == NUL) 3332 { 3333 if (curwin->w_s->b_syn_conceal) 3334 msg(_("syntax conceal on")); 3335 else 3336 msg(_("syntax conceal off")); 3337 } 3338 else if (STRNICMP(arg, "on", 2) == 0 && next - arg == 2) 3339 curwin->w_s->b_syn_conceal = TRUE; 3340 else if (STRNICMP(arg, "off", 3) == 0 && next - arg == 3) 3341 curwin->w_s->b_syn_conceal = FALSE; 3342 else 3343 semsg(_("E390: Illegal argument: %s"), arg); 3344 #endif 3345 } 3346 3347 /* 3348 * Handle ":syntax case" command. 3349 */ 3350 static void 3351 syn_cmd_case(exarg_T *eap, int syncing UNUSED) 3352 { 3353 char_u *arg = eap->arg; 3354 char_u *next; 3355 3356 eap->nextcmd = find_nextcmd(arg); 3357 if (eap->skip) 3358 return; 3359 3360 next = skiptowhite(arg); 3361 if (*arg == NUL) 3362 { 3363 if (curwin->w_s->b_syn_ic) 3364 msg(_("syntax case ignore")); 3365 else 3366 msg(_("syntax case match")); 3367 } 3368 else if (STRNICMP(arg, "match", 5) == 0 && next - arg == 5) 3369 curwin->w_s->b_syn_ic = FALSE; 3370 else if (STRNICMP(arg, "ignore", 6) == 0 && next - arg == 6) 3371 curwin->w_s->b_syn_ic = TRUE; 3372 else 3373 semsg(_("E390: Illegal argument: %s"), arg); 3374 } 3375 3376 /* 3377 * Handle ":syntax spell" command. 3378 */ 3379 static void 3380 syn_cmd_spell(exarg_T *eap, int syncing UNUSED) 3381 { 3382 char_u *arg = eap->arg; 3383 char_u *next; 3384 3385 eap->nextcmd = find_nextcmd(arg); 3386 if (eap->skip) 3387 return; 3388 3389 next = skiptowhite(arg); 3390 if (*arg == NUL) 3391 { 3392 if (curwin->w_s->b_syn_spell == SYNSPL_TOP) 3393 msg(_("syntax spell toplevel")); 3394 else if (curwin->w_s->b_syn_spell == SYNSPL_NOTOP) 3395 msg(_("syntax spell notoplevel")); 3396 else 3397 msg(_("syntax spell default")); 3398 } 3399 else if (STRNICMP(arg, "toplevel", 8) == 0 && next - arg == 8) 3400 curwin->w_s->b_syn_spell = SYNSPL_TOP; 3401 else if (STRNICMP(arg, "notoplevel", 10) == 0 && next - arg == 10) 3402 curwin->w_s->b_syn_spell = SYNSPL_NOTOP; 3403 else if (STRNICMP(arg, "default", 7) == 0 && next - arg == 7) 3404 curwin->w_s->b_syn_spell = SYNSPL_DEFAULT; 3405 else 3406 { 3407 semsg(_("E390: Illegal argument: %s"), arg); 3408 return; 3409 } 3410 3411 // assume spell checking changed, force a redraw 3412 redraw_win_later(curwin, NOT_VALID); 3413 } 3414 3415 /* 3416 * Handle ":syntax iskeyword" command. 3417 */ 3418 static void 3419 syn_cmd_iskeyword(exarg_T *eap, int syncing UNUSED) 3420 { 3421 char_u *arg = eap->arg; 3422 char_u save_chartab[32]; 3423 char_u *save_isk; 3424 3425 if (eap->skip) 3426 return; 3427 3428 arg = skipwhite(arg); 3429 if (*arg == NUL) 3430 { 3431 msg_puts("\n"); 3432 if (curwin->w_s->b_syn_isk != empty_option) 3433 { 3434 msg_puts(_("syntax iskeyword ")); 3435 msg_outtrans(curwin->w_s->b_syn_isk); 3436 } 3437 else 3438 msg_outtrans((char_u *)_("syntax iskeyword not set")); 3439 } 3440 else 3441 { 3442 if (STRNICMP(arg, "clear", 5) == 0) 3443 { 3444 mch_memmove(curwin->w_s->b_syn_chartab, curbuf->b_chartab, 3445 (size_t)32); 3446 clear_string_option(&curwin->w_s->b_syn_isk); 3447 } 3448 else 3449 { 3450 mch_memmove(save_chartab, curbuf->b_chartab, (size_t)32); 3451 save_isk = curbuf->b_p_isk; 3452 curbuf->b_p_isk = vim_strsave(arg); 3453 3454 buf_init_chartab(curbuf, FALSE); 3455 mch_memmove(curwin->w_s->b_syn_chartab, curbuf->b_chartab, 3456 (size_t)32); 3457 mch_memmove(curbuf->b_chartab, save_chartab, (size_t)32); 3458 clear_string_option(&curwin->w_s->b_syn_isk); 3459 curwin->w_s->b_syn_isk = curbuf->b_p_isk; 3460 curbuf->b_p_isk = save_isk; 3461 } 3462 } 3463 redraw_win_later(curwin, NOT_VALID); 3464 } 3465 3466 /* 3467 * Clear all syntax info for one buffer. 3468 */ 3469 void 3470 syntax_clear(synblock_T *block) 3471 { 3472 int i; 3473 3474 block->b_syn_error = FALSE; // clear previous error 3475 #ifdef FEAT_RELTIME 3476 block->b_syn_slow = FALSE; // clear previous timeout 3477 #endif 3478 block->b_syn_ic = FALSE; // Use case, by default 3479 block->b_syn_spell = SYNSPL_DEFAULT; // default spell checking 3480 block->b_syn_containedin = FALSE; 3481 #ifdef FEAT_CONCEAL 3482 block->b_syn_conceal = FALSE; 3483 #endif 3484 3485 // free the keywords 3486 clear_keywtab(&block->b_keywtab); 3487 clear_keywtab(&block->b_keywtab_ic); 3488 3489 // free the syntax patterns 3490 for (i = block->b_syn_patterns.ga_len; --i >= 0; ) 3491 syn_clear_pattern(block, i); 3492 ga_clear(&block->b_syn_patterns); 3493 3494 // free the syntax clusters 3495 for (i = block->b_syn_clusters.ga_len; --i >= 0; ) 3496 syn_clear_cluster(block, i); 3497 ga_clear(&block->b_syn_clusters); 3498 block->b_spell_cluster_id = 0; 3499 block->b_nospell_cluster_id = 0; 3500 3501 block->b_syn_sync_flags = 0; 3502 block->b_syn_sync_minlines = 0; 3503 block->b_syn_sync_maxlines = 0; 3504 block->b_syn_sync_linebreaks = 0; 3505 3506 vim_regfree(block->b_syn_linecont_prog); 3507 block->b_syn_linecont_prog = NULL; 3508 VIM_CLEAR(block->b_syn_linecont_pat); 3509 #ifdef FEAT_FOLDING 3510 block->b_syn_folditems = 0; 3511 #endif 3512 clear_string_option(&block->b_syn_isk); 3513 3514 // free the stored states 3515 syn_stack_free_all(block); 3516 invalidate_current_state(); 3517 3518 // Reset the counter for ":syn include" 3519 running_syn_inc_tag = 0; 3520 } 3521 3522 /* 3523 * Get rid of ownsyntax for window "wp". 3524 */ 3525 void 3526 reset_synblock(win_T *wp) 3527 { 3528 if (wp->w_s != &wp->w_buffer->b_s) 3529 { 3530 syntax_clear(wp->w_s); 3531 vim_free(wp->w_s); 3532 wp->w_s = &wp->w_buffer->b_s; 3533 } 3534 } 3535 3536 /* 3537 * Clear syncing info for one buffer. 3538 */ 3539 static void 3540 syntax_sync_clear(void) 3541 { 3542 int i; 3543 3544 // free the syntax patterns 3545 for (i = curwin->w_s->b_syn_patterns.ga_len; --i >= 0; ) 3546 if (SYN_ITEMS(curwin->w_s)[i].sp_syncing) 3547 syn_remove_pattern(curwin->w_s, i); 3548 3549 curwin->w_s->b_syn_sync_flags = 0; 3550 curwin->w_s->b_syn_sync_minlines = 0; 3551 curwin->w_s->b_syn_sync_maxlines = 0; 3552 curwin->w_s->b_syn_sync_linebreaks = 0; 3553 3554 vim_regfree(curwin->w_s->b_syn_linecont_prog); 3555 curwin->w_s->b_syn_linecont_prog = NULL; 3556 VIM_CLEAR(curwin->w_s->b_syn_linecont_pat); 3557 clear_string_option(&curwin->w_s->b_syn_isk); 3558 3559 syn_stack_free_all(curwin->w_s); // Need to recompute all syntax. 3560 } 3561 3562 /* 3563 * Remove one pattern from the buffer's pattern list. 3564 */ 3565 static void 3566 syn_remove_pattern( 3567 synblock_T *block, 3568 int idx) 3569 { 3570 synpat_T *spp; 3571 3572 spp = &(SYN_ITEMS(block)[idx]); 3573 #ifdef FEAT_FOLDING 3574 if (spp->sp_flags & HL_FOLD) 3575 --block->b_syn_folditems; 3576 #endif 3577 syn_clear_pattern(block, idx); 3578 mch_memmove(spp, spp + 1, 3579 sizeof(synpat_T) * (block->b_syn_patterns.ga_len - idx - 1)); 3580 --block->b_syn_patterns.ga_len; 3581 } 3582 3583 /* 3584 * Clear and free one syntax pattern. When clearing all, must be called from 3585 * last to first! 3586 */ 3587 static void 3588 syn_clear_pattern(synblock_T *block, int i) 3589 { 3590 vim_free(SYN_ITEMS(block)[i].sp_pattern); 3591 vim_regfree(SYN_ITEMS(block)[i].sp_prog); 3592 // Only free sp_cont_list and sp_next_list of first start pattern 3593 if (i == 0 || SYN_ITEMS(block)[i - 1].sp_type != SPTYPE_START) 3594 { 3595 vim_free(SYN_ITEMS(block)[i].sp_cont_list); 3596 vim_free(SYN_ITEMS(block)[i].sp_next_list); 3597 vim_free(SYN_ITEMS(block)[i].sp_syn.cont_in_list); 3598 } 3599 } 3600 3601 /* 3602 * Clear and free one syntax cluster. 3603 */ 3604 static void 3605 syn_clear_cluster(synblock_T *block, int i) 3606 { 3607 vim_free(SYN_CLSTR(block)[i].scl_name); 3608 vim_free(SYN_CLSTR(block)[i].scl_name_u); 3609 vim_free(SYN_CLSTR(block)[i].scl_list); 3610 } 3611 3612 /* 3613 * Handle ":syntax clear" command. 3614 */ 3615 static void 3616 syn_cmd_clear(exarg_T *eap, int syncing) 3617 { 3618 char_u *arg = eap->arg; 3619 char_u *arg_end; 3620 int id; 3621 3622 eap->nextcmd = find_nextcmd(arg); 3623 if (eap->skip) 3624 return; 3625 3626 /* 3627 * We have to disable this within ":syn include @group filename", 3628 * because otherwise @group would get deleted. 3629 * Only required for Vim 5.x syntax files, 6.0 ones don't contain ":syn 3630 * clear". 3631 */ 3632 if (curwin->w_s->b_syn_topgrp != 0) 3633 return; 3634 3635 if (ends_excmd2(eap->cmd, arg)) 3636 { 3637 /* 3638 * No argument: Clear all syntax items. 3639 */ 3640 if (syncing) 3641 syntax_sync_clear(); 3642 else 3643 { 3644 syntax_clear(curwin->w_s); 3645 if (curwin->w_s == &curwin->w_buffer->b_s) 3646 do_unlet((char_u *)"b:current_syntax", TRUE); 3647 do_unlet((char_u *)"w:current_syntax", TRUE); 3648 } 3649 } 3650 else 3651 { 3652 /* 3653 * Clear the group IDs that are in the argument. 3654 */ 3655 while (!ends_excmd2(eap->cmd, arg)) 3656 { 3657 arg_end = skiptowhite(arg); 3658 if (*arg == '@') 3659 { 3660 id = syn_scl_namen2id(arg + 1, (int)(arg_end - arg - 1)); 3661 if (id == 0) 3662 { 3663 semsg(_("E391: No such syntax cluster: %s"), arg); 3664 break; 3665 } 3666 else 3667 { 3668 /* 3669 * We can't physically delete a cluster without changing 3670 * the IDs of other clusters, so we do the next best thing 3671 * and make it empty. 3672 */ 3673 short scl_id = id - SYNID_CLUSTER; 3674 3675 VIM_CLEAR(SYN_CLSTR(curwin->w_s)[scl_id].scl_list); 3676 } 3677 } 3678 else 3679 { 3680 id = syn_namen2id(arg, (int)(arg_end - arg)); 3681 if (id == 0) 3682 { 3683 semsg(_(e_nogroup), arg); 3684 break; 3685 } 3686 else 3687 syn_clear_one(id, syncing); 3688 } 3689 arg = skipwhite(arg_end); 3690 } 3691 } 3692 redraw_curbuf_later(SOME_VALID); 3693 syn_stack_free_all(curwin->w_s); // Need to recompute all syntax. 3694 } 3695 3696 /* 3697 * Clear one syntax group for the current buffer. 3698 */ 3699 static void 3700 syn_clear_one(int id, int syncing) 3701 { 3702 synpat_T *spp; 3703 int idx; 3704 3705 // Clear keywords only when not ":syn sync clear group-name" 3706 if (!syncing) 3707 { 3708 (void)syn_clear_keyword(id, &curwin->w_s->b_keywtab); 3709 (void)syn_clear_keyword(id, &curwin->w_s->b_keywtab_ic); 3710 } 3711 3712 // clear the patterns for "id" 3713 for (idx = curwin->w_s->b_syn_patterns.ga_len; --idx >= 0; ) 3714 { 3715 spp = &(SYN_ITEMS(curwin->w_s)[idx]); 3716 if (spp->sp_syn.id != id || spp->sp_syncing != syncing) 3717 continue; 3718 syn_remove_pattern(curwin->w_s, idx); 3719 } 3720 } 3721 3722 /* 3723 * Handle ":syntax on" command. 3724 */ 3725 static void 3726 syn_cmd_on(exarg_T *eap, int syncing UNUSED) 3727 { 3728 syn_cmd_onoff(eap, "syntax"); 3729 } 3730 3731 /* 3732 * Handle ":syntax enable" command. 3733 */ 3734 static void 3735 syn_cmd_enable(exarg_T *eap, int syncing UNUSED) 3736 { 3737 set_internal_string_var((char_u *)"syntax_cmd", (char_u *)"enable"); 3738 syn_cmd_onoff(eap, "syntax"); 3739 do_unlet((char_u *)"g:syntax_cmd", TRUE); 3740 } 3741 3742 /* 3743 * Handle ":syntax reset" command. 3744 * It actually resets highlighting, not syntax. 3745 */ 3746 static void 3747 syn_cmd_reset(exarg_T *eap, int syncing UNUSED) 3748 { 3749 eap->nextcmd = check_nextcmd(eap->arg); 3750 if (!eap->skip) 3751 { 3752 set_internal_string_var((char_u *)"syntax_cmd", (char_u *)"reset"); 3753 do_cmdline_cmd((char_u *)"runtime! syntax/syncolor.vim"); 3754 do_unlet((char_u *)"g:syntax_cmd", TRUE); 3755 } 3756 } 3757 3758 /* 3759 * Handle ":syntax manual" command. 3760 */ 3761 static void 3762 syn_cmd_manual(exarg_T *eap, int syncing UNUSED) 3763 { 3764 syn_cmd_onoff(eap, "manual"); 3765 } 3766 3767 /* 3768 * Handle ":syntax off" command. 3769 */ 3770 static void 3771 syn_cmd_off(exarg_T *eap, int syncing UNUSED) 3772 { 3773 syn_cmd_onoff(eap, "nosyntax"); 3774 } 3775 3776 static void 3777 syn_cmd_onoff(exarg_T *eap, char *name) 3778 { 3779 char_u buf[100]; 3780 3781 eap->nextcmd = check_nextcmd(eap->arg); 3782 if (!eap->skip) 3783 { 3784 STRCPY(buf, "so "); 3785 vim_snprintf((char *)buf + 3, sizeof(buf) - 3, SYNTAX_FNAME, name); 3786 do_cmdline_cmd(buf); 3787 } 3788 } 3789 3790 /* 3791 * Handle ":syntax [list]" command: list current syntax words. 3792 */ 3793 static void 3794 syn_cmd_list( 3795 exarg_T *eap, 3796 int syncing) // when TRUE: list syncing items 3797 { 3798 char_u *arg = eap->arg; 3799 int id; 3800 char_u *arg_end; 3801 3802 eap->nextcmd = find_nextcmd(arg); 3803 if (eap->skip) 3804 return; 3805 3806 if (!syntax_present(curwin)) 3807 { 3808 msg(_(msg_no_items)); 3809 return; 3810 } 3811 3812 if (syncing) 3813 { 3814 if (curwin->w_s->b_syn_sync_flags & SF_CCOMMENT) 3815 { 3816 msg_puts(_("syncing on C-style comments")); 3817 syn_lines_msg(); 3818 syn_match_msg(); 3819 return; 3820 } 3821 else if (!(curwin->w_s->b_syn_sync_flags & SF_MATCH)) 3822 { 3823 if (curwin->w_s->b_syn_sync_minlines == 0) 3824 msg_puts(_("no syncing")); 3825 else 3826 { 3827 msg_puts(_("syncing starts ")); 3828 msg_outnum(curwin->w_s->b_syn_sync_minlines); 3829 msg_puts(_(" lines before top line")); 3830 syn_match_msg(); 3831 } 3832 return; 3833 } 3834 msg_puts_title(_("\n--- Syntax sync items ---")); 3835 if (curwin->w_s->b_syn_sync_minlines > 0 3836 || curwin->w_s->b_syn_sync_maxlines > 0 3837 || curwin->w_s->b_syn_sync_linebreaks > 0) 3838 { 3839 msg_puts(_("\nsyncing on items")); 3840 syn_lines_msg(); 3841 syn_match_msg(); 3842 } 3843 } 3844 else 3845 msg_puts_title(_("\n--- Syntax items ---")); 3846 if (ends_excmd2(eap->cmd, arg)) 3847 { 3848 /* 3849 * No argument: List all group IDs and all syntax clusters. 3850 */ 3851 for (id = 1; id <= highlight_num_groups() && !got_int; ++id) 3852 syn_list_one(id, syncing, FALSE); 3853 for (id = 0; id < curwin->w_s->b_syn_clusters.ga_len && !got_int; ++id) 3854 syn_list_cluster(id); 3855 } 3856 else 3857 { 3858 /* 3859 * List the group IDs and syntax clusters that are in the argument. 3860 */ 3861 while (!ends_excmd2(eap->cmd, arg) && !got_int) 3862 { 3863 arg_end = skiptowhite(arg); 3864 if (*arg == '@') 3865 { 3866 id = syn_scl_namen2id(arg + 1, (int)(arg_end - arg - 1)); 3867 if (id == 0) 3868 semsg(_("E392: No such syntax cluster: %s"), arg); 3869 else 3870 syn_list_cluster(id - SYNID_CLUSTER); 3871 } 3872 else 3873 { 3874 id = syn_namen2id(arg, (int)(arg_end - arg)); 3875 if (id == 0) 3876 semsg(_(e_nogroup), arg); 3877 else 3878 syn_list_one(id, syncing, TRUE); 3879 } 3880 arg = skipwhite(arg_end); 3881 } 3882 } 3883 eap->nextcmd = check_nextcmd(arg); 3884 } 3885 3886 static void 3887 syn_lines_msg(void) 3888 { 3889 if (curwin->w_s->b_syn_sync_maxlines > 0 3890 || curwin->w_s->b_syn_sync_minlines > 0) 3891 { 3892 msg_puts("; "); 3893 if (curwin->w_s->b_syn_sync_minlines > 0) 3894 { 3895 msg_puts(_("minimal ")); 3896 msg_outnum(curwin->w_s->b_syn_sync_minlines); 3897 if (curwin->w_s->b_syn_sync_maxlines) 3898 msg_puts(", "); 3899 } 3900 if (curwin->w_s->b_syn_sync_maxlines > 0) 3901 { 3902 msg_puts(_("maximal ")); 3903 msg_outnum(curwin->w_s->b_syn_sync_maxlines); 3904 } 3905 msg_puts(_(" lines before top line")); 3906 } 3907 } 3908 3909 static void 3910 syn_match_msg(void) 3911 { 3912 if (curwin->w_s->b_syn_sync_linebreaks > 0) 3913 { 3914 msg_puts(_("; match ")); 3915 msg_outnum(curwin->w_s->b_syn_sync_linebreaks); 3916 msg_puts(_(" line breaks")); 3917 } 3918 } 3919 3920 static int last_matchgroup; 3921 3922 struct name_list 3923 { 3924 int flag; 3925 char *name; 3926 }; 3927 3928 static void syn_list_flags(struct name_list *nl, int flags, int attr); 3929 3930 /* 3931 * List one syntax item, for ":syntax" or "syntax list syntax_name". 3932 */ 3933 static void 3934 syn_list_one( 3935 int id, 3936 int syncing, // when TRUE: list syncing items 3937 int link_only) // when TRUE; list link-only too 3938 { 3939 int attr; 3940 int idx; 3941 int did_header = FALSE; 3942 synpat_T *spp; 3943 static struct name_list namelist1[] = 3944 { 3945 {HL_DISPLAY, "display"}, 3946 {HL_CONTAINED, "contained"}, 3947 {HL_ONELINE, "oneline"}, 3948 {HL_KEEPEND, "keepend"}, 3949 {HL_EXTEND, "extend"}, 3950 {HL_EXCLUDENL, "excludenl"}, 3951 {HL_TRANSP, "transparent"}, 3952 {HL_FOLD, "fold"}, 3953 #ifdef FEAT_CONCEAL 3954 {HL_CONCEAL, "conceal"}, 3955 {HL_CONCEALENDS, "concealends"}, 3956 #endif 3957 {0, NULL} 3958 }; 3959 static struct name_list namelist2[] = 3960 { 3961 {HL_SKIPWHITE, "skipwhite"}, 3962 {HL_SKIPNL, "skipnl"}, 3963 {HL_SKIPEMPTY, "skipempty"}, 3964 {0, NULL} 3965 }; 3966 3967 attr = HL_ATTR(HLF_D); // highlight like directories 3968 3969 // list the keywords for "id" 3970 if (!syncing) 3971 { 3972 did_header = syn_list_keywords(id, &curwin->w_s->b_keywtab, FALSE, attr); 3973 did_header = syn_list_keywords(id, &curwin->w_s->b_keywtab_ic, 3974 did_header, attr); 3975 } 3976 3977 // list the patterns for "id" 3978 for (idx = 0; idx < curwin->w_s->b_syn_patterns.ga_len && !got_int; ++idx) 3979 { 3980 spp = &(SYN_ITEMS(curwin->w_s)[idx]); 3981 if (spp->sp_syn.id != id || spp->sp_syncing != syncing) 3982 continue; 3983 3984 (void)syn_list_header(did_header, 999, id); 3985 did_header = TRUE; 3986 last_matchgroup = 0; 3987 if (spp->sp_type == SPTYPE_MATCH) 3988 { 3989 put_pattern("match", ' ', spp, attr); 3990 msg_putchar(' '); 3991 } 3992 else if (spp->sp_type == SPTYPE_START) 3993 { 3994 while (SYN_ITEMS(curwin->w_s)[idx].sp_type == SPTYPE_START) 3995 put_pattern("start", '=', &SYN_ITEMS(curwin->w_s)[idx++], attr); 3996 if (SYN_ITEMS(curwin->w_s)[idx].sp_type == SPTYPE_SKIP) 3997 put_pattern("skip", '=', &SYN_ITEMS(curwin->w_s)[idx++], attr); 3998 while (idx < curwin->w_s->b_syn_patterns.ga_len 3999 && SYN_ITEMS(curwin->w_s)[idx].sp_type == SPTYPE_END) 4000 put_pattern("end", '=', &SYN_ITEMS(curwin->w_s)[idx++], attr); 4001 --idx; 4002 msg_putchar(' '); 4003 } 4004 syn_list_flags(namelist1, spp->sp_flags, attr); 4005 4006 if (spp->sp_cont_list != NULL) 4007 put_id_list((char_u *)"contains", spp->sp_cont_list, attr); 4008 4009 if (spp->sp_syn.cont_in_list != NULL) 4010 put_id_list((char_u *)"containedin", 4011 spp->sp_syn.cont_in_list, attr); 4012 4013 if (spp->sp_next_list != NULL) 4014 { 4015 put_id_list((char_u *)"nextgroup", spp->sp_next_list, attr); 4016 syn_list_flags(namelist2, spp->sp_flags, attr); 4017 } 4018 if (spp->sp_flags & (HL_SYNC_HERE|HL_SYNC_THERE)) 4019 { 4020 if (spp->sp_flags & HL_SYNC_HERE) 4021 msg_puts_attr("grouphere", attr); 4022 else 4023 msg_puts_attr("groupthere", attr); 4024 msg_putchar(' '); 4025 if (spp->sp_sync_idx >= 0) 4026 msg_outtrans(highlight_group_name(SYN_ITEMS(curwin->w_s) 4027 [spp->sp_sync_idx].sp_syn.id - 1)); 4028 else 4029 msg_puts("NONE"); 4030 msg_putchar(' '); 4031 } 4032 } 4033 4034 // list the link, if there is one 4035 if (highlight_link_id(id - 1) && (did_header || link_only) && !got_int) 4036 { 4037 (void)syn_list_header(did_header, 999, id); 4038 msg_puts_attr("links to", attr); 4039 msg_putchar(' '); 4040 msg_outtrans(highlight_group_name(highlight_link_id(id - 1) - 1)); 4041 } 4042 } 4043 4044 static void 4045 syn_list_flags(struct name_list *nlist, int flags, int attr) 4046 { 4047 int i; 4048 4049 for (i = 0; nlist[i].flag != 0; ++i) 4050 if (flags & nlist[i].flag) 4051 { 4052 msg_puts_attr(nlist[i].name, attr); 4053 msg_putchar(' '); 4054 } 4055 } 4056 4057 /* 4058 * List one syntax cluster, for ":syntax" or "syntax list syntax_name". 4059 */ 4060 static void 4061 syn_list_cluster(int id) 4062 { 4063 int endcol = 15; 4064 4065 // slight hack: roughly duplicate the guts of syn_list_header() 4066 msg_putchar('\n'); 4067 msg_outtrans(SYN_CLSTR(curwin->w_s)[id].scl_name); 4068 4069 if (msg_col >= endcol) // output at least one space 4070 endcol = msg_col + 1; 4071 if (Columns <= endcol) // avoid hang for tiny window 4072 endcol = Columns - 1; 4073 4074 msg_advance(endcol); 4075 if (SYN_CLSTR(curwin->w_s)[id].scl_list != NULL) 4076 { 4077 put_id_list((char_u *)"cluster", SYN_CLSTR(curwin->w_s)[id].scl_list, 4078 HL_ATTR(HLF_D)); 4079 } 4080 else 4081 { 4082 msg_puts_attr("cluster", HL_ATTR(HLF_D)); 4083 msg_puts("=NONE"); 4084 } 4085 } 4086 4087 static void 4088 put_id_list(char_u *name, short *list, int attr) 4089 { 4090 short *p; 4091 4092 msg_puts_attr((char *)name, attr); 4093 msg_putchar('='); 4094 for (p = list; *p; ++p) 4095 { 4096 if (*p >= SYNID_ALLBUT && *p < SYNID_TOP) 4097 { 4098 if (p[1]) 4099 msg_puts("ALLBUT"); 4100 else 4101 msg_puts("ALL"); 4102 } 4103 else if (*p >= SYNID_TOP && *p < SYNID_CONTAINED) 4104 { 4105 msg_puts("TOP"); 4106 } 4107 else if (*p >= SYNID_CONTAINED && *p < SYNID_CLUSTER) 4108 { 4109 msg_puts("CONTAINED"); 4110 } 4111 else if (*p >= SYNID_CLUSTER) 4112 { 4113 short scl_id = *p - SYNID_CLUSTER; 4114 4115 msg_putchar('@'); 4116 msg_outtrans(SYN_CLSTR(curwin->w_s)[scl_id].scl_name); 4117 } 4118 else 4119 msg_outtrans(highlight_group_name(*p - 1)); 4120 if (p[1]) 4121 msg_putchar(','); 4122 } 4123 msg_putchar(' '); 4124 } 4125 4126 static void 4127 put_pattern( 4128 char *s, 4129 int c, 4130 synpat_T *spp, 4131 int attr) 4132 { 4133 long n; 4134 int mask; 4135 int first; 4136 static char *sepchars = "/+=-#@\"|'^&"; 4137 int i; 4138 4139 // May have to write "matchgroup=group" 4140 if (last_matchgroup != spp->sp_syn_match_id) 4141 { 4142 last_matchgroup = spp->sp_syn_match_id; 4143 msg_puts_attr("matchgroup", attr); 4144 msg_putchar('='); 4145 if (last_matchgroup == 0) 4146 msg_outtrans((char_u *)"NONE"); 4147 else 4148 msg_outtrans(highlight_group_name(last_matchgroup - 1)); 4149 msg_putchar(' '); 4150 } 4151 4152 // output the name of the pattern and an '=' or ' ' 4153 msg_puts_attr(s, attr); 4154 msg_putchar(c); 4155 4156 // output the pattern, in between a char that is not in the pattern 4157 for (i = 0; vim_strchr(spp->sp_pattern, sepchars[i]) != NULL; ) 4158 if (sepchars[++i] == NUL) 4159 { 4160 i = 0; // no good char found, just use the first one 4161 break; 4162 } 4163 msg_putchar(sepchars[i]); 4164 msg_outtrans(spp->sp_pattern); 4165 msg_putchar(sepchars[i]); 4166 4167 // output any pattern options 4168 first = TRUE; 4169 for (i = 0; i < SPO_COUNT; ++i) 4170 { 4171 mask = (1 << i); 4172 if (spp->sp_off_flags & (mask + (mask << SPO_COUNT))) 4173 { 4174 if (!first) 4175 msg_putchar(','); // separate with commas 4176 msg_puts(spo_name_tab[i]); 4177 n = spp->sp_offsets[i]; 4178 if (i != SPO_LC_OFF) 4179 { 4180 if (spp->sp_off_flags & mask) 4181 msg_putchar('s'); 4182 else 4183 msg_putchar('e'); 4184 if (n > 0) 4185 msg_putchar('+'); 4186 } 4187 if (n || i == SPO_LC_OFF) 4188 msg_outnum(n); 4189 first = FALSE; 4190 } 4191 } 4192 msg_putchar(' '); 4193 } 4194 4195 /* 4196 * List or clear the keywords for one syntax group. 4197 * Return TRUE if the header has been printed. 4198 */ 4199 static int 4200 syn_list_keywords( 4201 int id, 4202 hashtab_T *ht, 4203 int did_header, // header has already been printed 4204 int attr) 4205 { 4206 int outlen; 4207 hashitem_T *hi; 4208 keyentry_T *kp; 4209 int todo; 4210 int prev_contained = 0; 4211 short *prev_next_list = NULL; 4212 short *prev_cont_in_list = NULL; 4213 int prev_skipnl = 0; 4214 int prev_skipwhite = 0; 4215 int prev_skipempty = 0; 4216 4217 /* 4218 * Unfortunately, this list of keywords is not sorted on alphabet but on 4219 * hash value... 4220 */ 4221 todo = (int)ht->ht_used; 4222 for (hi = ht->ht_array; todo > 0 && !got_int; ++hi) 4223 { 4224 if (!HASHITEM_EMPTY(hi)) 4225 { 4226 --todo; 4227 for (kp = HI2KE(hi); kp != NULL && !got_int; kp = kp->ke_next) 4228 { 4229 if (kp->k_syn.id == id) 4230 { 4231 if (prev_contained != (kp->flags & HL_CONTAINED) 4232 || prev_skipnl != (kp->flags & HL_SKIPNL) 4233 || prev_skipwhite != (kp->flags & HL_SKIPWHITE) 4234 || prev_skipempty != (kp->flags & HL_SKIPEMPTY) 4235 || prev_cont_in_list != kp->k_syn.cont_in_list 4236 || prev_next_list != kp->next_list) 4237 outlen = 9999; 4238 else 4239 outlen = (int)STRLEN(kp->keyword); 4240 // output "contained" and "nextgroup" on each line 4241 if (syn_list_header(did_header, outlen, id)) 4242 { 4243 prev_contained = 0; 4244 prev_next_list = NULL; 4245 prev_cont_in_list = NULL; 4246 prev_skipnl = 0; 4247 prev_skipwhite = 0; 4248 prev_skipempty = 0; 4249 } 4250 did_header = TRUE; 4251 if (prev_contained != (kp->flags & HL_CONTAINED)) 4252 { 4253 msg_puts_attr("contained", attr); 4254 msg_putchar(' '); 4255 prev_contained = (kp->flags & HL_CONTAINED); 4256 } 4257 if (kp->k_syn.cont_in_list != prev_cont_in_list) 4258 { 4259 put_id_list((char_u *)"containedin", 4260 kp->k_syn.cont_in_list, attr); 4261 msg_putchar(' '); 4262 prev_cont_in_list = kp->k_syn.cont_in_list; 4263 } 4264 if (kp->next_list != prev_next_list) 4265 { 4266 put_id_list((char_u *)"nextgroup", kp->next_list, attr); 4267 msg_putchar(' '); 4268 prev_next_list = kp->next_list; 4269 if (kp->flags & HL_SKIPNL) 4270 { 4271 msg_puts_attr("skipnl", attr); 4272 msg_putchar(' '); 4273 prev_skipnl = (kp->flags & HL_SKIPNL); 4274 } 4275 if (kp->flags & HL_SKIPWHITE) 4276 { 4277 msg_puts_attr("skipwhite", attr); 4278 msg_putchar(' '); 4279 prev_skipwhite = (kp->flags & HL_SKIPWHITE); 4280 } 4281 if (kp->flags & HL_SKIPEMPTY) 4282 { 4283 msg_puts_attr("skipempty", attr); 4284 msg_putchar(' '); 4285 prev_skipempty = (kp->flags & HL_SKIPEMPTY); 4286 } 4287 } 4288 msg_outtrans(kp->keyword); 4289 } 4290 } 4291 } 4292 } 4293 4294 return did_header; 4295 } 4296 4297 static void 4298 syn_clear_keyword(int id, hashtab_T *ht) 4299 { 4300 hashitem_T *hi; 4301 keyentry_T *kp; 4302 keyentry_T *kp_prev; 4303 keyentry_T *kp_next; 4304 int todo; 4305 4306 hash_lock(ht); 4307 todo = (int)ht->ht_used; 4308 for (hi = ht->ht_array; todo > 0; ++hi) 4309 { 4310 if (!HASHITEM_EMPTY(hi)) 4311 { 4312 --todo; 4313 kp_prev = NULL; 4314 for (kp = HI2KE(hi); kp != NULL; ) 4315 { 4316 if (kp->k_syn.id == id) 4317 { 4318 kp_next = kp->ke_next; 4319 if (kp_prev == NULL) 4320 { 4321 if (kp_next == NULL) 4322 hash_remove(ht, hi); 4323 else 4324 hi->hi_key = KE2HIKEY(kp_next); 4325 } 4326 else 4327 kp_prev->ke_next = kp_next; 4328 vim_free(kp->next_list); 4329 vim_free(kp->k_syn.cont_in_list); 4330 vim_free(kp); 4331 kp = kp_next; 4332 } 4333 else 4334 { 4335 kp_prev = kp; 4336 kp = kp->ke_next; 4337 } 4338 } 4339 } 4340 } 4341 hash_unlock(ht); 4342 } 4343 4344 /* 4345 * Clear a whole keyword table. 4346 */ 4347 static void 4348 clear_keywtab(hashtab_T *ht) 4349 { 4350 hashitem_T *hi; 4351 int todo; 4352 keyentry_T *kp; 4353 keyentry_T *kp_next; 4354 4355 todo = (int)ht->ht_used; 4356 for (hi = ht->ht_array; todo > 0; ++hi) 4357 { 4358 if (!HASHITEM_EMPTY(hi)) 4359 { 4360 --todo; 4361 for (kp = HI2KE(hi); kp != NULL; kp = kp_next) 4362 { 4363 kp_next = kp->ke_next; 4364 vim_free(kp->next_list); 4365 vim_free(kp->k_syn.cont_in_list); 4366 vim_free(kp); 4367 } 4368 } 4369 } 4370 hash_clear(ht); 4371 hash_init(ht); 4372 } 4373 4374 /* 4375 * Add a keyword to the list of keywords. 4376 */ 4377 static void 4378 add_keyword( 4379 char_u *name, // name of keyword 4380 int id, // group ID for this keyword 4381 int flags, // flags for this keyword 4382 short *cont_in_list, // containedin for this keyword 4383 short *next_list, // nextgroup for this keyword 4384 int conceal_char) 4385 { 4386 keyentry_T *kp; 4387 hashtab_T *ht; 4388 hashitem_T *hi; 4389 char_u *name_ic; 4390 long_u hash; 4391 char_u name_folded[MAXKEYWLEN + 1]; 4392 4393 if (curwin->w_s->b_syn_ic) 4394 name_ic = str_foldcase(name, (int)STRLEN(name), 4395 name_folded, MAXKEYWLEN + 1); 4396 else 4397 name_ic = name; 4398 kp = alloc(offsetof(keyentry_T, keyword) + STRLEN(name_ic) + 1); 4399 if (kp == NULL) 4400 return; 4401 STRCPY(kp->keyword, name_ic); 4402 kp->k_syn.id = id; 4403 kp->k_syn.inc_tag = current_syn_inc_tag; 4404 kp->flags = flags; 4405 kp->k_char = conceal_char; 4406 kp->k_syn.cont_in_list = copy_id_list(cont_in_list); 4407 if (cont_in_list != NULL) 4408 curwin->w_s->b_syn_containedin = TRUE; 4409 kp->next_list = copy_id_list(next_list); 4410 4411 if (curwin->w_s->b_syn_ic) 4412 ht = &curwin->w_s->b_keywtab_ic; 4413 else 4414 ht = &curwin->w_s->b_keywtab; 4415 4416 hash = hash_hash(kp->keyword); 4417 hi = hash_lookup(ht, kp->keyword, hash); 4418 if (HASHITEM_EMPTY(hi)) 4419 { 4420 // new keyword, add to hashtable 4421 kp->ke_next = NULL; 4422 hash_add_item(ht, hi, kp->keyword, hash); 4423 } 4424 else 4425 { 4426 // keyword already exists, prepend to list 4427 kp->ke_next = HI2KE(hi); 4428 hi->hi_key = KE2HIKEY(kp); 4429 } 4430 } 4431 4432 /* 4433 * Get the start and end of the group name argument. 4434 * Return a pointer to the first argument. 4435 * Return NULL if the end of the command was found instead of further args. 4436 */ 4437 static char_u * 4438 get_group_name( 4439 char_u *arg, // start of the argument 4440 char_u **name_end) // pointer to end of the name 4441 { 4442 char_u *rest; 4443 4444 *name_end = skiptowhite(arg); 4445 rest = skipwhite(*name_end); 4446 4447 /* 4448 * Check if there are enough arguments. The first argument may be a 4449 * pattern, where '|' is allowed, so only check for NUL. 4450 */ 4451 if (ends_excmd(*arg) || *rest == NUL) 4452 return NULL; 4453 return rest; 4454 } 4455 4456 /* 4457 * Check for syntax command option arguments. 4458 * This can be called at any place in the list of arguments, and just picks 4459 * out the arguments that are known. Can be called several times in a row to 4460 * collect all options in between other arguments. 4461 * Return a pointer to the next argument (which isn't an option). 4462 * Return NULL for any error; 4463 */ 4464 static char_u * 4465 get_syn_options( 4466 char_u *start, // next argument to be checked 4467 syn_opt_arg_T *opt, // various things 4468 int *conceal_char UNUSED, 4469 int skip) // TRUE if skipping over command 4470 { 4471 char_u *arg = start; 4472 char_u *gname_start, *gname; 4473 int syn_id; 4474 int len; 4475 char *p; 4476 int i; 4477 int fidx; 4478 static struct flag 4479 { 4480 char *name; 4481 int argtype; 4482 int flags; 4483 } flagtab[] = { {"cCoOnNtTaAiInNeEdD", 0, HL_CONTAINED}, 4484 {"oOnNeElLiInNeE", 0, HL_ONELINE}, 4485 {"kKeEeEpPeEnNdD", 0, HL_KEEPEND}, 4486 {"eExXtTeEnNdD", 0, HL_EXTEND}, 4487 {"eExXcClLuUdDeEnNlL", 0, HL_EXCLUDENL}, 4488 {"tTrRaAnNsSpPaArReEnNtT", 0, HL_TRANSP}, 4489 {"sSkKiIpPnNlL", 0, HL_SKIPNL}, 4490 {"sSkKiIpPwWhHiItTeE", 0, HL_SKIPWHITE}, 4491 {"sSkKiIpPeEmMpPtTyY", 0, HL_SKIPEMPTY}, 4492 {"gGrRoOuUpPhHeErReE", 0, HL_SYNC_HERE}, 4493 {"gGrRoOuUpPtThHeErReE", 0, HL_SYNC_THERE}, 4494 {"dDiIsSpPlLaAyY", 0, HL_DISPLAY}, 4495 {"fFoOlLdD", 0, HL_FOLD}, 4496 {"cCoOnNcCeEaAlL", 0, HL_CONCEAL}, 4497 {"cCoOnNcCeEaAlLeEnNdDsS", 0, HL_CONCEALENDS}, 4498 {"cCcChHaArR", 11, 0}, 4499 {"cCoOnNtTaAiInNsS", 1, 0}, 4500 {"cCoOnNtTaAiInNeEdDiInN", 2, 0}, 4501 {"nNeExXtTgGrRoOuUpP", 3, 0}, 4502 }; 4503 static char *first_letters = "cCoOkKeEtTsSgGdDfFnN"; 4504 4505 if (arg == NULL) // already detected error 4506 return NULL; 4507 4508 #ifdef FEAT_CONCEAL 4509 if (curwin->w_s->b_syn_conceal) 4510 opt->flags |= HL_CONCEAL; 4511 #endif 4512 4513 for (;;) 4514 { 4515 /* 4516 * This is used very often when a large number of keywords is defined. 4517 * Need to skip quickly when no option name is found. 4518 * Also avoid tolower(), it's slow. 4519 */ 4520 if (strchr(first_letters, *arg) == NULL) 4521 break; 4522 4523 for (fidx = sizeof(flagtab) / sizeof(struct flag); --fidx >= 0; ) 4524 { 4525 p = flagtab[fidx].name; 4526 for (i = 0, len = 0; p[i] != NUL; i += 2, ++len) 4527 if (arg[len] != p[i] && arg[len] != p[i + 1]) 4528 break; 4529 if (p[i] == NUL && (VIM_ISWHITE(arg[len]) 4530 || (flagtab[fidx].argtype > 0 4531 ? arg[len] == '=' 4532 : ends_excmd2(start, arg + len)))) 4533 { 4534 if (opt->keyword 4535 && (flagtab[fidx].flags == HL_DISPLAY 4536 || flagtab[fidx].flags == HL_FOLD 4537 || flagtab[fidx].flags == HL_EXTEND)) 4538 // treat "display", "fold" and "extend" as a keyword 4539 fidx = -1; 4540 break; 4541 } 4542 } 4543 if (fidx < 0) // no match found 4544 break; 4545 4546 if (flagtab[fidx].argtype == 1) 4547 { 4548 if (!opt->has_cont_list) 4549 { 4550 emsg(_("E395: contains argument not accepted here")); 4551 return NULL; 4552 } 4553 if (get_id_list(&arg, 8, &opt->cont_list, skip) == FAIL) 4554 return NULL; 4555 } 4556 else if (flagtab[fidx].argtype == 2) 4557 { 4558 if (get_id_list(&arg, 11, &opt->cont_in_list, skip) == FAIL) 4559 return NULL; 4560 } 4561 else if (flagtab[fidx].argtype == 3) 4562 { 4563 if (get_id_list(&arg, 9, &opt->next_list, skip) == FAIL) 4564 return NULL; 4565 } 4566 else if (flagtab[fidx].argtype == 11 && arg[5] == '=') 4567 { 4568 // cchar=? 4569 if (has_mbyte) 4570 { 4571 #ifdef FEAT_CONCEAL 4572 *conceal_char = mb_ptr2char(arg + 6); 4573 #endif 4574 arg += mb_ptr2len(arg + 6) - 1; 4575 } 4576 else 4577 { 4578 #ifdef FEAT_CONCEAL 4579 *conceal_char = arg[6]; 4580 #else 4581 ; 4582 #endif 4583 } 4584 #ifdef FEAT_CONCEAL 4585 if (!vim_isprintc_strict(*conceal_char)) 4586 { 4587 emsg(_("E844: invalid cchar value")); 4588 return NULL; 4589 } 4590 #endif 4591 arg = skipwhite(arg + 7); 4592 } 4593 else 4594 { 4595 opt->flags |= flagtab[fidx].flags; 4596 arg = skipwhite(arg + len); 4597 4598 if (flagtab[fidx].flags == HL_SYNC_HERE 4599 || flagtab[fidx].flags == HL_SYNC_THERE) 4600 { 4601 if (opt->sync_idx == NULL) 4602 { 4603 emsg(_("E393: group[t]here not accepted here")); 4604 return NULL; 4605 } 4606 gname_start = arg; 4607 arg = skiptowhite(arg); 4608 if (gname_start == arg) 4609 return NULL; 4610 gname = vim_strnsave(gname_start, (int)(arg - gname_start)); 4611 if (gname == NULL) 4612 return NULL; 4613 if (STRCMP(gname, "NONE") == 0) 4614 *opt->sync_idx = NONE_IDX; 4615 else 4616 { 4617 syn_id = syn_name2id(gname); 4618 for (i = curwin->w_s->b_syn_patterns.ga_len; --i >= 0; ) 4619 if (SYN_ITEMS(curwin->w_s)[i].sp_syn.id == syn_id 4620 && SYN_ITEMS(curwin->w_s)[i].sp_type == SPTYPE_START) 4621 { 4622 *opt->sync_idx = i; 4623 break; 4624 } 4625 if (i < 0) 4626 { 4627 semsg(_("E394: Didn't find region item for %s"), gname); 4628 vim_free(gname); 4629 return NULL; 4630 } 4631 } 4632 4633 vim_free(gname); 4634 arg = skipwhite(arg); 4635 } 4636 #ifdef FEAT_FOLDING 4637 else if (flagtab[fidx].flags == HL_FOLD 4638 && foldmethodIsSyntax(curwin)) 4639 // Need to update folds later. 4640 foldUpdateAll(curwin); 4641 #endif 4642 } 4643 } 4644 4645 return arg; 4646 } 4647 4648 /* 4649 * Adjustments to syntax item when declared in a ":syn include"'d file. 4650 * Set the contained flag, and if the item is not already contained, add it 4651 * to the specified top-level group, if any. 4652 */ 4653 static void 4654 syn_incl_toplevel(int id, int *flagsp) 4655 { 4656 if ((*flagsp & HL_CONTAINED) || curwin->w_s->b_syn_topgrp == 0) 4657 return; 4658 *flagsp |= HL_CONTAINED; 4659 if (curwin->w_s->b_syn_topgrp >= SYNID_CLUSTER) 4660 { 4661 // We have to alloc this, because syn_combine_list() will free it. 4662 short *grp_list = ALLOC_MULT(short, 2); 4663 int tlg_id = curwin->w_s->b_syn_topgrp - SYNID_CLUSTER; 4664 4665 if (grp_list != NULL) 4666 { 4667 grp_list[0] = id; 4668 grp_list[1] = 0; 4669 syn_combine_list(&SYN_CLSTR(curwin->w_s)[tlg_id].scl_list, 4670 &grp_list, CLUSTER_ADD); 4671 } 4672 } 4673 } 4674 4675 /* 4676 * Handle ":syntax include [@{group-name}] filename" command. 4677 */ 4678 static void 4679 syn_cmd_include(exarg_T *eap, int syncing UNUSED) 4680 { 4681 char_u *arg = eap->arg; 4682 int sgl_id = 1; 4683 char_u *group_name_end; 4684 char_u *rest; 4685 char *errormsg = NULL; 4686 int prev_toplvl_grp; 4687 int prev_syn_inc_tag; 4688 int source = FALSE; 4689 4690 eap->nextcmd = find_nextcmd(arg); 4691 if (eap->skip) 4692 return; 4693 4694 if (arg[0] == '@') 4695 { 4696 ++arg; 4697 rest = get_group_name(arg, &group_name_end); 4698 if (rest == NULL) 4699 { 4700 emsg(_("E397: Filename required")); 4701 return; 4702 } 4703 sgl_id = syn_check_cluster(arg, (int)(group_name_end - arg)); 4704 if (sgl_id == 0) 4705 return; 4706 // separate_nextcmd() and expand_filename() depend on this 4707 eap->arg = rest; 4708 } 4709 4710 /* 4711 * Everything that's left, up to the next command, should be the 4712 * filename to include. 4713 */ 4714 eap->argt |= (EX_XFILE | EX_NOSPC); 4715 separate_nextcmd(eap); 4716 if (*eap->arg == '<' || *eap->arg == '$' || mch_isFullName(eap->arg)) 4717 { 4718 // For an absolute path, "$VIM/..." or "<sfile>.." we ":source" the 4719 // file. Need to expand the file name first. In other cases 4720 // ":runtime!" is used. 4721 source = TRUE; 4722 if (expand_filename(eap, syn_cmdlinep, &errormsg) == FAIL) 4723 { 4724 if (errormsg != NULL) 4725 emsg(errormsg); 4726 return; 4727 } 4728 } 4729 4730 /* 4731 * Save and restore the existing top-level grouplist id and ":syn 4732 * include" tag around the actual inclusion. 4733 */ 4734 if (running_syn_inc_tag >= MAX_SYN_INC_TAG) 4735 { 4736 emsg(_("E847: Too many syntax includes")); 4737 return; 4738 } 4739 prev_syn_inc_tag = current_syn_inc_tag; 4740 current_syn_inc_tag = ++running_syn_inc_tag; 4741 prev_toplvl_grp = curwin->w_s->b_syn_topgrp; 4742 curwin->w_s->b_syn_topgrp = sgl_id; 4743 if (source ? do_source(eap->arg, FALSE, DOSO_NONE, NULL) == FAIL 4744 : source_runtime(eap->arg, DIP_ALL) == FAIL) 4745 semsg(_(e_notopen), eap->arg); 4746 curwin->w_s->b_syn_topgrp = prev_toplvl_grp; 4747 current_syn_inc_tag = prev_syn_inc_tag; 4748 } 4749 4750 /* 4751 * Handle ":syntax keyword {group-name} [{option}] keyword .." command. 4752 */ 4753 static void 4754 syn_cmd_keyword(exarg_T *eap, int syncing UNUSED) 4755 { 4756 char_u *arg = eap->arg; 4757 char_u *group_name_end; 4758 int syn_id; 4759 char_u *rest; 4760 char_u *keyword_copy = NULL; 4761 char_u *p; 4762 char_u *kw; 4763 syn_opt_arg_T syn_opt_arg; 4764 int cnt; 4765 int conceal_char = NUL; 4766 4767 rest = get_group_name(arg, &group_name_end); 4768 4769 if (rest != NULL) 4770 { 4771 if (eap->skip) 4772 syn_id = -1; 4773 else 4774 syn_id = syn_check_group(arg, (int)(group_name_end - arg)); 4775 if (syn_id != 0) 4776 // allocate a buffer, for removing backslashes in the keyword 4777 keyword_copy = alloc(STRLEN(rest) + 1); 4778 if (keyword_copy != NULL) 4779 { 4780 syn_opt_arg.flags = 0; 4781 syn_opt_arg.keyword = TRUE; 4782 syn_opt_arg.sync_idx = NULL; 4783 syn_opt_arg.has_cont_list = FALSE; 4784 syn_opt_arg.cont_in_list = NULL; 4785 syn_opt_arg.next_list = NULL; 4786 4787 /* 4788 * The options given apply to ALL keywords, so all options must be 4789 * found before keywords can be created. 4790 * 1: collect the options and copy the keywords to keyword_copy. 4791 */ 4792 cnt = 0; 4793 p = keyword_copy; 4794 for ( ; rest != NULL && !ends_excmd2(eap->arg, rest); 4795 rest = skipwhite(rest)) 4796 { 4797 rest = get_syn_options(rest, &syn_opt_arg, &conceal_char, 4798 eap->skip); 4799 if (rest == NULL || ends_excmd2(eap->arg, rest)) 4800 break; 4801 // Copy the keyword, removing backslashes, and add a NUL. 4802 while (*rest != NUL && !VIM_ISWHITE(*rest)) 4803 { 4804 if (*rest == '\\' && rest[1] != NUL) 4805 ++rest; 4806 *p++ = *rest++; 4807 } 4808 *p++ = NUL; 4809 ++cnt; 4810 } 4811 4812 if (!eap->skip) 4813 { 4814 // Adjust flags for use of ":syn include". 4815 syn_incl_toplevel(syn_id, &syn_opt_arg.flags); 4816 4817 /* 4818 * 2: Add an entry for each keyword. 4819 */ 4820 for (kw = keyword_copy; --cnt >= 0; kw += STRLEN(kw) + 1) 4821 { 4822 for (p = vim_strchr(kw, '['); ; ) 4823 { 4824 if (p != NULL) 4825 *p = NUL; 4826 add_keyword(kw, syn_id, syn_opt_arg.flags, 4827 syn_opt_arg.cont_in_list, 4828 syn_opt_arg.next_list, conceal_char); 4829 if (p == NULL) 4830 break; 4831 if (p[1] == NUL) 4832 { 4833 semsg(_("E789: Missing ']': %s"), kw); 4834 goto error; 4835 } 4836 if (p[1] == ']') 4837 { 4838 if (p[2] != NUL) 4839 { 4840 semsg(_("E890: trailing char after ']': %s]%s"), 4841 kw, &p[2]); 4842 goto error; 4843 } 4844 kw = p + 1; // skip over the "]" 4845 break; 4846 } 4847 if (has_mbyte) 4848 { 4849 int l = (*mb_ptr2len)(p + 1); 4850 4851 mch_memmove(p, p + 1, l); 4852 p += l; 4853 } 4854 else 4855 { 4856 p[0] = p[1]; 4857 ++p; 4858 } 4859 } 4860 } 4861 } 4862 error: 4863 vim_free(keyword_copy); 4864 vim_free(syn_opt_arg.cont_in_list); 4865 vim_free(syn_opt_arg.next_list); 4866 } 4867 } 4868 4869 if (rest != NULL) 4870 eap->nextcmd = check_nextcmd(rest); 4871 else 4872 semsg(_(e_invarg2), arg); 4873 4874 redraw_curbuf_later(SOME_VALID); 4875 syn_stack_free_all(curwin->w_s); // Need to recompute all syntax. 4876 } 4877 4878 /* 4879 * Handle ":syntax match {name} [{options}] {pattern} [{options}]". 4880 * 4881 * Also ":syntax sync match {name} [[grouphere | groupthere] {group-name}] .." 4882 */ 4883 static void 4884 syn_cmd_match( 4885 exarg_T *eap, 4886 int syncing) // TRUE for ":syntax sync match .. " 4887 { 4888 char_u *arg = eap->arg; 4889 char_u *group_name_end; 4890 char_u *rest; 4891 synpat_T item; // the item found in the line 4892 int syn_id; 4893 int idx; 4894 syn_opt_arg_T syn_opt_arg; 4895 int sync_idx = 0; 4896 int conceal_char = NUL; 4897 int orig_called_emsg = called_emsg; 4898 4899 // Isolate the group name, check for validity 4900 rest = get_group_name(arg, &group_name_end); 4901 4902 // Get options before the pattern 4903 syn_opt_arg.flags = 0; 4904 syn_opt_arg.keyword = FALSE; 4905 syn_opt_arg.sync_idx = syncing ? &sync_idx : NULL; 4906 syn_opt_arg.has_cont_list = TRUE; 4907 syn_opt_arg.cont_list = NULL; 4908 syn_opt_arg.cont_in_list = NULL; 4909 syn_opt_arg.next_list = NULL; 4910 rest = get_syn_options(rest, &syn_opt_arg, &conceal_char, eap->skip); 4911 4912 // get the pattern. 4913 init_syn_patterns(); 4914 CLEAR_FIELD(item); 4915 rest = get_syn_pattern(rest, &item); 4916 if (vim_regcomp_had_eol() && !(syn_opt_arg.flags & HL_EXCLUDENL)) 4917 syn_opt_arg.flags |= HL_HAS_EOL; 4918 4919 // Get options after the pattern 4920 rest = get_syn_options(rest, &syn_opt_arg, &conceal_char, eap->skip); 4921 4922 if (rest != NULL) // all arguments are valid 4923 { 4924 /* 4925 * Check for trailing command and illegal trailing arguments. 4926 */ 4927 eap->nextcmd = check_nextcmd(rest); 4928 if (!ends_excmd2(eap->cmd, rest) || eap->skip) 4929 rest = NULL; 4930 else if (ga_grow(&curwin->w_s->b_syn_patterns, 1) != FAIL 4931 && (syn_id = syn_check_group(arg, 4932 (int)(group_name_end - arg))) != 0) 4933 { 4934 syn_incl_toplevel(syn_id, &syn_opt_arg.flags); 4935 /* 4936 * Store the pattern in the syn_items list 4937 */ 4938 idx = curwin->w_s->b_syn_patterns.ga_len; 4939 SYN_ITEMS(curwin->w_s)[idx] = item; 4940 SYN_ITEMS(curwin->w_s)[idx].sp_syncing = syncing; 4941 SYN_ITEMS(curwin->w_s)[idx].sp_type = SPTYPE_MATCH; 4942 SYN_ITEMS(curwin->w_s)[idx].sp_syn.id = syn_id; 4943 SYN_ITEMS(curwin->w_s)[idx].sp_syn.inc_tag = current_syn_inc_tag; 4944 SYN_ITEMS(curwin->w_s)[idx].sp_flags = syn_opt_arg.flags; 4945 SYN_ITEMS(curwin->w_s)[idx].sp_sync_idx = sync_idx; 4946 SYN_ITEMS(curwin->w_s)[idx].sp_cont_list = syn_opt_arg.cont_list; 4947 SYN_ITEMS(curwin->w_s)[idx].sp_syn.cont_in_list = 4948 syn_opt_arg.cont_in_list; 4949 #ifdef FEAT_CONCEAL 4950 SYN_ITEMS(curwin->w_s)[idx].sp_cchar = conceal_char; 4951 #endif 4952 if (syn_opt_arg.cont_in_list != NULL) 4953 curwin->w_s->b_syn_containedin = TRUE; 4954 SYN_ITEMS(curwin->w_s)[idx].sp_next_list = syn_opt_arg.next_list; 4955 ++curwin->w_s->b_syn_patterns.ga_len; 4956 4957 // remember that we found a match for syncing on 4958 if (syn_opt_arg.flags & (HL_SYNC_HERE|HL_SYNC_THERE)) 4959 curwin->w_s->b_syn_sync_flags |= SF_MATCH; 4960 #ifdef FEAT_FOLDING 4961 if (syn_opt_arg.flags & HL_FOLD) 4962 ++curwin->w_s->b_syn_folditems; 4963 #endif 4964 4965 redraw_curbuf_later(SOME_VALID); 4966 syn_stack_free_all(curwin->w_s); // Need to recompute all syntax. 4967 return; // don't free the progs and patterns now 4968 } 4969 } 4970 4971 /* 4972 * Something failed, free the allocated memory. 4973 */ 4974 vim_regfree(item.sp_prog); 4975 vim_free(item.sp_pattern); 4976 vim_free(syn_opt_arg.cont_list); 4977 vim_free(syn_opt_arg.cont_in_list); 4978 vim_free(syn_opt_arg.next_list); 4979 4980 if (rest == NULL && called_emsg == orig_called_emsg) 4981 semsg(_(e_invarg2), arg); 4982 } 4983 4984 /* 4985 * Handle ":syntax region {group-name} [matchgroup={group-name}] 4986 * start {start} .. [skip {skip}] end {end} .. [{options}]". 4987 */ 4988 static void 4989 syn_cmd_region( 4990 exarg_T *eap, 4991 int syncing) // TRUE for ":syntax sync region .." 4992 { 4993 char_u *arg = eap->arg; 4994 char_u *group_name_end; 4995 char_u *rest; // next arg, NULL on error 4996 char_u *key_end; 4997 char_u *key = NULL; 4998 char_u *p; 4999 int item; 5000 #define ITEM_START 0 5001 #define ITEM_SKIP 1 5002 #define ITEM_END 2 5003 #define ITEM_MATCHGROUP 3 5004 struct pat_ptr 5005 { 5006 synpat_T *pp_synp; // pointer to syn_pattern 5007 int pp_matchgroup_id; // matchgroup ID 5008 struct pat_ptr *pp_next; // pointer to next pat_ptr 5009 } *(pat_ptrs[3]); 5010 // patterns found in the line 5011 struct pat_ptr *ppp; 5012 struct pat_ptr *ppp_next; 5013 int pat_count = 0; // nr of syn_patterns found 5014 int syn_id; 5015 int matchgroup_id = 0; 5016 int not_enough = FALSE; // not enough arguments 5017 int illegal = FALSE; // illegal arguments 5018 int success = FALSE; 5019 int idx; 5020 syn_opt_arg_T syn_opt_arg; 5021 int conceal_char = NUL; 5022 5023 // Isolate the group name, check for validity 5024 rest = get_group_name(arg, &group_name_end); 5025 5026 pat_ptrs[0] = NULL; 5027 pat_ptrs[1] = NULL; 5028 pat_ptrs[2] = NULL; 5029 5030 init_syn_patterns(); 5031 5032 syn_opt_arg.flags = 0; 5033 syn_opt_arg.keyword = FALSE; 5034 syn_opt_arg.sync_idx = NULL; 5035 syn_opt_arg.has_cont_list = TRUE; 5036 syn_opt_arg.cont_list = NULL; 5037 syn_opt_arg.cont_in_list = NULL; 5038 syn_opt_arg.next_list = NULL; 5039 5040 /* 5041 * get the options, patterns and matchgroup. 5042 */ 5043 while (rest != NULL && !ends_excmd2(eap->cmd, rest)) 5044 { 5045 // Check for option arguments 5046 rest = get_syn_options(rest, &syn_opt_arg, &conceal_char, eap->skip); 5047 if (rest == NULL || ends_excmd2(eap->cmd, rest)) 5048 break; 5049 5050 // must be a pattern or matchgroup then 5051 key_end = rest; 5052 while (*key_end && !VIM_ISWHITE(*key_end) && *key_end != '=') 5053 ++key_end; 5054 vim_free(key); 5055 key = vim_strnsave_up(rest, (int)(key_end - rest)); 5056 if (key == NULL) // out of memory 5057 { 5058 rest = NULL; 5059 break; 5060 } 5061 if (STRCMP(key, "MATCHGROUP") == 0) 5062 item = ITEM_MATCHGROUP; 5063 else if (STRCMP(key, "START") == 0) 5064 item = ITEM_START; 5065 else if (STRCMP(key, "END") == 0) 5066 item = ITEM_END; 5067 else if (STRCMP(key, "SKIP") == 0) 5068 { 5069 if (pat_ptrs[ITEM_SKIP] != NULL) // one skip pattern allowed 5070 { 5071 illegal = TRUE; 5072 break; 5073 } 5074 item = ITEM_SKIP; 5075 } 5076 else 5077 break; 5078 rest = skipwhite(key_end); 5079 if (*rest != '=') 5080 { 5081 rest = NULL; 5082 semsg(_("E398: Missing '=': %s"), arg); 5083 break; 5084 } 5085 rest = skipwhite(rest + 1); 5086 if (*rest == NUL) 5087 { 5088 not_enough = TRUE; 5089 break; 5090 } 5091 5092 if (item == ITEM_MATCHGROUP) 5093 { 5094 p = skiptowhite(rest); 5095 if ((p - rest == 4 && STRNCMP(rest, "NONE", 4) == 0) || eap->skip) 5096 matchgroup_id = 0; 5097 else 5098 { 5099 matchgroup_id = syn_check_group(rest, (int)(p - rest)); 5100 if (matchgroup_id == 0) 5101 { 5102 illegal = TRUE; 5103 break; 5104 } 5105 } 5106 rest = skipwhite(p); 5107 } 5108 else 5109 { 5110 /* 5111 * Allocate room for a syn_pattern, and link it in the list of 5112 * syn_patterns for this item, at the start (because the list is 5113 * used from end to start). 5114 */ 5115 ppp = ALLOC_ONE(struct pat_ptr); 5116 if (ppp == NULL) 5117 { 5118 rest = NULL; 5119 break; 5120 } 5121 ppp->pp_next = pat_ptrs[item]; 5122 pat_ptrs[item] = ppp; 5123 ppp->pp_synp = ALLOC_CLEAR_ONE(synpat_T); 5124 if (ppp->pp_synp == NULL) 5125 { 5126 rest = NULL; 5127 break; 5128 } 5129 5130 /* 5131 * Get the syntax pattern and the following offset(s). 5132 */ 5133 // Enable the appropriate \z specials. 5134 if (item == ITEM_START) 5135 reg_do_extmatch = REX_SET; 5136 else if (item == ITEM_SKIP || item == ITEM_END) 5137 reg_do_extmatch = REX_USE; 5138 rest = get_syn_pattern(rest, ppp->pp_synp); 5139 reg_do_extmatch = 0; 5140 if (item == ITEM_END && vim_regcomp_had_eol() 5141 && !(syn_opt_arg.flags & HL_EXCLUDENL)) 5142 ppp->pp_synp->sp_flags |= HL_HAS_EOL; 5143 ppp->pp_matchgroup_id = matchgroup_id; 5144 ++pat_count; 5145 } 5146 } 5147 vim_free(key); 5148 if (illegal || not_enough) 5149 rest = NULL; 5150 5151 /* 5152 * Must have a "start" and "end" pattern. 5153 */ 5154 if (rest != NULL && (pat_ptrs[ITEM_START] == NULL || 5155 pat_ptrs[ITEM_END] == NULL)) 5156 { 5157 not_enough = TRUE; 5158 rest = NULL; 5159 } 5160 5161 if (rest != NULL) 5162 { 5163 /* 5164 * Check for trailing garbage or command. 5165 * If OK, add the item. 5166 */ 5167 eap->nextcmd = check_nextcmd(rest); 5168 if (!ends_excmd(*rest) || eap->skip) 5169 rest = NULL; 5170 else if (ga_grow(&(curwin->w_s->b_syn_patterns), pat_count) != FAIL 5171 && (syn_id = syn_check_group(arg, 5172 (int)(group_name_end - arg))) != 0) 5173 { 5174 syn_incl_toplevel(syn_id, &syn_opt_arg.flags); 5175 /* 5176 * Store the start/skip/end in the syn_items list 5177 */ 5178 idx = curwin->w_s->b_syn_patterns.ga_len; 5179 for (item = ITEM_START; item <= ITEM_END; ++item) 5180 { 5181 for (ppp = pat_ptrs[item]; ppp != NULL; ppp = ppp->pp_next) 5182 { 5183 SYN_ITEMS(curwin->w_s)[idx] = *(ppp->pp_synp); 5184 SYN_ITEMS(curwin->w_s)[idx].sp_syncing = syncing; 5185 SYN_ITEMS(curwin->w_s)[idx].sp_type = 5186 (item == ITEM_START) ? SPTYPE_START : 5187 (item == ITEM_SKIP) ? SPTYPE_SKIP : SPTYPE_END; 5188 SYN_ITEMS(curwin->w_s)[idx].sp_flags |= syn_opt_arg.flags; 5189 SYN_ITEMS(curwin->w_s)[idx].sp_syn.id = syn_id; 5190 SYN_ITEMS(curwin->w_s)[idx].sp_syn.inc_tag = 5191 current_syn_inc_tag; 5192 SYN_ITEMS(curwin->w_s)[idx].sp_syn_match_id = 5193 ppp->pp_matchgroup_id; 5194 #ifdef FEAT_CONCEAL 5195 SYN_ITEMS(curwin->w_s)[idx].sp_cchar = conceal_char; 5196 #endif 5197 if (item == ITEM_START) 5198 { 5199 SYN_ITEMS(curwin->w_s)[idx].sp_cont_list = 5200 syn_opt_arg.cont_list; 5201 SYN_ITEMS(curwin->w_s)[idx].sp_syn.cont_in_list = 5202 syn_opt_arg.cont_in_list; 5203 if (syn_opt_arg.cont_in_list != NULL) 5204 curwin->w_s->b_syn_containedin = TRUE; 5205 SYN_ITEMS(curwin->w_s)[idx].sp_next_list = 5206 syn_opt_arg.next_list; 5207 } 5208 ++curwin->w_s->b_syn_patterns.ga_len; 5209 ++idx; 5210 #ifdef FEAT_FOLDING 5211 if (syn_opt_arg.flags & HL_FOLD) 5212 ++curwin->w_s->b_syn_folditems; 5213 #endif 5214 } 5215 } 5216 5217 redraw_curbuf_later(SOME_VALID); 5218 syn_stack_free_all(curwin->w_s); // Need to recompute all syntax. 5219 success = TRUE; // don't free the progs and patterns now 5220 } 5221 } 5222 5223 /* 5224 * Free the allocated memory. 5225 */ 5226 for (item = ITEM_START; item <= ITEM_END; ++item) 5227 for (ppp = pat_ptrs[item]; ppp != NULL; ppp = ppp_next) 5228 { 5229 if (!success && ppp->pp_synp != NULL) 5230 { 5231 vim_regfree(ppp->pp_synp->sp_prog); 5232 vim_free(ppp->pp_synp->sp_pattern); 5233 } 5234 vim_free(ppp->pp_synp); 5235 ppp_next = ppp->pp_next; 5236 vim_free(ppp); 5237 } 5238 5239 if (!success) 5240 { 5241 vim_free(syn_opt_arg.cont_list); 5242 vim_free(syn_opt_arg.cont_in_list); 5243 vim_free(syn_opt_arg.next_list); 5244 if (not_enough) 5245 semsg(_("E399: Not enough arguments: syntax region %s"), arg); 5246 else if (illegal || rest == NULL) 5247 semsg(_(e_invarg2), arg); 5248 } 5249 } 5250 5251 /* 5252 * A simple syntax group ID comparison function suitable for use in qsort() 5253 */ 5254 static int 5255 syn_compare_stub(const void *v1, const void *v2) 5256 { 5257 const short *s1 = v1; 5258 const short *s2 = v2; 5259 5260 return (*s1 > *s2 ? 1 : *s1 < *s2 ? -1 : 0); 5261 } 5262 5263 /* 5264 * Combines lists of syntax clusters. 5265 * *clstr1 and *clstr2 must both be allocated memory; they will be consumed. 5266 */ 5267 static void 5268 syn_combine_list(short **clstr1, short **clstr2, int list_op) 5269 { 5270 int count1 = 0; 5271 int count2 = 0; 5272 short *g1; 5273 short *g2; 5274 short *clstr = NULL; 5275 int count; 5276 int round; 5277 5278 /* 5279 * Handle degenerate cases. 5280 */ 5281 if (*clstr2 == NULL) 5282 return; 5283 if (*clstr1 == NULL || list_op == CLUSTER_REPLACE) 5284 { 5285 if (list_op == CLUSTER_REPLACE) 5286 vim_free(*clstr1); 5287 if (list_op == CLUSTER_REPLACE || list_op == CLUSTER_ADD) 5288 *clstr1 = *clstr2; 5289 else 5290 vim_free(*clstr2); 5291 return; 5292 } 5293 5294 for (g1 = *clstr1; *g1; g1++) 5295 ++count1; 5296 for (g2 = *clstr2; *g2; g2++) 5297 ++count2; 5298 5299 /* 5300 * For speed purposes, sort both lists. 5301 */ 5302 qsort(*clstr1, (size_t)count1, sizeof(short), syn_compare_stub); 5303 qsort(*clstr2, (size_t)count2, sizeof(short), syn_compare_stub); 5304 5305 /* 5306 * We proceed in two passes; in round 1, we count the elements to place 5307 * in the new list, and in round 2, we allocate and populate the new 5308 * list. For speed, we use a mergesort-like method, adding the smaller 5309 * of the current elements in each list to the new list. 5310 */ 5311 for (round = 1; round <= 2; round++) 5312 { 5313 g1 = *clstr1; 5314 g2 = *clstr2; 5315 count = 0; 5316 5317 /* 5318 * First, loop through the lists until one of them is empty. 5319 */ 5320 while (*g1 && *g2) 5321 { 5322 /* 5323 * We always want to add from the first list. 5324 */ 5325 if (*g1 < *g2) 5326 { 5327 if (round == 2) 5328 clstr[count] = *g1; 5329 count++; 5330 g1++; 5331 continue; 5332 } 5333 /* 5334 * We only want to add from the second list if we're adding the 5335 * lists. 5336 */ 5337 if (list_op == CLUSTER_ADD) 5338 { 5339 if (round == 2) 5340 clstr[count] = *g2; 5341 count++; 5342 } 5343 if (*g1 == *g2) 5344 g1++; 5345 g2++; 5346 } 5347 5348 /* 5349 * Now add the leftovers from whichever list didn't get finished 5350 * first. As before, we only want to add from the second list if 5351 * we're adding the lists. 5352 */ 5353 for (; *g1; g1++, count++) 5354 if (round == 2) 5355 clstr[count] = *g1; 5356 if (list_op == CLUSTER_ADD) 5357 for (; *g2; g2++, count++) 5358 if (round == 2) 5359 clstr[count] = *g2; 5360 5361 if (round == 1) 5362 { 5363 /* 5364 * If the group ended up empty, we don't need to allocate any 5365 * space for it. 5366 */ 5367 if (count == 0) 5368 { 5369 clstr = NULL; 5370 break; 5371 } 5372 clstr = ALLOC_MULT(short, count + 1); 5373 if (clstr == NULL) 5374 break; 5375 clstr[count] = 0; 5376 } 5377 } 5378 5379 /* 5380 * Finally, put the new list in place. 5381 */ 5382 vim_free(*clstr1); 5383 vim_free(*clstr2); 5384 *clstr1 = clstr; 5385 } 5386 5387 /* 5388 * Lookup a syntax cluster name and return its ID. 5389 * If it is not found, 0 is returned. 5390 */ 5391 static int 5392 syn_scl_name2id(char_u *name) 5393 { 5394 int i; 5395 char_u *name_u; 5396 5397 // Avoid using stricmp() too much, it's slow on some systems 5398 name_u = vim_strsave_up(name); 5399 if (name_u == NULL) 5400 return 0; 5401 for (i = curwin->w_s->b_syn_clusters.ga_len; --i >= 0; ) 5402 if (SYN_CLSTR(curwin->w_s)[i].scl_name_u != NULL 5403 && STRCMP(name_u, SYN_CLSTR(curwin->w_s)[i].scl_name_u) == 0) 5404 break; 5405 vim_free(name_u); 5406 return (i < 0 ? 0 : i + SYNID_CLUSTER); 5407 } 5408 5409 /* 5410 * Like syn_scl_name2id(), but take a pointer + length argument. 5411 */ 5412 static int 5413 syn_scl_namen2id(char_u *linep, int len) 5414 { 5415 char_u *name; 5416 int id = 0; 5417 5418 name = vim_strnsave(linep, len); 5419 if (name != NULL) 5420 { 5421 id = syn_scl_name2id(name); 5422 vim_free(name); 5423 } 5424 return id; 5425 } 5426 5427 /* 5428 * Find syntax cluster name in the table and return its ID. 5429 * The argument is a pointer to the name and the length of the name. 5430 * If it doesn't exist yet, a new entry is created. 5431 * Return 0 for failure. 5432 */ 5433 static int 5434 syn_check_cluster(char_u *pp, int len) 5435 { 5436 int id; 5437 char_u *name; 5438 5439 name = vim_strnsave(pp, len); 5440 if (name == NULL) 5441 return 0; 5442 5443 id = syn_scl_name2id(name); 5444 if (id == 0) // doesn't exist yet 5445 id = syn_add_cluster(name); 5446 else 5447 vim_free(name); 5448 return id; 5449 } 5450 5451 /* 5452 * Add new syntax cluster and return its ID. 5453 * "name" must be an allocated string, it will be consumed. 5454 * Return 0 for failure. 5455 */ 5456 static int 5457 syn_add_cluster(char_u *name) 5458 { 5459 int len; 5460 5461 /* 5462 * First call for this growarray: init growing array. 5463 */ 5464 if (curwin->w_s->b_syn_clusters.ga_data == NULL) 5465 { 5466 curwin->w_s->b_syn_clusters.ga_itemsize = sizeof(syn_cluster_T); 5467 curwin->w_s->b_syn_clusters.ga_growsize = 10; 5468 } 5469 5470 len = curwin->w_s->b_syn_clusters.ga_len; 5471 if (len >= MAX_CLUSTER_ID) 5472 { 5473 emsg(_("E848: Too many syntax clusters")); 5474 vim_free(name); 5475 return 0; 5476 } 5477 5478 /* 5479 * Make room for at least one other cluster entry. 5480 */ 5481 if (ga_grow(&curwin->w_s->b_syn_clusters, 1) == FAIL) 5482 { 5483 vim_free(name); 5484 return 0; 5485 } 5486 5487 CLEAR_POINTER(&(SYN_CLSTR(curwin->w_s)[len])); 5488 SYN_CLSTR(curwin->w_s)[len].scl_name = name; 5489 SYN_CLSTR(curwin->w_s)[len].scl_name_u = vim_strsave_up(name); 5490 SYN_CLSTR(curwin->w_s)[len].scl_list = NULL; 5491 ++curwin->w_s->b_syn_clusters.ga_len; 5492 5493 if (STRICMP(name, "Spell") == 0) 5494 curwin->w_s->b_spell_cluster_id = len + SYNID_CLUSTER; 5495 if (STRICMP(name, "NoSpell") == 0) 5496 curwin->w_s->b_nospell_cluster_id = len + SYNID_CLUSTER; 5497 5498 return len + SYNID_CLUSTER; 5499 } 5500 5501 /* 5502 * Handle ":syntax cluster {cluster-name} [contains={groupname},..] 5503 * [add={groupname},..] [remove={groupname},..]". 5504 */ 5505 static void 5506 syn_cmd_cluster(exarg_T *eap, int syncing UNUSED) 5507 { 5508 char_u *arg = eap->arg; 5509 char_u *group_name_end; 5510 char_u *rest; 5511 int scl_id; 5512 short *clstr_list; 5513 int got_clstr = FALSE; 5514 int opt_len; 5515 int list_op; 5516 5517 eap->nextcmd = find_nextcmd(arg); 5518 if (eap->skip) 5519 return; 5520 5521 rest = get_group_name(arg, &group_name_end); 5522 5523 if (rest != NULL) 5524 { 5525 scl_id = syn_check_cluster(arg, (int)(group_name_end - arg)); 5526 if (scl_id == 0) 5527 return; 5528 scl_id -= SYNID_CLUSTER; 5529 5530 for (;;) 5531 { 5532 if (STRNICMP(rest, "add", 3) == 0 5533 && (VIM_ISWHITE(rest[3]) || rest[3] == '=')) 5534 { 5535 opt_len = 3; 5536 list_op = CLUSTER_ADD; 5537 } 5538 else if (STRNICMP(rest, "remove", 6) == 0 5539 && (VIM_ISWHITE(rest[6]) || rest[6] == '=')) 5540 { 5541 opt_len = 6; 5542 list_op = CLUSTER_SUBTRACT; 5543 } 5544 else if (STRNICMP(rest, "contains", 8) == 0 5545 && (VIM_ISWHITE(rest[8]) || rest[8] == '=')) 5546 { 5547 opt_len = 8; 5548 list_op = CLUSTER_REPLACE; 5549 } 5550 else 5551 break; 5552 5553 clstr_list = NULL; 5554 if (get_id_list(&rest, opt_len, &clstr_list, eap->skip) == FAIL) 5555 { 5556 semsg(_(e_invarg2), rest); 5557 break; 5558 } 5559 if (scl_id >= 0) 5560 syn_combine_list(&SYN_CLSTR(curwin->w_s)[scl_id].scl_list, 5561 &clstr_list, list_op); 5562 else 5563 vim_free(clstr_list); 5564 got_clstr = TRUE; 5565 } 5566 5567 if (got_clstr) 5568 { 5569 redraw_curbuf_later(SOME_VALID); 5570 syn_stack_free_all(curwin->w_s); // Need to recompute all. 5571 } 5572 } 5573 5574 if (!got_clstr) 5575 emsg(_("E400: No cluster specified")); 5576 if (rest == NULL || !ends_excmd2(eap->cmd, rest)) 5577 semsg(_(e_invarg2), arg); 5578 } 5579 5580 /* 5581 * On first call for current buffer: Init growing array. 5582 */ 5583 static void 5584 init_syn_patterns(void) 5585 { 5586 curwin->w_s->b_syn_patterns.ga_itemsize = sizeof(synpat_T); 5587 curwin->w_s->b_syn_patterns.ga_growsize = 10; 5588 } 5589 5590 /* 5591 * Get one pattern for a ":syntax match" or ":syntax region" command. 5592 * Stores the pattern and program in a synpat_T. 5593 * Returns a pointer to the next argument, or NULL in case of an error. 5594 */ 5595 static char_u * 5596 get_syn_pattern(char_u *arg, synpat_T *ci) 5597 { 5598 char_u *end; 5599 int *p; 5600 int idx; 5601 char_u *cpo_save; 5602 5603 // need at least three chars 5604 if (arg == NULL || arg[0] == NUL || arg[1] == NUL || arg[2] == NUL) 5605 return NULL; 5606 5607 end = skip_regexp(arg + 1, *arg, TRUE); 5608 if (*end != *arg) // end delimiter not found 5609 { 5610 semsg(_("E401: Pattern delimiter not found: %s"), arg); 5611 return NULL; 5612 } 5613 // store the pattern and compiled regexp program 5614 if ((ci->sp_pattern = vim_strnsave(arg + 1, (int)(end - arg - 1))) == NULL) 5615 return NULL; 5616 5617 // Make 'cpoptions' empty, to avoid the 'l' flag 5618 cpo_save = p_cpo; 5619 p_cpo = (char_u *)""; 5620 ci->sp_prog = vim_regcomp(ci->sp_pattern, RE_MAGIC); 5621 p_cpo = cpo_save; 5622 5623 if (ci->sp_prog == NULL) 5624 return NULL; 5625 ci->sp_ic = curwin->w_s->b_syn_ic; 5626 #ifdef FEAT_PROFILE 5627 syn_clear_time(&ci->sp_time); 5628 #endif 5629 5630 /* 5631 * Check for a match, highlight or region offset. 5632 */ 5633 ++end; 5634 do 5635 { 5636 for (idx = SPO_COUNT; --idx >= 0; ) 5637 if (STRNCMP(end, spo_name_tab[idx], 3) == 0) 5638 break; 5639 if (idx >= 0) 5640 { 5641 p = &(ci->sp_offsets[idx]); 5642 if (idx != SPO_LC_OFF) 5643 switch (end[3]) 5644 { 5645 case 's': break; 5646 case 'b': break; 5647 case 'e': idx += SPO_COUNT; break; 5648 default: idx = -1; break; 5649 } 5650 if (idx >= 0) 5651 { 5652 ci->sp_off_flags |= (1 << idx); 5653 if (idx == SPO_LC_OFF) // lc=99 5654 { 5655 end += 3; 5656 *p = getdigits(&end); 5657 5658 // "lc=" offset automatically sets "ms=" offset 5659 if (!(ci->sp_off_flags & (1 << SPO_MS_OFF))) 5660 { 5661 ci->sp_off_flags |= (1 << SPO_MS_OFF); 5662 ci->sp_offsets[SPO_MS_OFF] = *p; 5663 } 5664 } 5665 else // yy=x+99 5666 { 5667 end += 4; 5668 if (*end == '+') 5669 { 5670 ++end; 5671 *p = getdigits(&end); // positive offset 5672 } 5673 else if (*end == '-') 5674 { 5675 ++end; 5676 *p = -getdigits(&end); // negative offset 5677 } 5678 } 5679 if (*end != ',') 5680 break; 5681 ++end; 5682 } 5683 } 5684 } while (idx >= 0); 5685 5686 if (!ends_excmd2(arg, end) && !VIM_ISWHITE(*end)) 5687 { 5688 semsg(_("E402: Garbage after pattern: %s"), arg); 5689 return NULL; 5690 } 5691 return skipwhite(end); 5692 } 5693 5694 /* 5695 * Handle ":syntax sync .." command. 5696 */ 5697 static void 5698 syn_cmd_sync(exarg_T *eap, int syncing UNUSED) 5699 { 5700 char_u *arg_start = eap->arg; 5701 char_u *arg_end; 5702 char_u *key = NULL; 5703 char_u *next_arg; 5704 int illegal = FALSE; 5705 int finished = FALSE; 5706 long n; 5707 char_u *cpo_save; 5708 5709 if (ends_excmd2(eap->cmd, arg_start)) 5710 { 5711 syn_cmd_list(eap, TRUE); 5712 return; 5713 } 5714 5715 while (!ends_excmd2(eap->cmd, arg_start)) 5716 { 5717 arg_end = skiptowhite(arg_start); 5718 next_arg = skipwhite(arg_end); 5719 vim_free(key); 5720 key = vim_strnsave_up(arg_start, (int)(arg_end - arg_start)); 5721 if (STRCMP(key, "CCOMMENT") == 0) 5722 { 5723 if (!eap->skip) 5724 curwin->w_s->b_syn_sync_flags |= SF_CCOMMENT; 5725 if (!ends_excmd2(eap->cmd, next_arg)) 5726 { 5727 arg_end = skiptowhite(next_arg); 5728 if (!eap->skip) 5729 curwin->w_s->b_syn_sync_id = syn_check_group(next_arg, 5730 (int)(arg_end - next_arg)); 5731 next_arg = skipwhite(arg_end); 5732 } 5733 else if (!eap->skip) 5734 curwin->w_s->b_syn_sync_id = syn_name2id((char_u *)"Comment"); 5735 } 5736 else if ( STRNCMP(key, "LINES", 5) == 0 5737 || STRNCMP(key, "MINLINES", 8) == 0 5738 || STRNCMP(key, "MAXLINES", 8) == 0 5739 || STRNCMP(key, "LINEBREAKS", 10) == 0) 5740 { 5741 if (key[4] == 'S') 5742 arg_end = key + 6; 5743 else if (key[0] == 'L') 5744 arg_end = key + 11; 5745 else 5746 arg_end = key + 9; 5747 if (arg_end[-1] != '=' || !VIM_ISDIGIT(*arg_end)) 5748 { 5749 illegal = TRUE; 5750 break; 5751 } 5752 n = getdigits(&arg_end); 5753 if (!eap->skip) 5754 { 5755 if (key[4] == 'B') 5756 curwin->w_s->b_syn_sync_linebreaks = n; 5757 else if (key[1] == 'A') 5758 curwin->w_s->b_syn_sync_maxlines = n; 5759 else 5760 curwin->w_s->b_syn_sync_minlines = n; 5761 } 5762 } 5763 else if (STRCMP(key, "FROMSTART") == 0) 5764 { 5765 if (!eap->skip) 5766 { 5767 curwin->w_s->b_syn_sync_minlines = MAXLNUM; 5768 curwin->w_s->b_syn_sync_maxlines = 0; 5769 } 5770 } 5771 else if (STRCMP(key, "LINECONT") == 0) 5772 { 5773 if (*next_arg == NUL) // missing pattern 5774 { 5775 illegal = TRUE; 5776 break; 5777 } 5778 if (curwin->w_s->b_syn_linecont_pat != NULL) 5779 { 5780 emsg(_("E403: syntax sync: line continuations pattern specified twice")); 5781 finished = TRUE; 5782 break; 5783 } 5784 arg_end = skip_regexp(next_arg + 1, *next_arg, TRUE); 5785 if (*arg_end != *next_arg) // end delimiter not found 5786 { 5787 illegal = TRUE; 5788 break; 5789 } 5790 5791 if (!eap->skip) 5792 { 5793 // store the pattern and compiled regexp program 5794 if ((curwin->w_s->b_syn_linecont_pat = vim_strnsave(next_arg + 1, 5795 (int)(arg_end - next_arg - 1))) == NULL) 5796 { 5797 finished = TRUE; 5798 break; 5799 } 5800 curwin->w_s->b_syn_linecont_ic = curwin->w_s->b_syn_ic; 5801 5802 // Make 'cpoptions' empty, to avoid the 'l' flag 5803 cpo_save = p_cpo; 5804 p_cpo = (char_u *)""; 5805 curwin->w_s->b_syn_linecont_prog = 5806 vim_regcomp(curwin->w_s->b_syn_linecont_pat, RE_MAGIC); 5807 p_cpo = cpo_save; 5808 #ifdef FEAT_PROFILE 5809 syn_clear_time(&curwin->w_s->b_syn_linecont_time); 5810 #endif 5811 5812 if (curwin->w_s->b_syn_linecont_prog == NULL) 5813 { 5814 VIM_CLEAR(curwin->w_s->b_syn_linecont_pat); 5815 finished = TRUE; 5816 break; 5817 } 5818 } 5819 next_arg = skipwhite(arg_end + 1); 5820 } 5821 else 5822 { 5823 eap->arg = next_arg; 5824 if (STRCMP(key, "MATCH") == 0) 5825 syn_cmd_match(eap, TRUE); 5826 else if (STRCMP(key, "REGION") == 0) 5827 syn_cmd_region(eap, TRUE); 5828 else if (STRCMP(key, "CLEAR") == 0) 5829 syn_cmd_clear(eap, TRUE); 5830 else 5831 illegal = TRUE; 5832 finished = TRUE; 5833 break; 5834 } 5835 arg_start = next_arg; 5836 } 5837 vim_free(key); 5838 if (illegal) 5839 semsg(_("E404: Illegal arguments: %s"), arg_start); 5840 else if (!finished) 5841 { 5842 eap->nextcmd = check_nextcmd(arg_start); 5843 redraw_curbuf_later(SOME_VALID); 5844 syn_stack_free_all(curwin->w_s); // Need to recompute all syntax. 5845 } 5846 } 5847 5848 /* 5849 * Convert a line of highlight group names into a list of group ID numbers. 5850 * "arg" should point to the "contains" or "nextgroup" keyword. 5851 * "arg" is advanced to after the last group name. 5852 * Careful: the argument is modified (NULs added). 5853 * returns FAIL for some error, OK for success. 5854 */ 5855 static int 5856 get_id_list( 5857 char_u **arg, 5858 int keylen, // length of keyword 5859 short **list, // where to store the resulting list, if not 5860 // NULL, the list is silently skipped! 5861 int skip) 5862 { 5863 char_u *p = NULL; 5864 char_u *end; 5865 int round; 5866 int count; 5867 int total_count = 0; 5868 short *retval = NULL; 5869 char_u *name; 5870 regmatch_T regmatch; 5871 int id; 5872 int i; 5873 int failed = FALSE; 5874 5875 /* 5876 * We parse the list twice: 5877 * round == 1: count the number of items, allocate the array. 5878 * round == 2: fill the array with the items. 5879 * In round 1 new groups may be added, causing the number of items to 5880 * grow when a regexp is used. In that case round 1 is done once again. 5881 */ 5882 for (round = 1; round <= 2; ++round) 5883 { 5884 /* 5885 * skip "contains" 5886 */ 5887 p = skipwhite(*arg + keylen); 5888 if (*p != '=') 5889 { 5890 semsg(_("E405: Missing equal sign: %s"), *arg); 5891 break; 5892 } 5893 p = skipwhite(p + 1); 5894 if (ends_excmd2(*arg, p)) 5895 { 5896 semsg(_("E406: Empty argument: %s"), *arg); 5897 break; 5898 } 5899 5900 /* 5901 * parse the arguments after "contains" 5902 */ 5903 count = 0; 5904 while (!ends_excmd2(*arg, p)) 5905 { 5906 for (end = p; *end && !VIM_ISWHITE(*end) && *end != ','; ++end) 5907 ; 5908 name = alloc(end - p + 3); // leave room for "^$" 5909 if (name == NULL) 5910 { 5911 failed = TRUE; 5912 break; 5913 } 5914 vim_strncpy(name + 1, p, end - p); 5915 if ( STRCMP(name + 1, "ALLBUT") == 0 5916 || STRCMP(name + 1, "ALL") == 0 5917 || STRCMP(name + 1, "TOP") == 0 5918 || STRCMP(name + 1, "CONTAINED") == 0) 5919 { 5920 if (TOUPPER_ASC(**arg) != 'C') 5921 { 5922 semsg(_("E407: %s not allowed here"), name + 1); 5923 failed = TRUE; 5924 vim_free(name); 5925 break; 5926 } 5927 if (count != 0) 5928 { 5929 semsg(_("E408: %s must be first in contains list"), 5930 name + 1); 5931 failed = TRUE; 5932 vim_free(name); 5933 break; 5934 } 5935 if (name[1] == 'A') 5936 id = SYNID_ALLBUT; 5937 else if (name[1] == 'T') 5938 id = SYNID_TOP; 5939 else 5940 id = SYNID_CONTAINED; 5941 id += current_syn_inc_tag; 5942 } 5943 else if (name[1] == '@') 5944 { 5945 if (skip) 5946 id = -1; 5947 else 5948 id = syn_check_cluster(name + 2, (int)(end - p - 1)); 5949 } 5950 else 5951 { 5952 /* 5953 * Handle full group name. 5954 */ 5955 if (vim_strpbrk(name + 1, (char_u *)"\\.*^$~[") == NULL) 5956 id = syn_check_group(name + 1, (int)(end - p)); 5957 else 5958 { 5959 /* 5960 * Handle match of regexp with group names. 5961 */ 5962 *name = '^'; 5963 STRCAT(name, "$"); 5964 regmatch.regprog = vim_regcomp(name, RE_MAGIC); 5965 if (regmatch.regprog == NULL) 5966 { 5967 failed = TRUE; 5968 vim_free(name); 5969 break; 5970 } 5971 5972 regmatch.rm_ic = TRUE; 5973 id = 0; 5974 for (i = highlight_num_groups(); --i >= 0; ) 5975 { 5976 if (vim_regexec(®match, highlight_group_name(i), 5977 (colnr_T)0)) 5978 { 5979 if (round == 2) 5980 { 5981 // Got more items than expected; can happen 5982 // when adding items that match: 5983 // "contains=a.*b,axb". 5984 // Go back to first round 5985 if (count >= total_count) 5986 { 5987 vim_free(retval); 5988 round = 1; 5989 } 5990 else 5991 retval[count] = i + 1; 5992 } 5993 ++count; 5994 id = -1; // remember that we found one 5995 } 5996 } 5997 vim_regfree(regmatch.regprog); 5998 } 5999 } 6000 vim_free(name); 6001 if (id == 0) 6002 { 6003 semsg(_("E409: Unknown group name: %s"), p); 6004 failed = TRUE; 6005 break; 6006 } 6007 if (id > 0) 6008 { 6009 if (round == 2) 6010 { 6011 // Got more items than expected, go back to first round 6012 if (count >= total_count) 6013 { 6014 vim_free(retval); 6015 round = 1; 6016 } 6017 else 6018 retval[count] = id; 6019 } 6020 ++count; 6021 } 6022 p = skipwhite(end); 6023 if (*p != ',') 6024 break; 6025 p = skipwhite(p + 1); // skip comma in between arguments 6026 } 6027 if (failed) 6028 break; 6029 if (round == 1) 6030 { 6031 retval = ALLOC_MULT(short, count + 1); 6032 if (retval == NULL) 6033 break; 6034 retval[count] = 0; // zero means end of the list 6035 total_count = count; 6036 } 6037 } 6038 6039 *arg = p; 6040 if (failed || retval == NULL) 6041 { 6042 vim_free(retval); 6043 return FAIL; 6044 } 6045 6046 if (*list == NULL) 6047 *list = retval; 6048 else 6049 vim_free(retval); // list already found, don't overwrite it 6050 6051 return OK; 6052 } 6053 6054 /* 6055 * Make a copy of an ID list. 6056 */ 6057 static short * 6058 copy_id_list(short *list) 6059 { 6060 int len; 6061 int count; 6062 short *retval; 6063 6064 if (list == NULL) 6065 return NULL; 6066 6067 for (count = 0; list[count]; ++count) 6068 ; 6069 len = (count + 1) * sizeof(short); 6070 retval = alloc(len); 6071 if (retval != NULL) 6072 mch_memmove(retval, list, (size_t)len); 6073 6074 return retval; 6075 } 6076 6077 /* 6078 * Check if syntax group "ssp" is in the ID list "list" of "cur_si". 6079 * "cur_si" can be NULL if not checking the "containedin" list. 6080 * Used to check if a syntax item is in the "contains" or "nextgroup" list of 6081 * the current item. 6082 * This function is called very often, keep it fast!! 6083 */ 6084 static int 6085 in_id_list( 6086 stateitem_T *cur_si, // current item or NULL 6087 short *list, // id list 6088 struct sp_syn *ssp, // group id and ":syn include" tag of group 6089 int contained) // group id is contained 6090 { 6091 int retval; 6092 short *scl_list; 6093 short item; 6094 short id = ssp->id; 6095 static int depth = 0; 6096 int r; 6097 6098 // If ssp has a "containedin" list and "cur_si" is in it, return TRUE. 6099 if (cur_si != NULL && ssp->cont_in_list != NULL 6100 && !(cur_si->si_flags & HL_MATCH)) 6101 { 6102 // Ignore transparent items without a contains argument. Double check 6103 // that we don't go back past the first one. 6104 while ((cur_si->si_flags & HL_TRANS_CONT) 6105 && cur_si > (stateitem_T *)(current_state.ga_data)) 6106 --cur_si; 6107 // cur_si->si_idx is -1 for keywords, these never contain anything. 6108 if (cur_si->si_idx >= 0 && in_id_list(NULL, ssp->cont_in_list, 6109 &(SYN_ITEMS(syn_block)[cur_si->si_idx].sp_syn), 6110 SYN_ITEMS(syn_block)[cur_si->si_idx].sp_flags & HL_CONTAINED)) 6111 return TRUE; 6112 } 6113 6114 if (list == NULL) 6115 return FALSE; 6116 6117 /* 6118 * If list is ID_LIST_ALL, we are in a transparent item that isn't 6119 * inside anything. Only allow not-contained groups. 6120 */ 6121 if (list == ID_LIST_ALL) 6122 return !contained; 6123 6124 /* 6125 * If the first item is "ALLBUT", return TRUE if "id" is NOT in the 6126 * contains list. We also require that "id" is at the same ":syn include" 6127 * level as the list. 6128 */ 6129 item = *list; 6130 if (item >= SYNID_ALLBUT && item < SYNID_CLUSTER) 6131 { 6132 if (item < SYNID_TOP) 6133 { 6134 // ALL or ALLBUT: accept all groups in the same file 6135 if (item - SYNID_ALLBUT != ssp->inc_tag) 6136 return FALSE; 6137 } 6138 else if (item < SYNID_CONTAINED) 6139 { 6140 // TOP: accept all not-contained groups in the same file 6141 if (item - SYNID_TOP != ssp->inc_tag || contained) 6142 return FALSE; 6143 } 6144 else 6145 { 6146 // CONTAINED: accept all contained groups in the same file 6147 if (item - SYNID_CONTAINED != ssp->inc_tag || !contained) 6148 return FALSE; 6149 } 6150 item = *++list; 6151 retval = FALSE; 6152 } 6153 else 6154 retval = TRUE; 6155 6156 /* 6157 * Return "retval" if id is in the contains list. 6158 */ 6159 while (item != 0) 6160 { 6161 if (item == id) 6162 return retval; 6163 if (item >= SYNID_CLUSTER) 6164 { 6165 scl_list = SYN_CLSTR(syn_block)[item - SYNID_CLUSTER].scl_list; 6166 // restrict recursiveness to 30 to avoid an endless loop for a 6167 // cluster that includes itself (indirectly) 6168 if (scl_list != NULL && depth < 30) 6169 { 6170 ++depth; 6171 r = in_id_list(NULL, scl_list, ssp, contained); 6172 --depth; 6173 if (r) 6174 return retval; 6175 } 6176 } 6177 item = *++list; 6178 } 6179 return !retval; 6180 } 6181 6182 struct subcommand 6183 { 6184 char *name; // subcommand name 6185 void (*func)(exarg_T *, int); // function to call 6186 }; 6187 6188 static struct subcommand subcommands[] = 6189 { 6190 {"case", syn_cmd_case}, 6191 {"clear", syn_cmd_clear}, 6192 {"cluster", syn_cmd_cluster}, 6193 {"conceal", syn_cmd_conceal}, 6194 {"enable", syn_cmd_enable}, 6195 {"include", syn_cmd_include}, 6196 {"iskeyword", syn_cmd_iskeyword}, 6197 {"keyword", syn_cmd_keyword}, 6198 {"list", syn_cmd_list}, 6199 {"manual", syn_cmd_manual}, 6200 {"match", syn_cmd_match}, 6201 {"on", syn_cmd_on}, 6202 {"off", syn_cmd_off}, 6203 {"region", syn_cmd_region}, 6204 {"reset", syn_cmd_reset}, 6205 {"spell", syn_cmd_spell}, 6206 {"sync", syn_cmd_sync}, 6207 {"", syn_cmd_list}, 6208 {NULL, NULL} 6209 }; 6210 6211 /* 6212 * ":syntax". 6213 * This searches the subcommands[] table for the subcommand name, and calls a 6214 * syntax_subcommand() function to do the rest. 6215 */ 6216 void 6217 ex_syntax(exarg_T *eap) 6218 { 6219 char_u *arg = eap->arg; 6220 char_u *subcmd_end; 6221 char_u *subcmd_name; 6222 int i; 6223 6224 syn_cmdlinep = eap->cmdlinep; 6225 6226 // isolate subcommand name 6227 for (subcmd_end = arg; ASCII_ISALPHA(*subcmd_end); ++subcmd_end) 6228 ; 6229 subcmd_name = vim_strnsave(arg, (int)(subcmd_end - arg)); 6230 if (subcmd_name != NULL) 6231 { 6232 if (eap->skip) // skip error messages for all subcommands 6233 ++emsg_skip; 6234 for (i = 0; ; ++i) 6235 { 6236 if (subcommands[i].name == NULL) 6237 { 6238 semsg(_("E410: Invalid :syntax subcommand: %s"), subcmd_name); 6239 break; 6240 } 6241 if (STRCMP(subcmd_name, (char_u *)subcommands[i].name) == 0) 6242 { 6243 eap->arg = skipwhite(subcmd_end); 6244 (subcommands[i].func)(eap, FALSE); 6245 break; 6246 } 6247 } 6248 vim_free(subcmd_name); 6249 if (eap->skip) 6250 --emsg_skip; 6251 } 6252 } 6253 6254 void 6255 ex_ownsyntax(exarg_T *eap) 6256 { 6257 char_u *old_value; 6258 char_u *new_value; 6259 6260 if (curwin->w_s == &curwin->w_buffer->b_s) 6261 { 6262 curwin->w_s = ALLOC_ONE(synblock_T); 6263 memset(curwin->w_s, 0, sizeof(synblock_T)); 6264 hash_init(&curwin->w_s->b_keywtab); 6265 hash_init(&curwin->w_s->b_keywtab_ic); 6266 #ifdef FEAT_SPELL 6267 // TODO: keep the spell checking as it was. 6268 curwin->w_p_spell = FALSE; // No spell checking 6269 clear_string_option(&curwin->w_s->b_p_spc); 6270 clear_string_option(&curwin->w_s->b_p_spf); 6271 clear_string_option(&curwin->w_s->b_p_spl); 6272 #endif 6273 clear_string_option(&curwin->w_s->b_syn_isk); 6274 } 6275 6276 // save value of b:current_syntax 6277 old_value = get_var_value((char_u *)"b:current_syntax"); 6278 if (old_value != NULL) 6279 old_value = vim_strsave(old_value); 6280 6281 // Apply the "syntax" autocommand event, this finds and loads the syntax 6282 // file. 6283 apply_autocmds(EVENT_SYNTAX, eap->arg, curbuf->b_fname, TRUE, curbuf); 6284 6285 // move value of b:current_syntax to w:current_syntax 6286 new_value = get_var_value((char_u *)"b:current_syntax"); 6287 if (new_value != NULL) 6288 set_internal_string_var((char_u *)"w:current_syntax", new_value); 6289 6290 // restore value of b:current_syntax 6291 if (old_value == NULL) 6292 do_unlet((char_u *)"b:current_syntax", TRUE); 6293 else 6294 { 6295 set_internal_string_var((char_u *)"b:current_syntax", old_value); 6296 vim_free(old_value); 6297 } 6298 } 6299 6300 int 6301 syntax_present(win_T *win) 6302 { 6303 return (win->w_s->b_syn_patterns.ga_len != 0 6304 || win->w_s->b_syn_clusters.ga_len != 0 6305 || win->w_s->b_keywtab.ht_used > 0 6306 || win->w_s->b_keywtab_ic.ht_used > 0); 6307 } 6308 6309 6310 static enum 6311 { 6312 EXP_SUBCMD, // expand ":syn" sub-commands 6313 EXP_CASE, // expand ":syn case" arguments 6314 EXP_SPELL, // expand ":syn spell" arguments 6315 EXP_SYNC // expand ":syn sync" arguments 6316 } expand_what; 6317 6318 /* 6319 * Reset include_link, include_default, include_none to 0. 6320 * Called when we are done expanding. 6321 */ 6322 void 6323 reset_expand_highlight(void) 6324 { 6325 include_link = include_default = include_none = 0; 6326 } 6327 6328 /* 6329 * Handle command line completion for :match and :echohl command: Add "None" 6330 * as highlight group. 6331 */ 6332 void 6333 set_context_in_echohl_cmd(expand_T *xp, char_u *arg) 6334 { 6335 xp->xp_context = EXPAND_HIGHLIGHT; 6336 xp->xp_pattern = arg; 6337 include_none = 1; 6338 } 6339 6340 /* 6341 * Handle command line completion for :syntax command. 6342 */ 6343 void 6344 set_context_in_syntax_cmd(expand_T *xp, char_u *arg) 6345 { 6346 char_u *p; 6347 6348 // Default: expand subcommands 6349 xp->xp_context = EXPAND_SYNTAX; 6350 expand_what = EXP_SUBCMD; 6351 xp->xp_pattern = arg; 6352 include_link = 0; 6353 include_default = 0; 6354 6355 // (part of) subcommand already typed 6356 if (*arg != NUL) 6357 { 6358 p = skiptowhite(arg); 6359 if (*p != NUL) // past first word 6360 { 6361 xp->xp_pattern = skipwhite(p); 6362 if (*skiptowhite(xp->xp_pattern) != NUL) 6363 xp->xp_context = EXPAND_NOTHING; 6364 else if (STRNICMP(arg, "case", p - arg) == 0) 6365 expand_what = EXP_CASE; 6366 else if (STRNICMP(arg, "spell", p - arg) == 0) 6367 expand_what = EXP_SPELL; 6368 else if (STRNICMP(arg, "sync", p - arg) == 0) 6369 expand_what = EXP_SYNC; 6370 else if ( STRNICMP(arg, "keyword", p - arg) == 0 6371 || STRNICMP(arg, "region", p - arg) == 0 6372 || STRNICMP(arg, "match", p - arg) == 0 6373 || STRNICMP(arg, "list", p - arg) == 0) 6374 xp->xp_context = EXPAND_HIGHLIGHT; 6375 else 6376 xp->xp_context = EXPAND_NOTHING; 6377 } 6378 } 6379 } 6380 6381 /* 6382 * Function given to ExpandGeneric() to obtain the list syntax names for 6383 * expansion. 6384 */ 6385 char_u * 6386 get_syntax_name(expand_T *xp UNUSED, int idx) 6387 { 6388 switch (expand_what) 6389 { 6390 case EXP_SUBCMD: 6391 return (char_u *)subcommands[idx].name; 6392 case EXP_CASE: 6393 { 6394 static char *case_args[] = {"match", "ignore", NULL}; 6395 return (char_u *)case_args[idx]; 6396 } 6397 case EXP_SPELL: 6398 { 6399 static char *spell_args[] = 6400 {"toplevel", "notoplevel", "default", NULL}; 6401 return (char_u *)spell_args[idx]; 6402 } 6403 case EXP_SYNC: 6404 { 6405 static char *sync_args[] = 6406 {"ccomment", "clear", "fromstart", 6407 "linebreaks=", "linecont", "lines=", "match", 6408 "maxlines=", "minlines=", "region", NULL}; 6409 return (char_u *)sync_args[idx]; 6410 } 6411 } 6412 return NULL; 6413 } 6414 6415 6416 /* 6417 * Function called for expression evaluation: get syntax ID at file position. 6418 */ 6419 int 6420 syn_get_id( 6421 win_T *wp, 6422 long lnum, 6423 colnr_T col, 6424 int trans, // remove transparency 6425 int *spellp, // return: can do spell checking 6426 int keep_state) // keep state of char at "col" 6427 { 6428 // When the position is not after the current position and in the same 6429 // line of the same buffer, need to restart parsing. 6430 if (wp->w_buffer != syn_buf 6431 || lnum != current_lnum 6432 || col < current_col) 6433 syntax_start(wp, lnum); 6434 else if (wp->w_buffer == syn_buf 6435 && lnum == current_lnum 6436 && col > current_col) 6437 // next_match may not be correct when moving around, e.g. with the 6438 // "skip" expression in searchpair() 6439 next_match_idx = -1; 6440 6441 (void)get_syntax_attr(col, spellp, keep_state); 6442 6443 return (trans ? current_trans_id : current_id); 6444 } 6445 6446 #if defined(FEAT_CONCEAL) || defined(PROTO) 6447 /* 6448 * Get extra information about the syntax item. Must be called right after 6449 * get_syntax_attr(). 6450 * Stores the current item sequence nr in "*seqnrp". 6451 * Returns the current flags. 6452 */ 6453 int 6454 get_syntax_info(int *seqnrp) 6455 { 6456 *seqnrp = current_seqnr; 6457 return current_flags; 6458 } 6459 6460 /* 6461 * Return conceal substitution character 6462 */ 6463 int 6464 syn_get_sub_char(void) 6465 { 6466 return current_sub_char; 6467 } 6468 #endif 6469 6470 #if defined(FEAT_EVAL) || defined(PROTO) 6471 /* 6472 * Return the syntax ID at position "i" in the current stack. 6473 * The caller must have called syn_get_id() before to fill the stack. 6474 * Returns -1 when "i" is out of range. 6475 */ 6476 int 6477 syn_get_stack_item(int i) 6478 { 6479 if (i >= current_state.ga_len) 6480 { 6481 // Need to invalidate the state, because we didn't properly finish it 6482 // for the last character, "keep_state" was TRUE. 6483 invalidate_current_state(); 6484 current_col = MAXCOL; 6485 return -1; 6486 } 6487 return CUR_STATE(i).si_id; 6488 } 6489 #endif 6490 6491 #if defined(FEAT_FOLDING) || defined(PROTO) 6492 /* 6493 * Function called to get folding level for line "lnum" in window "wp". 6494 */ 6495 int 6496 syn_get_foldlevel(win_T *wp, long lnum) 6497 { 6498 int level = 0; 6499 int i; 6500 6501 // Return quickly when there are no fold items at all. 6502 if (wp->w_s->b_syn_folditems != 0 6503 && !wp->w_s->b_syn_error 6504 # ifdef SYN_TIME_LIMIT 6505 && !wp->w_s->b_syn_slow 6506 # endif 6507 ) 6508 { 6509 syntax_start(wp, lnum); 6510 6511 for (i = 0; i < current_state.ga_len; ++i) 6512 if (CUR_STATE(i).si_flags & HL_FOLD) 6513 ++level; 6514 } 6515 if (level > wp->w_p_fdn) 6516 { 6517 level = wp->w_p_fdn; 6518 if (level < 0) 6519 level = 0; 6520 } 6521 return level; 6522 } 6523 #endif 6524 6525 #if defined(FEAT_PROFILE) || defined(PROTO) 6526 /* 6527 * ":syntime". 6528 */ 6529 void 6530 ex_syntime(exarg_T *eap) 6531 { 6532 if (STRCMP(eap->arg, "on") == 0) 6533 syn_time_on = TRUE; 6534 else if (STRCMP(eap->arg, "off") == 0) 6535 syn_time_on = FALSE; 6536 else if (STRCMP(eap->arg, "clear") == 0) 6537 syntime_clear(); 6538 else if (STRCMP(eap->arg, "report") == 0) 6539 syntime_report(); 6540 else 6541 semsg(_(e_invarg2), eap->arg); 6542 } 6543 6544 static void 6545 syn_clear_time(syn_time_T *st) 6546 { 6547 profile_zero(&st->total); 6548 profile_zero(&st->slowest); 6549 st->count = 0; 6550 st->match = 0; 6551 } 6552 6553 /* 6554 * Clear the syntax timing for the current buffer. 6555 */ 6556 static void 6557 syntime_clear(void) 6558 { 6559 int idx; 6560 synpat_T *spp; 6561 6562 if (!syntax_present(curwin)) 6563 { 6564 msg(_(msg_no_items)); 6565 return; 6566 } 6567 for (idx = 0; idx < curwin->w_s->b_syn_patterns.ga_len; ++idx) 6568 { 6569 spp = &(SYN_ITEMS(curwin->w_s)[idx]); 6570 syn_clear_time(&spp->sp_time); 6571 } 6572 } 6573 6574 /* 6575 * Function given to ExpandGeneric() to obtain the possible arguments of the 6576 * ":syntime {on,off,clear,report}" command. 6577 */ 6578 char_u * 6579 get_syntime_arg(expand_T *xp UNUSED, int idx) 6580 { 6581 switch (idx) 6582 { 6583 case 0: return (char_u *)"on"; 6584 case 1: return (char_u *)"off"; 6585 case 2: return (char_u *)"clear"; 6586 case 3: return (char_u *)"report"; 6587 } 6588 return NULL; 6589 } 6590 6591 typedef struct 6592 { 6593 proftime_T total; 6594 int count; 6595 int match; 6596 proftime_T slowest; 6597 proftime_T average; 6598 int id; 6599 char_u *pattern; 6600 } time_entry_T; 6601 6602 static int 6603 syn_compare_syntime(const void *v1, const void *v2) 6604 { 6605 const time_entry_T *s1 = v1; 6606 const time_entry_T *s2 = v2; 6607 6608 return profile_cmp(&s1->total, &s2->total); 6609 } 6610 6611 /* 6612 * Clear the syntax timing for the current buffer. 6613 */ 6614 static void 6615 syntime_report(void) 6616 { 6617 int idx; 6618 synpat_T *spp; 6619 # ifdef FEAT_FLOAT 6620 proftime_T tm; 6621 # endif 6622 int len; 6623 proftime_T total_total; 6624 int total_count = 0; 6625 garray_T ga; 6626 time_entry_T *p; 6627 6628 if (!syntax_present(curwin)) 6629 { 6630 msg(_(msg_no_items)); 6631 return; 6632 } 6633 6634 ga_init2(&ga, sizeof(time_entry_T), 50); 6635 profile_zero(&total_total); 6636 for (idx = 0; idx < curwin->w_s->b_syn_patterns.ga_len; ++idx) 6637 { 6638 spp = &(SYN_ITEMS(curwin->w_s)[idx]); 6639 if (spp->sp_time.count > 0) 6640 { 6641 (void)ga_grow(&ga, 1); 6642 p = ((time_entry_T *)ga.ga_data) + ga.ga_len; 6643 p->total = spp->sp_time.total; 6644 profile_add(&total_total, &spp->sp_time.total); 6645 p->count = spp->sp_time.count; 6646 p->match = spp->sp_time.match; 6647 total_count += spp->sp_time.count; 6648 p->slowest = spp->sp_time.slowest; 6649 # ifdef FEAT_FLOAT 6650 profile_divide(&spp->sp_time.total, spp->sp_time.count, &tm); 6651 p->average = tm; 6652 # endif 6653 p->id = spp->sp_syn.id; 6654 p->pattern = spp->sp_pattern; 6655 ++ga.ga_len; 6656 } 6657 } 6658 6659 // Sort on total time. Skip if there are no items to avoid passing NULL 6660 // pointer to qsort(). 6661 if (ga.ga_len > 1) 6662 qsort(ga.ga_data, (size_t)ga.ga_len, sizeof(time_entry_T), 6663 syn_compare_syntime); 6664 6665 msg_puts_title(_(" TOTAL COUNT MATCH SLOWEST AVERAGE NAME PATTERN")); 6666 msg_puts("\n"); 6667 for (idx = 0; idx < ga.ga_len && !got_int; ++idx) 6668 { 6669 p = ((time_entry_T *)ga.ga_data) + idx; 6670 6671 msg_puts(profile_msg(&p->total)); 6672 msg_puts(" "); // make sure there is always a separating space 6673 msg_advance(13); 6674 msg_outnum(p->count); 6675 msg_puts(" "); 6676 msg_advance(20); 6677 msg_outnum(p->match); 6678 msg_puts(" "); 6679 msg_advance(26); 6680 msg_puts(profile_msg(&p->slowest)); 6681 msg_puts(" "); 6682 msg_advance(38); 6683 # ifdef FEAT_FLOAT 6684 msg_puts(profile_msg(&p->average)); 6685 msg_puts(" "); 6686 # endif 6687 msg_advance(50); 6688 msg_outtrans(highlight_group_name(p->id - 1)); 6689 msg_puts(" "); 6690 6691 msg_advance(69); 6692 if (Columns < 80) 6693 len = 20; // will wrap anyway 6694 else 6695 len = Columns - 70; 6696 if (len > (int)STRLEN(p->pattern)) 6697 len = (int)STRLEN(p->pattern); 6698 msg_outtrans_len(p->pattern, len); 6699 msg_puts("\n"); 6700 } 6701 ga_clear(&ga); 6702 if (!got_int) 6703 { 6704 msg_puts("\n"); 6705 msg_puts(profile_msg(&total_total)); 6706 msg_advance(13); 6707 msg_outnum(total_count); 6708 msg_puts("\n"); 6709 } 6710 } 6711 #endif 6712 6713 #endif // FEAT_SYN_HL 6714