To: vim_dev@googlegroups.com Subject: Patch 9.0.0736 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 9.0.0736 Problem: Quickfix listing does not handle very long messages. Solution: Use a growarray instead of a fixed size buffer. (Yegappan Lakshmanan, closes #11357) Files: src/quickfix.c, src/testdir/test_quickfix.vim *** ../vim-9.0.0735/src/quickfix.c 2022-08-29 20:45:11.344535306 +0100 --- src/quickfix.c 2022-10-13 11:47:57.445145504 +0100 *************** *** 176,183 **** static char_u *qf_pop_dir(struct dir_stack_T **); static char_u *qf_guess_filepath(qf_list_T *qfl, char_u *); static void qf_jump_newwin(qf_info_T *qi, int dir, int errornr, int forceit, int newwin); ! static void qf_fmt_text(char_u *text, char_u *buf, int bufsize); ! static void qf_range_text(qfline_T *qfp, char_u *buf, int bufsize); static int qf_win_pos_update(qf_info_T *qi, int old_qf_index); static win_T *qf_find_win(qf_info_T *qi); static buf_T *qf_find_buf(qf_info_T *qi); --- 176,183 ---- static char_u *qf_pop_dir(struct dir_stack_T **); static char_u *qf_guess_filepath(qf_list_T *qfl, char_u *); static void qf_jump_newwin(qf_info_T *qi, int dir, int errornr, int forceit, int newwin); ! static void qf_fmt_text(garray_T *gap, char_u *text); ! static void qf_range_text(garray_T *gap, qfline_T *qfp); static int qf_win_pos_update(qf_info_T *qi, int old_qf_index); static win_T *qf_find_win(qf_info_T *qi); static buf_T *qf_find_buf(qf_info_T *qi); *************** *** 3286,3304 **** linenr_T old_lnum) { linenr_T i; ! int len; // Update the screen before showing the message, unless the screen // scrolled up. if (!msg_scrolled) update_topline_redraw(); ! sprintf((char *)IObuff, _("(%d of %d)%s%s: "), qf_index, qf_get_curlist(qi)->qf_count, qf_ptr->qf_cleared ? _(" (line deleted)") : "", (char *)qf_types(qf_ptr->qf_type, qf_ptr->qf_nr)); // Add the message, skipping leading whitespace and newlines. ! len = (int)STRLEN(IObuff); ! qf_fmt_text(skipwhite(qf_ptr->qf_text), IObuff + len, IOSIZE - len); // Output the message. Overwrite to avoid scrolling when the 'O' // flag is present in 'shortmess'; But when not jumping, print the --- 3286,3305 ---- linenr_T old_lnum) { linenr_T i; ! garray_T ga; // Update the screen before showing the message, unless the screen // scrolled up. if (!msg_scrolled) update_topline_redraw(); ! vim_snprintf((char *)IObuff, IOSIZE, _("(%d of %d)%s%s: "), qf_index, qf_get_curlist(qi)->qf_count, qf_ptr->qf_cleared ? _(" (line deleted)") : "", (char *)qf_types(qf_ptr->qf_type, qf_ptr->qf_nr)); // Add the message, skipping leading whitespace and newlines. ! ga_init2(&ga, 1, 256); ! ga_concat(&ga, IObuff); ! qf_fmt_text(&ga, skipwhite(qf_ptr->qf_text)); // Output the message. Overwrite to avoid scrolling when the 'O' // flag is present in 'shortmess'; But when not jumping, print the *************** *** 3308,3315 **** msg_scroll = TRUE; else if (!msg_scrolled && shortmess(SHM_OVERALL)) msg_scroll = FALSE; ! msg_attr_keep((char *)IObuff, 0, TRUE); msg_scroll = i; } /* --- 3309,3317 ---- msg_scroll = TRUE; else if (!msg_scrolled && shortmess(SHM_OVERALL)) msg_scroll = FALSE; ! msg_attr_keep((char *)ga.ga_data, 0, TRUE); msg_scroll = i; + ga_clear(&ga); } /* *************** *** 3574,3579 **** --- 3576,3582 ---- char_u *fname; buf_T *buf; int filter_entry; + garray_T ga; fname = NULL; if (qfp->qf_module != NULL && *qfp->qf_module != NUL) *************** *** 3614,3659 **** if (qfp->qf_lnum != 0) msg_puts_attr(":", qfSepAttr); if (qfp->qf_lnum == 0) ! IObuff[0] = NUL; else ! qf_range_text(qfp, IObuff, IOSIZE); ! sprintf((char *)IObuff + STRLEN(IObuff), "%s", ! (char *)qf_types(qfp->qf_type, qfp->qf_nr)); ! msg_puts_attr((char *)IObuff, qfLineAttr); msg_puts_attr(":", qfSepAttr); if (qfp->qf_pattern != NULL) { ! qf_fmt_text(qfp->qf_pattern, IObuff, IOSIZE); ! msg_puts((char *)IObuff); msg_puts_attr(":", qfSepAttr); } msg_puts(" "); { - char_u *tbuf = IObuff; - size_t tbuflen = IOSIZE; - size_t len = STRLEN(qfp->qf_text) + 3; - - if (len > IOSIZE) - { - tbuf = alloc(len); - if (tbuf != NULL) - tbuflen = len; - else - tbuf = IObuff; - } - // Remove newlines and leading whitespace from the text. For an // unrecognized line keep the indent, the compiler may mark a word // with ^^^^. ! qf_fmt_text((fname != NULL || qfp->qf_lnum != 0) ! ? skipwhite(qfp->qf_text) : qfp->qf_text, ! tbuf, (int)tbuflen); ! msg_prt_line(tbuf, FALSE); ! ! if (tbuf != IObuff) ! vim_free(tbuf); } out_flush(); // show one line at a time } --- 3617,3649 ---- if (qfp->qf_lnum != 0) msg_puts_attr(":", qfSepAttr); + ga_init2(&ga, 1, 256); if (qfp->qf_lnum == 0) ! ga_append(&ga, NUL); else ! qf_range_text(&ga, qfp); ! ga_concat(&ga, qf_types(qfp->qf_type, qfp->qf_nr)); ! ga_append(&ga, NUL); ! msg_puts_attr((char *)ga.ga_data, qfLineAttr); ! ga_clear(&ga); msg_puts_attr(":", qfSepAttr); if (qfp->qf_pattern != NULL) { ! qf_fmt_text(&ga, qfp->qf_pattern); ! msg_puts((char *)ga.ga_data); ! ga_clear(&ga); msg_puts_attr(":", qfSepAttr); } msg_puts(" "); { // Remove newlines and leading whitespace from the text. For an // unrecognized line keep the indent, the compiler may mark a word // with ^^^^. ! qf_fmt_text(&ga, (fname != NULL || qfp->qf_lnum != 0) ! ? skipwhite(qfp->qf_text) : qfp->qf_text); ! msg_prt_line((char_u *)ga.ga_data, FALSE); ! ga_clear(&ga); } out_flush(); // show one line at a time } *************** *** 3738,3774 **** /* * Remove newlines and leading whitespace from an error message. ! * Put the result in "buf[bufsize]". */ static void ! qf_fmt_text(char_u *text, char_u *buf, int bufsize) { - int i; char_u *p = text; ! for (i = 0; *p != NUL && i < bufsize - 1; ++i) { if (*p == '\n') { ! buf[i] = ' '; while (*++p != NUL) if (!VIM_ISWHITE(*p) && *p != '\n') break; } else ! buf[i] = *p++; } ! buf[i] = NUL; } /* ! * Range information from lnum, col, end_lnum, and end_col. ! * Put the result in "buf[bufsize]". */ static void ! qf_range_text(qfline_T *qfp, char_u *buf, int bufsize) { int len; vim_snprintf((char *)buf, bufsize, "%ld", qfp->qf_lnum); len = (int)STRLEN(buf); --- 3728,3767 ---- /* * Remove newlines and leading whitespace from an error message. ! * Add the result to the grow array "gap". */ static void ! qf_fmt_text(garray_T *gap, char_u *text) { char_u *p = text; ! while (*p != NUL) { if (*p == '\n') { ! ga_append(gap, ' '); while (*++p != NUL) if (!VIM_ISWHITE(*p) && *p != '\n') break; } else ! ga_append(gap, *p++); } ! ! ga_append(gap, NUL); } /* ! * Add the range information from the lnum, col, end_lnum, and end_col values ! * of a quickfix entry to the grow array "gap". */ static void ! qf_range_text(garray_T *gap, qfline_T *qfp) { + char_u *buf = IObuff; + int bufsize = IOSIZE; int len; + vim_snprintf((char *)buf, bufsize, "%ld", qfp->qf_lnum); len = (int)STRLEN(buf); *************** *** 3790,3795 **** --- 3783,3790 ---- } } buf[len] = NUL; + + ga_concat_len(gap, buf, len); } /* *************** *** 4597,4622 **** int first_bufline, char_u *qftf_str) { - int len; buf_T *errbuf; // If the 'quickfixtextfunc' function returned a non-empty custom string // for this entry, then use it. if (qftf_str != NULL && *qftf_str != NUL) ! vim_strncpy(IObuff, qftf_str, IOSIZE - 1); else { if (qfp->qf_module != NULL) ! { ! vim_strncpy(IObuff, qfp->qf_module, IOSIZE - 1); ! len = (int)STRLEN(IObuff); ! } else if (qfp->qf_fnum != 0 && (errbuf = buflist_findnr(qfp->qf_fnum)) != NULL && errbuf->b_fname != NULL) { if (qfp->qf_type == 1) // :helpgrep ! vim_strncpy(IObuff, gettail(errbuf->b_fname), IOSIZE - 1); else { // Shorten the file name if not done already. --- 4592,4616 ---- int first_bufline, char_u *qftf_str) { buf_T *errbuf; + garray_T ga; + + ga_init2(&ga, 1, 256); // If the 'quickfixtextfunc' function returned a non-empty custom string // for this entry, then use it. if (qftf_str != NULL && *qftf_str != NUL) ! ga_concat(&ga, qftf_str); else { if (qfp->qf_module != NULL) ! ga_concat(&ga, qfp->qf_module); else if (qfp->qf_fnum != 0 && (errbuf = buflist_findnr(qfp->qf_fnum)) != NULL && errbuf->b_fname != NULL) { if (qfp->qf_type == 1) // :helpgrep ! ga_concat(&ga, gettail(errbuf->b_fname)); else { // Shorten the file name if not done already. *************** *** 4629,4675 **** mch_dirname(dirname, MAXPATHL); shorten_buf_fname(errbuf, dirname, FALSE); } ! vim_strncpy(IObuff, errbuf->b_fname, IOSIZE - 1); } - len = (int)STRLEN(IObuff); } - else - len = 0; ! if (len < IOSIZE - 1) ! IObuff[len++] = '|'; if (qfp->qf_lnum > 0) { ! qf_range_text(qfp, IObuff + len, IOSIZE - len); ! len += (int)STRLEN(IObuff + len); ! ! vim_snprintf((char *)IObuff + len, IOSIZE - len, "%s", ! (char *)qf_types(qfp->qf_type, qfp->qf_nr)); ! len += (int)STRLEN(IObuff + len); } else if (qfp->qf_pattern != NULL) ! { ! qf_fmt_text(qfp->qf_pattern, IObuff + len, IOSIZE - len); ! len += (int)STRLEN(IObuff + len); ! } ! if (len < IOSIZE - 2) ! { ! IObuff[len++] = '|'; ! IObuff[len++] = ' '; ! } // Remove newlines and leading whitespace from the text. // For an unrecognized line keep the indent, the compiler may // mark a word with ^^^^. ! qf_fmt_text(len > 3 ? skipwhite(qfp->qf_text) : qfp->qf_text, ! IObuff + len, IOSIZE - len); } ! if (ml_append_buf(buf, lnum, IObuff, ! (colnr_T)STRLEN(IObuff) + 1, FALSE) == FAIL) return FAIL; return OK; } --- 4623,4657 ---- mch_dirname(dirname, MAXPATHL); shorten_buf_fname(errbuf, dirname, FALSE); } ! ga_concat(&ga, errbuf->b_fname); } } ! ga_append(&ga, '|'); if (qfp->qf_lnum > 0) { ! qf_range_text(&ga, qfp); ! ga_concat(&ga, qf_types(qfp->qf_type, qfp->qf_nr)); } else if (qfp->qf_pattern != NULL) ! qf_fmt_text(&ga, qfp->qf_pattern); ! ga_append(&ga, '|'); ! ga_append(&ga, ' '); // Remove newlines and leading whitespace from the text. // For an unrecognized line keep the indent, the compiler may // mark a word with ^^^^. ! qf_fmt_text(&ga, ga.ga_len > 3 ? skipwhite(qfp->qf_text) : qfp->qf_text); } ! ga_append(&ga, NUL); ! ! if (ml_append_buf(buf, lnum, ga.ga_data, ga.ga_len + 1, FALSE) == FAIL) return FAIL; + ga_clear(&ga); + return OK; } *** ../vim-9.0.0735/src/testdir/test_quickfix.vim 2022-10-05 21:45:23.775124283 +0100 --- src/testdir/test_quickfix.vim 2022-10-13 11:47:57.445145504 +0100 *************** *** 6334,6337 **** --- 6334,6375 ---- call setloclist(0, [], 'f') endfunc + " Test for a very long error line and a very long information line + func Test_very_long_error_line() + let msg = repeat('abcdefghijklmn', 146) + let emsg = 'Xlonglines.c:1:' . msg + call writefile([msg, emsg], 'Xerror', 'D') + cfile Xerror + cwindow + call assert_equal($'|| {msg}', getline(1)) + call assert_equal($'Xlonglines.c|1| {msg}', getline(2)) + cclose + + let l = execute('clist!')->split("\n") + call assert_equal([$' 1: {msg}', $' 2 Xlonglines.c:1: {msg}'], l) + + let l = execute('cc')->split("\n") + call assert_equal([$'(2 of 2): {msg}'], l) + + call setqflist([], 'f') + endfunc + + " In the quickfix window, spaces at the beginning of an informational line + " should not be removed but should be removed from an error line. + func Test_info_line_with_space() + cexpr ["a.c:20:12: error: expected ';' before ':' token", + \ ' 20 | Afunc():', '', ' | ^'] + copen + call assert_equal(["a.c|20 col 12| error: expected ';' before ':' token", + \ '|| 20 | Afunc():', '|| ', + \ '|| | ^'], getline(1, '$')) + cclose + + let l = execute('clist!')->split("\n") + call assert_equal([" 1 a.c:20 col 12: error: expected ';' before ':' token", + \ ' 2: 20 | Afunc():', ' 3: ', ' 4: | ^'], l) + + call setqflist([], 'f') + endfunc + " vim: shiftwidth=2 sts=2 expandtab *** ../vim-9.0.0735/src/version.c 2022-10-12 21:32:38.428890899 +0100 --- src/version.c 2022-10-13 11:49:13.088369085 +0100 *************** *** 701,702 **** --- 701,704 ---- { /* Add new patch number below this line */ + /**/ + 736, /**/ -- GUEST: He's killed the best man! SECOND GUEST: (holding a limp WOMAN) He's killed my auntie. FATHER: No, please! This is supposed to be a happy occasion! Let's not bicker and argue about who killed who ... "Monty Python and the Holy Grail" PYTHON (MONTY) PICTURES LTD /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// \\\ \\\ sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///