Mercurial > vim
comparison src/quickfix.c @ 16505:28e3ba82d8c8 v8.1.1256
patch 8.1.1256: cannot navigate through errors relative to the cursor
commit https://github.com/vim/vim/commit/3ff33114d70fc0f7e9c3187c5fec9028f6499cf3
Author: Bram Moolenaar <Bram@vim.org>
Date: Fri May 3 21:56:35 2019 +0200
patch 8.1.1256: cannot navigate through errors relative to the cursor
Problem: Cannot navigate through errors relative to the cursor.
Solution: Add :cabove, :cbelow, :labove and :lbelow. (Yegappan Lakshmanan,
closes #4316)
author | Bram Moolenaar <Bram@vim.org> |
---|---|
date | Fri, 03 May 2019 22:00:06 +0200 |
parents | 393dd420a753 |
children | 6e87a69b8e0c |
comparison
equal
deleted
inserted
replaced
16504:d70715c33e4f | 16505:28e3ba82d8c8 |
---|---|
175 static void qf_fill_buffer(qf_list_T *qfl, buf_T *buf, qfline_T *old_last); | 175 static void qf_fill_buffer(qf_list_T *qfl, buf_T *buf, qfline_T *old_last); |
176 static buf_T *load_dummy_buffer(char_u *fname, char_u *dirname_start, char_u *resulting_dir); | 176 static buf_T *load_dummy_buffer(char_u *fname, char_u *dirname_start, char_u *resulting_dir); |
177 static void wipe_dummy_buffer(buf_T *buf, char_u *dirname_start); | 177 static void wipe_dummy_buffer(buf_T *buf, char_u *dirname_start); |
178 static void unload_dummy_buffer(buf_T *buf, char_u *dirname_start); | 178 static void unload_dummy_buffer(buf_T *buf, char_u *dirname_start); |
179 static qf_info_T *ll_get_or_alloc_list(win_T *); | 179 static qf_info_T *ll_get_or_alloc_list(win_T *); |
180 static char_u *e_no_more_items = (char_u *)N_("E553: No more items"); | |
180 | 181 |
181 // Quickfix window check helper macro | 182 // Quickfix window check helper macro |
182 #define IS_QF_WINDOW(wp) (bt_quickfix(wp->w_buffer) && wp->w_llist_ref == NULL) | 183 #define IS_QF_WINDOW(wp) (bt_quickfix(wp->w_buffer) && wp->w_llist_ref == NULL) |
183 // Location list window check helper macro | 184 // Location list window check helper macro |
184 #define IS_LL_WINDOW(wp) (bt_quickfix(wp->w_buffer) && wp->w_llist_ref != NULL) | 185 #define IS_LL_WINDOW(wp) (bt_quickfix(wp->w_buffer) && wp->w_llist_ref != NULL) |
1492 { | 1493 { |
1493 return qfl == NULL || qfl->qf_count <= 0; | 1494 return qfl == NULL || qfl->qf_count <= 0; |
1494 } | 1495 } |
1495 | 1496 |
1496 /* | 1497 /* |
1498 * Returns TRUE if the specified quickfix/location list is not empty and | |
1499 * has valid entries. | |
1500 */ | |
1501 static int | |
1502 qf_list_has_valid_entries(qf_list_T *qfl) | |
1503 { | |
1504 return !qf_list_empty(qfl) && !qfl->qf_nonevalid; | |
1505 } | |
1506 | |
1507 /* | |
1497 * Return a pointer to a list in the specified quickfix stack | 1508 * Return a pointer to a list in the specified quickfix stack |
1498 */ | 1509 */ |
1499 static qf_list_T * | 1510 static qf_list_T * |
1500 qf_get_list(qf_info_T *qi, int idx) | 1511 qf_get_list(qf_info_T *qi, int idx) |
1501 { | 1512 { |
2698 { | 2709 { |
2699 qfline_T *qf_ptr = qfl->qf_ptr; | 2710 qfline_T *qf_ptr = qfl->qf_ptr; |
2700 int qf_idx = qfl->qf_index; | 2711 int qf_idx = qfl->qf_index; |
2701 qfline_T *prev_qf_ptr; | 2712 qfline_T *prev_qf_ptr; |
2702 int prev_index; | 2713 int prev_index; |
2703 static char_u *e_no_more_items = (char_u *)N_("E553: No more items"); | |
2704 char_u *err = e_no_more_items; | 2714 char_u *err = e_no_more_items; |
2705 | 2715 |
2706 while (errornr--) | 2716 while (errornr--) |
2707 { | 2717 { |
2708 prev_qf_ptr = qf_ptr; | 2718 prev_qf_ptr = qf_ptr; |
4884 | 4894 |
4885 qfl = qf_get_curlist(qi); | 4895 qfl = qf_get_curlist(qi); |
4886 qfp = qfl->qf_start; | 4896 qfp = qfl->qf_start; |
4887 | 4897 |
4888 // check if the list has valid errors | 4898 // check if the list has valid errors |
4889 if (qfl->qf_count <= 0 || qfl->qf_nonevalid) | 4899 if (!qf_list_has_valid_entries(qfl)) |
4890 return 1; | 4900 return 1; |
4891 | 4901 |
4892 for (i = 1; i <= qfl->qf_index && qfp!= NULL; i++, qfp = qfp->qf_next) | 4902 for (i = 1; i <= qfl->qf_index && qfp!= NULL; i++, qfp = qfp->qf_next) |
4893 { | 4903 { |
4894 if (qfp->qf_valid) | 4904 if (qfp->qf_valid) |
4922 qfline_T *qfp; | 4932 qfline_T *qfp; |
4923 int i, eidx; | 4933 int i, eidx; |
4924 int prev_fnum = 0; | 4934 int prev_fnum = 0; |
4925 | 4935 |
4926 // check if the list has valid errors | 4936 // check if the list has valid errors |
4927 if (qfl->qf_count <= 0 || qfl->qf_nonevalid) | 4937 if (!qf_list_has_valid_entries(qfl)) |
4928 return 1; | 4938 return 1; |
4929 | 4939 |
4930 eidx = 0; | 4940 eidx = 0; |
4931 FOR_ALL_QFL_ITEMS(qfl, qfp, i) | 4941 FOR_ALL_QFL_ITEMS(qfl, qfp, i) |
4932 { | 4942 { |
5040 dir = FORWARD; | 5050 dir = FORWARD; |
5041 break; | 5051 break; |
5042 } | 5052 } |
5043 | 5053 |
5044 qf_jump(qi, dir, errornr, eap->forceit); | 5054 qf_jump(qi, dir, errornr, eap->forceit); |
5055 } | |
5056 | |
5057 /* | |
5058 * Find the first entry in the quickfix list 'qfl' from buffer 'bnr'. | |
5059 * The index of the entry is stored in 'errornr'. | |
5060 * Returns NULL if an entry is not found. | |
5061 */ | |
5062 static qfline_T * | |
5063 qf_find_first_entry_in_buf(qf_list_T *qfl, int bnr, int *errornr) | |
5064 { | |
5065 qfline_T *qfp = NULL; | |
5066 int idx = 0; | |
5067 | |
5068 // Find the first entry in this file | |
5069 FOR_ALL_QFL_ITEMS(qfl, qfp, idx) | |
5070 if (qfp->qf_fnum == bnr) | |
5071 break; | |
5072 | |
5073 *errornr = idx; | |
5074 return qfp; | |
5075 } | |
5076 | |
5077 /* | |
5078 * Find the first quickfix entry on the same line as 'entry'. Updates 'errornr' | |
5079 * with the error number for the first entry. Assumes the entries are sorted in | |
5080 * the quickfix list by line number. | |
5081 */ | |
5082 static qfline_T * | |
5083 qf_find_first_entry_on_line(qfline_T *entry, int *errornr) | |
5084 { | |
5085 while (!got_int | |
5086 && entry->qf_prev != NULL | |
5087 && entry->qf_fnum == entry->qf_prev->qf_fnum | |
5088 && entry->qf_lnum == entry->qf_prev->qf_lnum) | |
5089 { | |
5090 entry = entry->qf_prev; | |
5091 --*errornr; | |
5092 } | |
5093 | |
5094 return entry; | |
5095 } | |
5096 | |
5097 /* | |
5098 * Find the last quickfix entry on the same line as 'entry'. Updates 'errornr' | |
5099 * with the error number for the last entry. Assumes the entries are sorted in | |
5100 * the quickfix list by line number. | |
5101 */ | |
5102 static qfline_T * | |
5103 qf_find_last_entry_on_line(qfline_T *entry, int *errornr) | |
5104 { | |
5105 while (!got_int && | |
5106 entry->qf_next != NULL | |
5107 && entry->qf_fnum == entry->qf_next->qf_fnum | |
5108 && entry->qf_lnum == entry->qf_next->qf_lnum) | |
5109 { | |
5110 entry = entry->qf_next; | |
5111 ++*errornr; | |
5112 } | |
5113 | |
5114 return entry; | |
5115 } | |
5116 | |
5117 /* | |
5118 * Find the first quickfix entry below line 'lnum' in buffer 'bnr'. | |
5119 * 'qfp' points to the very first entry in the buffer and 'errornr' is the | |
5120 * index of the very first entry in the quickfix list. | |
5121 * Returns NULL if an entry is not found after 'lnum'. | |
5122 */ | |
5123 static qfline_T * | |
5124 qf_find_entry_on_next_line( | |
5125 int bnr, | |
5126 linenr_T lnum, | |
5127 qfline_T *qfp, | |
5128 int *errornr) | |
5129 { | |
5130 if (qfp->qf_lnum > lnum) | |
5131 // First entry is after line 'lnum' | |
5132 return qfp; | |
5133 | |
5134 // Find the entry just before or at the line 'lnum' | |
5135 while (qfp->qf_next != NULL | |
5136 && qfp->qf_next->qf_fnum == bnr | |
5137 && qfp->qf_next->qf_lnum <= lnum) | |
5138 { | |
5139 qfp = qfp->qf_next; | |
5140 ++*errornr; | |
5141 } | |
5142 | |
5143 if (qfp->qf_next == NULL || qfp->qf_next->qf_fnum != bnr) | |
5144 // No entries found after 'lnum' | |
5145 return NULL; | |
5146 | |
5147 // Use the entry just after line 'lnum' | |
5148 qfp = qfp->qf_next; | |
5149 ++*errornr; | |
5150 | |
5151 return qfp; | |
5152 } | |
5153 | |
5154 /* | |
5155 * Find the first quickfix entry before line 'lnum' in buffer 'bnr'. | |
5156 * 'qfp' points to the very first entry in the buffer and 'errornr' is the | |
5157 * index of the very first entry in the quickfix list. | |
5158 * Returns NULL if an entry is not found before 'lnum'. | |
5159 */ | |
5160 static qfline_T * | |
5161 qf_find_entry_on_prev_line( | |
5162 int bnr, | |
5163 linenr_T lnum, | |
5164 qfline_T *qfp, | |
5165 int *errornr) | |
5166 { | |
5167 // Find the entry just before the line 'lnum' | |
5168 while (qfp->qf_next != NULL | |
5169 && qfp->qf_next->qf_fnum == bnr | |
5170 && qfp->qf_next->qf_lnum < lnum) | |
5171 { | |
5172 qfp = qfp->qf_next; | |
5173 ++*errornr; | |
5174 } | |
5175 | |
5176 if (qfp->qf_lnum >= lnum) // entry is after 'lnum' | |
5177 return NULL; | |
5178 | |
5179 // If multiple entries are on the same line, then use the first entry | |
5180 qfp = qf_find_first_entry_on_line(qfp, errornr); | |
5181 | |
5182 return qfp; | |
5183 } | |
5184 | |
5185 /* | |
5186 * Find a quickfix entry in 'qfl' closest to line 'lnum' in buffer 'bnr' in | |
5187 * the direction 'dir'. | |
5188 */ | |
5189 static qfline_T * | |
5190 qf_find_closest_entry( | |
5191 qf_list_T *qfl, | |
5192 int bnr, | |
5193 linenr_T lnum, | |
5194 int dir, | |
5195 int *errornr) | |
5196 { | |
5197 qfline_T *qfp; | |
5198 | |
5199 *errornr = 0; | |
5200 | |
5201 // Find the first entry in this file | |
5202 qfp = qf_find_first_entry_in_buf(qfl, bnr, errornr); | |
5203 if (qfp == NULL) | |
5204 return NULL; // no entry in this file | |
5205 | |
5206 if (dir == FORWARD) | |
5207 qfp = qf_find_entry_on_next_line(bnr, lnum, qfp, errornr); | |
5208 else | |
5209 qfp = qf_find_entry_on_prev_line(bnr, lnum, qfp, errornr); | |
5210 | |
5211 return qfp; | |
5212 } | |
5213 | |
5214 /* | |
5215 * Get the nth quickfix entry below the specified entry treating multiple | |
5216 * entries on a single line as one. Searches forward in the list. | |
5217 */ | |
5218 static qfline_T * | |
5219 qf_get_nth_below_entry(qfline_T *entry, int *errornr, int n) | |
5220 { | |
5221 while (n-- > 0 && !got_int) | |
5222 { | |
5223 qfline_T *first_entry = entry; | |
5224 int first_errornr = *errornr; | |
5225 | |
5226 // Treat all the entries on the same line in this file as one | |
5227 entry = qf_find_last_entry_on_line(entry, errornr); | |
5228 | |
5229 if (entry->qf_next == NULL | |
5230 || entry->qf_next->qf_fnum != entry->qf_fnum) | |
5231 { | |
5232 // If multiple entries are on the same line, then use the first | |
5233 // entry | |
5234 entry = first_entry; | |
5235 *errornr = first_errornr; | |
5236 break; | |
5237 } | |
5238 | |
5239 entry = entry->qf_next; | |
5240 ++*errornr; | |
5241 } | |
5242 | |
5243 return entry; | |
5244 } | |
5245 | |
5246 /* | |
5247 * Get the nth quickfix entry above the specified entry treating multiple | |
5248 * entries on a single line as one. Searches backwards in the list. | |
5249 */ | |
5250 static qfline_T * | |
5251 qf_get_nth_above_entry(qfline_T *entry, int *errornr, int n) | |
5252 { | |
5253 while (n-- > 0 && !got_int) | |
5254 { | |
5255 if (entry->qf_prev == NULL | |
5256 || entry->qf_prev->qf_fnum != entry->qf_fnum) | |
5257 break; | |
5258 | |
5259 entry = entry->qf_prev; | |
5260 --*errornr; | |
5261 | |
5262 // If multiple entries are on the same line, then use the first entry | |
5263 entry = qf_find_first_entry_on_line(entry, errornr); | |
5264 } | |
5265 | |
5266 return entry; | |
5267 } | |
5268 | |
5269 /* | |
5270 * Find the n'th quickfix entry adjacent to line 'lnum' in buffer 'bnr' in the | |
5271 * specified direction. | |
5272 * Returns the error number in the quickfix list or 0 if an entry is not found. | |
5273 */ | |
5274 static int | |
5275 qf_find_nth_adj_entry(qf_list_T *qfl, int bnr, linenr_T lnum, int n, int dir) | |
5276 { | |
5277 qfline_T *adj_entry; | |
5278 int errornr; | |
5279 | |
5280 // Find an entry closest to the specified line | |
5281 adj_entry = qf_find_closest_entry(qfl, bnr, lnum, dir, &errornr); | |
5282 if (adj_entry == NULL) | |
5283 return 0; | |
5284 | |
5285 if (--n > 0) | |
5286 { | |
5287 // Go to the n'th entry in the current buffer | |
5288 if (dir == FORWARD) | |
5289 adj_entry = qf_get_nth_below_entry(adj_entry, &errornr, n); | |
5290 else | |
5291 adj_entry = qf_get_nth_above_entry(adj_entry, &errornr, n); | |
5292 } | |
5293 | |
5294 return errornr; | |
5295 } | |
5296 | |
5297 /* | |
5298 * Jump to a quickfix entry in the current file nearest to the current line. | |
5299 * ":cabove", ":cbelow", ":labove" and ":lbelow" commands | |
5300 */ | |
5301 void | |
5302 ex_cbelow(exarg_T *eap) | |
5303 { | |
5304 qf_info_T *qi; | |
5305 qf_list_T *qfl; | |
5306 int dir; | |
5307 int buf_has_flag; | |
5308 int errornr = 0; | |
5309 | |
5310 if (eap->addr_count > 0 && eap->line2 <= 0) | |
5311 { | |
5312 emsg(_(e_invrange)); | |
5313 return; | |
5314 } | |
5315 | |
5316 // Check whether the current buffer has any quickfix entries | |
5317 if (eap->cmdidx == CMD_cabove || eap->cmdidx == CMD_cbelow) | |
5318 buf_has_flag = BUF_HAS_QF_ENTRY; | |
5319 else | |
5320 buf_has_flag = BUF_HAS_LL_ENTRY; | |
5321 if (!(curbuf->b_has_qf_entry & buf_has_flag)) | |
5322 { | |
5323 emsg(_(e_quickfix)); | |
5324 return; | |
5325 } | |
5326 | |
5327 if ((qi = qf_cmd_get_stack(eap, TRUE)) == NULL) | |
5328 return; | |
5329 | |
5330 qfl = qf_get_curlist(qi); | |
5331 // check if the list has valid errors | |
5332 if (!qf_list_has_valid_entries(qfl)) | |
5333 { | |
5334 emsg(_(e_quickfix)); | |
5335 return; | |
5336 } | |
5337 | |
5338 if (eap->cmdidx == CMD_cbelow || eap->cmdidx == CMD_lbelow) | |
5339 dir = FORWARD; | |
5340 else | |
5341 dir = BACKWARD; | |
5342 | |
5343 errornr = qf_find_nth_adj_entry(qfl, curbuf->b_fnum, curwin->w_cursor.lnum, | |
5344 eap->addr_count > 0 ? eap->line2 : 0, dir); | |
5345 | |
5346 if (errornr > 0) | |
5347 qf_jump(qi, 0, errornr, FALSE); | |
5348 else | |
5349 emsg(_(e_no_more_items)); | |
5045 } | 5350 } |
5046 | 5351 |
5047 /* | 5352 /* |
5048 * Return the autocmd name for the :cfile Ex commands | 5353 * Return the autocmd name for the :cfile Ex commands |
5049 */ | 5354 */ |