lix/src/libutil/fmt.hh

151 lines
3.1 KiB
C++
Raw Normal View History

2020-04-21 19:25:41 +00:00
#pragma once
#include <boost/format.hpp>
2020-06-19 21:29:19 +00:00
#include <boost/algorithm/string/replace.hpp>
2020-04-21 19:25:41 +00:00
#include <string>
#include "ansicolor.hh"
namespace nix {
/* Inherit some names from other namespaces for convenience. */
using std::string;
using boost::format;
/* A variadic template that does nothing. Useful to call a function
for all variadic arguments but ignoring the result. */
struct nop { template<typename... T> nop(T...) {} };
struct FormatOrString
{
string s;
FormatOrString(const string & s) : s(s) { };
template<class F>
FormatOrString(const F & f) : s(f.str()) { };
FormatOrString(const char * s) : s(s) { };
};
/* 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). */
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;
}
inline std::string fmt(const char * s)
{
return s;
}
inline std::string fmt(const FormatOrString & fs)
{
return fs.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 yellow.
template <class T>
2020-05-04 22:19:20 +00:00
struct yellowtxt
2020-04-21 19:25:41 +00:00
{
2020-05-06 20:07:20 +00:00
yellowtxt(const T &s) : value(s) {}
const T &value;
2020-04-21 19:25:41 +00:00
};
template <class T>
2020-05-04 22:19:20 +00:00
std::ostream& operator<<(std::ostream &out, const yellowtxt<T> &y)
2020-04-21 19:25:41 +00:00
{
return out << ANSI_YELLOW << y.value << ANSI_NORMAL;
}
2020-05-04 22:19:20 +00:00
template <class T>
struct normaltxt
{
2020-05-06 20:07:20 +00:00
normaltxt(const T &s) : value(s) {}
const T &value;
2020-05-04 22:19:20 +00:00
};
template <class T>
std::ostream& operator<<(std::ostream &out, const normaltxt<T> &y)
{
return out << ANSI_NORMAL << y.value;
}
2020-04-21 19:25:41 +00:00
class hintformat
{
public:
hintformat(const string &format) :fmt(format)
{
2020-06-19 21:29:19 +00:00
fmt.exceptions(boost::io::all_error_bits ^
boost::io::too_many_args_bit ^
boost::io::too_few_args_bit);
2020-04-21 19:25:41 +00:00
}
hintformat(const hintformat &hf)
: fmt(hf.fmt)
{}
2020-04-21 19:25:41 +00:00
template<class T>
hintformat& operator%(const T &value)
{
2020-05-04 22:19:20 +00:00
fmt % yellowtxt(value);
2020-04-21 19:25:41 +00:00
return *this;
}
std::string str() const
{
return fmt.str();
}
private:
format fmt;
};
std::ostream& operator<<(std::ostream &os, const hintformat &hf);
template<typename... Args>
inline hintformat hintfmt(const std::string & fs, const Args & ... args)
{
hintformat f(fs);
formatHelper(f, args...);
return f;
}
2020-06-19 21:29:19 +00:00
inline hintformat hintfmt(std::string fs)
{
// we won't be receiving any args in this case, so escape all percents.
boost::replace_all(fs, "%", "%%");
hintformat f(fs);
formatHelper(f);
return f;
}
2020-04-21 19:25:41 +00:00
}