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));