2020-04-21 22:25:41 +03:00
|
|
|
#pragma once
|
2023-04-01 06:18:41 +03:00
|
|
|
///@file
|
2020-04-21 22:25:41 +03:00
|
|
|
|
|
|
|
#include <boost/format.hpp>
|
|
|
|
#include <string>
|
|
|
|
#include "ansicolor.hh"
|
|
|
|
|
|
|
|
|
|
|
|
namespace nix {
|
|
|
|
|
2023-03-27 04:12:25 +03:00
|
|
|
/**
|
2024-02-04 05:16:30 +02:00
|
|
|
* A helper for writing `boost::format` expressions.
|
|
|
|
*
|
|
|
|
* These are equivalent:
|
|
|
|
*
|
|
|
|
* ```
|
|
|
|
* formatHelper(formatter, a_0, ..., a_n)
|
|
|
|
* formatter % a_0 % ... % a_n
|
|
|
|
* ```
|
|
|
|
*
|
|
|
|
* With a single argument, `formatHelper(s)` is a no-op.
|
2023-03-27 04:12:25 +03:00
|
|
|
*/
|
2020-04-21 22:25:41 +03:00
|
|
|
template<class F>
|
|
|
|
inline void formatHelper(F & f)
|
2024-02-04 05:16:30 +02:00
|
|
|
{ }
|
2020-04-21 22:25:41 +03:00
|
|
|
|
|
|
|
template<class F, typename T, typename... Args>
|
|
|
|
inline void formatHelper(F & f, const T & x, const Args & ... args)
|
|
|
|
{
|
2024-02-04 05:16:30 +02:00
|
|
|
// Interpolate one argument and then recurse.
|
2020-04-21 22:25:41 +03:00
|
|
|
formatHelper(f % x, args...);
|
|
|
|
}
|
2024-02-04 06:35:19 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Set the correct exceptions for `fmt`.
|
|
|
|
*/
|
2024-03-04 19:32:02 +02:00
|
|
|
inline void setExceptions(boost::format & fmt)
|
2024-02-04 06:35:19 +02:00
|
|
|
{
|
|
|
|
fmt.exceptions(
|
|
|
|
boost::io::all_error_bits ^
|
|
|
|
boost::io::too_many_args_bit ^
|
|
|
|
boost::io::too_few_args_bit);
|
|
|
|
}
|
2020-04-21 22:25:41 +03:00
|
|
|
|
2024-02-04 05:16:30 +02:00
|
|
|
/**
|
|
|
|
* A helper for writing a `boost::format` expression to a string.
|
|
|
|
*
|
|
|
|
* These are (roughly) equivalent:
|
|
|
|
*
|
|
|
|
* ```
|
|
|
|
* fmt(formatString, a_0, ..., a_n)
|
|
|
|
* (boost::format(formatString) % a_0 % ... % a_n).str()
|
|
|
|
* ```
|
|
|
|
*
|
|
|
|
* However, when called with a single argument, the string is returned
|
|
|
|
* unchanged.
|
|
|
|
*
|
|
|
|
* If you write code like this:
|
|
|
|
*
|
|
|
|
* ```
|
|
|
|
* std::cout << boost::format(stringFromUserInput) << std::endl;
|
|
|
|
* ```
|
|
|
|
*
|
|
|
|
* And `stringFromUserInput` contains formatting placeholders like `%s`, then
|
|
|
|
* the code will crash at runtime. `fmt` helps you avoid this pitfall.
|
|
|
|
*/
|
2020-04-21 22:25:41 +03:00
|
|
|
inline std::string fmt(const std::string & s)
|
|
|
|
{
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
2023-11-01 17:33:22 +02:00
|
|
|
inline std::string fmt(std::string_view s)
|
|
|
|
{
|
|
|
|
return std::string(s);
|
|
|
|
}
|
|
|
|
|
2020-04-21 22:25:41 +03:00
|
|
|
inline std::string fmt(const char * s)
|
|
|
|
{
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename... Args>
|
|
|
|
inline std::string fmt(const std::string & fs, const Args & ... args)
|
|
|
|
{
|
|
|
|
boost::format f(fs);
|
2024-02-04 06:35:19 +02:00
|
|
|
setExceptions(f);
|
2020-04-21 22:25:41 +03:00
|
|
|
formatHelper(f, args...);
|
|
|
|
return f.str();
|
|
|
|
}
|
|
|
|
|
2024-02-04 05:16:30 +02:00
|
|
|
/**
|
|
|
|
* Values wrapped in this struct are printed in magenta.
|
|
|
|
*
|
2024-02-04 06:35:19 +02:00
|
|
|
* By default, arguments to `HintFmt` are printed in magenta. To avoid this,
|
2024-02-04 05:16:30 +02:00
|
|
|
* either wrap the argument in `Uncolored` or add a specialization of
|
2024-02-04 06:35:19 +02:00
|
|
|
* `HintFmt::operator%`.
|
2024-02-04 05:16:30 +02:00
|
|
|
*/
|
2020-04-21 22:25:41 +03:00
|
|
|
template <class T>
|
2024-02-04 05:16:30 +02:00
|
|
|
struct Magenta
|
2020-04-21 22:25:41 +03:00
|
|
|
{
|
2024-02-04 05:16:30 +02:00
|
|
|
Magenta(const T &s) : value(s) {}
|
2020-10-07 17:33:19 +03:00
|
|
|
const T & value;
|
2020-04-21 22:25:41 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
template <class T>
|
2024-02-04 05:16:30 +02:00
|
|
|
std::ostream & operator<<(std::ostream & out, const Magenta<T> & y)
|
2020-04-21 22:25:41 +03:00
|
|
|
{
|
2021-09-14 11:38:10 +03:00
|
|
|
return out << ANSI_WARNING << y.value << ANSI_NORMAL;
|
2020-04-21 22:25:41 +03:00
|
|
|
}
|
|
|
|
|
2024-02-04 05:16:30 +02:00
|
|
|
/**
|
|
|
|
* Values wrapped in this class are printed without coloring.
|
|
|
|
*
|
2024-02-04 06:35:19 +02:00
|
|
|
* By default, arguments to `HintFmt` are printed in magenta (see `Magenta`).
|
2024-02-04 05:16:30 +02:00
|
|
|
*/
|
2020-05-05 01:19:20 +03:00
|
|
|
template <class T>
|
2024-02-04 05:16:30 +02:00
|
|
|
struct Uncolored
|
2020-05-05 01:19:20 +03:00
|
|
|
{
|
2024-02-04 05:16:30 +02:00
|
|
|
Uncolored(const T & s) : value(s) {}
|
2020-10-07 17:33:19 +03:00
|
|
|
const T & value;
|
2020-05-05 01:19:20 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
template <class T>
|
2024-02-04 05:16:30 +02:00
|
|
|
std::ostream & operator<<(std::ostream & out, const Uncolored<T> & y)
|
2020-05-05 01:19:20 +03:00
|
|
|
{
|
|
|
|
return out << ANSI_NORMAL << y.value;
|
|
|
|
}
|
|
|
|
|
2024-02-04 05:16:30 +02:00
|
|
|
/**
|
|
|
|
* A wrapper around `boost::format` which colors interpolated arguments in
|
|
|
|
* magenta by default.
|
|
|
|
*/
|
2024-02-04 06:35:19 +02:00
|
|
|
class HintFmt
|
2020-04-21 22:25:41 +03:00
|
|
|
{
|
2024-02-04 05:16:30 +02:00
|
|
|
private:
|
|
|
|
boost::format fmt;
|
|
|
|
|
2020-04-21 22:25:41 +03:00
|
|
|
public:
|
2024-02-04 05:16:30 +02:00
|
|
|
/**
|
|
|
|
* Format the given string literally, without interpolating format
|
|
|
|
* placeholders.
|
|
|
|
*/
|
2024-02-04 06:35:19 +02:00
|
|
|
HintFmt(const std::string & literal)
|
|
|
|
: HintFmt("%s", Uncolored(literal))
|
2024-02-04 05:16:30 +02:00
|
|
|
{ }
|
|
|
|
|
2024-03-26 09:55:15 +02:00
|
|
|
static HintFmt fromFormatString(const std::string & format) {
|
|
|
|
return HintFmt(boost::format(format));
|
|
|
|
}
|
|
|
|
|
2024-02-04 05:16:30 +02:00
|
|
|
/**
|
|
|
|
* Interpolate the given arguments into the format string.
|
|
|
|
*/
|
|
|
|
template<typename... Args>
|
2024-02-04 06:35:19 +02:00
|
|
|
HintFmt(const std::string & format, const Args & ... args)
|
|
|
|
: HintFmt(boost::format(format), args...)
|
|
|
|
{ }
|
2024-02-04 05:16:30 +02:00
|
|
|
|
2024-02-04 06:35:19 +02:00
|
|
|
HintFmt(const HintFmt & hf)
|
2020-10-07 17:33:19 +03:00
|
|
|
: fmt(hf.fmt)
|
|
|
|
{ }
|
|
|
|
|
2024-02-04 06:35:19 +02:00
|
|
|
template<typename... Args>
|
|
|
|
HintFmt(boost::format && fmt, const Args & ... args)
|
2020-10-07 17:33:19 +03:00
|
|
|
: fmt(std::move(fmt))
|
2024-02-04 06:35:19 +02:00
|
|
|
{
|
|
|
|
setExceptions(fmt);
|
|
|
|
formatHelper(*this, args...);
|
|
|
|
}
|
2020-04-24 21:44:23 +03:00
|
|
|
|
2020-04-21 22:25:41 +03:00
|
|
|
template<class T>
|
2024-02-04 06:35:19 +02:00
|
|
|
HintFmt & operator%(const T & value)
|
2020-04-21 22:25:41 +03:00
|
|
|
{
|
2024-02-04 05:16:30 +02:00
|
|
|
fmt % Magenta(value);
|
2020-04-21 22:25:41 +03:00
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
2020-06-22 20:32:20 +03:00
|
|
|
template<class T>
|
2024-02-04 06:35:19 +02:00
|
|
|
HintFmt & operator%(const Uncolored<T> & value)
|
2020-06-22 20:32:20 +03:00
|
|
|
{
|
|
|
|
fmt % value.value;
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
2020-04-21 22:25:41 +03:00
|
|
|
std::string str() const
|
|
|
|
{
|
|
|
|
return fmt.str();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2024-02-04 06:35:19 +02:00
|
|
|
std::ostream & operator<<(std::ostream & os, const HintFmt & hf);
|
2022-01-21 17:13:34 +02:00
|
|
|
|
2020-04-21 22:25:41 +03:00
|
|
|
}
|