Mercurial > vim
comparison src/highlight.c @ 21054:b1fac55cf8a3 v8.2.1078
patch 8.2.1078: highlight and match functionality together in one file
Commit: https://github.com/vim/vim/commit/06cf97e714fd8bf9b35ff5f8a6f2302c79acdd03
Author: Bram Moolenaar <Bram@vim.org>
Date: Sun Jun 28 13:17:26 2020 +0200
patch 8.2.1078: highlight and match functionality together in one file
Problem: Highlight and match functionality together in one file.
Solution: Move match functionality to a separate file. (Yegappan Lakshmanan,
closes #6352)
author | Bram Moolenaar <Bram@vim.org> |
---|---|
date | Sun, 28 Jun 2020 13:30:04 +0200 |
parents | ca2e18364888 |
children | a9ff3e0d6d54 |
comparison
equal
deleted
inserted
replaced
21053:c1f0a0815090 | 21054:b1fac55cf8a3 |
---|---|
7 * See README.txt for an overview of the Vim source code. | 7 * See README.txt for an overview of the Vim source code. |
8 */ | 8 */ |
9 | 9 |
10 /* | 10 /* |
11 * Highlighting stuff. | 11 * Highlighting stuff. |
12 * Includes highlighting matches. | |
13 */ | 12 */ |
14 | 13 |
15 #include "vim.h" | 14 #include "vim.h" |
16 | 15 |
17 #define SG_TERM 1 // term has been set | 16 #define SG_TERM 1 // term has been set |
3692 gui_mch_free_font(gui.ital_font); | 3691 gui_mch_free_font(gui.ital_font); |
3693 gui_mch_free_font(gui.boldital_font); | 3692 gui_mch_free_font(gui.boldital_font); |
3694 # endif | 3693 # endif |
3695 } | 3694 } |
3696 #endif | 3695 #endif |
3697 | |
3698 | |
3699 #if defined(FEAT_SEARCH_EXTRA) || defined(PROTO) | |
3700 | |
3701 # define SEARCH_HL_PRIORITY 0 | |
3702 | |
3703 /* | |
3704 * Add match to the match list of window 'wp'. The pattern 'pat' will be | |
3705 * highlighted with the group 'grp' with priority 'prio'. | |
3706 * Optionally, a desired ID 'id' can be specified (greater than or equal to 1). | |
3707 * If no particular ID is desired, -1 must be specified for 'id'. | |
3708 * Return ID of added match, -1 on failure. | |
3709 */ | |
3710 static int | |
3711 match_add( | |
3712 win_T *wp, | |
3713 char_u *grp, | |
3714 char_u *pat, | |
3715 int prio, | |
3716 int id, | |
3717 list_T *pos_list, | |
3718 char_u *conceal_char UNUSED) // pointer to conceal replacement char | |
3719 { | |
3720 matchitem_T *cur; | |
3721 matchitem_T *prev; | |
3722 matchitem_T *m; | |
3723 int hlg_id; | |
3724 regprog_T *regprog = NULL; | |
3725 int rtype = SOME_VALID; | |
3726 | |
3727 if (*grp == NUL || (pat != NULL && *pat == NUL)) | |
3728 return -1; | |
3729 if (id < -1 || id == 0) | |
3730 { | |
3731 semsg(_("E799: Invalid ID: %d (must be greater than or equal to 1)"), | |
3732 id); | |
3733 return -1; | |
3734 } | |
3735 if (id != -1) | |
3736 { | |
3737 cur = wp->w_match_head; | |
3738 while (cur != NULL) | |
3739 { | |
3740 if (cur->id == id) | |
3741 { | |
3742 semsg(_("E801: ID already taken: %d"), id); | |
3743 return -1; | |
3744 } | |
3745 cur = cur->next; | |
3746 } | |
3747 } | |
3748 if ((hlg_id = syn_namen2id(grp, (int)STRLEN(grp))) == 0) | |
3749 { | |
3750 semsg(_(e_nogroup), grp); | |
3751 return -1; | |
3752 } | |
3753 if (pat != NULL && (regprog = vim_regcomp(pat, RE_MAGIC)) == NULL) | |
3754 { | |
3755 semsg(_(e_invarg2), pat); | |
3756 return -1; | |
3757 } | |
3758 | |
3759 // Find available match ID. | |
3760 while (id == -1) | |
3761 { | |
3762 cur = wp->w_match_head; | |
3763 while (cur != NULL && cur->id != wp->w_next_match_id) | |
3764 cur = cur->next; | |
3765 if (cur == NULL) | |
3766 id = wp->w_next_match_id; | |
3767 wp->w_next_match_id++; | |
3768 } | |
3769 | |
3770 // Build new match. | |
3771 m = ALLOC_CLEAR_ONE(matchitem_T); | |
3772 m->id = id; | |
3773 m->priority = prio; | |
3774 m->pattern = pat == NULL ? NULL : vim_strsave(pat); | |
3775 m->hlg_id = hlg_id; | |
3776 m->match.regprog = regprog; | |
3777 m->match.rmm_ic = FALSE; | |
3778 m->match.rmm_maxcol = 0; | |
3779 # if defined(FEAT_CONCEAL) | |
3780 m->conceal_char = 0; | |
3781 if (conceal_char != NULL) | |
3782 m->conceal_char = (*mb_ptr2char)(conceal_char); | |
3783 # endif | |
3784 | |
3785 // Set up position matches | |
3786 if (pos_list != NULL) | |
3787 { | |
3788 linenr_T toplnum = 0; | |
3789 linenr_T botlnum = 0; | |
3790 listitem_T *li; | |
3791 int i; | |
3792 | |
3793 CHECK_LIST_MATERIALIZE(pos_list); | |
3794 for (i = 0, li = pos_list->lv_first; li != NULL && i < MAXPOSMATCH; | |
3795 i++, li = li->li_next) | |
3796 { | |
3797 linenr_T lnum = 0; | |
3798 colnr_T col = 0; | |
3799 int len = 1; | |
3800 list_T *subl; | |
3801 listitem_T *subli; | |
3802 int error = FALSE; | |
3803 | |
3804 if (li->li_tv.v_type == VAR_LIST) | |
3805 { | |
3806 subl = li->li_tv.vval.v_list; | |
3807 if (subl == NULL) | |
3808 goto fail; | |
3809 subli = subl->lv_first; | |
3810 if (subli == NULL) | |
3811 goto fail; | |
3812 lnum = tv_get_number_chk(&subli->li_tv, &error); | |
3813 if (error == TRUE) | |
3814 goto fail; | |
3815 if (lnum == 0) | |
3816 { | |
3817 --i; | |
3818 continue; | |
3819 } | |
3820 m->pos.pos[i].lnum = lnum; | |
3821 subli = subli->li_next; | |
3822 if (subli != NULL) | |
3823 { | |
3824 col = tv_get_number_chk(&subli->li_tv, &error); | |
3825 if (error == TRUE) | |
3826 goto fail; | |
3827 subli = subli->li_next; | |
3828 if (subli != NULL) | |
3829 { | |
3830 len = tv_get_number_chk(&subli->li_tv, &error); | |
3831 if (error == TRUE) | |
3832 goto fail; | |
3833 } | |
3834 } | |
3835 m->pos.pos[i].col = col; | |
3836 m->pos.pos[i].len = len; | |
3837 } | |
3838 else if (li->li_tv.v_type == VAR_NUMBER) | |
3839 { | |
3840 if (li->li_tv.vval.v_number == 0) | |
3841 { | |
3842 --i; | |
3843 continue; | |
3844 } | |
3845 m->pos.pos[i].lnum = li->li_tv.vval.v_number; | |
3846 m->pos.pos[i].col = 0; | |
3847 m->pos.pos[i].len = 0; | |
3848 } | |
3849 else | |
3850 { | |
3851 emsg(_("E290: List or number required")); | |
3852 goto fail; | |
3853 } | |
3854 if (toplnum == 0 || lnum < toplnum) | |
3855 toplnum = lnum; | |
3856 if (botlnum == 0 || lnum >= botlnum) | |
3857 botlnum = lnum + 1; | |
3858 } | |
3859 | |
3860 // Calculate top and bottom lines for redrawing area | |
3861 if (toplnum != 0) | |
3862 { | |
3863 if (wp->w_buffer->b_mod_set) | |
3864 { | |
3865 if (wp->w_buffer->b_mod_top > toplnum) | |
3866 wp->w_buffer->b_mod_top = toplnum; | |
3867 if (wp->w_buffer->b_mod_bot < botlnum) | |
3868 wp->w_buffer->b_mod_bot = botlnum; | |
3869 } | |
3870 else | |
3871 { | |
3872 wp->w_buffer->b_mod_set = TRUE; | |
3873 wp->w_buffer->b_mod_top = toplnum; | |
3874 wp->w_buffer->b_mod_bot = botlnum; | |
3875 wp->w_buffer->b_mod_xlines = 0; | |
3876 } | |
3877 m->pos.toplnum = toplnum; | |
3878 m->pos.botlnum = botlnum; | |
3879 rtype = VALID; | |
3880 } | |
3881 } | |
3882 | |
3883 // Insert new match. The match list is in ascending order with regard to | |
3884 // the match priorities. | |
3885 cur = wp->w_match_head; | |
3886 prev = cur; | |
3887 while (cur != NULL && prio >= cur->priority) | |
3888 { | |
3889 prev = cur; | |
3890 cur = cur->next; | |
3891 } | |
3892 if (cur == prev) | |
3893 wp->w_match_head = m; | |
3894 else | |
3895 prev->next = m; | |
3896 m->next = cur; | |
3897 | |
3898 redraw_win_later(wp, rtype); | |
3899 return id; | |
3900 | |
3901 fail: | |
3902 vim_free(m); | |
3903 return -1; | |
3904 } | |
3905 | |
3906 /* | |
3907 * Delete match with ID 'id' in the match list of window 'wp'. | |
3908 * Print error messages if 'perr' is TRUE. | |
3909 */ | |
3910 static int | |
3911 match_delete(win_T *wp, int id, int perr) | |
3912 { | |
3913 matchitem_T *cur = wp->w_match_head; | |
3914 matchitem_T *prev = cur; | |
3915 int rtype = SOME_VALID; | |
3916 | |
3917 if (id < 1) | |
3918 { | |
3919 if (perr == TRUE) | |
3920 semsg(_("E802: Invalid ID: %d (must be greater than or equal to 1)"), | |
3921 id); | |
3922 return -1; | |
3923 } | |
3924 while (cur != NULL && cur->id != id) | |
3925 { | |
3926 prev = cur; | |
3927 cur = cur->next; | |
3928 } | |
3929 if (cur == NULL) | |
3930 { | |
3931 if (perr == TRUE) | |
3932 semsg(_("E803: ID not found: %d"), id); | |
3933 return -1; | |
3934 } | |
3935 if (cur == prev) | |
3936 wp->w_match_head = cur->next; | |
3937 else | |
3938 prev->next = cur->next; | |
3939 vim_regfree(cur->match.regprog); | |
3940 vim_free(cur->pattern); | |
3941 if (cur->pos.toplnum != 0) | |
3942 { | |
3943 if (wp->w_buffer->b_mod_set) | |
3944 { | |
3945 if (wp->w_buffer->b_mod_top > cur->pos.toplnum) | |
3946 wp->w_buffer->b_mod_top = cur->pos.toplnum; | |
3947 if (wp->w_buffer->b_mod_bot < cur->pos.botlnum) | |
3948 wp->w_buffer->b_mod_bot = cur->pos.botlnum; | |
3949 } | |
3950 else | |
3951 { | |
3952 wp->w_buffer->b_mod_set = TRUE; | |
3953 wp->w_buffer->b_mod_top = cur->pos.toplnum; | |
3954 wp->w_buffer->b_mod_bot = cur->pos.botlnum; | |
3955 wp->w_buffer->b_mod_xlines = 0; | |
3956 } | |
3957 rtype = VALID; | |
3958 } | |
3959 vim_free(cur); | |
3960 redraw_win_later(wp, rtype); | |
3961 return 0; | |
3962 } | |
3963 | |
3964 /* | |
3965 * Delete all matches in the match list of window 'wp'. | |
3966 */ | |
3967 void | |
3968 clear_matches(win_T *wp) | |
3969 { | |
3970 matchitem_T *m; | |
3971 | |
3972 while (wp->w_match_head != NULL) | |
3973 { | |
3974 m = wp->w_match_head->next; | |
3975 vim_regfree(wp->w_match_head->match.regprog); | |
3976 vim_free(wp->w_match_head->pattern); | |
3977 vim_free(wp->w_match_head); | |
3978 wp->w_match_head = m; | |
3979 } | |
3980 redraw_win_later(wp, SOME_VALID); | |
3981 } | |
3982 | |
3983 /* | |
3984 * Get match from ID 'id' in window 'wp'. | |
3985 * Return NULL if match not found. | |
3986 */ | |
3987 static matchitem_T * | |
3988 get_match(win_T *wp, int id) | |
3989 { | |
3990 matchitem_T *cur = wp->w_match_head; | |
3991 | |
3992 while (cur != NULL && cur->id != id) | |
3993 cur = cur->next; | |
3994 return cur; | |
3995 } | |
3996 | |
3997 /* | |
3998 * Init for calling prepare_search_hl(). | |
3999 */ | |
4000 void | |
4001 init_search_hl(win_T *wp, match_T *search_hl) | |
4002 { | |
4003 matchitem_T *cur; | |
4004 | |
4005 // Setup for match and 'hlsearch' highlighting. Disable any previous | |
4006 // match | |
4007 cur = wp->w_match_head; | |
4008 while (cur != NULL) | |
4009 { | |
4010 cur->hl.rm = cur->match; | |
4011 if (cur->hlg_id == 0) | |
4012 cur->hl.attr = 0; | |
4013 else | |
4014 cur->hl.attr = syn_id2attr(cur->hlg_id); | |
4015 cur->hl.buf = wp->w_buffer; | |
4016 cur->hl.lnum = 0; | |
4017 cur->hl.first_lnum = 0; | |
4018 # ifdef FEAT_RELTIME | |
4019 // Set the time limit to 'redrawtime'. | |
4020 profile_setlimit(p_rdt, &(cur->hl.tm)); | |
4021 # endif | |
4022 cur = cur->next; | |
4023 } | |
4024 search_hl->buf = wp->w_buffer; | |
4025 search_hl->lnum = 0; | |
4026 search_hl->first_lnum = 0; | |
4027 // time limit is set at the toplevel, for all windows | |
4028 } | |
4029 | |
4030 /* | |
4031 * If there is a match fill "shl" and return one. | |
4032 * Return zero otherwise. | |
4033 */ | |
4034 static int | |
4035 next_search_hl_pos( | |
4036 match_T *shl, // points to a match | |
4037 linenr_T lnum, | |
4038 posmatch_T *posmatch, // match positions | |
4039 colnr_T mincol) // minimal column for a match | |
4040 { | |
4041 int i; | |
4042 int found = -1; | |
4043 | |
4044 for (i = posmatch->cur; i < MAXPOSMATCH; i++) | |
4045 { | |
4046 llpos_T *pos = &posmatch->pos[i]; | |
4047 | |
4048 if (pos->lnum == 0) | |
4049 break; | |
4050 if (pos->len == 0 && pos->col < mincol) | |
4051 continue; | |
4052 if (pos->lnum == lnum) | |
4053 { | |
4054 if (found >= 0) | |
4055 { | |
4056 // if this match comes before the one at "found" then swap | |
4057 // them | |
4058 if (pos->col < posmatch->pos[found].col) | |
4059 { | |
4060 llpos_T tmp = *pos; | |
4061 | |
4062 *pos = posmatch->pos[found]; | |
4063 posmatch->pos[found] = tmp; | |
4064 } | |
4065 } | |
4066 else | |
4067 found = i; | |
4068 } | |
4069 } | |
4070 posmatch->cur = 0; | |
4071 if (found >= 0) | |
4072 { | |
4073 colnr_T start = posmatch->pos[found].col == 0 | |
4074 ? 0 : posmatch->pos[found].col - 1; | |
4075 colnr_T end = posmatch->pos[found].col == 0 | |
4076 ? MAXCOL : start + posmatch->pos[found].len; | |
4077 | |
4078 shl->lnum = lnum; | |
4079 shl->rm.startpos[0].lnum = 0; | |
4080 shl->rm.startpos[0].col = start; | |
4081 shl->rm.endpos[0].lnum = 0; | |
4082 shl->rm.endpos[0].col = end; | |
4083 shl->is_addpos = TRUE; | |
4084 posmatch->cur = found + 1; | |
4085 return 1; | |
4086 } | |
4087 return 0; | |
4088 } | |
4089 | |
4090 /* | |
4091 * Search for a next 'hlsearch' or match. | |
4092 * Uses shl->buf. | |
4093 * Sets shl->lnum and shl->rm contents. | |
4094 * Note: Assumes a previous match is always before "lnum", unless | |
4095 * shl->lnum is zero. | |
4096 * Careful: Any pointers for buffer lines will become invalid. | |
4097 */ | |
4098 static void | |
4099 next_search_hl( | |
4100 win_T *win, | |
4101 match_T *search_hl, | |
4102 match_T *shl, // points to search_hl or a match | |
4103 linenr_T lnum, | |
4104 colnr_T mincol, // minimal column for a match | |
4105 matchitem_T *cur) // to retrieve match positions if any | |
4106 { | |
4107 linenr_T l; | |
4108 colnr_T matchcol; | |
4109 long nmatched; | |
4110 int called_emsg_before = called_emsg; | |
4111 | |
4112 // for :{range}s/pat only highlight inside the range | |
4113 if (lnum < search_first_line || lnum > search_last_line) | |
4114 { | |
4115 shl->lnum = 0; | |
4116 return; | |
4117 } | |
4118 | |
4119 if (shl->lnum != 0) | |
4120 { | |
4121 // Check for three situations: | |
4122 // 1. If the "lnum" is below a previous match, start a new search. | |
4123 // 2. If the previous match includes "mincol", use it. | |
4124 // 3. Continue after the previous match. | |
4125 l = shl->lnum + shl->rm.endpos[0].lnum - shl->rm.startpos[0].lnum; | |
4126 if (lnum > l) | |
4127 shl->lnum = 0; | |
4128 else if (lnum < l || shl->rm.endpos[0].col > mincol) | |
4129 return; | |
4130 } | |
4131 | |
4132 /* | |
4133 * Repeat searching for a match until one is found that includes "mincol" | |
4134 * or none is found in this line. | |
4135 */ | |
4136 for (;;) | |
4137 { | |
4138 # ifdef FEAT_RELTIME | |
4139 // Stop searching after passing the time limit. | |
4140 if (profile_passed_limit(&(shl->tm))) | |
4141 { | |
4142 shl->lnum = 0; // no match found in time | |
4143 break; | |
4144 } | |
4145 # endif | |
4146 // Three situations: | |
4147 // 1. No useful previous match: search from start of line. | |
4148 // 2. Not Vi compatible or empty match: continue at next character. | |
4149 // Break the loop if this is beyond the end of the line. | |
4150 // 3. Vi compatible searching: continue at end of previous match. | |
4151 if (shl->lnum == 0) | |
4152 matchcol = 0; | |
4153 else if (vim_strchr(p_cpo, CPO_SEARCH) == NULL | |
4154 || (shl->rm.endpos[0].lnum == 0 | |
4155 && shl->rm.endpos[0].col <= shl->rm.startpos[0].col)) | |
4156 { | |
4157 char_u *ml; | |
4158 | |
4159 matchcol = shl->rm.startpos[0].col; | |
4160 ml = ml_get_buf(shl->buf, lnum, FALSE) + matchcol; | |
4161 if (*ml == NUL) | |
4162 { | |
4163 ++matchcol; | |
4164 shl->lnum = 0; | |
4165 break; | |
4166 } | |
4167 if (has_mbyte) | |
4168 matchcol += mb_ptr2len(ml); | |
4169 else | |
4170 ++matchcol; | |
4171 } | |
4172 else | |
4173 matchcol = shl->rm.endpos[0].col; | |
4174 | |
4175 shl->lnum = lnum; | |
4176 if (shl->rm.regprog != NULL) | |
4177 { | |
4178 // Remember whether shl->rm is using a copy of the regprog in | |
4179 // cur->match. | |
4180 int regprog_is_copy = (shl != search_hl && cur != NULL | |
4181 && shl == &cur->hl | |
4182 && cur->match.regprog == cur->hl.rm.regprog); | |
4183 int timed_out = FALSE; | |
4184 | |
4185 nmatched = vim_regexec_multi(&shl->rm, win, shl->buf, lnum, | |
4186 matchcol, | |
4187 #ifdef FEAT_RELTIME | |
4188 &(shl->tm), &timed_out | |
4189 #else | |
4190 NULL, NULL | |
4191 #endif | |
4192 ); | |
4193 // Copy the regprog, in case it got freed and recompiled. | |
4194 if (regprog_is_copy) | |
4195 cur->match.regprog = cur->hl.rm.regprog; | |
4196 | |
4197 if (called_emsg > called_emsg_before || got_int || timed_out) | |
4198 { | |
4199 // Error while handling regexp: stop using this regexp. | |
4200 if (shl == search_hl) | |
4201 { | |
4202 // don't free regprog in the match list, it's a copy | |
4203 vim_regfree(shl->rm.regprog); | |
4204 set_no_hlsearch(TRUE); | |
4205 } | |
4206 shl->rm.regprog = NULL; | |
4207 shl->lnum = 0; | |
4208 got_int = FALSE; // avoid the "Type :quit to exit Vim" message | |
4209 break; | |
4210 } | |
4211 } | |
4212 else if (cur != NULL) | |
4213 nmatched = next_search_hl_pos(shl, lnum, &(cur->pos), matchcol); | |
4214 else | |
4215 nmatched = 0; | |
4216 if (nmatched == 0) | |
4217 { | |
4218 shl->lnum = 0; // no match found | |
4219 break; | |
4220 } | |
4221 if (shl->rm.startpos[0].lnum > 0 | |
4222 || shl->rm.startpos[0].col >= mincol | |
4223 || nmatched > 1 | |
4224 || shl->rm.endpos[0].col > mincol) | |
4225 { | |
4226 shl->lnum += shl->rm.startpos[0].lnum; | |
4227 break; // useful match found | |
4228 } | |
4229 } | |
4230 } | |
4231 | |
4232 /* | |
4233 * Advance to the match in window "wp" line "lnum" or past it. | |
4234 */ | |
4235 void | |
4236 prepare_search_hl(win_T *wp, match_T *search_hl, linenr_T lnum) | |
4237 { | |
4238 matchitem_T *cur; // points to the match list | |
4239 match_T *shl; // points to search_hl or a match | |
4240 int shl_flag; // flag to indicate whether search_hl | |
4241 // has been processed or not | |
4242 int pos_inprogress; // marks that position match search is | |
4243 // in progress | |
4244 int n; | |
4245 | |
4246 // When using a multi-line pattern, start searching at the top | |
4247 // of the window or just after a closed fold. | |
4248 // Do this both for search_hl and the match list. | |
4249 cur = wp->w_match_head; | |
4250 shl_flag = WIN_IS_POPUP(wp); // skip search_hl in a popup window | |
4251 while (cur != NULL || shl_flag == FALSE) | |
4252 { | |
4253 if (shl_flag == FALSE) | |
4254 { | |
4255 shl = search_hl; | |
4256 shl_flag = TRUE; | |
4257 } | |
4258 else | |
4259 shl = &cur->hl; | |
4260 if (shl->rm.regprog != NULL | |
4261 && shl->lnum == 0 | |
4262 && re_multiline(shl->rm.regprog)) | |
4263 { | |
4264 if (shl->first_lnum == 0) | |
4265 { | |
4266 # ifdef FEAT_FOLDING | |
4267 for (shl->first_lnum = lnum; | |
4268 shl->first_lnum > wp->w_topline; --shl->first_lnum) | |
4269 if (hasFoldingWin(wp, shl->first_lnum - 1, | |
4270 NULL, NULL, TRUE, NULL)) | |
4271 break; | |
4272 # else | |
4273 shl->first_lnum = wp->w_topline; | |
4274 # endif | |
4275 } | |
4276 if (cur != NULL) | |
4277 cur->pos.cur = 0; | |
4278 pos_inprogress = TRUE; | |
4279 n = 0; | |
4280 while (shl->first_lnum < lnum && (shl->rm.regprog != NULL | |
4281 || (cur != NULL && pos_inprogress))) | |
4282 { | |
4283 next_search_hl(wp, search_hl, shl, shl->first_lnum, (colnr_T)n, | |
4284 shl == search_hl ? NULL : cur); | |
4285 pos_inprogress = cur == NULL || cur->pos.cur == 0 | |
4286 ? FALSE : TRUE; | |
4287 if (shl->lnum != 0) | |
4288 { | |
4289 shl->first_lnum = shl->lnum | |
4290 + shl->rm.endpos[0].lnum | |
4291 - shl->rm.startpos[0].lnum; | |
4292 n = shl->rm.endpos[0].col; | |
4293 } | |
4294 else | |
4295 { | |
4296 ++shl->first_lnum; | |
4297 n = 0; | |
4298 } | |
4299 } | |
4300 } | |
4301 if (shl != search_hl && cur != NULL) | |
4302 cur = cur->next; | |
4303 } | |
4304 } | |
4305 | |
4306 /* | |
4307 * Prepare for 'hlsearch' and match highlighting in one window line. | |
4308 * Return TRUE if there is such highlighting and set "search_attr" to the | |
4309 * current highlight attribute. | |
4310 */ | |
4311 int | |
4312 prepare_search_hl_line( | |
4313 win_T *wp, | |
4314 linenr_T lnum, | |
4315 colnr_T mincol, | |
4316 char_u **line, | |
4317 match_T *search_hl, | |
4318 int *search_attr) | |
4319 { | |
4320 matchitem_T *cur; // points to the match list | |
4321 match_T *shl; // points to search_hl or a match | |
4322 int shl_flag; // flag to indicate whether search_hl | |
4323 // has been processed or not | |
4324 int area_highlighting = FALSE; | |
4325 | |
4326 /* | |
4327 * Handle highlighting the last used search pattern and matches. | |
4328 * Do this for both search_hl and the match list. | |
4329 * Do not use search_hl in a popup window. | |
4330 */ | |
4331 cur = wp->w_match_head; | |
4332 shl_flag = WIN_IS_POPUP(wp); | |
4333 while (cur != NULL || shl_flag == FALSE) | |
4334 { | |
4335 if (shl_flag == FALSE) | |
4336 { | |
4337 shl = search_hl; | |
4338 shl_flag = TRUE; | |
4339 } | |
4340 else | |
4341 shl = &cur->hl; | |
4342 shl->startcol = MAXCOL; | |
4343 shl->endcol = MAXCOL; | |
4344 shl->attr_cur = 0; | |
4345 shl->is_addpos = FALSE; | |
4346 if (cur != NULL) | |
4347 cur->pos.cur = 0; | |
4348 next_search_hl(wp, search_hl, shl, lnum, mincol, | |
4349 shl == search_hl ? NULL : cur); | |
4350 | |
4351 // Need to get the line again, a multi-line regexp may have made it | |
4352 // invalid. | |
4353 *line = ml_get_buf(wp->w_buffer, lnum, FALSE); | |
4354 | |
4355 if (shl->lnum != 0 && shl->lnum <= lnum) | |
4356 { | |
4357 if (shl->lnum == lnum) | |
4358 shl->startcol = shl->rm.startpos[0].col; | |
4359 else | |
4360 shl->startcol = 0; | |
4361 if (lnum == shl->lnum + shl->rm.endpos[0].lnum | |
4362 - shl->rm.startpos[0].lnum) | |
4363 shl->endcol = shl->rm.endpos[0].col; | |
4364 else | |
4365 shl->endcol = MAXCOL; | |
4366 // Highlight one character for an empty match. | |
4367 if (shl->startcol == shl->endcol) | |
4368 { | |
4369 if (has_mbyte && (*line)[shl->endcol] != NUL) | |
4370 shl->endcol += (*mb_ptr2len)((*line) + shl->endcol); | |
4371 else | |
4372 ++shl->endcol; | |
4373 } | |
4374 if ((long)shl->startcol < mincol) // match at leftcol | |
4375 { | |
4376 shl->attr_cur = shl->attr; | |
4377 *search_attr = shl->attr; | |
4378 } | |
4379 area_highlighting = TRUE; | |
4380 } | |
4381 if (shl != search_hl && cur != NULL) | |
4382 cur = cur->next; | |
4383 } | |
4384 return area_highlighting; | |
4385 } | |
4386 | |
4387 /* | |
4388 * For a position in a line: Check for start/end of 'hlsearch' and other | |
4389 * matches. | |
4390 * After end, check for start/end of next match. | |
4391 * When another match, have to check for start again. | |
4392 * Watch out for matching an empty string! | |
4393 * Return the updated search_attr. | |
4394 */ | |
4395 int | |
4396 update_search_hl( | |
4397 win_T *wp, | |
4398 linenr_T lnum, | |
4399 colnr_T col, | |
4400 char_u **line, | |
4401 match_T *search_hl, | |
4402 int *has_match_conc UNUSED, | |
4403 int *match_conc UNUSED, | |
4404 int did_line_attr, | |
4405 int lcs_eol_one) | |
4406 { | |
4407 matchitem_T *cur; // points to the match list | |
4408 match_T *shl; // points to search_hl or a match | |
4409 int shl_flag; // flag to indicate whether search_hl | |
4410 // has been processed or not | |
4411 int pos_inprogress; // marks that position match search is in | |
4412 // progress | |
4413 int search_attr = 0; | |
4414 | |
4415 | |
4416 // Do this for 'search_hl' and the match list (ordered by priority). | |
4417 cur = wp->w_match_head; | |
4418 shl_flag = WIN_IS_POPUP(wp); | |
4419 while (cur != NULL || shl_flag == FALSE) | |
4420 { | |
4421 if (shl_flag == FALSE | |
4422 && (cur == NULL | |
4423 || cur->priority > SEARCH_HL_PRIORITY)) | |
4424 { | |
4425 shl = search_hl; | |
4426 shl_flag = TRUE; | |
4427 } | |
4428 else | |
4429 shl = &cur->hl; | |
4430 if (cur != NULL) | |
4431 cur->pos.cur = 0; | |
4432 pos_inprogress = TRUE; | |
4433 while (shl->rm.regprog != NULL || (cur != NULL && pos_inprogress)) | |
4434 { | |
4435 if (shl->startcol != MAXCOL | |
4436 && col >= shl->startcol | |
4437 && col < shl->endcol) | |
4438 { | |
4439 int next_col = col + mb_ptr2len(*line + col); | |
4440 | |
4441 if (shl->endcol < next_col) | |
4442 shl->endcol = next_col; | |
4443 shl->attr_cur = shl->attr; | |
4444 # ifdef FEAT_CONCEAL | |
4445 // Match with the "Conceal" group results in hiding | |
4446 // the match. | |
4447 if (cur != NULL | |
4448 && shl != search_hl | |
4449 && syn_name2id((char_u *)"Conceal") == cur->hlg_id) | |
4450 { | |
4451 *has_match_conc = col == shl->startcol ? 2 : 1; | |
4452 *match_conc = cur->conceal_char; | |
4453 } | |
4454 else | |
4455 *has_match_conc = 0; | |
4456 # endif | |
4457 } | |
4458 else if (col == shl->endcol) | |
4459 { | |
4460 shl->attr_cur = 0; | |
4461 next_search_hl(wp, search_hl, shl, lnum, col, | |
4462 shl == search_hl ? NULL : cur); | |
4463 pos_inprogress = !(cur == NULL || cur->pos.cur == 0); | |
4464 | |
4465 // Need to get the line again, a multi-line regexp may have | |
4466 // made it invalid. | |
4467 *line = ml_get_buf(wp->w_buffer, lnum, FALSE); | |
4468 | |
4469 if (shl->lnum == lnum) | |
4470 { | |
4471 shl->startcol = shl->rm.startpos[0].col; | |
4472 if (shl->rm.endpos[0].lnum == 0) | |
4473 shl->endcol = shl->rm.endpos[0].col; | |
4474 else | |
4475 shl->endcol = MAXCOL; | |
4476 | |
4477 if (shl->startcol == shl->endcol) | |
4478 { | |
4479 // highlight empty match, try again after | |
4480 // it | |
4481 if (has_mbyte) | |
4482 shl->endcol += (*mb_ptr2len)(*line + shl->endcol); | |
4483 else | |
4484 ++shl->endcol; | |
4485 } | |
4486 | |
4487 // Loop to check if the match starts at the | |
4488 // current position | |
4489 continue; | |
4490 } | |
4491 } | |
4492 break; | |
4493 } | |
4494 if (shl != search_hl && cur != NULL) | |
4495 cur = cur->next; | |
4496 } | |
4497 | |
4498 // Use attributes from match with highest priority among 'search_hl' and | |
4499 // the match list. | |
4500 cur = wp->w_match_head; | |
4501 shl_flag = WIN_IS_POPUP(wp); | |
4502 while (cur != NULL || shl_flag == FALSE) | |
4503 { | |
4504 if (shl_flag == FALSE | |
4505 && (cur == NULL || | |
4506 cur->priority > SEARCH_HL_PRIORITY)) | |
4507 { | |
4508 shl = search_hl; | |
4509 shl_flag = TRUE; | |
4510 } | |
4511 else | |
4512 shl = &cur->hl; | |
4513 if (shl->attr_cur != 0) | |
4514 search_attr = shl->attr_cur; | |
4515 if (shl != search_hl && cur != NULL) | |
4516 cur = cur->next; | |
4517 } | |
4518 // Only highlight one character after the last column. | |
4519 if (*(*line + col) == NUL && (did_line_attr >= 1 | |
4520 || (wp->w_p_list && lcs_eol_one == -1))) | |
4521 search_attr = 0; | |
4522 return search_attr; | |
4523 } | |
4524 | |
4525 int | |
4526 get_prevcol_hl_flag(win_T *wp, match_T *search_hl, long curcol) | |
4527 { | |
4528 long prevcol = curcol; | |
4529 int prevcol_hl_flag = FALSE; | |
4530 matchitem_T *cur; // points to the match list | |
4531 | |
4532 // we're not really at that column when skipping some text | |
4533 if ((long)(wp->w_p_wrap ? wp->w_skipcol : wp->w_leftcol) > prevcol) | |
4534 ++prevcol; | |
4535 | |
4536 if (!search_hl->is_addpos && prevcol == (long)search_hl->startcol) | |
4537 prevcol_hl_flag = TRUE; | |
4538 else | |
4539 { | |
4540 cur = wp->w_match_head; | |
4541 while (cur != NULL) | |
4542 { | |
4543 if (!cur->hl.is_addpos && prevcol == (long)cur->hl.startcol) | |
4544 { | |
4545 prevcol_hl_flag = TRUE; | |
4546 break; | |
4547 } | |
4548 cur = cur->next; | |
4549 } | |
4550 } | |
4551 return prevcol_hl_flag; | |
4552 } | |
4553 | |
4554 /* | |
4555 * Get highlighting for the char after the text in "char_attr" from 'hlsearch' | |
4556 * or match highlighting. | |
4557 */ | |
4558 void | |
4559 get_search_match_hl(win_T *wp, match_T *search_hl, long col, int *char_attr) | |
4560 { | |
4561 matchitem_T *cur; // points to the match list | |
4562 match_T *shl; // points to search_hl or a match | |
4563 int shl_flag; // flag to indicate whether search_hl | |
4564 // has been processed or not | |
4565 | |
4566 cur = wp->w_match_head; | |
4567 shl_flag = WIN_IS_POPUP(wp); | |
4568 while (cur != NULL || shl_flag == FALSE) | |
4569 { | |
4570 if (shl_flag == FALSE | |
4571 && ((cur != NULL | |
4572 && cur->priority > SEARCH_HL_PRIORITY) | |
4573 || cur == NULL)) | |
4574 { | |
4575 shl = search_hl; | |
4576 shl_flag = TRUE; | |
4577 } | |
4578 else | |
4579 shl = &cur->hl; | |
4580 if (col - 1 == (long)shl->startcol | |
4581 && (shl == search_hl || !shl->is_addpos)) | |
4582 *char_attr = shl->attr; | |
4583 if (shl != search_hl && cur != NULL) | |
4584 cur = cur->next; | |
4585 } | |
4586 } | |
4587 | |
4588 #endif // FEAT_SEARCH_EXTRA | |
4589 | |
4590 #if defined(FEAT_EVAL) || defined(PROTO) | |
4591 # ifdef FEAT_SEARCH_EXTRA | |
4592 static int | |
4593 matchadd_dict_arg(typval_T *tv, char_u **conceal_char, win_T **win) | |
4594 { | |
4595 dictitem_T *di; | |
4596 | |
4597 if (tv->v_type != VAR_DICT) | |
4598 { | |
4599 emsg(_(e_dictreq)); | |
4600 return FAIL; | |
4601 } | |
4602 | |
4603 if (dict_find(tv->vval.v_dict, (char_u *)"conceal", -1) != NULL) | |
4604 *conceal_char = dict_get_string(tv->vval.v_dict, | |
4605 (char_u *)"conceal", FALSE); | |
4606 | |
4607 if ((di = dict_find(tv->vval.v_dict, (char_u *)"window", -1)) != NULL) | |
4608 { | |
4609 *win = find_win_by_nr_or_id(&di->di_tv); | |
4610 if (*win == NULL) | |
4611 { | |
4612 emsg(_(e_invalwindow)); | |
4613 return FAIL; | |
4614 } | |
4615 } | |
4616 | |
4617 return OK; | |
4618 } | |
4619 #endif | |
4620 | |
4621 /* | |
4622 * "clearmatches()" function | |
4623 */ | |
4624 void | |
4625 f_clearmatches(typval_T *argvars UNUSED, typval_T *rettv UNUSED) | |
4626 { | |
4627 #ifdef FEAT_SEARCH_EXTRA | |
4628 win_T *win = get_optional_window(argvars, 0); | |
4629 | |
4630 if (win != NULL) | |
4631 clear_matches(win); | |
4632 #endif | |
4633 } | |
4634 | |
4635 /* | |
4636 * "getmatches()" function | |
4637 */ | |
4638 void | |
4639 f_getmatches(typval_T *argvars UNUSED, typval_T *rettv UNUSED) | |
4640 { | |
4641 # ifdef FEAT_SEARCH_EXTRA | |
4642 dict_T *dict; | |
4643 matchitem_T *cur; | |
4644 int i; | |
4645 win_T *win = get_optional_window(argvars, 0); | |
4646 | |
4647 if (rettv_list_alloc(rettv) == FAIL || win == NULL) | |
4648 return; | |
4649 | |
4650 cur = win->w_match_head; | |
4651 while (cur != NULL) | |
4652 { | |
4653 dict = dict_alloc(); | |
4654 if (dict == NULL) | |
4655 return; | |
4656 if (cur->match.regprog == NULL) | |
4657 { | |
4658 // match added with matchaddpos() | |
4659 for (i = 0; i < MAXPOSMATCH; ++i) | |
4660 { | |
4661 llpos_T *llpos; | |
4662 char buf[30]; // use 30 to avoid compiler warning | |
4663 list_T *l; | |
4664 | |
4665 llpos = &cur->pos.pos[i]; | |
4666 if (llpos->lnum == 0) | |
4667 break; | |
4668 l = list_alloc(); | |
4669 if (l == NULL) | |
4670 break; | |
4671 list_append_number(l, (varnumber_T)llpos->lnum); | |
4672 if (llpos->col > 0) | |
4673 { | |
4674 list_append_number(l, (varnumber_T)llpos->col); | |
4675 list_append_number(l, (varnumber_T)llpos->len); | |
4676 } | |
4677 sprintf(buf, "pos%d", i + 1); | |
4678 dict_add_list(dict, buf, l); | |
4679 } | |
4680 } | |
4681 else | |
4682 { | |
4683 dict_add_string(dict, "pattern", cur->pattern); | |
4684 } | |
4685 dict_add_string(dict, "group", syn_id2name(cur->hlg_id)); | |
4686 dict_add_number(dict, "priority", (long)cur->priority); | |
4687 dict_add_number(dict, "id", (long)cur->id); | |
4688 # if defined(FEAT_CONCEAL) | |
4689 if (cur->conceal_char) | |
4690 { | |
4691 char_u buf[MB_MAXBYTES + 1]; | |
4692 | |
4693 buf[(*mb_char2bytes)((int)cur->conceal_char, buf)] = NUL; | |
4694 dict_add_string(dict, "conceal", (char_u *)&buf); | |
4695 } | |
4696 # endif | |
4697 list_append_dict(rettv->vval.v_list, dict); | |
4698 cur = cur->next; | |
4699 } | |
4700 # endif | |
4701 } | |
4702 | |
4703 /* | |
4704 * "setmatches()" function | |
4705 */ | |
4706 void | |
4707 f_setmatches(typval_T *argvars UNUSED, typval_T *rettv UNUSED) | |
4708 { | |
4709 #ifdef FEAT_SEARCH_EXTRA | |
4710 list_T *l; | |
4711 listitem_T *li; | |
4712 dict_T *d; | |
4713 list_T *s = NULL; | |
4714 win_T *win = get_optional_window(argvars, 1); | |
4715 | |
4716 rettv->vval.v_number = -1; | |
4717 if (argvars[0].v_type != VAR_LIST) | |
4718 { | |
4719 emsg(_(e_listreq)); | |
4720 return; | |
4721 } | |
4722 if (win == NULL) | |
4723 return; | |
4724 | |
4725 if ((l = argvars[0].vval.v_list) != NULL) | |
4726 { | |
4727 // To some extent make sure that we are dealing with a list from | |
4728 // "getmatches()". | |
4729 li = l->lv_first; | |
4730 while (li != NULL) | |
4731 { | |
4732 if (li->li_tv.v_type != VAR_DICT | |
4733 || (d = li->li_tv.vval.v_dict) == NULL) | |
4734 { | |
4735 emsg(_(e_invarg)); | |
4736 return; | |
4737 } | |
4738 if (!(dict_find(d, (char_u *)"group", -1) != NULL | |
4739 && (dict_find(d, (char_u *)"pattern", -1) != NULL | |
4740 || dict_find(d, (char_u *)"pos1", -1) != NULL) | |
4741 && dict_find(d, (char_u *)"priority", -1) != NULL | |
4742 && dict_find(d, (char_u *)"id", -1) != NULL)) | |
4743 { | |
4744 emsg(_(e_invarg)); | |
4745 return; | |
4746 } | |
4747 li = li->li_next; | |
4748 } | |
4749 | |
4750 clear_matches(win); | |
4751 li = l->lv_first; | |
4752 while (li != NULL) | |
4753 { | |
4754 int i = 0; | |
4755 char buf[30]; // use 30 to avoid compiler warning | |
4756 dictitem_T *di; | |
4757 char_u *group; | |
4758 int priority; | |
4759 int id; | |
4760 char_u *conceal; | |
4761 | |
4762 d = li->li_tv.vval.v_dict; | |
4763 if (dict_find(d, (char_u *)"pattern", -1) == NULL) | |
4764 { | |
4765 if (s == NULL) | |
4766 { | |
4767 s = list_alloc(); | |
4768 if (s == NULL) | |
4769 return; | |
4770 } | |
4771 | |
4772 // match from matchaddpos() | |
4773 for (i = 1; i < 9; i++) | |
4774 { | |
4775 sprintf((char *)buf, (char *)"pos%d", i); | |
4776 if ((di = dict_find(d, (char_u *)buf, -1)) != NULL) | |
4777 { | |
4778 if (di->di_tv.v_type != VAR_LIST) | |
4779 return; | |
4780 | |
4781 list_append_tv(s, &di->di_tv); | |
4782 s->lv_refcount++; | |
4783 } | |
4784 else | |
4785 break; | |
4786 } | |
4787 } | |
4788 | |
4789 group = dict_get_string(d, (char_u *)"group", TRUE); | |
4790 priority = (int)dict_get_number(d, (char_u *)"priority"); | |
4791 id = (int)dict_get_number(d, (char_u *)"id"); | |
4792 conceal = dict_find(d, (char_u *)"conceal", -1) != NULL | |
4793 ? dict_get_string(d, (char_u *)"conceal", TRUE) | |
4794 : NULL; | |
4795 if (i == 0) | |
4796 { | |
4797 match_add(win, group, | |
4798 dict_get_string(d, (char_u *)"pattern", FALSE), | |
4799 priority, id, NULL, conceal); | |
4800 } | |
4801 else | |
4802 { | |
4803 match_add(win, group, NULL, priority, id, s, conceal); | |
4804 list_unref(s); | |
4805 s = NULL; | |
4806 } | |
4807 vim_free(group); | |
4808 vim_free(conceal); | |
4809 | |
4810 li = li->li_next; | |
4811 } | |
4812 rettv->vval.v_number = 0; | |
4813 } | |
4814 #endif | |
4815 } | |
4816 | |
4817 /* | |
4818 * "matchadd()" function | |
4819 */ | |
4820 void | |
4821 f_matchadd(typval_T *argvars UNUSED, typval_T *rettv UNUSED) | |
4822 { | |
4823 # ifdef FEAT_SEARCH_EXTRA | |
4824 char_u buf[NUMBUFLEN]; | |
4825 char_u *grp = tv_get_string_buf_chk(&argvars[0], buf); // group | |
4826 char_u *pat = tv_get_string_buf_chk(&argvars[1], buf); // pattern | |
4827 int prio = 10; // default priority | |
4828 int id = -1; | |
4829 int error = FALSE; | |
4830 char_u *conceal_char = NULL; | |
4831 win_T *win = curwin; | |
4832 | |
4833 rettv->vval.v_number = -1; | |
4834 | |
4835 if (grp == NULL || pat == NULL) | |
4836 return; | |
4837 if (argvars[2].v_type != VAR_UNKNOWN) | |
4838 { | |
4839 prio = (int)tv_get_number_chk(&argvars[2], &error); | |
4840 if (argvars[3].v_type != VAR_UNKNOWN) | |
4841 { | |
4842 id = (int)tv_get_number_chk(&argvars[3], &error); | |
4843 if (argvars[4].v_type != VAR_UNKNOWN | |
4844 && matchadd_dict_arg(&argvars[4], &conceal_char, &win) == FAIL) | |
4845 return; | |
4846 } | |
4847 } | |
4848 if (error == TRUE) | |
4849 return; | |
4850 if (id >= 1 && id <= 3) | |
4851 { | |
4852 semsg(_("E798: ID is reserved for \":match\": %d"), id); | |
4853 return; | |
4854 } | |
4855 | |
4856 rettv->vval.v_number = match_add(win, grp, pat, prio, id, NULL, | |
4857 conceal_char); | |
4858 # endif | |
4859 } | |
4860 | |
4861 /* | |
4862 * "matchaddpos()" function | |
4863 */ | |
4864 void | |
4865 f_matchaddpos(typval_T *argvars UNUSED, typval_T *rettv UNUSED) | |
4866 { | |
4867 # ifdef FEAT_SEARCH_EXTRA | |
4868 char_u buf[NUMBUFLEN]; | |
4869 char_u *group; | |
4870 int prio = 10; | |
4871 int id = -1; | |
4872 int error = FALSE; | |
4873 list_T *l; | |
4874 char_u *conceal_char = NULL; | |
4875 win_T *win = curwin; | |
4876 | |
4877 rettv->vval.v_number = -1; | |
4878 | |
4879 group = tv_get_string_buf_chk(&argvars[0], buf); | |
4880 if (group == NULL) | |
4881 return; | |
4882 | |
4883 if (argvars[1].v_type != VAR_LIST) | |
4884 { | |
4885 semsg(_(e_listarg), "matchaddpos()"); | |
4886 return; | |
4887 } | |
4888 l = argvars[1].vval.v_list; | |
4889 if (l == NULL) | |
4890 return; | |
4891 | |
4892 if (argvars[2].v_type != VAR_UNKNOWN) | |
4893 { | |
4894 prio = (int)tv_get_number_chk(&argvars[2], &error); | |
4895 if (argvars[3].v_type != VAR_UNKNOWN) | |
4896 { | |
4897 id = (int)tv_get_number_chk(&argvars[3], &error); | |
4898 | |
4899 if (argvars[4].v_type != VAR_UNKNOWN | |
4900 && matchadd_dict_arg(&argvars[4], &conceal_char, &win) == FAIL) | |
4901 return; | |
4902 } | |
4903 } | |
4904 if (error == TRUE) | |
4905 return; | |
4906 | |
4907 // id == 3 is ok because matchaddpos() is supposed to substitute :3match | |
4908 if (id == 1 || id == 2) | |
4909 { | |
4910 semsg(_("E798: ID is reserved for \":match\": %d"), id); | |
4911 return; | |
4912 } | |
4913 | |
4914 rettv->vval.v_number = match_add(win, group, NULL, prio, id, l, | |
4915 conceal_char); | |
4916 # endif | |
4917 } | |
4918 | |
4919 /* | |
4920 * "matcharg()" function | |
4921 */ | |
4922 void | |
4923 f_matcharg(typval_T *argvars UNUSED, typval_T *rettv) | |
4924 { | |
4925 if (rettv_list_alloc(rettv) == OK) | |
4926 { | |
4927 # ifdef FEAT_SEARCH_EXTRA | |
4928 int id = (int)tv_get_number(&argvars[0]); | |
4929 matchitem_T *m; | |
4930 | |
4931 if (id >= 1 && id <= 3) | |
4932 { | |
4933 if ((m = (matchitem_T *)get_match(curwin, id)) != NULL) | |
4934 { | |
4935 list_append_string(rettv->vval.v_list, | |
4936 syn_id2name(m->hlg_id), -1); | |
4937 list_append_string(rettv->vval.v_list, m->pattern, -1); | |
4938 } | |
4939 else | |
4940 { | |
4941 list_append_string(rettv->vval.v_list, NULL, -1); | |
4942 list_append_string(rettv->vval.v_list, NULL, -1); | |
4943 } | |
4944 } | |
4945 # endif | |
4946 } | |
4947 } | |
4948 | |
4949 /* | |
4950 * "matchdelete()" function | |
4951 */ | |
4952 void | |
4953 f_matchdelete(typval_T *argvars UNUSED, typval_T *rettv UNUSED) | |
4954 { | |
4955 # ifdef FEAT_SEARCH_EXTRA | |
4956 win_T *win = get_optional_window(argvars, 1); | |
4957 | |
4958 if (win == NULL) | |
4959 rettv->vval.v_number = -1; | |
4960 else | |
4961 rettv->vval.v_number = match_delete(win, | |
4962 (int)tv_get_number(&argvars[0]), TRUE); | |
4963 # endif | |
4964 } | |
4965 #endif | |
4966 | |
4967 #if defined(FEAT_SEARCH_EXTRA) || defined(PROTO) | |
4968 /* | |
4969 * ":[N]match {group} {pattern}" | |
4970 * Sets nextcmd to the start of the next command, if any. Also called when | |
4971 * skipping commands to find the next command. | |
4972 */ | |
4973 void | |
4974 ex_match(exarg_T *eap) | |
4975 { | |
4976 char_u *p; | |
4977 char_u *g = NULL; | |
4978 char_u *end; | |
4979 int c; | |
4980 int id; | |
4981 | |
4982 if (eap->line2 <= 3) | |
4983 id = eap->line2; | |
4984 else | |
4985 { | |
4986 emsg(_(e_invcmd)); | |
4987 return; | |
4988 } | |
4989 | |
4990 // First clear any old pattern. | |
4991 if (!eap->skip) | |
4992 match_delete(curwin, id, FALSE); | |
4993 | |
4994 if (ends_excmd2(eap->cmd, eap->arg)) | |
4995 end = eap->arg; | |
4996 else if ((STRNICMP(eap->arg, "none", 4) == 0 | |
4997 && (VIM_ISWHITE(eap->arg[4]) | |
4998 || ends_excmd2(eap->arg, eap->arg + 4)))) | |
4999 end = eap->arg + 4; | |
5000 else | |
5001 { | |
5002 p = skiptowhite(eap->arg); | |
5003 if (!eap->skip) | |
5004 g = vim_strnsave(eap->arg, p - eap->arg); | |
5005 p = skipwhite(p); | |
5006 if (*p == NUL) | |
5007 { | |
5008 // There must be two arguments. | |
5009 vim_free(g); | |
5010 semsg(_(e_invarg2), eap->arg); | |
5011 return; | |
5012 } | |
5013 end = skip_regexp(p + 1, *p, TRUE); | |
5014 if (!eap->skip) | |
5015 { | |
5016 if (*end != NUL && !ends_excmd2(end, skipwhite(end + 1))) | |
5017 { | |
5018 vim_free(g); | |
5019 eap->errmsg = e_trailing; | |
5020 return; | |
5021 } | |
5022 if (*end != *p) | |
5023 { | |
5024 vim_free(g); | |
5025 semsg(_(e_invarg2), p); | |
5026 return; | |
5027 } | |
5028 | |
5029 c = *end; | |
5030 *end = NUL; | |
5031 match_add(curwin, g, p + 1, 10, id, NULL, NULL); | |
5032 vim_free(g); | |
5033 *end = c; | |
5034 } | |
5035 } | |
5036 eap->nextcmd = find_nextcmd(end); | |
5037 } | |
5038 #endif |