diff --git a/include/cpptrace/formatting.hpp b/include/cpptrace/formatting.hpp index ce76088..6a46085 100644 --- a/include/cpptrace/formatting.hpp +++ b/include/cpptrace/formatting.hpp @@ -37,6 +37,7 @@ namespace cpptrace { formatter& set_snippets(bool); formatter& set_snippet_context(int); formatter& include_column(bool); + formatter& show_filtered_frames(bool); formatter& set_filter(std::function); std::string format(const stacktrace_frame&) const; diff --git a/src/formatting.cpp b/src/formatting.cpp index eb17bbb..6526bf8 100644 --- a/src/formatting.cpp +++ b/src/formatting.cpp @@ -21,6 +21,7 @@ namespace cpptrace { bool snippets = false; int context_lines = 2; bool columns = true; + bool show_filtered_frames = true; std::function filter; } options; @@ -43,6 +44,9 @@ namespace cpptrace { void include_column(bool columns) { options.columns = columns; } + void show_filtered_frames(bool show) { + options.show_filtered_frames = show; + } void set_filter(std::function filter) { options.filter = filter; } @@ -140,20 +144,24 @@ namespace cpptrace { const auto frame_number_width = detail::n_digits(static_cast(frames.size()) - 1); for(const auto& frame : frames) { if(options.filter && !options.filter(frame)) { - counter++; - continue; - } - print_frame_internal(stream, frame, color, frame_number_width, counter); - if(frame.line.has_value() && !frame.filename.empty() && options.snippets) { - auto snippet = detail::get_snippet( - frame.filename, - frame.line.value(), - options.context_lines, - color - ); - if(!snippet.empty()) { - stream << '\n'; - stream << snippet; + if(!options.show_filtered_frames) { + counter++; + continue; + } + print_placeholder_frame(stream, frame_number_width, counter); + } else { + print_frame_internal(stream, frame, color, frame_number_width, counter); + if(frame.line.has_value() && !frame.filename.empty() && options.snippets) { + auto snippet = detail::get_snippet( + frame.filename, + frame.line.value(), + options.context_lines, + color + ); + if(!snippet.empty()) { + stream << '\n'; + stream << snippet; + } } } if(newline_at_end || &frame != &frames.back()) { @@ -174,6 +182,11 @@ namespace cpptrace { stream << line; } + void print_placeholder_frame(std::ostream& stream, unsigned frame_number_width, std::size_t counter) const { + std::string line = microfmt::format("#{<{}} (filtered)", frame_number_width, counter); + stream << line; + } + void print_frame_internal( std::ostream& stream, const stacktrace_frame& frame, @@ -258,6 +271,10 @@ namespace cpptrace { pimpl->include_column(columns); return *this; } + formatter& formatter::show_filtered_frames(bool show) { + pimpl->show_filtered_frames(show); + return *this; + } formatter& formatter::set_filter(std::function filter) { pimpl->set_filter(std::move(filter)); return *this; diff --git a/test/unit/lib/formatting.cpp b/test/unit/lib/formatting.cpp index ca4292e..34787e7 100644 --- a/test/unit/lib/formatting.cpp +++ b/test/unit/lib/formatting.cpp @@ -191,6 +191,24 @@ TEST(FormatterTest, Filtering) { return frame.filename.find("foo.cpp") != std::string::npos; }); auto res = split(formatter.format(make_test_stacktrace()), "\n"); + EXPECT_THAT( + res, + ElementsAre( + "Stack trace (most recent call first):", + "#0 0x0000000000000001 in foo() at foo.cpp:20:30", + "#1 (filtered)", + "#2 0x0000000000000003 in main at foo.cpp:40:25" + ) + ); +} + +TEST(FormatterTest, DontShowFilteredFrames) { + auto formatter = cpptrace::formatter{} + .set_filter([] (const cpptrace::stacktrace_frame& frame) -> bool { + return frame.filename.find("foo.cpp") != std::string::npos; + }) + .show_filtered_frames(false); + auto res = split(formatter.format(make_test_stacktrace()), "\n"); EXPECT_THAT( res, ElementsAre( @@ -213,6 +231,7 @@ TEST(FormatterTest, MoveSemantics) { ElementsAre( "Stack trace (most recent call first):", "#0 0x0000000000000001 in foo() at foo.cpp:20:30", + "#1 (filtered)", "#2 0x0000000000000003 in main at foo.cpp:40:25" ) ); @@ -224,6 +243,7 @@ TEST(FormatterTest, MoveSemantics) { ElementsAre( "Stack trace (most recent call first):", "#0 0x0000000000000001 in foo() at foo.cpp:20:30", + "#1 (filtered)", "#2 0x0000000000000003 in main at foo.cpp:40:25" ) ); @@ -241,6 +261,7 @@ TEST(FormatterTest, CopySemantics) { ElementsAre( "Stack trace (most recent call first):", "#0 0x0000000000000001 in foo() at foo.cpp:20:30", + "#1 (filtered)", "#2 0x0000000000000003 in main at foo.cpp:40:25" ) ); @@ -252,6 +273,7 @@ TEST(FormatterTest, CopySemantics) { ElementsAre( "Stack trace (most recent call first):", "#0 0x0000000000000001 in foo() at foo.cpp:20:30", + "#1 (filtered)", "#2 0x0000000000000003 in main at foo.cpp:40:25" ) );