Uni20
Asynchronous tensor and runtime library.
Loading...
Searching...
No Matches
presentation_stacktrace.hpp
Go to the documentation of this file.
1#pragma once
2
10#include <uni20/config.hpp>
11
12#if UNI20_HAS_STACKTRACE
13#include <stacktrace>
14
15#include <algorithm>
16#include <fmt/core.h>
17#include <string>
18#include <vector>
19
20namespace uni20::presentation
21{
22
24struct stacktrace_format_options
25{
26 std::size_t indent = 2;
27 terminal::TerminalStyle tree_style = terminal::TerminalStyle("LightGray");
28 terminal::TerminalStyle index_style = terminal::TerminalStyle("LightGray");
29 terminal::TerminalStyle description_style = {};
30 terminal::TerminalStyle source_file_style = terminal::TerminalStyle("Cyan");
31 terminal::TerminalStyle source_line_style = terminal::TerminalStyle("LightGray");
32};
33
42inline styled_text format_stacktrace(std::stacktrace const& stacktrace, output_policy const& policy,
43 stacktrace_format_options const& options = {})
44{
45 styled_text text;
46 std::size_t frame_index = 0;
47 auto const frame_count = stacktrace.size();
48
49 for (auto const& frame : stacktrace)
50 {
51 bool const is_last = frame_index + 1 == frame_count;
52 std::string description = frame.description();
53 if (description.empty())
54 {
55 description = "(unknown)";
56 }
57
58 styled_text prefix;
59 prefix.append(std::string(options.indent, ' '));
60 prefix.append(is_last ? semantic_glyph::tree_last : semantic_glyph::tree_branch, options.tree_style);
61 prefix.append(" ");
62 prefix.append(fmt::format("#{}", frame_index), options.index_style);
63 prefix.append(" ");
64
65 styled_text frame_text;
66 frame_text.append(description, options.description_style);
67 if (!frame.source_file().empty())
68 {
69 frame_text.append(" at ");
70 frame_text.append(frame.source_file(), options.source_file_style);
71 frame_text.append(fmt::format(":{}", frame.source_line()), options.source_line_style);
72 }
73
74 std::vector<styled_text> lines{frame_text};
75 auto const prefix_width = display_width(prefix, policy);
76 if (policy.wrap_width.has_value() && *policy.wrap_width > prefix_width)
77 {
78 lines = wrap_text(frame_text, std::max<std::size_t>(*policy.wrap_width - prefix_width, 1), policy);
79 }
80 if (lines.empty())
81 {
82 lines.emplace_back();
83 }
84
85 text.append(prefix).append(lines.front()).append("\n");
86 for (std::size_t line = 1; line < lines.size(); ++line)
87 {
88 text.append(std::string(options.indent, ' '));
89 styled_text connector;
90 connector.append(is_last ? semantic_glyph::tree_space : semantic_glyph::tree_vertical, options.tree_style);
91 text.append(connector);
92 auto const connector_width = display_width(connector, policy);
93 text.append(std::string(prefix_width - options.indent - connector_width, ' '));
94 text.append(lines[line]).append("\n");
95 }
96 ++frame_index;
97 }
98
99 if (frame_index == 0)
100 {
101 text.append(std::string(options.indent, ' '));
102 text.append("(empty stacktrace)", options.description_style);
103 text.append("\n");
104 }
105 return text;
106}
107
108} // namespace uni20::presentation
109#endif
Definition terminal.hpp:262
styled_text & append(std::string_view text, terminal::TerminalStyle style={})
Append a text span.
Definition presentation.cpp:1164
presentation::styled_text text
Definition display.cpp:141
Definition data_table.cpp:8
semantic_glyph
Names semantic glyphs independently of their rendered spelling.
Definition presentation.hpp:117
std::vector< std::string > wrap_text(std::string_view text, std::size_t max_width, output_policy const &policy)
Wrap rendered text by display cells or bytes.
Definition presentation.cpp:2831
std::size_t display_width(std::string_view text, output_policy const &policy, std::size_t initial_column)
Measure rendered text width under the selected policy.
Definition presentation.cpp:2560
std::vector< styled_text > lines
Definition presentation.cpp:2015