lix/src/libutil/fmt.hh
Eelco Dolstra df552ff53e Remove std::string alias (for real this time)
Also use std::string_view in a few more places.
2022-02-25 16:13:02 +01:00

170 lines
3.7 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#pragma once
#include <boost/format.hpp>
#include <string>
#include <regex>
#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<typename... T> nop(T...) {} };
struct FormatOrString
{
std::string s;
FormatOrString(std::string s) : s(std::move(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>
struct yellowtxt
{
yellowtxt(const T &s) : value(s) {}
const T & value;
};
template <class T>
std::ostream & operator<<(std::ostream & out, const yellowtxt<T> & y)
{
return out << ANSI_WARNING << y.value << ANSI_NORMAL;
}
template <class T>
struct normaltxt
{
normaltxt(const T & s) : value(s) {}
const T & value;
};
template <class T>
std::ostream & operator<<(std::ostream & out, const normaltxt<T> & 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<class T>
hintformat & operator%(const T & value)
{
fmt % yellowtxt(value);
return *this;
}
template<class T>
hintformat & operator%(const normaltxt<T> & 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<typename... Args>
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));
}
/* Highlight all the given matches in the given string `s` by wrapping
them between `prefix` and `postfix`.
If some matches overlap, then their union will be wrapped rather
than the individual matches. */
std::string hiliteMatches(
std::string_view s,
std::vector<std::smatch> matches,
std::string_view prefix,
std::string_view postfix);
}