aboutsummaryrefslogtreecommitdiff
path: root/src/libutil/fmt.hh
blob: d182adc3a14fa27d012daace7a96ab5ff32bb767 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
#pragma once

#include <boost/format.hpp>
#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>
struct yellowify
{
    yellowify(T &s) : value(s) {}
    T &value;
};

template <class T>
std::ostream& operator<<(std::ostream &out, const yellowify<T> &y)
{
    return out << ANSI_YELLOW << y.value << ANSI_NORMAL;
}

class hintformat
{
public:
    hintformat(const string &format) :fmt(format)
    {
        fmt.exceptions(boost::io::all_error_bits ^ boost::io::too_many_args_bit);
    }

    hintformat(const hintformat &hf)
    : fmt(hf.fmt)
    {}

    template<class T>
    hintformat& operator%(const T &value)
    {
        fmt % yellowify(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;
}

}