comparison src/quickfix.c @ 30803:bba8d0f45cb8 v9.0.0736

patch 9.0.0736: quickfix listing does not handle very long messages Commit: https://github.com/vim/vim/commit/f8412c9d7cc487dacf47a217ae947da68a525c53 Author: Yegappan Lakshmanan <yegappan@yahoo.com> Date: Thu Oct 13 11:59:22 2022 +0100 patch 9.0.0736: quickfix listing does not handle very long messages Problem: Quickfix listing does not handle very long messages. Solution: Use a growarray instead of a fixed size buffer. (Yegappan Lakshmanan, closes #11357)
author Bram Moolenaar <Bram@vim.org>
date Thu, 13 Oct 2022 13:00:07 +0200
parents b01273bbc75e
children d7066cbac096
comparison
equal deleted inserted replaced
30802:15130b9714c5 30803:bba8d0f45cb8
174 static int qf_get_fnum(qf_list_T *qfl, char_u *, char_u *); 174 static int qf_get_fnum(qf_list_T *qfl, char_u *, char_u *);
175 static char_u *qf_push_dir(char_u *, struct dir_stack_T **, int is_file_stack); 175 static char_u *qf_push_dir(char_u *, struct dir_stack_T **, int is_file_stack);
176 static char_u *qf_pop_dir(struct dir_stack_T **); 176 static char_u *qf_pop_dir(struct dir_stack_T **);
177 static char_u *qf_guess_filepath(qf_list_T *qfl, char_u *); 177 static char_u *qf_guess_filepath(qf_list_T *qfl, char_u *);
178 static void qf_jump_newwin(qf_info_T *qi, int dir, int errornr, int forceit, int newwin); 178 static void qf_jump_newwin(qf_info_T *qi, int dir, int errornr, int forceit, int newwin);
179 static void qf_fmt_text(char_u *text, char_u *buf, int bufsize); 179 static void qf_fmt_text(garray_T *gap, char_u *text);
180 static void qf_range_text(qfline_T *qfp, char_u *buf, int bufsize); 180 static void qf_range_text(garray_T *gap, qfline_T *qfp);
181 static int qf_win_pos_update(qf_info_T *qi, int old_qf_index); 181 static int qf_win_pos_update(qf_info_T *qi, int old_qf_index);
182 static win_T *qf_find_win(qf_info_T *qi); 182 static win_T *qf_find_win(qf_info_T *qi);
183 static buf_T *qf_find_buf(qf_info_T *qi); 183 static buf_T *qf_find_buf(qf_info_T *qi);
184 static void qf_update_buffer(qf_info_T *qi, qfline_T *old_last); 184 static void qf_update_buffer(qf_info_T *qi, qfline_T *old_last);
185 static void qf_fill_buffer(qf_list_T *qfl, buf_T *buf, qfline_T *old_last, int qf_winid); 185 static void qf_fill_buffer(qf_list_T *qfl, buf_T *buf, qfline_T *old_last, int qf_winid);
3284 qfline_T *qf_ptr, 3284 qfline_T *qf_ptr,
3285 buf_T *old_curbuf, 3285 buf_T *old_curbuf,
3286 linenr_T old_lnum) 3286 linenr_T old_lnum)
3287 { 3287 {
3288 linenr_T i; 3288 linenr_T i;
3289 int len; 3289 garray_T ga;
3290 3290
3291 // Update the screen before showing the message, unless the screen 3291 // Update the screen before showing the message, unless the screen
3292 // scrolled up. 3292 // scrolled up.
3293 if (!msg_scrolled) 3293 if (!msg_scrolled)
3294 update_topline_redraw(); 3294 update_topline_redraw();
3295 sprintf((char *)IObuff, _("(%d of %d)%s%s: "), qf_index, 3295 vim_snprintf((char *)IObuff, IOSIZE, _("(%d of %d)%s%s: "), qf_index,
3296 qf_get_curlist(qi)->qf_count, 3296 qf_get_curlist(qi)->qf_count,
3297 qf_ptr->qf_cleared ? _(" (line deleted)") : "", 3297 qf_ptr->qf_cleared ? _(" (line deleted)") : "",
3298 (char *)qf_types(qf_ptr->qf_type, qf_ptr->qf_nr)); 3298 (char *)qf_types(qf_ptr->qf_type, qf_ptr->qf_nr));
3299 // Add the message, skipping leading whitespace and newlines. 3299 // Add the message, skipping leading whitespace and newlines.
3300 len = (int)STRLEN(IObuff); 3300 ga_init2(&ga, 1, 256);
3301 qf_fmt_text(skipwhite(qf_ptr->qf_text), IObuff + len, IOSIZE - len); 3301 ga_concat(&ga, IObuff);
3302 qf_fmt_text(&ga, skipwhite(qf_ptr->qf_text));
3302 3303
3303 // Output the message. Overwrite to avoid scrolling when the 'O' 3304 // Output the message. Overwrite to avoid scrolling when the 'O'
3304 // flag is present in 'shortmess'; But when not jumping, print the 3305 // flag is present in 'shortmess'; But when not jumping, print the
3305 // whole message. 3306 // whole message.
3306 i = msg_scroll; 3307 i = msg_scroll;
3307 if (curbuf == old_curbuf && curwin->w_cursor.lnum == old_lnum) 3308 if (curbuf == old_curbuf && curwin->w_cursor.lnum == old_lnum)
3308 msg_scroll = TRUE; 3309 msg_scroll = TRUE;
3309 else if (!msg_scrolled && shortmess(SHM_OVERALL)) 3310 else if (!msg_scrolled && shortmess(SHM_OVERALL))
3310 msg_scroll = FALSE; 3311 msg_scroll = FALSE;
3311 msg_attr_keep((char *)IObuff, 0, TRUE); 3312 msg_attr_keep((char *)ga.ga_data, 0, TRUE);
3312 msg_scroll = i; 3313 msg_scroll = i;
3314 ga_clear(&ga);
3313 } 3315 }
3314 3316
3315 /* 3317 /*
3316 * Find a usable window for opening a file from the quickfix/location list. If 3318 * Find a usable window for opening a file from the quickfix/location list. If
3317 * a window is not found then open a new window. If 'newwin' is TRUE, then open 3319 * a window is not found then open a new window. If 'newwin' is TRUE, then open
3572 qf_list_entry(qfline_T *qfp, int qf_idx, int cursel) 3574 qf_list_entry(qfline_T *qfp, int qf_idx, int cursel)
3573 { 3575 {
3574 char_u *fname; 3576 char_u *fname;
3575 buf_T *buf; 3577 buf_T *buf;
3576 int filter_entry; 3578 int filter_entry;
3579 garray_T ga;
3577 3580
3578 fname = NULL; 3581 fname = NULL;
3579 if (qfp->qf_module != NULL && *qfp->qf_module != NUL) 3582 if (qfp->qf_module != NULL && *qfp->qf_module != NUL)
3580 vim_snprintf((char *)IObuff, IOSIZE, "%2d %s", qf_idx, 3583 vim_snprintf((char *)IObuff, IOSIZE, "%2d %s", qf_idx,
3581 (char *)qfp->qf_module); 3584 (char *)qfp->qf_module);
3612 msg_putchar('\n'); 3615 msg_putchar('\n');
3613 msg_outtrans_attr(IObuff, cursel ? HL_ATTR(HLF_QFL) : qfFileAttr); 3616 msg_outtrans_attr(IObuff, cursel ? HL_ATTR(HLF_QFL) : qfFileAttr);
3614 3617
3615 if (qfp->qf_lnum != 0) 3618 if (qfp->qf_lnum != 0)
3616 msg_puts_attr(":", qfSepAttr); 3619 msg_puts_attr(":", qfSepAttr);
3620 ga_init2(&ga, 1, 256);
3617 if (qfp->qf_lnum == 0) 3621 if (qfp->qf_lnum == 0)
3618 IObuff[0] = NUL; 3622 ga_append(&ga, NUL);
3619 else 3623 else
3620 qf_range_text(qfp, IObuff, IOSIZE); 3624 qf_range_text(&ga, qfp);
3621 sprintf((char *)IObuff + STRLEN(IObuff), "%s", 3625 ga_concat(&ga, qf_types(qfp->qf_type, qfp->qf_nr));
3622 (char *)qf_types(qfp->qf_type, qfp->qf_nr)); 3626 ga_append(&ga, NUL);
3623 msg_puts_attr((char *)IObuff, qfLineAttr); 3627 msg_puts_attr((char *)ga.ga_data, qfLineAttr);
3628 ga_clear(&ga);
3624 msg_puts_attr(":", qfSepAttr); 3629 msg_puts_attr(":", qfSepAttr);
3625 if (qfp->qf_pattern != NULL) 3630 if (qfp->qf_pattern != NULL)
3626 { 3631 {
3627 qf_fmt_text(qfp->qf_pattern, IObuff, IOSIZE); 3632 qf_fmt_text(&ga, qfp->qf_pattern);
3628 msg_puts((char *)IObuff); 3633 msg_puts((char *)ga.ga_data);
3634 ga_clear(&ga);
3629 msg_puts_attr(":", qfSepAttr); 3635 msg_puts_attr(":", qfSepAttr);
3630 } 3636 }
3631 msg_puts(" "); 3637 msg_puts(" ");
3632 3638
3633 { 3639 {
3634 char_u *tbuf = IObuff;
3635 size_t tbuflen = IOSIZE;
3636 size_t len = STRLEN(qfp->qf_text) + 3;
3637
3638 if (len > IOSIZE)
3639 {
3640 tbuf = alloc(len);
3641 if (tbuf != NULL)
3642 tbuflen = len;
3643 else
3644 tbuf = IObuff;
3645 }
3646
3647 // Remove newlines and leading whitespace from the text. For an 3640 // Remove newlines and leading whitespace from the text. For an
3648 // unrecognized line keep the indent, the compiler may mark a word 3641 // unrecognized line keep the indent, the compiler may mark a word
3649 // with ^^^^. 3642 // with ^^^^.
3650 qf_fmt_text((fname != NULL || qfp->qf_lnum != 0) 3643 qf_fmt_text(&ga, (fname != NULL || qfp->qf_lnum != 0)
3651 ? skipwhite(qfp->qf_text) : qfp->qf_text, 3644 ? skipwhite(qfp->qf_text) : qfp->qf_text);
3652 tbuf, (int)tbuflen); 3645 msg_prt_line((char_u *)ga.ga_data, FALSE);
3653 msg_prt_line(tbuf, FALSE); 3646 ga_clear(&ga);
3654
3655 if (tbuf != IObuff)
3656 vim_free(tbuf);
3657 } 3647 }
3658 out_flush(); // show one line at a time 3648 out_flush(); // show one line at a time
3659 } 3649 }
3660 3650
3661 /* 3651 /*
3736 } 3726 }
3737 } 3727 }
3738 3728
3739 /* 3729 /*
3740 * Remove newlines and leading whitespace from an error message. 3730 * Remove newlines and leading whitespace from an error message.
3741 * Put the result in "buf[bufsize]". 3731 * Add the result to the grow array "gap".
3742 */ 3732 */
3743 static void 3733 static void
3744 qf_fmt_text(char_u *text, char_u *buf, int bufsize) 3734 qf_fmt_text(garray_T *gap, char_u *text)
3745 { 3735 {
3746 int i;
3747 char_u *p = text; 3736 char_u *p = text;
3748 3737
3749 for (i = 0; *p != NUL && i < bufsize - 1; ++i) 3738 while (*p != NUL)
3750 { 3739 {
3751 if (*p == '\n') 3740 if (*p == '\n')
3752 { 3741 {
3753 buf[i] = ' '; 3742 ga_append(gap, ' ');
3754 while (*++p != NUL) 3743 while (*++p != NUL)
3755 if (!VIM_ISWHITE(*p) && *p != '\n') 3744 if (!VIM_ISWHITE(*p) && *p != '\n')
3756 break; 3745 break;
3757 } 3746 }
3758 else 3747 else
3759 buf[i] = *p++; 3748 ga_append(gap, *p++);
3760 } 3749 }
3761 buf[i] = NUL; 3750
3762 } 3751 ga_append(gap, NUL);
3763 3752 }
3764 /* 3753
3765 * Range information from lnum, col, end_lnum, and end_col. 3754 /*
3766 * Put the result in "buf[bufsize]". 3755 * Add the range information from the lnum, col, end_lnum, and end_col values
3756 * of a quickfix entry to the grow array "gap".
3767 */ 3757 */
3768 static void 3758 static void
3769 qf_range_text(qfline_T *qfp, char_u *buf, int bufsize) 3759 qf_range_text(garray_T *gap, qfline_T *qfp)
3770 { 3760 {
3761 char_u *buf = IObuff;
3762 int bufsize = IOSIZE;
3771 int len; 3763 int len;
3764
3772 vim_snprintf((char *)buf, bufsize, "%ld", qfp->qf_lnum); 3765 vim_snprintf((char *)buf, bufsize, "%ld", qfp->qf_lnum);
3773 len = (int)STRLEN(buf); 3766 len = (int)STRLEN(buf);
3774 3767
3775 if (qfp->qf_end_lnum > 0 && qfp->qf_lnum != qfp->qf_end_lnum) 3768 if (qfp->qf_end_lnum > 0 && qfp->qf_lnum != qfp->qf_end_lnum)
3776 { 3769 {
3788 "-%d", qfp->qf_end_col); 3781 "-%d", qfp->qf_end_col);
3789 len += (int)STRLEN(buf + len); 3782 len += (int)STRLEN(buf + len);
3790 } 3783 }
3791 } 3784 }
3792 buf[len] = NUL; 3785 buf[len] = NUL;
3786
3787 ga_concat_len(gap, buf, len);
3793 } 3788 }
3794 3789
3795 /* 3790 /*
3796 * Display information (list number, list size and the title) about a 3791 * Display information (list number, list size and the title) about a
3797 * quickfix/location list. 3792 * quickfix/location list.
4595 qfline_T *qfp, 4590 qfline_T *qfp,
4596 char_u *dirname, 4591 char_u *dirname,
4597 int first_bufline, 4592 int first_bufline,
4598 char_u *qftf_str) 4593 char_u *qftf_str)
4599 { 4594 {
4600 int len;
4601 buf_T *errbuf; 4595 buf_T *errbuf;
4596 garray_T ga;
4597
4598 ga_init2(&ga, 1, 256);
4602 4599
4603 // If the 'quickfixtextfunc' function returned a non-empty custom string 4600 // If the 'quickfixtextfunc' function returned a non-empty custom string
4604 // for this entry, then use it. 4601 // for this entry, then use it.
4605 if (qftf_str != NULL && *qftf_str != NUL) 4602 if (qftf_str != NULL && *qftf_str != NUL)
4606 vim_strncpy(IObuff, qftf_str, IOSIZE - 1); 4603 ga_concat(&ga, qftf_str);
4607 else 4604 else
4608 { 4605 {
4609 if (qfp->qf_module != NULL) 4606 if (qfp->qf_module != NULL)
4610 { 4607 ga_concat(&ga, qfp->qf_module);
4611 vim_strncpy(IObuff, qfp->qf_module, IOSIZE - 1);
4612 len = (int)STRLEN(IObuff);
4613 }
4614 else if (qfp->qf_fnum != 0 4608 else if (qfp->qf_fnum != 0
4615 && (errbuf = buflist_findnr(qfp->qf_fnum)) != NULL 4609 && (errbuf = buflist_findnr(qfp->qf_fnum)) != NULL
4616 && errbuf->b_fname != NULL) 4610 && errbuf->b_fname != NULL)
4617 { 4611 {
4618 if (qfp->qf_type == 1) // :helpgrep 4612 if (qfp->qf_type == 1) // :helpgrep
4619 vim_strncpy(IObuff, gettail(errbuf->b_fname), IOSIZE - 1); 4613 ga_concat(&ga, gettail(errbuf->b_fname));
4620 else 4614 else
4621 { 4615 {
4622 // Shorten the file name if not done already. 4616 // Shorten the file name if not done already.
4623 // For optimization, do this only for the first entry in a 4617 // For optimization, do this only for the first entry in a
4624 // buffer. 4618 // buffer.
4627 { 4621 {
4628 if (*dirname == NUL) 4622 if (*dirname == NUL)
4629 mch_dirname(dirname, MAXPATHL); 4623 mch_dirname(dirname, MAXPATHL);
4630 shorten_buf_fname(errbuf, dirname, FALSE); 4624 shorten_buf_fname(errbuf, dirname, FALSE);
4631 } 4625 }
4632 vim_strncpy(IObuff, errbuf->b_fname, IOSIZE - 1); 4626 ga_concat(&ga, errbuf->b_fname);
4633 } 4627 }
4634 len = (int)STRLEN(IObuff); 4628 }
4635 } 4629
4636 else 4630 ga_append(&ga, '|');
4637 len = 0;
4638
4639 if (len < IOSIZE - 1)
4640 IObuff[len++] = '|';
4641 4631
4642 if (qfp->qf_lnum > 0) 4632 if (qfp->qf_lnum > 0)
4643 { 4633 {
4644 qf_range_text(qfp, IObuff + len, IOSIZE - len); 4634 qf_range_text(&ga, qfp);
4645 len += (int)STRLEN(IObuff + len); 4635 ga_concat(&ga, qf_types(qfp->qf_type, qfp->qf_nr));
4646
4647 vim_snprintf((char *)IObuff + len, IOSIZE - len, "%s",
4648 (char *)qf_types(qfp->qf_type, qfp->qf_nr));
4649 len += (int)STRLEN(IObuff + len);
4650 } 4636 }
4651 else if (qfp->qf_pattern != NULL) 4637 else if (qfp->qf_pattern != NULL)
4652 { 4638 qf_fmt_text(&ga, qfp->qf_pattern);
4653 qf_fmt_text(qfp->qf_pattern, IObuff + len, IOSIZE - len); 4639 ga_append(&ga, '|');
4654 len += (int)STRLEN(IObuff + len); 4640 ga_append(&ga, ' ');
4655 }
4656 if (len < IOSIZE - 2)
4657 {
4658 IObuff[len++] = '|';
4659 IObuff[len++] = ' ';
4660 }
4661 4641
4662 // Remove newlines and leading whitespace from the text. 4642 // Remove newlines and leading whitespace from the text.
4663 // For an unrecognized line keep the indent, the compiler may 4643 // For an unrecognized line keep the indent, the compiler may
4664 // mark a word with ^^^^. 4644 // mark a word with ^^^^.
4665 qf_fmt_text(len > 3 ? skipwhite(qfp->qf_text) : qfp->qf_text, 4645 qf_fmt_text(&ga, ga.ga_len > 3 ? skipwhite(qfp->qf_text) : qfp->qf_text);
4666 IObuff + len, IOSIZE - len); 4646 }
4667 } 4647
4668 4648 ga_append(&ga, NUL);
4669 if (ml_append_buf(buf, lnum, IObuff, 4649
4670 (colnr_T)STRLEN(IObuff) + 1, FALSE) == FAIL) 4650 if (ml_append_buf(buf, lnum, ga.ga_data, ga.ga_len + 1, FALSE) == FAIL)
4671 return FAIL; 4651 return FAIL;
4652
4653 ga_clear(&ga);
4672 4654
4673 return OK; 4655 return OK;
4674 } 4656 }
4675 4657
4676 /* 4658 /*