2

If I make a mistake in a class in some C++ code, I'll typically get a ton of messages from the compiler about how hard it's tried to find something suitable in system header files. This floods the quickfix window with a lot of stuff I barely understand or which I don't need to be told about because it was a trivial typo; so I just want to start on the first message pointing to my own code and to skip over everything about system headers (except sometimes).

Is there a way to fold all the references to system headers, and to skip them with :cnext, but to have them still available if I choose to unfold them?

I suppose that ideally :cnext would respect the state of each fold, jumping right over a fold if it's closed, but advancing through a fold if I've chosen to open it.

I found one reference on the matter but it seems more concerned with grouping files (which is simplified by make's directory-change announcements) and not so much with the directories in which the headers live.

Sample output (abridged) for a couple of simple errors follows:

g++ -Wall -Werror -std=c++17 -O3 test.cc ; true
test.cc:9:4: error: #warning "example before" [-Werror=cpp]
    9 |   #warning "example before"
      |    ^~~~~~~
test.cc:12:4: error: #warning "example after" [-Werror=cpp]
   12 |   #warning "example after"
      |    ^~~~~~~
test.cc: In function ‘int main()’:
test.cc:10:31: error: no matching function for call to ‘std::vector<Test>::vector(int, int)’
   10 |   std::vector<Test> test(10, 0);
      |                               ^
In file included from /usr/include/c++/10/vector:67,
                 from test.cc:1:
/usr/include/c++/10/bits/stl_vector.h:653:2: note: candidate: ‘template<class _InputIterator, class> std::vector<_Tp, _Alloc>::vector(_InputIterator, _InputIterator, const allocator_type&) [with _InputIterator = _InputIterator; <template-parameter-2-2> = <template-parameter-1-2>; _Tp = Test; _Alloc = std::allocator<Test>]’
  653 |  vector(_InputIterator __first, _InputIterator __last,
      |  ^~~~~~
/usr/include/c++/10/bits/stl_vector.h:653:2: note:   template argument deduction/substitution failed:
In file included from /usr/include/c++/10/bits/stl_algobase.h:65,
                 from /usr/include/c++/10/vector:60,
                 from test.cc:1:
/usr/include/c++/10/bits/stl_iterator_base_types.h: In substitution of ‘template<class _InIter> using _RequireInputIter = std::__enable_if_t<std::is_convertible<typename std::iterator_traits< <template-parameter-1-1> >::iterator_category, std::input_iterator_tag>::value> [with _InIter = int]’:
/usr/include/c++/10/bits/stl_vector.h:652:9:   required from here
/usr/include/c++/10/bits/stl_iterator_base_types.h:249:11: error: no type named ‘iterator_category’ in ‘struct std::iterator_traits<int>’
  249 |     using _RequireInputIter =
      |           ^~~~~~~~~~~~~~~~~
In file included from /usr/include/c++/10/vector:67,
                 from test.cc:1:
/usr/include/c++/10/bits/stl_vector.h:625:7: note: candidate: ‘std::vector<_Tp, _Alloc>::vector(std::initializer_list<_Tp>, const allocator_type&) [with _Tp = Test; _Alloc = std::allocator<Test>; std::vector<_Tp, _Alloc>::allocator_type = std::allocator<Test>]’
  625 |       vector(initializer_list<value_type> __l,
      |       ^~~~~~
[...]
/usr/include/c++/10/bits/stl_vector.h:487:7: note:   candidate expects 0 arguments, 2 provided
test.cc:11:32: error: no matching function for call to ‘std::vector<Test>::vector(int, int)’
   11 |   std::vector<Test> test2(10, 0);
      |                                ^
In file included from /usr/include/c++/10/vector:67,
                 from test.cc:1:
/usr/include/c++/10/bits/stl_vector.h:653:2: note: candidate: ‘template<class _InputIterator, class> std::vector<_Tp, _Alloc>::vector(_InputIterator, _InputIterator, const allocator_type&) [with _InputIterator = _InputIterator; <template-parameter-2-2> = <template-parameter-1-2>; _Tp = Test; _Alloc = std::allocator<Test>]’
  653 |  vector(_InputIterator __first, _InputIterator __last,
      |  ^~~~~~
clang++ -Wall -Werror -std=c++17 -O3 test.cc
test.cc:9:4: error: "example before" [-Werror,-W#warnings]
  #warning "example before"
   ^
test.cc:10:21: error: no matching constructor for initialization of 'std::vector<Test>'
  std::vector<Test> test(10, 0);
                    ^    ~~~~~
/usr/bin/../lib/gcc/aarch64-linux-gnu/10/../../../../include/c++/10/bits/stl_vector.h:510:7: note: candidate constructor not viable: no known conversion from 'int' to 'const std::vector<Test, std::allocator<Test>>::allocator_type' (aka 'const std::allocator<Test>') for 2nd argument
      vector(size_type __n, const allocator_type& __a = allocator_type())
      ^
/usr/bin/../lib/gcc/aarch64-linux-gnu/10/../../../../include/c++/10/bits/stl_vector.h:522:7: note: candidate constructor not viable: no known conversion from 'int' to 'const std::vector<Test, std::allocator<Test>>::value_type' (aka 'const Test') for 2nd argument
      vector(size_type __n, const value_type& __value,
      ^
[...]
/usr/bin/../lib/gcc/aarch64-linux-gnu/10/../../../../include/c++/10/bits/stl_vector.h:589:7: note: candidate constructor not viable: requires 3 arguments, but 2 were provided
      vector(vector&& __rv, const allocator_type& __m, false_type)
      ^
/usr/bin/../lib/gcc/aarch64-linux-gnu/10/../../../../include/c++/10/bits/stl_vector.h:487:7: note: candidate constructor not viable: requires 0 arguments, but 2 were provided
      vector() = default;
      ^
test.cc:12:4: error: "example after" [-Werror,-W#warnings]
  #warning "example after"
   ^
4 errors generated.
4
  • Welcome to Vi and Vim!
    – D. Ben Knoble
    Commented Mar 3, 2023 at 18:07
  • It would be helpfully if you give us an example of list of error messages, the way you would like to 'group' / fold them. It will help us to help you to create the foldexpr you need. Commented Mar 3, 2023 at 20:42
  • I don't have a solution to fold the quickfix list or make :cnext respect it, but I use mappings on C-n and C-p in the quickfix list to jump from errors in one file to errors in the next/previous. github.com/benknoble/Dotfiles/blob/master/links/vim/autoload/bk/…
    – D. Ben Knoble
    Commented Mar 3, 2023 at 21:47
  • 1
    @VivianDeSmedt Good idea. I've updated the question.
    – sh1
    Commented Mar 5, 2023 at 0:16

3 Answers 3

1

For the first example if you define the following function (e.g. .vimrc)

function! FoldError(lnum)
  let l:line = getline(a:lnum)
  if matchstr(l:line, ' ^|| In file included') != ''
    return '>1'
  endif
  if matchstr(l:line, '^||') != ''
    return '='
  endif
  if matchstr(l:line, '^/usr/bin') != ''
    return '>2'
  endif
  return '>1'
endfunction

And run the following commands in the QuickFix window:

set foldmethod=expr
set foldexpr=FoldError(v:lnum)

After running zx to refresh the folds you'll get something like:

enter image description here

It doesn't solve your :cnext problem but give you a more readable view on your errors in the QuickFix window.

2

cnext does not respect folds and you can't make it to.

The procedure of creating folds is rather a standard one:

  1. Create ftplugin file for your filetype, i.e. ~/after/ftplugin/qf.vim

  2. Set local options foldmethod and foldexpr, i.e. setl fdm=expr fde=MyLineToFoldLevel(v:lnum)

  3. Define your custom function to calc desired fold level (zero or one, unless you want nested folds) by line number.

How exactly one implements the step no. 3 is out of the scope of this question.

1

Combining both answers, I put the following into ~/.vim/after/ftplugin/qf.vim:

function! FoldError(lnum)
  let l:line = getline(a:lnum)
  if matchstr(l:line, '^/') != ''
    return 1
  endif
  if matchstr(l:line, '^|') != ''
    return -1
  endif
  return 0
endfunction

setl fde=FoldError(v:lnum)
setl fdm=expr

Since the output from the compilers has been processed into a different format, it seems that the first character is all that's needed to identify the type of line that it is. Either it begins with a |, meaning it's some kind of commentary, otherwise it's a filename. If it begins with a / then it's outside of the tree I'm working on.


Also, filetype plugin on to make sure that the above script is executed at the appropriate time.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.