diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c index e7d2da2fc6..ddf2a7247f 100644 --- a/src/nvim/quickfix.c +++ b/src/nvim/quickfix.c @@ -91,6 +91,7 @@ struct qfline_S { int qf_end_col; ///< column when the error has range or zero int qf_nr; ///< error number char *qf_module; ///< module name for this error + char *qf_fname; ///< different filename if there're hard links char *qf_pattern; ///< search pattern for the error char *qf_text; ///< description of the error char qf_viscol; ///< set to true if qf_col and qf_end_col is screen column @@ -1866,11 +1867,13 @@ static int qf_add_entry(qf_list_T *qfl, char *dir, char *fname, char *module, in char vis_col, char *pattern, int nr, char type, typval_T *user_data, char valid) { + buf_T *buf; qfline_T *qfp = xmalloc(sizeof(qfline_T)); + char *fullname = NULL; + char *p = NULL; if (bufnum != 0) { - buf_T *buf = buflist_findnr(bufnum); - + buf = buflist_findnr(bufnum); qfp->qf_fnum = bufnum; if (buf != NULL) { buf->b_has_qf_entry |= @@ -1878,7 +1881,21 @@ static int qf_add_entry(qf_list_T *qfl, char *dir, char *fname, char *module, in } } else { qfp->qf_fnum = qf_get_fnum(qfl, dir, fname); + buf = buflist_findnr(qfp->qf_fnum); } + if (fname != NULL) { + fullname = fix_fname(fname); + } + qfp->qf_fname = NULL; + if (buf != NULL && buf->b_ffname != NULL && fullname != NULL) { + if (path_fnamecmp(fullname, buf->b_ffname) != 0) { + p = path_try_shorten_fname(fullname); + if (p != NULL) { + qfp->qf_fname = xstrdup(p); + } + } + } + xfree(fullname); qfp->qf_text = xstrdup(mesg); qfp->qf_lnum = lnum; qfp->qf_end_lnum = end_lnum; @@ -3145,7 +3162,7 @@ static void qf_list_entry(qfline_T *qfp, int qf_idx, bool cursel) buf_T *buf; if (qfp->qf_fnum != 0 && (buf = buflist_findnr(qfp->qf_fnum)) != NULL) { - fname = buf->b_fname; + fname = qfp->qf_fname == NULL ? buf->b_fname : qfp->qf_fname; if (qfp->qf_type == 1) { // :helpgrep fname = path_tail(fname); } @@ -3431,6 +3448,7 @@ static void qf_free_items(qf_list_T *qfl) qfline_T *qfp = qfl->qf_start; qfline_T *qfpnext = qfp->qf_next; if (!stop) { + xfree(qfp->qf_fname); xfree(qfp->qf_module); xfree(qfp->qf_text); xfree(qfp->qf_pattern); @@ -4059,7 +4077,7 @@ static int qf_buf_add_line(qf_list_T *qfl, buf_T *buf, linenr_T lnum, const qfli } shorten_buf_fname(errbuf, dirname, false); } - ga_concat(gap, errbuf->b_fname); + ga_concat(gap, qfp->qf_fname == NULL ? errbuf->b_fname : qfp->qf_fname); } } diff --git a/test/old/testdir/test_quickfix.vim b/test/old/testdir/test_quickfix.vim index 524e8608f6..753875963b 100644 --- a/test/old/testdir/test_quickfix.vim +++ b/test/old/testdir/test_quickfix.vim @@ -4140,6 +4140,7 @@ endfunc " The following test used to crash Vim func Test_lvimgrep_crash() + " this leaves a swapfile .test_quickfix.vim.swp around, why? sv Xtest augroup QF_Test au! @@ -4202,8 +4203,8 @@ endfunc " :vimgrep/:lvimgrep commands are running. func Test_vimgrep_autocmd() call setqflist([], 'f') - call writefile(['stars'], 'Xtest1.txt') - call writefile(['stars'], 'Xtest2.txt') + call writefile(['stars'], 'Xtest1.txt', 'D') + call writefile(['stars'], 'Xtest2.txt', 'D') " Test 1: " When searching for a pattern using :vimgrep, if the quickfix list is @@ -4233,9 +4234,9 @@ func Test_vimgrep_autocmd() autocmd BufRead Xtest2.txt call setloclist(g:save_winid, [], 'f') call assert_fails('lvimgrep stars Xtest*.txt', 'E926:') au! BufRead Xtest2.txt + " cleanup the swap files + bw! Xtest2.txt Xtest1.txt - call delete('Xtest1.txt') - call delete('Xtest2.txt') call setqflist([], 'f') endfunc @@ -6458,4 +6459,41 @@ func Test_cbuffer_range() call XbufferTests_range('l') endfunc +" Test for displaying fname pass from setqflist when the name +" are hard links to prevent seemly duplicate entries. +func Xtest_hardlink_fname(cchar) + call s:setup_commands(a:cchar) + %bwipe + " Create a sample source file + let lines =<< trim END + void sample() {} + int main() { sample(); return 0; } + END + call writefile(lines, 'test_qf_hardlink1.c', 'D') + defer delete('test_qf_hardlink1.c') + defer delete('test_qf_hardlink2.c') + call system('ln test_qf_hardlink1.c test_qf_hardlink2.c') + if v:shell_error + throw 'Skipped: ln throws error on this platform' + endif + call g:Xsetlist([], 'f') + " Make a qflist that contains the file and it's hard link + " like how LSP plugins set response into qflist + call g:Xsetlist([{'filename' : 'test_qf_hardlink1.c', 'lnum' : 1}, + \ {'filename' : 'test_qf_hardlink2.c', 'lnum' : 1}], ' ') + Xopen + " Ensure that two entries are displayed with different name + " so that they aren't seen as duplication. + call assert_equal(['test_qf_hardlink1.c|1| ', + \ 'test_qf_hardlink2.c|1| '], getline(1, '$')) + Xclose +endfunc + +func Test_hardlink_fname() + CheckUnix + CheckExecutable ln + call Xtest_hardlink_fname('c') + call Xtest_hardlink_fname('l') +endfunc + " vim: shiftwidth=2 sts=2 expandtab