2013-03-26 00:14:38 +01:00
|
|
|
#ifndef option_types_hh_INCLUDED
|
|
|
|
#define option_types_hh_INCLUDED
|
|
|
|
|
2013-04-09 20:05:40 +02:00
|
|
|
#include "exception.hh"
|
2013-03-26 00:14:38 +01:00
|
|
|
#include "string.hh"
|
2013-03-29 19:31:06 +01:00
|
|
|
#include "units.hh"
|
2014-10-06 20:21:32 +02:00
|
|
|
#include "coord.hh"
|
2014-11-12 22:27:07 +01:00
|
|
|
#include "memoryview.hh"
|
2013-03-26 00:14:38 +01:00
|
|
|
|
2013-03-29 19:31:06 +01:00
|
|
|
#include <tuple>
|
|
|
|
#include <vector>
|
2014-11-11 00:24:02 +01:00
|
|
|
#include <unordered_map>
|
2013-05-06 13:52:20 +02:00
|
|
|
#include <unordered_set>
|
2013-03-29 19:31:06 +01:00
|
|
|
|
2013-03-26 00:14:38 +01:00
|
|
|
namespace Kakoune
|
|
|
|
{
|
|
|
|
|
2014-10-07 22:11:55 +02:00
|
|
|
inline String option_to_string(StringView opt) { return opt; }
|
|
|
|
inline void option_from_string(StringView str, String& opt) { opt = str; }
|
2013-03-26 13:47:14 +01:00
|
|
|
|
2013-05-13 14:23:07 +02:00
|
|
|
inline String option_to_string(int opt) { return to_string(opt); }
|
2014-10-07 22:11:55 +02:00
|
|
|
inline void option_from_string(StringView str, int& opt) { opt = str_to_int(str); }
|
2013-03-29 19:34:57 +01:00
|
|
|
inline bool option_add(int& opt, int val) { opt += val; return val != 0; }
|
2013-03-26 13:47:14 +01:00
|
|
|
|
|
|
|
inline String option_to_string(bool opt) { return opt ? "true" : "false"; }
|
2014-10-07 22:11:55 +02:00
|
|
|
inline void option_from_string(StringView str, bool& opt)
|
2013-03-26 13:47:14 +01:00
|
|
|
{
|
|
|
|
if (str == "true" or str == "yes")
|
|
|
|
opt = true;
|
|
|
|
else if (str == "false" or str == "no")
|
|
|
|
opt = false;
|
|
|
|
else
|
|
|
|
throw runtime_error("boolean values are either true, yes, false or no");
|
|
|
|
}
|
|
|
|
|
2013-07-24 22:41:41 +02:00
|
|
|
constexpr Codepoint list_separator = ':';
|
2013-04-02 18:56:09 +02:00
|
|
|
|
2013-03-26 13:47:14 +01:00
|
|
|
template<typename T>
|
|
|
|
String option_to_string(const std::vector<T>& opt)
|
|
|
|
{
|
|
|
|
String res;
|
|
|
|
for (size_t i = 0; i < opt.size(); ++i)
|
|
|
|
{
|
2013-07-24 22:41:13 +02:00
|
|
|
res += escape(option_to_string(opt[i]), list_separator, '\\');
|
2013-03-26 13:47:14 +01:00
|
|
|
if (i != opt.size() - 1)
|
2013-04-02 18:56:09 +02:00
|
|
|
res += list_separator;
|
2013-03-26 13:47:14 +01:00
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename T>
|
2014-10-07 22:11:55 +02:00
|
|
|
void option_from_string(StringView str, std::vector<T>& opt)
|
2013-03-26 13:47:14 +01:00
|
|
|
{
|
|
|
|
opt.clear();
|
2013-07-24 22:41:13 +02:00
|
|
|
std::vector<String> elems = split(str, list_separator, '\\');
|
2013-03-26 13:47:14 +01:00
|
|
|
for (auto& elem: elems)
|
|
|
|
{
|
|
|
|
T opt_elem;
|
|
|
|
option_from_string(elem, opt_elem);
|
|
|
|
opt.push_back(opt_elem);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-03-29 19:34:57 +01:00
|
|
|
template<typename T>
|
|
|
|
bool option_add(std::vector<T>& opt, const std::vector<T>& vec)
|
|
|
|
{
|
|
|
|
std::copy(vec.begin(), vec.end(), back_inserter(opt));
|
|
|
|
return not vec.empty();
|
|
|
|
}
|
|
|
|
|
2013-05-06 13:52:20 +02:00
|
|
|
template<typename T>
|
|
|
|
String option_to_string(const std::unordered_set<T>& opt)
|
|
|
|
{
|
|
|
|
String res;
|
|
|
|
for (auto it = begin(opt); it != end(opt); ++it)
|
|
|
|
{
|
|
|
|
if (it != begin(opt))
|
|
|
|
res += list_separator;
|
2013-07-24 22:41:13 +02:00
|
|
|
res += escape(option_to_string(*it), list_separator, '\\');
|
2013-05-06 13:52:20 +02:00
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename T>
|
2014-10-07 22:11:55 +02:00
|
|
|
void option_from_string(StringView str, std::unordered_set<T>& opt)
|
2013-05-06 13:52:20 +02:00
|
|
|
{
|
|
|
|
opt.clear();
|
2013-07-24 22:41:13 +02:00
|
|
|
std::vector<String> elems = split(str, list_separator, '\\');
|
2013-05-06 13:52:20 +02:00
|
|
|
for (auto& elem: elems)
|
|
|
|
{
|
|
|
|
T opt_elem;
|
|
|
|
option_from_string(elem, opt_elem);
|
|
|
|
opt.insert(opt_elem);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename T>
|
|
|
|
bool option_add(std::unordered_set<T>& opt, const std::unordered_set<T>& set)
|
|
|
|
{
|
|
|
|
std::copy(set.begin(), set.end(), std::inserter(opt, opt.begin()));
|
|
|
|
return not set.empty();
|
|
|
|
}
|
|
|
|
|
2014-11-11 00:24:02 +01:00
|
|
|
template<typename Key, typename Value>
|
|
|
|
String option_to_string(const std::unordered_map<Key, Value>& opt)
|
|
|
|
{
|
|
|
|
String res;
|
|
|
|
for (auto it = begin(opt); it != end(opt); ++it)
|
|
|
|
{
|
|
|
|
if (it != begin(opt))
|
|
|
|
res += list_separator;
|
|
|
|
String elem = escape(option_to_string(it->first), '=', '\\') + "=" +
|
|
|
|
escape(option_to_string(it->second), '=', '\\');
|
|
|
|
res += escape(elem, list_separator, '\\');
|
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename Key, typename Value>
|
|
|
|
void option_from_string(StringView str, std::unordered_map<Key, Value>& opt)
|
|
|
|
{
|
|
|
|
opt.clear();
|
|
|
|
std::vector<String> elems = split(str, list_separator, '\\');
|
|
|
|
for (auto& elem: elems)
|
|
|
|
{
|
|
|
|
std::vector<String> pair_str = split(elem, '=', '\\');
|
|
|
|
if (pair_str.size() != 2)
|
|
|
|
throw runtime_error("map option expects key=value");
|
|
|
|
std::pair<Key, Value> pair;
|
|
|
|
option_from_string(pair_str[0], pair.first);
|
|
|
|
option_from_string(pair_str[1], pair.second);
|
|
|
|
opt.insert(std::move(pair));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-10-06 20:32:25 +02:00
|
|
|
constexpr Codepoint tuple_separator = ',';
|
2013-03-26 13:47:14 +01:00
|
|
|
|
2013-03-29 19:31:06 +01:00
|
|
|
template<size_t I, typename... Types>
|
|
|
|
struct TupleOptionDetail
|
2013-03-26 00:14:38 +01:00
|
|
|
{
|
2013-03-29 19:31:06 +01:00
|
|
|
static String to_string(const std::tuple<Types...>& opt)
|
|
|
|
{
|
2013-04-02 18:56:09 +02:00
|
|
|
return TupleOptionDetail<I-1, Types...>::to_string(opt) +
|
2013-07-24 22:41:13 +02:00
|
|
|
tuple_separator + escape(option_to_string(std::get<I>(opt)), tuple_separator, '\\');
|
2013-03-29 19:31:06 +01:00
|
|
|
}
|
|
|
|
|
2013-07-26 01:17:12 +02:00
|
|
|
static void from_string(memoryview<String> elems, std::tuple<Types...>& opt)
|
2013-03-29 19:31:06 +01:00
|
|
|
{
|
2013-04-02 18:56:09 +02:00
|
|
|
option_from_string(elems[I], std::get<I>(opt));
|
|
|
|
TupleOptionDetail<I-1, Types...>::from_string(elems, opt);
|
2013-03-29 19:31:06 +01:00
|
|
|
}
|
|
|
|
};
|
2013-03-26 00:14:38 +01:00
|
|
|
|
2013-03-29 19:31:06 +01:00
|
|
|
template<typename... Types>
|
|
|
|
struct TupleOptionDetail<0, Types...>
|
|
|
|
{
|
|
|
|
static String to_string(const std::tuple<Types...>& opt)
|
|
|
|
{
|
|
|
|
return option_to_string(std::get<0>(opt));
|
|
|
|
}
|
2013-03-26 00:14:38 +01:00
|
|
|
|
2013-07-26 01:17:12 +02:00
|
|
|
static void from_string(memoryview<String> elems, std::tuple<Types...>& opt)
|
2013-03-29 19:31:06 +01:00
|
|
|
{
|
2013-04-02 18:56:09 +02:00
|
|
|
option_from_string(elems[0], std::get<0>(opt));
|
2013-03-29 19:31:06 +01:00
|
|
|
}
|
2013-03-26 00:14:38 +01:00
|
|
|
};
|
|
|
|
|
2013-03-29 19:31:06 +01:00
|
|
|
template<typename... Types>
|
|
|
|
String option_to_string(const std::tuple<Types...>& opt)
|
|
|
|
{
|
|
|
|
return TupleOptionDetail<sizeof...(Types)-1, Types...>::to_string(opt);
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename... Types>
|
2014-10-07 22:11:55 +02:00
|
|
|
void option_from_string(StringView str, std::tuple<Types...>& opt)
|
2013-03-29 19:31:06 +01:00
|
|
|
{
|
2013-07-24 22:41:13 +02:00
|
|
|
auto elems = split(str, tuple_separator, '\\');
|
2013-04-02 18:56:09 +02:00
|
|
|
if (elems.size() != sizeof...(Types))
|
|
|
|
throw runtime_error("not enough elements in tuple");
|
|
|
|
TupleOptionDetail<sizeof...(Types)-1, Types...>::from_string(elems, opt);
|
2013-03-29 19:31:06 +01:00
|
|
|
}
|
|
|
|
|
2013-05-13 14:23:07 +02:00
|
|
|
template<typename RealType, typename ValueType>
|
|
|
|
inline String option_to_string(const StronglyTypedNumber<RealType, ValueType>& opt)
|
|
|
|
{
|
|
|
|
return to_string(opt);
|
|
|
|
}
|
2013-03-29 19:31:06 +01:00
|
|
|
|
2013-05-13 14:23:07 +02:00
|
|
|
template<typename RealType, typename ValueType>
|
2014-10-07 22:11:55 +02:00
|
|
|
inline void option_from_string(StringView str, StronglyTypedNumber<RealType, ValueType>& opt)
|
2013-03-29 19:31:06 +01:00
|
|
|
{
|
2013-05-17 14:09:42 +02:00
|
|
|
opt = StronglyTypedNumber<RealType, ValueType>{str_to_int(str)};
|
2013-03-29 19:31:06 +01:00
|
|
|
}
|
2013-03-26 00:14:38 +01:00
|
|
|
|
2013-05-13 14:23:07 +02:00
|
|
|
template<typename RealType, typename ValueType>
|
2013-03-29 19:34:57 +01:00
|
|
|
inline bool option_add(StronglyTypedNumber<RealType, ValueType>& opt,
|
|
|
|
StronglyTypedNumber<RealType, ValueType> val)
|
|
|
|
{
|
2013-05-06 13:52:20 +02:00
|
|
|
opt += val;
|
|
|
|
return val != 0;
|
2013-03-29 19:34:57 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
template<typename T>
|
|
|
|
bool option_add(T&, const T&)
|
|
|
|
{
|
|
|
|
throw runtime_error("no add operation supported for this option type");
|
|
|
|
}
|
|
|
|
|
2014-10-06 20:21:32 +02:00
|
|
|
template<typename EffectiveType, typename LineType, typename ColumnType>
|
2014-10-07 22:11:55 +02:00
|
|
|
inline void option_from_string(StringView str, LineAndColumn<EffectiveType, LineType, ColumnType>& opt)
|
2014-10-06 20:21:32 +02:00
|
|
|
{
|
2014-10-06 20:32:25 +02:00
|
|
|
auto vals = split(str, tuple_separator);
|
2014-10-06 20:21:32 +02:00
|
|
|
if (vals.size() != 2)
|
2014-10-06 20:32:25 +02:00
|
|
|
throw runtime_error("expected <line>"_str + tuple_separator + "<column>");
|
2014-10-06 20:21:32 +02:00
|
|
|
opt.line = str_to_int(vals[0]);
|
|
|
|
opt.column = str_to_int(vals[1]);
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename EffectiveType, typename LineType, typename ColumnType>
|
|
|
|
inline String option_to_string(const LineAndColumn<EffectiveType, LineType, ColumnType>& opt)
|
|
|
|
{
|
2014-10-06 20:32:25 +02:00
|
|
|
return to_string(opt.line) + tuple_separator + to_string(opt.column);
|
2014-10-06 20:21:32 +02:00
|
|
|
}
|
|
|
|
|
2013-10-21 19:57:48 +02:00
|
|
|
enum YesNoAsk
|
|
|
|
{
|
|
|
|
Yes,
|
|
|
|
No,
|
|
|
|
Ask
|
|
|
|
};
|
|
|
|
|
|
|
|
inline String option_to_string(YesNoAsk opt)
|
|
|
|
{
|
|
|
|
switch (opt)
|
|
|
|
{
|
|
|
|
case Yes: return "yes";
|
|
|
|
case No: return "no";
|
|
|
|
case Ask: return "ask";
|
|
|
|
}
|
|
|
|
kak_assert(false);
|
|
|
|
return "ask";
|
|
|
|
}
|
|
|
|
|
2014-10-07 22:11:55 +02:00
|
|
|
inline void option_from_string(StringView str, YesNoAsk& opt)
|
2013-10-21 19:57:48 +02:00
|
|
|
{
|
|
|
|
if (str == "yes" or str == "true")
|
|
|
|
opt = Yes;
|
|
|
|
else if (str == "no" or str == "false")
|
|
|
|
opt = No;
|
|
|
|
else if (str == "ask")
|
|
|
|
opt = Ask;
|
2013-11-16 01:26:56 +01:00
|
|
|
else
|
|
|
|
throw runtime_error("invalid value '" + str + "', expected yes, no or ask");
|
2013-10-21 19:57:48 +02:00
|
|
|
}
|
|
|
|
|
2013-03-26 00:14:38 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
#endif // option_types_hh_INCLUDED
|