nix-super/src/libutil/fmt.hh

152 lines
3 KiB
C++
Raw Normal View History

2020-04-21 22:25:41 +03:00
#pragma once
///@file
2020-04-21 22:25:41 +03:00
#include <boost/format.hpp>
#include <string>
#include "ansicolor.hh"
namespace nix {
/**
* Inherit some names from other namespaces for convenience.
*/
2020-04-21 22:25:41 +03:00
using boost::format;
/**
* A variadic template that does nothing. Useful to call a function
* for all variadic arguments but ignoring the result.
*/
2020-04-21 22:25:41 +03:00
struct nop { template<typename... T> nop(T...) {} };
/**
* A helper for formatting strings. fmt(format, a_0, ..., a_n) is
* equivalent to boost::format(format) % a_0 % ... %
* ... a_n. However, fmt(s) is equivalent to s (so no %-expansion
* takes place).
*/
2020-04-21 22:25:41 +03:00
template<class F>
inline void formatHelper(F & f)
{
}
template<class F, typename T, typename... Args>
inline void formatHelper(F & f, const T & x, const Args & ... args)
{
formatHelper(f % x, args...);
}
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);
f.exceptions(boost::io::all_error_bits ^ boost::io::too_many_args_bit);
formatHelper(f, args...);
return f.str();
}
// format function for hints in errors. same as fmt, except templated values
// are always in magenta.
2020-04-21 22:25:41 +03:00
template <class T>
struct magentatxt
2020-04-21 22:25:41 +03:00
{
magentatxt(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>
std::ostream & operator<<(std::ostream & out, const magentatxt<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
}
2020-05-05 01:19:20 +03:00
template <class T>
struct normaltxt
{
2020-10-07 17:33:19 +03:00
normaltxt(const T & s) : value(s) {}
const T & value;
2020-05-05 01:19:20 +03:00
};
template <class T>
2020-10-07 17:33:19 +03:00
std::ostream & operator<<(std::ostream & out, const normaltxt<T> & y)
2020-05-05 01:19:20 +03:00
{
return out << ANSI_NORMAL << y.value;
}
2020-04-21 22:25:41 +03:00
class hintformat
{
public:
hintformat(const std::string & format) : fmt(format)
2020-04-21 22:25:41 +03:00
{
2020-10-07 17:33:19 +03:00
fmt.exceptions(boost::io::all_error_bits ^
2020-06-20 00:29:19 +03:00
boost::io::too_many_args_bit ^
boost::io::too_few_args_bit);
2020-04-21 22:25:41 +03:00
}
2020-10-07 17:33:19 +03:00
hintformat(const hintformat & hf)
: fmt(hf.fmt)
{ }
hintformat(format && fmt)
: fmt(std::move(fmt))
{ }
2020-04-21 22:25:41 +03:00
template<class T>
2020-10-07 17:33:19 +03:00
hintformat & operator%(const T & value)
2020-04-21 22:25:41 +03:00
{
fmt % magentatxt(value);
2020-04-21 22:25:41 +03:00
return *this;
}
template<class T>
2020-10-07 17:33:19 +03:00
hintformat & operator%(const normaltxt<T> & value)
{
fmt % value.value;
return *this;
}
2020-04-21 22:25:41 +03:00
std::string str() const
{
return fmt.str();
}
private:
format fmt;
};
2020-10-07 17:33:19 +03:00
std::ostream & operator<<(std::ostream & os, const hintformat & hf);
2020-04-21 22:25:41 +03:00
template<typename... Args>
inline hintformat hintfmt(const std::string & fs, const Args & ... args)
{
hintformat f(fs);
formatHelper(f, args...);
return f;
}
inline hintformat hintfmt(const std::string & plain_string)
2020-06-20 00:29:19 +03:00
{
// we won't be receiving any args in this case, so just print the original string
return hintfmt("%s", normaltxt(plain_string));
2020-06-20 00:29:19 +03:00
}
2020-04-21 22:25:41 +03:00
}