From ce97e0004d8fdd19ba5c6ed39e187c2a4c998fa3 Mon Sep 17 00:00:00 2001 From: Jeremy Rifkin <51220084+jeremy-rifkin@users.noreply.github.com> Date: Thu, 13 Feb 2025 23:22:12 -0600 Subject: [PATCH] Add basic option for shortening paths in the formatter --- include/cpptrace/formatting.hpp | 7 +++++++ src/formatting.cpp | 16 +++++++++++++++- src/utils/utils.hpp | 4 ++-- test/unit/lib/formatting.cpp | 21 +++++++++++++++++++++ 4 files changed, 45 insertions(+), 3 deletions(-) diff --git a/include/cpptrace/formatting.hpp b/include/cpptrace/formatting.hpp index 4ed4ebe..c1d87f7 100644 --- a/include/cpptrace/formatting.hpp +++ b/include/cpptrace/formatting.hpp @@ -34,6 +34,13 @@ namespace cpptrace { none, }; formatter& addresses(address_mode); + enum class path_mode { + // full path is used + full, + // only the file name is used + basename, + }; + formatter& paths(path_mode); formatter& snippets(bool); formatter& snippet_context(int); formatter& columns(bool); diff --git a/src/formatting.cpp b/src/formatting.cpp index 9a99f22..5758fdd 100644 --- a/src/formatting.cpp +++ b/src/formatting.cpp @@ -18,6 +18,7 @@ namespace cpptrace { std::string header = "Stack trace (most recent call first):"; color_mode color = color_mode::automatic; address_mode addresses = address_mode::raw; + path_mode paths = path_mode::full; bool snippets = false; int context_lines = 2; bool columns = true; @@ -35,6 +36,9 @@ namespace cpptrace { void addresses(formatter::address_mode mode) { options.addresses = mode; } + void paths(path_mode mode) { + options.paths = mode; + } void snippets(bool snippets) { options.snippets = snippets; } @@ -213,7 +217,13 @@ namespace cpptrace { microfmt::print(stream, " in {}{}{}", yellow, frame.symbol, reset); } if(!frame.filename.empty()) { - microfmt::print(stream, " at {}{}{}", green, frame.filename, reset); + microfmt::print( + stream, + " at {}{}{}", + green, + options.paths == path_mode::full ? frame.filename : detail::basename(frame.filename, true), + reset + ); if(frame.line.has_value()) { microfmt::print(stream, ":{}{}{}", blue, frame.line.value(), reset); if(frame.column.has_value() && options.columns) { @@ -258,6 +268,10 @@ namespace cpptrace { pimpl->addresses(mode); return *this; } + formatter& formatter::paths(path_mode mode) { + pimpl->paths(mode); + return *this; + } formatter& formatter::snippets(bool snippets) { pimpl->snippets(snippets); return *this; diff --git a/src/utils/utils.hpp b/src/utils/utils.hpp index 3d0e3b1..4bfa695 100644 --- a/src/utils/utils.hpp +++ b/src/utils/utils.hpp @@ -162,9 +162,9 @@ namespace detail { // shamelessly stolen from stackoverflow bool directory_exists(const std::string& path); - inline std::string basename(const std::string& path) { + inline std::string basename(const std::string& path, bool maybe_windows = false) { // Assumes no trailing /'s - auto pos = path.rfind('/'); + auto pos = path.find_last_of(maybe_windows ? "/\\" : "/"); if(pos == std::string::npos) { return path; } else { diff --git a/test/unit/lib/formatting.cpp b/test/unit/lib/formatting.cpp index 5e89d75..25e1f1d 100644 --- a/test/unit/lib/formatting.cpp +++ b/test/unit/lib/formatting.cpp @@ -96,6 +96,27 @@ TEST(FormatterTest, ObjectAddresses) { ); } +TEST(FormatterTest, PathShortening) { + cpptrace::stacktrace trace; + trace.frames.push_back({0x1, 0x1001, {20}, {30}, "/home/foo/foo.cpp", "foo()", false}); + trace.frames.push_back({0x2, 0x1002, {30}, {40}, "/bar.cpp", "bar()", false}); + trace.frames.push_back({0x3, 0x1003, {40}, {25}, "baz/foo.cpp", "main", false}); + trace.frames.push_back({0x3, 0x1003, {50}, {25}, "C:\\foo\\bar\\baz.cpp", "main", false}); + auto formatter = cpptrace::formatter{} + .paths(cpptrace::formatter::path_mode::basename); + auto res = split(formatter.format(trace), "\n"); + EXPECT_THAT( + res, + ElementsAre( + "Stack trace (most recent call first):", + "#0 0x0000000000000001 in foo() at foo.cpp:20:30", + "#1 0x0000000000000002 in bar() at bar.cpp:30:40", + "#2 0x0000000000000003 in main at foo.cpp:40:25", + "#3 0x0000000000000003 in main at baz.cpp:50:25" + ) + ); +} + #ifndef CPPTRACE_NO_TEST_SNIPPETS TEST(FormatterTest, Snippets) { cpptrace::stacktrace trace;