72FE_API Stream stream(std::ostream& os)
noexcept;
75FE_API
bool is_terminal(Stream s)
noexcept;
77constexpr std::string_view sgr(FG color)
noexcept {
81 case FG::Red:
return "\033[31m";
95constexpr bool escape(std::string_view str,
size_t i,
size_t end)
noexcept {
96 return str[i] ==
'\\' && i + 1 != end && (str[i + 1] ==
'`' || str[i + 1] ==
'\\');
100FE_API
size_t tick(std::string_view str,
size_t i)
noexcept;
103FE_API
void stream_raw(std::ostream& os, std::string_view str,
size_t begin,
size_t end);
106FE_API
size_t raw_width(std::string_view str,
size_t begin,
size_t end)
noexcept;
110void scan_cite(std::string_view str,
auto&& f) {
111 for (
size_t i = 0, e = str.size(); i != e;) {
112 auto l = tick(str, i);
113 auto r = l == std::string_view::npos ? l : tick(str, l + 1);
114 if (r == std::string_view::npos)
return f(i, e,
false);
165FE_API
std::ostream& operator<<(
std::ostream& os,
FG color);
172 if (c ==
'`' || c ==
'\\') *out++ =
'\\';
185 explicit Cited(std::string str) noexcept
186 : str_(std::move(str)) {}
188 [[nodiscard]]
constexpr std::string_view
view() const noexcept {
return str_; }
189 constexpr operator std::string_view() const noexcept {
return str_; }
202 constexpr Cite() noexcept = default;
204 constexpr
Cite(const
char (&s)[N]) noexcept
208 constexpr explicit Cite(std::string_view s) noexcept
211 [[nodiscard]]
constexpr std::string_view
view() const noexcept {
return str_; }
212 [[nodiscard]]
constexpr bool empty() const noexcept {
return str_.empty(); }
213 constexpr explicit operator bool() const noexcept {
return !str_.empty(); }
216 std::string_view str_;
227template<
class T,
class U = std::remove_cvref_t<T>>
228using cite_arg_t = std::conditional_t<std::is_same_v<U, Cite> || std::is_same_v<U, Cited>,
Cite, Escaped<U>>;
232template<
class... Args>
233std::string vformat_cite(std::string_view fmt,
const Args&... args) {
234 auto vformat = [fmt]<
class... A>(A... a) {
return std::vformat(fmt, std::make_format_args(a...)); };
235 return vformat(cite_arg_t<Args>{args}...);
241template<
class... Args>
242using cite_string = std::format_string<detail::cite_arg_t<Args>...>;
246template<
class... Args>
248 return Cited(detail::vformat_cite(fmt.get(), args...));
255FE_API
void render_cite(std::ostream& os, std::string_view str,
bool color);
278template<
class T = std::logic_error,
class... Args>
280 auto oss = std::ostringstream();
289struct std::formatter<
fe::term::detail::Escaped<T>> {
290 std::string_view spec;
292 constexpr auto parse(std::format_parse_context& ctx) {
293 auto i = ctx.begin();
294 for (; i != ctx.end() && *i !=
'}'; ++i)
295 if (*i ==
'{')
throw std::format_error(
"fe::term::format_cite: a nested replacement field needs Cite");
296 spec = std::string_view(ctx.begin(), i);
300 auto format(
const fe::term::detail::Escaped<T>& escaped, std::format_context& ctx)
const {
301 auto str = spec.empty() ? std::format(
"{}", escaped.val)
302 : std::vformat(std::format(
"{{:{}}}", spec), std::make_format_args(escaped.val));
308struct std::formatter<
fe::term::Cite> : std::formatter<std::string_view> {
309 auto format(fe::term::Cite cite, std::format_context& ctx)
const {
310 return std::formatter<std::string_view>::format(cite.
view(), ctx);
A borrowed fragment whose backticks stay markup; format_cite escapes every other argument.
constexpr Cite() noexcept=default
The empty fragment - a context that says nothing.
Cited(std::string str) noexcept
RAII guard that restores a value at the end of the scope.
A borrowed fragment whose backticks stay markup; format_cite escapes every other argument.
constexpr Cite(const Cited &cited) noexcept
constexpr Cite(std::string_view s) noexcept
constexpr bool empty() const noexcept
constexpr Cite() noexcept=default
The empty fragment - a context that says nothing.
constexpr std::string_view view() const noexcept
An owning message fragment that spells `citations` of its own; what format_cite yields.
constexpr std::string_view view() const noexcept
Cited(std::string str) noexcept
Lightweight stream-based terminal colors for diagnostics and CLI output.
FE_API std::string escape_cite(std::string_view str)
As above but into a fresh std::string.
FE_API size_t cite_width(std::string_view str, bool color)
Number of columns str actually occupies once render_cite renders it with color - fewer than str....
Restore< Mode, &mode, &set_mode > ScopedMode
Overrides the color mode for the duration of the scope.
FG
Foreground colors that can be streamed into an std::ostream.
Mode
Controls whether color escape sequences are emitted.
FE_API void set_mode(Mode m) noexcept
Overrides the current terminal color mode.
FE_API bool use_color(std::ostream &os) noexcept
Whether color escape sequences are emitted for os right now.
FE_API void resolve_mode(std::ostream &os=std::cerr) noexcept
Decides Mode::Auto for detached buffers, depending on whether os refers to a terminal.
Cited format_cite(cite_string< Args... > fmt, Args &&... args)
std::format for a message that follows that convention; assemble a fragment of your own with it.
std::format_string< detail::cite_arg_t< Args >... > cite_string
A std::format_string whose backticks delimit a `citation` while those of its arguments are data.
O escape_cite_to(O out, std::string_view str)
Escapes str into out so that render_cite reproduces it verbatim instead of reading it as markup.
FE_API std::optional< size_t > width(std::ostream &os) noexcept
Number of columns of the terminal os refers to.
FE_API Mode mode() noexcept
Returns the current terminal color mode.
FE_API bool auto_detached() noexcept
Whether Mode::Auto emits colors into a detached buffer - anything a std::formatter writes into.
FE_API void render_cite(std::ostream &os, std::string_view str, bool color)
Streams str into os, coloring each `citation` and dropping its backticks - or keeping them verbatim...
FE_API void set_auto_detached(bool b) noexcept
Overrides auto_detached.
void throwf(cite_string< Args... > fmt, Args &&... args)
<
basic_ostream_formatter< char > ostream_formatter