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