Mercurial > vim
comparison src/quickfix.c @ 16543:1d2b3bb35414 v8.1.1275
patch 8.1.1275: cannot navigate to errors before/after the cursor
commit https://github.com/vim/vim/commit/cf6a55c4b0cbf38b0c3fbed5ffd9a3fd0d2ede0e
Author: Bram Moolenaar <Bram@vim.org>
Date: Sun May 5 15:02:30 2019 +0200
patch 8.1.1275: cannot navigate to errors before/after the cursor
Problem: Cannot navigate to errors before/after the cursor.
Solution: Add the :cbefore and :cafter commands. (Yegappan Lakshmanan,
closes #4340)
author | Bram Moolenaar <Bram@vim.org> |
---|---|
date | Sun, 05 May 2019 15:15:04 +0200 |
parents | 6e87a69b8e0c |
children | 1302bc0b80db |
comparison
equal
deleted
inserted
replaced
16542:5545614fe8e1 | 16543:1d2b3bb35414 |
---|---|
5126 | 5126 |
5127 return entry; | 5127 return entry; |
5128 } | 5128 } |
5129 | 5129 |
5130 /* | 5130 /* |
5131 * Find the first quickfix entry below line 'lnum' in buffer 'bnr'. | 5131 * Returns TRUE if the specified quickfix entry is |
5132 * after the given line (linewise is TRUE) | |
5133 * or after the line and column. | |
5134 */ | |
5135 static int | |
5136 qf_entry_after_pos(qfline_T *qfp, pos_T *pos, int linewise) | |
5137 { | |
5138 if (linewise) | |
5139 return qfp->qf_lnum > pos->lnum; | |
5140 else | |
5141 return (qfp->qf_lnum > pos->lnum || | |
5142 (qfp->qf_lnum == pos->lnum && qfp->qf_col > pos->col)); | |
5143 } | |
5144 | |
5145 /* | |
5146 * Returns TRUE if the specified quickfix entry is | |
5147 * before the given line (linewise is TRUE) | |
5148 * or before the line and column. | |
5149 */ | |
5150 static int | |
5151 qf_entry_before_pos(qfline_T *qfp, pos_T *pos, int linewise) | |
5152 { | |
5153 if (linewise) | |
5154 return qfp->qf_lnum < pos->lnum; | |
5155 else | |
5156 return (qfp->qf_lnum < pos->lnum || | |
5157 (qfp->qf_lnum == pos->lnum && qfp->qf_col < pos->col)); | |
5158 } | |
5159 | |
5160 /* | |
5161 * Returns TRUE if the specified quickfix entry is | |
5162 * on or after the given line (linewise is TRUE) | |
5163 * or on or after the line and column. | |
5164 */ | |
5165 static int | |
5166 qf_entry_on_or_after_pos(qfline_T *qfp, pos_T *pos, int linewise) | |
5167 { | |
5168 if (linewise) | |
5169 return qfp->qf_lnum >= pos->lnum; | |
5170 else | |
5171 return (qfp->qf_lnum > pos->lnum || | |
5172 (qfp->qf_lnum == pos->lnum && qfp->qf_col >= pos->col)); | |
5173 } | |
5174 | |
5175 /* | |
5176 * Returns TRUE if the specified quickfix entry is | |
5177 * on or before the given line (linewise is TRUE) | |
5178 * or on or before the line and column. | |
5179 */ | |
5180 static int | |
5181 qf_entry_on_or_before_pos(qfline_T *qfp, pos_T *pos, int linewise) | |
5182 { | |
5183 if (linewise) | |
5184 return qfp->qf_lnum <= pos->lnum; | |
5185 else | |
5186 return (qfp->qf_lnum < pos->lnum || | |
5187 (qfp->qf_lnum == pos->lnum && qfp->qf_col <= pos->col)); | |
5188 } | |
5189 | |
5190 /* | |
5191 * Find the first quickfix entry after position 'pos' in buffer 'bnr'. | |
5192 * If 'linewise' is TRUE, returns the entry after the specified line and treats | |
5193 * multiple entries on a single line as one. Otherwise returns the entry after | |
5194 * the specified line and column. | |
5132 * 'qfp' points to the very first entry in the buffer and 'errornr' is the | 5195 * 'qfp' points to the very first entry in the buffer and 'errornr' is the |
5133 * index of the very first entry in the quickfix list. | 5196 * index of the very first entry in the quickfix list. |
5134 * Returns NULL if an entry is not found after 'lnum'. | 5197 * Returns NULL if an entry is not found after 'pos'. |
5135 */ | 5198 */ |
5136 static qfline_T * | 5199 static qfline_T * |
5137 qf_find_entry_on_next_line( | 5200 qf_find_entry_after_pos( |
5138 int bnr, | 5201 int bnr, |
5139 linenr_T lnum, | 5202 pos_T *pos, |
5203 int linewise, | |
5140 qfline_T *qfp, | 5204 qfline_T *qfp, |
5141 int *errornr) | 5205 int *errornr) |
5142 { | 5206 { |
5143 if (qfp->qf_lnum > lnum) | 5207 if (qf_entry_after_pos(qfp, pos, linewise)) |
5144 // First entry is after line 'lnum' | 5208 // First entry is after postion 'pos' |
5145 return qfp; | 5209 return qfp; |
5146 | 5210 |
5147 // Find the entry just before or at the line 'lnum' | 5211 // Find the entry just before or at the position 'pos' |
5148 while (qfp->qf_next != NULL | 5212 while (qfp->qf_next != NULL |
5149 && qfp->qf_next->qf_fnum == bnr | 5213 && qfp->qf_next->qf_fnum == bnr |
5150 && qfp->qf_next->qf_lnum <= lnum) | 5214 && qf_entry_on_or_before_pos(qfp->qf_next, pos, linewise)) |
5151 { | 5215 { |
5152 qfp = qfp->qf_next; | 5216 qfp = qfp->qf_next; |
5153 ++*errornr; | 5217 ++*errornr; |
5154 } | 5218 } |
5155 | 5219 |
5156 if (qfp->qf_next == NULL || qfp->qf_next->qf_fnum != bnr) | 5220 if (qfp->qf_next == NULL || qfp->qf_next->qf_fnum != bnr) |
5157 // No entries found after 'lnum' | 5221 // No entries found after position 'pos' |
5158 return NULL; | 5222 return NULL; |
5159 | 5223 |
5160 // Use the entry just after line 'lnum' | 5224 // Use the entry just after position 'pos' |
5161 qfp = qfp->qf_next; | 5225 qfp = qfp->qf_next; |
5162 ++*errornr; | 5226 ++*errornr; |
5163 | 5227 |
5164 return qfp; | 5228 return qfp; |
5165 } | 5229 } |
5166 | 5230 |
5167 /* | 5231 /* |
5168 * Find the first quickfix entry before line 'lnum' in buffer 'bnr'. | 5232 * Find the first quickfix entry before position 'pos' in buffer 'bnr'. |
5233 * If 'linewise' is TRUE, returns the entry before the specified line and | |
5234 * treats multiple entries on a single line as one. Otherwise returns the entry | |
5235 * before the specified line and column. | |
5169 * 'qfp' points to the very first entry in the buffer and 'errornr' is the | 5236 * 'qfp' points to the very first entry in the buffer and 'errornr' is the |
5170 * index of the very first entry in the quickfix list. | 5237 * index of the very first entry in the quickfix list. |
5171 * Returns NULL if an entry is not found before 'lnum'. | 5238 * Returns NULL if an entry is not found before 'pos'. |
5172 */ | 5239 */ |
5173 static qfline_T * | 5240 static qfline_T * |
5174 qf_find_entry_on_prev_line( | 5241 qf_find_entry_before_pos( |
5175 int bnr, | 5242 int bnr, |
5176 linenr_T lnum, | 5243 pos_T *pos, |
5244 int linewise, | |
5177 qfline_T *qfp, | 5245 qfline_T *qfp, |
5178 int *errornr) | 5246 int *errornr) |
5179 { | 5247 { |
5180 // Find the entry just before the line 'lnum' | 5248 // Find the entry just before the position 'pos' |
5181 while (qfp->qf_next != NULL | 5249 while (qfp->qf_next != NULL |
5182 && qfp->qf_next->qf_fnum == bnr | 5250 && qfp->qf_next->qf_fnum == bnr |
5183 && qfp->qf_next->qf_lnum < lnum) | 5251 && qf_entry_before_pos(qfp->qf_next, pos, linewise)) |
5184 { | 5252 { |
5185 qfp = qfp->qf_next; | 5253 qfp = qfp->qf_next; |
5186 ++*errornr; | 5254 ++*errornr; |
5187 } | 5255 } |
5188 | 5256 |
5189 if (qfp->qf_lnum >= lnum) // entry is after 'lnum' | 5257 if (qf_entry_on_or_after_pos(qfp, pos, linewise)) |
5190 return NULL; | 5258 return NULL; |
5191 | 5259 |
5192 // If multiple entries are on the same line, then use the first entry | 5260 if (linewise) |
5193 qfp = qf_find_first_entry_on_line(qfp, errornr); | 5261 // If multiple entries are on the same line, then use the first entry |
5262 qfp = qf_find_first_entry_on_line(qfp, errornr); | |
5194 | 5263 |
5195 return qfp; | 5264 return qfp; |
5196 } | 5265 } |
5197 | 5266 |
5198 /* | 5267 /* |
5199 * Find a quickfix entry in 'qfl' closest to line 'lnum' in buffer 'bnr' in | 5268 * Find a quickfix entry in 'qfl' closest to position 'pos' in buffer 'bnr' in |
5200 * the direction 'dir'. | 5269 * the direction 'dir'. |
5201 */ | 5270 */ |
5202 static qfline_T * | 5271 static qfline_T * |
5203 qf_find_closest_entry( | 5272 qf_find_closest_entry( |
5204 qf_list_T *qfl, | 5273 qf_list_T *qfl, |
5205 int bnr, | 5274 int bnr, |
5206 linenr_T lnum, | 5275 pos_T *pos, |
5207 int dir, | 5276 int dir, |
5277 int linewise, | |
5208 int *errornr) | 5278 int *errornr) |
5209 { | 5279 { |
5210 qfline_T *qfp; | 5280 qfline_T *qfp; |
5211 | 5281 |
5212 *errornr = 0; | 5282 *errornr = 0; |
5215 qfp = qf_find_first_entry_in_buf(qfl, bnr, errornr); | 5285 qfp = qf_find_first_entry_in_buf(qfl, bnr, errornr); |
5216 if (qfp == NULL) | 5286 if (qfp == NULL) |
5217 return NULL; // no entry in this file | 5287 return NULL; // no entry in this file |
5218 | 5288 |
5219 if (dir == FORWARD) | 5289 if (dir == FORWARD) |
5220 qfp = qf_find_entry_on_next_line(bnr, lnum, qfp, errornr); | 5290 qfp = qf_find_entry_after_pos(bnr, pos, linewise, qfp, errornr); |
5221 else | 5291 else |
5222 qfp = qf_find_entry_on_prev_line(bnr, lnum, qfp, errornr); | 5292 qfp = qf_find_entry_before_pos(bnr, pos, linewise, qfp, errornr); |
5223 | 5293 |
5224 return qfp; | 5294 return qfp; |
5225 } | 5295 } |
5226 | 5296 |
5227 /* | 5297 /* |
5228 * Get the nth quickfix entry below the specified entry treating multiple | 5298 * Get the nth quickfix entry below the specified entry. Searches forward in |
5229 * entries on a single line as one. Searches forward in the list. | 5299 * the list. If linewise is TRUE, then treat multiple entries on a single line |
5300 * as one. | |
5230 */ | 5301 */ |
5231 static qfline_T * | 5302 static qfline_T * |
5232 qf_get_nth_below_entry(qfline_T *entry, int *errornr, int n) | 5303 qf_get_nth_below_entry(qfline_T *entry, int n, int linewise, int *errornr) |
5233 { | 5304 { |
5234 while (n-- > 0 && !got_int) | 5305 while (n-- > 0 && !got_int) |
5235 { | 5306 { |
5236 qfline_T *first_entry = entry; | 5307 qfline_T *first_entry = entry; |
5237 int first_errornr = *errornr; | 5308 int first_errornr = *errornr; |
5238 | 5309 |
5239 // Treat all the entries on the same line in this file as one | 5310 if (linewise) |
5240 entry = qf_find_last_entry_on_line(entry, errornr); | 5311 // Treat all the entries on the same line in this file as one |
5312 entry = qf_find_last_entry_on_line(entry, errornr); | |
5241 | 5313 |
5242 if (entry->qf_next == NULL | 5314 if (entry->qf_next == NULL |
5243 || entry->qf_next->qf_fnum != entry->qf_fnum) | 5315 || entry->qf_next->qf_fnum != entry->qf_fnum) |
5244 { | 5316 { |
5245 // If multiple entries are on the same line, then use the first | 5317 if (linewise) |
5246 // entry | 5318 { |
5247 entry = first_entry; | 5319 // If multiple entries are on the same line, then use the first |
5248 *errornr = first_errornr; | 5320 // entry |
5321 entry = first_entry; | |
5322 *errornr = first_errornr; | |
5323 } | |
5249 break; | 5324 break; |
5250 } | 5325 } |
5251 | 5326 |
5252 entry = entry->qf_next; | 5327 entry = entry->qf_next; |
5253 ++*errornr; | 5328 ++*errornr; |
5255 | 5330 |
5256 return entry; | 5331 return entry; |
5257 } | 5332 } |
5258 | 5333 |
5259 /* | 5334 /* |
5260 * Get the nth quickfix entry above the specified entry treating multiple | 5335 * Get the nth quickfix entry above the specified entry. Searches backwards in |
5261 * entries on a single line as one. Searches backwards in the list. | 5336 * the list. If linewise is TRUE, then treat multiple entries on a single line |
5337 * as one. | |
5262 */ | 5338 */ |
5263 static qfline_T * | 5339 static qfline_T * |
5264 qf_get_nth_above_entry(qfline_T *entry, int *errornr, int n) | 5340 qf_get_nth_above_entry(qfline_T *entry, int n, int linewise, int *errornr) |
5265 { | 5341 { |
5266 while (n-- > 0 && !got_int) | 5342 while (n-- > 0 && !got_int) |
5267 { | 5343 { |
5268 if (entry->qf_prev == NULL | 5344 if (entry->qf_prev == NULL |
5269 || entry->qf_prev->qf_fnum != entry->qf_fnum) | 5345 || entry->qf_prev->qf_fnum != entry->qf_fnum) |
5271 | 5347 |
5272 entry = entry->qf_prev; | 5348 entry = entry->qf_prev; |
5273 --*errornr; | 5349 --*errornr; |
5274 | 5350 |
5275 // If multiple entries are on the same line, then use the first entry | 5351 // If multiple entries are on the same line, then use the first entry |
5276 entry = qf_find_first_entry_on_line(entry, errornr); | 5352 if (linewise) |
5353 entry = qf_find_first_entry_on_line(entry, errornr); | |
5277 } | 5354 } |
5278 | 5355 |
5279 return entry; | 5356 return entry; |
5280 } | 5357 } |
5281 | 5358 |
5282 /* | 5359 /* |
5283 * Find the n'th quickfix entry adjacent to line 'lnum' in buffer 'bnr' in the | 5360 * Find the n'th quickfix entry adjacent to position 'pos' in buffer 'bnr' in |
5284 * specified direction. | 5361 * the specified direction. Returns the error number in the quickfix list or 0 |
5285 * Returns the error number in the quickfix list or 0 if an entry is not found. | 5362 * if an entry is not found. |
5286 */ | 5363 */ |
5287 static int | 5364 static int |
5288 qf_find_nth_adj_entry(qf_list_T *qfl, int bnr, linenr_T lnum, int n, int dir) | 5365 qf_find_nth_adj_entry( |
5366 qf_list_T *qfl, | |
5367 int bnr, | |
5368 pos_T *pos, | |
5369 int n, | |
5370 int dir, | |
5371 int linewise) | |
5289 { | 5372 { |
5290 qfline_T *adj_entry; | 5373 qfline_T *adj_entry; |
5291 int errornr; | 5374 int errornr; |
5292 | 5375 |
5293 // Find an entry closest to the specified line | 5376 // Find an entry closest to the specified position |
5294 adj_entry = qf_find_closest_entry(qfl, bnr, lnum, dir, &errornr); | 5377 adj_entry = qf_find_closest_entry(qfl, bnr, pos, dir, linewise, &errornr); |
5295 if (adj_entry == NULL) | 5378 if (adj_entry == NULL) |
5296 return 0; | 5379 return 0; |
5297 | 5380 |
5298 if (--n > 0) | 5381 if (--n > 0) |
5299 { | 5382 { |
5300 // Go to the n'th entry in the current buffer | 5383 // Go to the n'th entry in the current buffer |
5301 if (dir == FORWARD) | 5384 if (dir == FORWARD) |
5302 adj_entry = qf_get_nth_below_entry(adj_entry, &errornr, n); | 5385 adj_entry = qf_get_nth_below_entry(adj_entry, n, linewise, |
5386 &errornr); | |
5303 else | 5387 else |
5304 adj_entry = qf_get_nth_above_entry(adj_entry, &errornr, n); | 5388 adj_entry = qf_get_nth_above_entry(adj_entry, n, linewise, |
5389 &errornr); | |
5305 } | 5390 } |
5306 | 5391 |
5307 return errornr; | 5392 return errornr; |
5308 } | 5393 } |
5309 | 5394 |
5310 /* | 5395 /* |
5311 * Jump to a quickfix entry in the current file nearest to the current line. | 5396 * Jump to a quickfix entry in the current file nearest to the current line or |
5312 * ":cabove", ":cbelow", ":labove" and ":lbelow" commands | 5397 * current line/col. |
5398 * ":cabove", ":cbelow", ":labove", ":lbelow", ":cafter", ":cbefore", | |
5399 * ":lafter" and ":lbefore" commands | |
5313 */ | 5400 */ |
5314 void | 5401 void |
5315 ex_cbelow(exarg_T *eap) | 5402 ex_cbelow(exarg_T *eap) |
5316 { | 5403 { |
5317 qf_info_T *qi; | 5404 qf_info_T *qi; |
5318 qf_list_T *qfl; | 5405 qf_list_T *qfl; |
5319 int dir; | 5406 int dir; |
5320 int buf_has_flag; | 5407 int buf_has_flag; |
5321 int errornr = 0; | 5408 int errornr = 0; |
5409 pos_T pos; | |
5322 | 5410 |
5323 if (eap->addr_count > 0 && eap->line2 <= 0) | 5411 if (eap->addr_count > 0 && eap->line2 <= 0) |
5324 { | 5412 { |
5325 emsg(_(e_invrange)); | 5413 emsg(_(e_invrange)); |
5326 return; | 5414 return; |
5327 } | 5415 } |
5328 | 5416 |
5329 // Check whether the current buffer has any quickfix entries | 5417 // Check whether the current buffer has any quickfix entries |
5330 if (eap->cmdidx == CMD_cabove || eap->cmdidx == CMD_cbelow) | 5418 if (eap->cmdidx == CMD_cabove || eap->cmdidx == CMD_cbelow |
5419 || eap->cmdidx == CMD_cbefore || eap->cmdidx == CMD_cafter) | |
5331 buf_has_flag = BUF_HAS_QF_ENTRY; | 5420 buf_has_flag = BUF_HAS_QF_ENTRY; |
5332 else | 5421 else |
5333 buf_has_flag = BUF_HAS_LL_ENTRY; | 5422 buf_has_flag = BUF_HAS_LL_ENTRY; |
5334 if (!(curbuf->b_has_qf_entry & buf_has_flag)) | 5423 if (!(curbuf->b_has_qf_entry & buf_has_flag)) |
5335 { | 5424 { |
5346 { | 5435 { |
5347 emsg(_(e_quickfix)); | 5436 emsg(_(e_quickfix)); |
5348 return; | 5437 return; |
5349 } | 5438 } |
5350 | 5439 |
5351 if (eap->cmdidx == CMD_cbelow || eap->cmdidx == CMD_lbelow) | 5440 if (eap->cmdidx == CMD_cbelow |
5441 || eap->cmdidx == CMD_lbelow | |
5442 || eap->cmdidx == CMD_cafter | |
5443 || eap->cmdidx == CMD_lafter) | |
5444 // Forward motion commands | |
5352 dir = FORWARD; | 5445 dir = FORWARD; |
5353 else | 5446 else |
5354 dir = BACKWARD; | 5447 dir = BACKWARD; |
5355 | 5448 |
5356 errornr = qf_find_nth_adj_entry(qfl, curbuf->b_fnum, curwin->w_cursor.lnum, | 5449 pos = curwin->w_cursor; |
5357 eap->addr_count > 0 ? eap->line2 : 0, dir); | 5450 // A quickfix entry column number is 1 based whereas cursor column |
5451 // number is 0 based. Adjust the column number. | |
5452 pos.col++; | |
5453 errornr = qf_find_nth_adj_entry(qfl, curbuf->b_fnum, &pos, | |
5454 eap->addr_count > 0 ? eap->line2 : 0, dir, | |
5455 eap->cmdidx == CMD_cbelow | |
5456 || eap->cmdidx == CMD_lbelow | |
5457 || eap->cmdidx == CMD_cabove | |
5458 || eap->cmdidx == CMD_labove); | |
5358 | 5459 |
5359 if (errornr > 0) | 5460 if (errornr > 0) |
5360 qf_jump(qi, 0, errornr, FALSE); | 5461 qf_jump(qi, 0, errornr, FALSE); |
5361 else | 5462 else |
5362 emsg(_(e_no_more_items)); | 5463 emsg(_(e_no_more_items)); |