Add a format function for printf like formatting
This commit is contained in:
parent
8761fc34f4
commit
13a5af70ae
|
@ -205,4 +205,46 @@ Vector<StringView> wrap_lines(StringView text, CharCount max_width)
|
||||||
return lines;
|
return lines;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String format(StringView fmt, ArrayView<const StringView> params)
|
||||||
|
{
|
||||||
|
ByteCount size = fmt.length();
|
||||||
|
for (auto& s : params) size += s.length();
|
||||||
|
String res;
|
||||||
|
res.reserve(size);
|
||||||
|
|
||||||
|
int implicitIndex = 0;
|
||||||
|
for (auto it = fmt.begin(), end = fmt.end(); it != end;)
|
||||||
|
{
|
||||||
|
auto opening = std::find(it, end, '{');
|
||||||
|
res += StringView{it, opening};
|
||||||
|
if (opening == end)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (opening != it && res.back() == '\\')
|
||||||
|
{
|
||||||
|
res.back() = '{';
|
||||||
|
it = opening + 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto closing = std::find(it, end, '}');
|
||||||
|
if (closing == end)
|
||||||
|
throw runtime_error("Format string error, unclosed '{'");
|
||||||
|
int index;
|
||||||
|
if (closing == opening + 1)
|
||||||
|
index = implicitIndex;
|
||||||
|
else
|
||||||
|
index = str_to_int({opening+1, closing});
|
||||||
|
|
||||||
|
if (index >= params.size())
|
||||||
|
throw runtime_error("Format string parameter index too big");
|
||||||
|
|
||||||
|
res += params[index];
|
||||||
|
implicitIndex = index+1;
|
||||||
|
it = closing+1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#include "utf8.hh"
|
#include "utf8.hh"
|
||||||
#include "hash.hh"
|
#include "hash.hh"
|
||||||
#include "vector.hh"
|
#include "vector.hh"
|
||||||
|
#include "array_view.hh"
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <climits>
|
#include <climits>
|
||||||
|
@ -276,6 +277,27 @@ String expand_tabs(StringView line, CharCount tabstop, CharCount col = 0);
|
||||||
|
|
||||||
Vector<StringView> wrap_lines(StringView text, CharCount max_width);
|
Vector<StringView> wrap_lines(StringView text, CharCount max_width);
|
||||||
|
|
||||||
|
namespace detail
|
||||||
|
{
|
||||||
|
|
||||||
|
template<typename T> using IsString = std::is_convertible<T, StringView>;
|
||||||
|
|
||||||
|
template<typename T, class = typename std::enable_if<!IsString<T>::value>::type>
|
||||||
|
String format_param(const T& val) { return to_string(val); }
|
||||||
|
|
||||||
|
template<typename T, class = typename std::enable_if<IsString<T>::value>::type>
|
||||||
|
StringView format_param(const T& val) { return val; }
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
String format(StringView fmt, ArrayView<const StringView> params);
|
||||||
|
|
||||||
|
template<typename... Types>
|
||||||
|
String format(StringView fmt, Types... params)
|
||||||
|
{
|
||||||
|
return format(fmt, ArrayView<const StringView>{{detail::format_param(params)...}});
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // string_hh_INCLUDED
|
#endif // string_hh_INCLUDED
|
||||||
|
|
|
@ -137,6 +137,8 @@ void test_string()
|
||||||
kak_assert(subsequence_match("tchou kanaky", "knk"));
|
kak_assert(subsequence_match("tchou kanaky", "knk"));
|
||||||
kak_assert(subsequence_match("tchou kanaky", "tchou kanaky"));
|
kak_assert(subsequence_match("tchou kanaky", "tchou kanaky"));
|
||||||
kak_assert(not subsequence_match("tchou kanaky", "tchou kanaky"));
|
kak_assert(not subsequence_match("tchou kanaky", "tchou kanaky"));
|
||||||
|
|
||||||
|
kak_assert(format("Youhou {1} {} {0} \\{}", 10, "hehe", 5) == "Youhou hehe 5 10 {}");
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_keys()
|
void test_keys()
|
||||||
|
|
Loading…
Reference in New Issue
Block a user