Uni20
Asynchronous tensor and runtime library.
Loading...
Searching...
No Matches
display.hpp
Go to the documentation of this file.
1#pragma once
2
3#include "presentation.hpp"
4
5#include <fmt/core.h>
6#include <fmt/format.h>
7
8#include <cstddef>
9#include <functional>
10#include <initializer_list>
11#include <optional>
12#include <source_location>
13#include <string>
14#include <string_view>
15#include <type_traits>
16#include <utility>
17#include <variant>
18#include <vector>
19
20namespace uni20::display
21{
22
24enum class stream
25{
26 out,
27 err
28};
29
32{
33 fixed,
34 share,
35 fit
36};
37
40{
42 std::size_t value = 1;
43 std::size_t minimum = 1;
44};
45
46namespace width
47{
49[[nodiscard]] column_width fixed(std::size_t cells);
50
52[[nodiscard]] column_width share(std::size_t weight = 1, std::size_t minimum = 1);
53
59[[nodiscard]] column_width fit(std::size_t minimum = 1);
60} // namespace width
61
64{
66 text,
67 number
68};
69
80
81namespace format
82{
85
87[[nodiscard]] column_format number(std::string pattern = "{}", terminal::TerminalStyle style = {});
88
90[[nodiscard]] column_format fixed(int precision, terminal::TerminalStyle style = {});
91
93[[nodiscard]] column_format scientific(int precision, terminal::TerminalStyle style = {});
94
96[[nodiscard]] column_format general(int precision, terminal::TerminalStyle style = {});
97} // namespace format
98
109
111using event_content = std::variant<presentation::styled_text, presentation::report_builder>;
112
114struct event
115{
118 bool newline = true;
119 std::string context;
120 std::source_location where;
122 bool preserve_layout = false;
123};
124
126using sink = std::function<void(event const&)>;
127
129template <typename... Args> struct format_string
130{
131 fmt::format_string<Args...> format;
132 std::source_location where;
133
134 template <typename String>
135 consteval format_string(String const& value, std::source_location location = std::source_location::current())
136 : format(value), where(location)
137 {}
138};
139
141template <typename... Args> using checked_format_string = std::type_identity_t<format_string<Args...>>;
142
144void set_sink(sink replacement);
145
147void reset_sink();
148
150[[nodiscard]] sink current_sink();
151
154 public:
155 explicit scoped_sink(sink replacement);
156 scoped_sink(scoped_sink const&) = delete;
158 scoped_sink(scoped_sink&& other) noexcept;
159 scoped_sink& operator=(scoped_sink&& other) noexcept;
160 ~scoped_sink();
161
162 private:
163 sink previous_;
164 bool active_ = true;
165};
166
171 public:
172 explicit streaming_table(std::string title = {}, stream destination = stream::out);
173
174 streaming_table& column(std::string heading, column_width width_spec = width::share(),
176 column_format format = {});
183 streaming_table& column(std::string heading, column_format format);
185 streaming_table& column(std::string heading, column_width width_spec, column_format format);
188 streaming_table& wrap_width(std::size_t width);
189 streaming_table& header_separator(bool enabled = true);
192
194 void row(std::vector<formatted_cell> cells, std::source_location where = std::source_location::current());
195
196 void row(std::vector<presentation::styled_text> cells,
197 std::source_location where = std::source_location::current());
198 void row(std::vector<std::string> cells, std::source_location where = std::source_location::current());
199 void row(std::initializer_list<std::string> cells, std::source_location where = std::source_location::current());
200
201 template <typename... Values> void row(Values&&... values);
202
203 private:
204 struct column_spec
205 {
206 std::string heading;
209 column_format format;
210 };
211
212 std::string title_;
213 stream destination_ = stream::out;
215 std::vector<column_spec> columns_;
216 std::vector<std::size_t> widths_;
217 std::vector<std::optional<std::size_t>> decimal_positions_;
218 bool header_separator_ = true;
219 bool header_emitted_ = false;
220 bool widths_resolved_ = false;
221 bool vertical_fallback_ = false;
222 sink output_ = {};
223
224 void ensure_can_change_schema() const;
225 void resolve_widths();
226 void expand_fit_columns(std::vector<formatted_cell> const& cells);
227 void emit_rows(std::vector<formatted_cell> const& cells, std::source_location where);
228 void emit_text(presentation::styled_text text, bool newline, std::source_location where);
229};
230
232[[nodiscard]] streaming_table table(std::string title = {}, stream destination = stream::out);
233
235template <typename... Args>
237 checked_format_string<Args...> format, Args&&... args);
238
240void emit(presentation::styled_text text, stream destination = stream::err, bool newline = true,
241 std::source_location where = std::source_location::current());
242
244void emit(presentation::report_builder report, stream destination = stream::err, bool newline = true,
245 std::source_location where = std::source_location::current());
246
248template <typename... Args>
249void status(presentation::semantic_glyph glyph, checked_format_string<Args...> format, Args&&... args);
250
252template <typename... Args> void info(checked_format_string<Args...> format, Args&&... args);
253
255template <typename... Args> void success(checked_format_string<Args...> format, Args&&... args);
256
258template <typename... Args> void warning(checked_format_string<Args...> format, Args&&... args);
259
261template <typename... Args> void failure(checked_format_string<Args...> format, Args&&... args);
262
264template <typename... Args> void fatal(checked_format_string<Args...> format, Args&&... args);
265
267template <typename... Args> void partial(checked_format_string<Args...> format, Args&&... args);
268
270template <typename... Args> void deferred(checked_format_string<Args...> format, Args&&... args);
271
273template <typename... Args> void skipped(checked_format_string<Args...> format, Args&&... args);
274
275namespace detail
276{
278
279template <typename T>
280inline constexpr bool display_numeric_value =
281 std::is_arithmetic_v<std::remove_cvref_t<T>> && !std::is_same_v<std::remove_cvref_t<T>, bool> &&
282 !std::is_same_v<std::remove_cvref_t<T>, char> && !std::is_same_v<std::remove_cvref_t<T>, signed char> &&
283 !std::is_same_v<std::remove_cvref_t<T>, unsigned char>;
284
285[[nodiscard]] inline bool expects_number(column_format const& format)
286{
287 return format.kind == column_value_kind::number;
288}
289
290[[nodiscard]] inline formatted_cell make_text_cell(presentation::styled_text value, column_format const& format = {})
291{
292 auto const exception = expects_number(format);
293 return formatted_cell{.text = std::move(value), .decimal_candidate = false, .decimal_exception = exception};
294}
295
296[[nodiscard]] inline formatted_cell format_cell_value(column_format const& format, presentation::styled_text value)
297{
298 return make_text_cell(std::move(value), format);
299}
300
301[[nodiscard]] inline formatted_cell format_cell_value(column_format const& format,
303{
304 return make_text_cell(value.content, format);
305}
306
307[[nodiscard]] inline presentation::styled_text make_plain_cell(std::string_view value,
309{
311 text.append(value, std::move(style));
312 return text;
313}
314
315[[nodiscard]] inline formatted_cell format_cell_value(column_format const& format, char const* value)
316{
317 auto const exception = expects_number(format);
318 return formatted_cell{.text = make_plain_cell(value != nullptr ? std::string_view(value) : std::string_view{},
319 exception ? format.exception_style : format.style),
320 .decimal_candidate = false,
321 .decimal_exception = exception};
322}
323
324template <typename T> [[nodiscard]] formatted_cell format_cell_value(column_format const& format, T&& value)
325{
326 using value_type = std::remove_cvref_t<T>;
327 if constexpr (display_numeric_value<T>)
328 {
329 auto const numeric = expects_number(format);
330 auto const finite = uni20::isfinite(value);
331 auto text = make_plain_cell(numeric ? fmt::format(fmt::runtime(format.pattern), std::forward<T>(value))
332 : fmt::format("{}", std::forward<T>(value)),
333 finite ? format.style : format.exception_style);
334 return formatted_cell{.text = std::move(text),
335 .decimal_candidate = numeric && finite,
336 .decimal_exception = numeric && !finite,
337 .keep_together = true};
338 }
339 else if constexpr (std::is_same_v<value_type, std::string>)
340 {
341 auto const exception = expects_number(format);
342 return formatted_cell{
343 .text = make_plain_cell(std::forward<T>(value), exception ? format.exception_style : format.style),
344 .decimal_candidate = false,
345 .decimal_exception = exception};
346 }
347 else if constexpr (std::is_same_v<value_type, std::string_view>)
348 {
349 auto const exception = expects_number(format);
350 return formatted_cell{.text = make_plain_cell(value, exception ? format.exception_style : format.style),
351 .decimal_candidate = false,
352 .decimal_exception = exception};
353 }
354 else if constexpr (std::is_array_v<value_type>)
355 {
356 auto const exception = expects_number(format);
357 return formatted_cell{
358 .text = make_plain_cell(std::string_view(value), exception ? format.exception_style : format.style),
359 .decimal_candidate = false,
360 .decimal_exception = exception};
361 }
362 else if constexpr (std::is_convertible_v<T, char const*>)
363 {
364 return format_cell_value(format, static_cast<char const*>(value));
365 }
366 else
367 {
368 auto const exception = expects_number(format);
369 return formatted_cell{.text = make_plain_cell(fmt::format("{}", std::forward<T>(value)),
370 exception ? format.exception_style : format.style),
371 .decimal_candidate = false,
372 .decimal_exception = exception};
373 }
374}
375} // namespace detail
376
377template <typename... Args>
379 Args&&... args)
380{
381 auto style = detail::status_style(glyph);
383 text.append(glyph, style).append(" ").append(fmt::format(format.format, std::forward<Args>(args)...), style);
384 return text;
385}
386
387template <typename... Args>
389{
390 emit(status_cell(glyph, format, std::forward<Args>(args)...), stream::err, true, format.where);
391}
392
393template <typename... Args> void info(checked_format_string<Args...> format, Args&&... args)
394{
395 status(presentation::semantic_glyph::info, format, std::forward<Args>(args)...);
396}
397
398template <typename... Args> void success(checked_format_string<Args...> format, Args&&... args)
399{
400 status(presentation::semantic_glyph::success, format, std::forward<Args>(args)...);
401}
402
403template <typename... Args> void warning(checked_format_string<Args...> format, Args&&... args)
404{
405 status(presentation::semantic_glyph::warning, format, std::forward<Args>(args)...);
406}
407
408template <typename... Args> void failure(checked_format_string<Args...> format, Args&&... args)
409{
410 status(presentation::semantic_glyph::failure, format, std::forward<Args>(args)...);
411}
412
413template <typename... Args> void fatal(checked_format_string<Args...> format, Args&&... args)
414{
415 status(presentation::semantic_glyph::fatal, format, std::forward<Args>(args)...);
416}
417
418template <typename... Args> void partial(checked_format_string<Args...> format, Args&&... args)
419{
420 status(presentation::semantic_glyph::partial, format, std::forward<Args>(args)...);
421}
422
423template <typename... Args> void deferred(checked_format_string<Args...> format, Args&&... args)
424{
425 status(presentation::semantic_glyph::deferred, format, std::forward<Args>(args)...);
426}
427
428template <typename... Args> void skipped(checked_format_string<Args...> format, Args&&... args)
429{
430 status(presentation::semantic_glyph::skipped, format, std::forward<Args>(args)...);
431}
432
433template <typename... Values> void streaming_table::row(Values&&... values)
434{
435 std::vector<formatted_cell> cells;
436 cells.reserve(sizeof...(Values));
437 std::size_t column = 0;
438 ((cells.push_back(detail::format_cell_value(column < columns_.size() ? columns_[column].format : column_format{},
439 std::forward<Values>(values))),
440 ++column),
441 ...);
442 this->emit_rows(cells, std::source_location::current());
443}
444
445} // namespace uni20::display
Definition terminal.hpp:262
Temporarily replace the display sink and restore it on destruction.
Definition display.hpp:153
scoped_sink & operator=(scoped_sink const &)=delete
~scoped_sink()
Definition display.cpp:838
scoped_sink(scoped_sink const &)=delete
Schema-first table for progress output where rows are emitted immediately.
Definition display.hpp:170
void row(std::vector< formatted_cell > cells, std::source_location where=std::source_location::current())
Emit preformatted cells without discarding their numeric alignment semantics.
Definition display.cpp:448
streaming_table & header_separator(bool enabled=true)
Definition display.cpp:441
streaming_table & output(sink destination, presentation::output_policy policy)
Route this table through an instance-owned sink and policy, without changing global display routing.
Definition display.cpp:779
streaming_table & column(std::string heading, column_width width_spec=width::share(), presentation::table_alignment alignment=presentation::table_alignment::right, column_format format={})
streaming_table & wrap_width(std::size_t width)
Definition display.cpp:434
streaming_table & column(std::string heading, presentation::table_alignment alignment, column_format format)
Add a flexible-width column with explicit alignment and format.
streaming_table & column(std::string heading, presentation::table_alignment alignment)
Add a flexible-width column with an explicit alignment.
Builder for simple terminal reports with headings, status lines, fields, and tables.
Definition presentation.hpp:602
A sequence of styled text spans and semantic glyph tokens.
Definition presentation.hpp:216
styled_text & append(std::string_view text, terminal::TerminalStyle style={})
Append a text span.
Definition presentation.cpp:1164
locale_t value
Definition data_table.cpp:49
bool decimal_exception
Definition display.cpp:150
bool decimal_candidate
Definition display.cpp:149
std::size_t width
Definition display.cpp:142
constexpr bool isfinite(I const &x) noexcept
Returns whether an integer scalar is finite.
Definition math.hpp:121
Definition format.hpp:36
Definition qnum.hpp:403
column_width share(std::size_t weight, std::size_t minimum)
Request a flexible streaming table column with the given share weight.
Definition display.cpp:308
Definition display.cpp:16
void set_sink(sink replacement)
Replace the process-wide display sink.
Definition display.cpp:802
void warning(checked_format_string< Args... > format, Args &&... args)
Emit a non-fatal warning display message.
Definition display.hpp:403
void info(checked_format_string< Args... > format, Args &&... args)
Emit an informational display message.
Definition display.hpp:393
void skipped(checked_format_string< Args... > format, Args &&... args)
Emit a skipped/unavailable display message.
Definition display.hpp:428
presentation::styled_text status_cell(presentation::semantic_glyph glyph, checked_format_string< Args... > format, Args &&... args)
Build styled status text without emitting it.
Definition display.hpp:378
stream
Selects the ordinary display stream for a message.
Definition display.hpp:25
std::variant< presentation::styled_text, presentation::report_builder > event_content
Presentation payload carried to a display sink before final rendering.
Definition display.hpp:111
void emit(presentation::styled_text text, stream destination, bool newline, std::source_location where)
Emit styled text through the active display sink.
Definition display.cpp:843
streaming_table table(std::string title, stream destination)
Create a schema-first streaming display table.
Definition display.cpp:800
void deferred(checked_format_string< Args... > format, Args &&... args)
Emit an intentionally deferred display message.
Definition display.hpp:423
column_width_mode
Width allocation mode for a streaming display table column.
Definition display.hpp:32
void reset_sink()
Restore the default C++ terminal display sink.
Definition display.cpp:809
void failure(checked_format_string< Args... > format, Args &&... args)
Emit a failure display message.
Definition display.hpp:408
sink current_sink()
Return a copy of the active display sink.
Definition display.cpp:815
std::function< void(event const &)> sink
Callable that receives display events for final routing and rendering.
Definition display.hpp:126
column_value_kind
Semantic value type expected by a streaming table column.
Definition display.hpp:64
void fatal(checked_format_string< Args... > format, Args &&... args)
Emit a fatal-status display message.
Definition display.hpp:413
void status(presentation::semantic_glyph glyph, checked_format_string< Args... > format, Args &&... args)
Emit a semantic status message through the active display sink.
Definition display.hpp:388
std::type_identity_t< format_string< Args... > > checked_format_string
Non-deduced format-string parameter type used by display helper templates.
Definition display.hpp:141
typename optional_traits< T >::value_type value_type
Definition data_table.hpp:42
semantic_glyph
Names semantic glyphs independently of their rendered spelling.
Definition presentation.hpp:117
table_alignment
Selects table cell alignment in report-style output.
Definition presentation.hpp:89
terminal::TerminalStyle style
Definition presentation.cpp:2434
table_alignment alignment
Definition presentation.cpp:2018
std::optional< semantic_glyph > glyph
Definition presentation.cpp:2435
Default formatting and styling for values emitted in a streaming table column.
Definition display.hpp:72
terminal::TerminalStyle exception_style
Definition display.hpp:76
terminal::TerminalStyle style
Definition display.hpp:75
std::string pattern
Definition display.hpp:74
std::size_t minimum_width
Preferred fit-column minimum width for numeric columns. Zero selects the default for the format.
Definition display.hpp:78
column_value_kind kind
Definition display.hpp:73
Schema-level width request for a streaming display table column.
Definition display.hpp:40
std::size_t value
Definition display.hpp:42
std::size_t minimum
Definition display.hpp:43
column_width_mode mode
Definition display.hpp:41
Human-facing display event routed through the active sink.
Definition display.hpp:115
std::string context
Definition display.hpp:119
bool newline
Definition display.hpp:118
stream destination
Definition display.hpp:116
event_content content
Definition display.hpp:117
std::source_location where
Definition display.hpp:120
bool preserve_layout
Sinks must retain the supplied line breaks without applying additional wrapping.
Definition display.hpp:122
Compile-time checked display format string with call-site metadata.
Definition display.hpp:130
std::source_location where
Definition display.hpp:132
fmt::format_string< Args... > format
Definition display.hpp:131
consteval format_string(String const &value, std::source_location location=std::source_location::current())
Definition display.hpp:135
Already formatted display text with numeric alignment semantics retained by its producer.
Definition display.hpp:103
bool keep_together
Definition display.hpp:107
presentation::styled_text text
Definition display.hpp:104
bool decimal_candidate
Definition display.hpp:105
bool decimal_exception
Definition display.hpp:106
Output policy shared by presentation renderers and layout helpers.
Definition presentation.hpp:186
Cell specification for table rows, including optional style, column span, and alignment.
Definition presentation.hpp:401