#pragma once #include #include #include "ansicolor.hh" namespace nix { /* Inherit some names from other namespaces for convenience. */ 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 nop(T...) {} }; struct FormatOrString { std::string s; FormatOrString(std::string s) : s(std::move(s)) { }; template 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 inline void formatHelper(F & f) { } template 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 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 struct yellowtxt { yellowtxt(const T &s) : value(s) {} const T & value; }; template std::ostream & operator<<(std::ostream & out, const yellowtxt & y) { return out << ANSI_WARNING << y.value << ANSI_NORMAL; } template struct normaltxt { normaltxt(const T & s) : value(s) {} const T & value; }; template std::ostream & operator<<(std::ostream & out, const normaltxt & y) { return out << ANSI_NORMAL << y.value; } class hintformat { public: hintformat(const std::string & format) : fmt(format) { fmt.exceptions(boost::io::all_error_bits ^ boost::io::too_many_args_bit ^ boost::io::too_few_args_bit); } hintformat(const hintformat & hf) : fmt(hf.fmt) { } hintformat(format && fmt) : fmt(std::move(fmt)) { } template hintformat & operator%(const T & value) { fmt % yellowtxt(value); return *this; } template hintformat & operator%(const normaltxt & value) { fmt % value.value; return *this; } std::string str() const { return fmt.str(); } private: format fmt; }; std::ostream & operator<<(std::ostream & os, const hintformat & hf); template inline hintformat hintfmt(const std::string & fs, const Args & ... args) { hintformat f(fs); formatHelper(f, args...); return f; } inline hintformat hintfmt(std::string plain_string) { // we won't be receiving any args in this case, so just print the original string return hintfmt("%s", normaltxt(plain_string)); } }