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"
|
2015-01-06 14:40:56 +01:00
|
|
|
#include "array_view.hh"
|
2017-03-06 20:57:18 +01:00
|
|
|
#include "hash_map.hh"
|
2015-11-19 00:43:51 +01:00
|
|
|
#include "flags.hh"
|
2015-11-20 09:50:53 +01:00
|
|
|
#include "enum.hh"
|
2013-03-26 00:14:38 +01:00
|
|
|
|
2013-03-29 19:31:06 +01:00
|
|
|
#include <tuple>
|
|
|
|
#include <vector>
|
|
|
|
|
2013-03-26 00:14:38 +01:00
|
|
|
namespace Kakoune
|
|
|
|
{
|
|
|
|
|
2016-08-06 10:05:50 +02:00
|
|
|
template<typename T>
|
2017-03-15 18:42:02 +01:00
|
|
|
constexpr decltype(T::option_type_name) option_type_name(Meta::Type<T>)
|
2016-08-06 10:05:50 +02:00
|
|
|
{
|
2017-03-15 18:42:02 +01:00
|
|
|
return T::option_type_name;
|
|
|
|
}
|
2016-08-06 10:05:50 +02:00
|
|
|
|
|
|
|
template<typename Enum>
|
2017-03-15 18:42:02 +01:00
|
|
|
typename std::enable_if<std::is_enum<Enum>::value, String>::type
|
|
|
|
option_type_name(Meta::Type<Enum>)
|
2016-08-06 10:05:50 +02:00
|
|
|
{
|
2017-03-15 18:55:34 +01:00
|
|
|
constexpr StringView type = with_bit_ops(Meta::Type<Enum>{}) ? "flags" : "enum";
|
2017-03-15 18:42:02 +01:00
|
|
|
auto name = enum_desc(Meta::Type<Enum>{});
|
|
|
|
return type + "(" + join(name | transform(std::mem_fn(&EnumDesc<Enum>::name)), '|') + ")";
|
|
|
|
}
|
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); }
|
2015-12-12 12:26:34 +01:00
|
|
|
inline bool option_add(int& opt, StringView str)
|
|
|
|
{
|
|
|
|
auto val = str_to_int(str);
|
|
|
|
opt += val;
|
|
|
|
return val != 0;
|
|
|
|
}
|
2017-03-15 18:42:02 +01:00
|
|
|
inline StringView option_type_name(Meta::Type<int>) { return "int"; }
|
2013-03-26 13:47:14 +01:00
|
|
|
|
2016-04-01 02:27:23 +02:00
|
|
|
inline String option_to_string(size_t opt) { return to_string(opt); }
|
|
|
|
inline void option_from_string(StringView str, size_t& opt) { opt = str_to_int(str); }
|
|
|
|
|
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");
|
|
|
|
}
|
2017-03-15 18:42:02 +01:00
|
|
|
inline StringView option_type_name(Meta::Type<bool>) { return "bool"; }
|
2013-03-26 13:47:14 +01:00
|
|
|
|
2015-03-30 14:33:46 +02:00
|
|
|
constexpr char list_separator = ':';
|
2013-04-02 18:56:09 +02:00
|
|
|
|
2015-01-12 14:58:41 +01:00
|
|
|
template<typename T, MemoryDomain domain>
|
|
|
|
String option_to_string(const Vector<T, domain>& opt)
|
2013-03-26 13:47:14 +01:00
|
|
|
{
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2015-01-12 14:58:41 +01:00
|
|
|
template<typename T, MemoryDomain domain>
|
|
|
|
void option_from_string(StringView str, Vector<T, domain>& opt)
|
2013-03-26 13:47:14 +01:00
|
|
|
{
|
|
|
|
opt.clear();
|
2015-01-09 14:57:21 +01:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-01-12 14:58:41 +01:00
|
|
|
template<typename T, MemoryDomain domain>
|
2015-12-12 12:26:34 +01:00
|
|
|
bool option_add(Vector<T, domain>& opt, StringView str)
|
2013-03-29 19:34:57 +01:00
|
|
|
{
|
2015-12-12 12:26:34 +01:00
|
|
|
Vector<T, domain> vec;
|
|
|
|
option_from_string(str, vec);
|
|
|
|
std::copy(std::make_move_iterator(vec.begin()),
|
|
|
|
std::make_move_iterator(vec.end()),
|
|
|
|
back_inserter(opt));
|
2013-03-29 19:34:57 +01:00
|
|
|
return not vec.empty();
|
|
|
|
}
|
|
|
|
|
2016-08-06 10:05:50 +02:00
|
|
|
template<typename T, MemoryDomain D>
|
2017-03-15 18:42:02 +01:00
|
|
|
String option_type_name(Meta::Type<Vector<T, D>>)
|
2016-08-06 10:05:50 +02:00
|
|
|
{
|
2017-03-15 18:42:02 +01:00
|
|
|
return option_type_name(Meta::Type<T>{}) + StringView{"-list"};
|
|
|
|
}
|
2016-08-06 10:05:50 +02:00
|
|
|
|
2017-03-06 20:57:18 +01:00
|
|
|
template<typename Key, typename Value, MemoryDomain domain>
|
|
|
|
String option_to_string(const HashMap<Key, Value, domain>& 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->key), '=', '\\') + "=" +
|
|
|
|
escape(option_to_string(it->value), '=', '\\');
|
|
|
|
res += escape(elem, list_separator, '\\');
|
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename Key, typename Value, MemoryDomain domain>
|
|
|
|
void option_from_string(StringView str, HashMap<Key, Value, domain>& opt)
|
|
|
|
{
|
|
|
|
opt.clear();
|
|
|
|
for (auto& elem : split(str, list_separator, '\\'))
|
|
|
|
{
|
|
|
|
Vector<String> pair_str = split(elem, '=', '\\');
|
|
|
|
if (pair_str.size() != 2)
|
|
|
|
throw runtime_error("map option expects key=value");
|
|
|
|
Key key;
|
|
|
|
Value value;
|
|
|
|
option_from_string(pair_str[0], key);
|
|
|
|
option_from_string(pair_str[1], value);
|
|
|
|
opt.insert({ std::move(key), std::move(value) });
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename K, typename V, MemoryDomain D>
|
2017-03-15 18:42:02 +01:00
|
|
|
String option_type_name(Meta::Type<HashMap<K, V, D>>)
|
2017-03-06 20:57:18 +01:00
|
|
|
{
|
2017-03-15 18:42:02 +01:00
|
|
|
return format("{}-to-{}-map", option_type_name(Meta::Type<K>{}),
|
|
|
|
option_type_name(Meta::Type<V>{}));
|
|
|
|
}
|
2017-03-06 20:57:18 +01:00
|
|
|
|
2015-08-23 13:13:14 +02:00
|
|
|
constexpr char 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
|
|
|
}
|
|
|
|
|
2015-03-09 14:48:41 +01:00
|
|
|
static void from_string(ConstArrayView<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
|
|
|
|
2015-03-09 14:48:41 +01:00
|
|
|
static void from_string(ConstArrayView<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))
|
2015-01-22 14:10:21 +01:00
|
|
|
throw runtime_error(elems.size() < sizeof...(Types) ?
|
|
|
|
"not enough elements in tuple"
|
|
|
|
: "to many elements in tuple");
|
2013-04-02 18:56:09 +02:00
|
|
|
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,
|
2015-12-12 12:26:34 +01:00
|
|
|
StringView str)
|
2013-03-29 19:34:57 +01:00
|
|
|
{
|
2015-12-12 12:26:34 +01:00
|
|
|
int val = str_to_int(str);
|
2013-05-06 13:52:20 +02:00
|
|
|
opt += val;
|
|
|
|
return val != 0;
|
2013-03-29 19:34:57 +01:00
|
|
|
}
|
|
|
|
|
2016-12-30 07:43:32 +01:00
|
|
|
struct WorstMatch { template<typename T> WorstMatch(T&&) {} };
|
|
|
|
|
|
|
|
inline bool option_add(WorstMatch, StringView str)
|
2013-03-29 19:34:57 +01:00
|
|
|
{
|
|
|
|
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
|
|
|
{
|
2015-08-23 13:13:14 +02:00
|
|
|
auto vals = split(str, ',');
|
2014-10-06 20:21:32 +02:00
|
|
|
if (vals.size() != 2)
|
2015-08-23 13:13:14 +02:00
|
|
|
throw runtime_error("expected <line>,<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)
|
|
|
|
{
|
2015-08-23 13:13:14 +02:00
|
|
|
return format("{},{}", opt.line, opt.column);
|
2014-10-06 20:21:32 +02:00
|
|
|
}
|
|
|
|
|
2015-11-19 22:58:26 +01:00
|
|
|
enum class DebugFlags
|
|
|
|
{
|
|
|
|
None = 0,
|
|
|
|
Hooks = 1 << 0,
|
|
|
|
Shell = 1 << 1,
|
2015-11-21 13:11:19 +01:00
|
|
|
Profile = 1 << 2,
|
2016-11-26 14:29:17 +01:00
|
|
|
Keys = 1 << 3,
|
2015-11-19 22:58:26 +01:00
|
|
|
};
|
|
|
|
|
2017-03-15 18:55:34 +01:00
|
|
|
constexpr bool with_bit_ops(Meta::Type<DebugFlags>) { return true; }
|
2015-11-19 22:58:26 +01:00
|
|
|
|
2017-03-15 18:42:02 +01:00
|
|
|
constexpr Array<EnumDesc<DebugFlags>, 4> enum_desc(Meta::Type<DebugFlags>)
|
2015-11-19 22:58:26 +01:00
|
|
|
{
|
2015-11-20 09:50:53 +01:00
|
|
|
return { {
|
|
|
|
{ DebugFlags::Hooks, "hooks" },
|
2015-11-21 13:11:19 +01:00
|
|
|
{ DebugFlags::Shell, "shell" },
|
2016-11-26 14:29:17 +01:00
|
|
|
{ DebugFlags::Profile, "profile" },
|
|
|
|
{ DebugFlags::Keys, "keys" }
|
2015-11-20 09:50:53 +01:00
|
|
|
} };
|
|
|
|
}
|
2015-11-19 00:43:51 +01:00
|
|
|
|
2017-03-15 19:28:32 +01:00
|
|
|
template<typename Flags, typename = decltype(enum_desc(Meta::Type<Flags>{}))>
|
|
|
|
EnableIfWithBitOps<Flags, String> option_to_string(Flags flags)
|
|
|
|
{
|
|
|
|
constexpr auto desc = enum_desc(Meta::Type<Flags>{});
|
|
|
|
String res;
|
|
|
|
for (int i = 0; i < desc.size(); ++i)
|
|
|
|
{
|
|
|
|
if (not (flags & desc[i].value))
|
|
|
|
continue;
|
|
|
|
if (not res.empty())
|
|
|
|
res += "|";
|
|
|
|
res += desc[i].name;
|
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename Enum, typename = decltype(enum_desc(Meta::Type<Enum>{}))>
|
|
|
|
EnableIfWithoutBitOps<Enum, String> option_to_string(Enum e)
|
|
|
|
{
|
|
|
|
constexpr auto desc = enum_desc(Meta::Type<Enum>{});
|
|
|
|
auto it = find_if(desc, [e](const EnumDesc<Enum>& d) { return d.value == e; });
|
|
|
|
if (it != desc.end())
|
|
|
|
return it->name.str();
|
|
|
|
kak_assert(false);
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename Flags, typename = decltype(enum_desc(Meta::Type<Flags>{}))>
|
|
|
|
EnableIfWithBitOps<Flags> option_from_string(StringView str, Flags& flags)
|
|
|
|
{
|
|
|
|
constexpr auto desc = enum_desc(Meta::Type<Flags>{});
|
|
|
|
flags = Flags{};
|
|
|
|
for (auto s : str | split<StringView>('|'))
|
|
|
|
{
|
|
|
|
auto it = find_if(desc, [s](const EnumDesc<Flags>& d) { return d.name == s; });
|
|
|
|
if (it == desc.end())
|
|
|
|
throw runtime_error(format("invalid flag value '{}'", s));
|
|
|
|
flags |= it->value;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename Enum, typename = decltype(enum_desc(Meta::Type<Enum>{}))>
|
|
|
|
EnableIfWithoutBitOps<Enum> option_from_string(StringView str, Enum& e)
|
|
|
|
{
|
|
|
|
constexpr auto desc = enum_desc(Meta::Type<Enum>{});
|
|
|
|
auto it = find_if(desc, [str](const EnumDesc<Enum>& d) { return d.name == str; });
|
|
|
|
if (it == desc.end())
|
|
|
|
throw runtime_error(format("invalid enum value '{}'", str));
|
|
|
|
e = it->value;
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename Flags, typename = decltype(enum_desc(Meta::Type<Flags>{}))>
|
|
|
|
EnableIfWithBitOps<Flags, bool> option_add(Flags& opt, StringView str)
|
|
|
|
{
|
|
|
|
Flags res = Flags{};
|
|
|
|
option_from_string(str, res);
|
|
|
|
opt |= res;
|
|
|
|
return res != (Flags)0;
|
|
|
|
}
|
|
|
|
|
2016-04-01 02:27:23 +02:00
|
|
|
template<typename P, typename T>
|
|
|
|
struct PrefixedList
|
2015-12-12 12:45:45 +01:00
|
|
|
{
|
2016-04-01 02:27:23 +02:00
|
|
|
P prefix;
|
2015-12-12 12:45:45 +01:00
|
|
|
Vector<T, MemoryDomain::Options> list;
|
|
|
|
};
|
|
|
|
|
2016-04-01 02:27:23 +02:00
|
|
|
template<typename P, typename T>
|
|
|
|
inline bool operator==(const PrefixedList<P, T>& lhs, const PrefixedList<P, T>& rhs)
|
2015-12-12 12:45:45 +01:00
|
|
|
{
|
2016-04-01 02:27:23 +02:00
|
|
|
return lhs.prefix == rhs.prefix and lhs.list == rhs.list;
|
2015-12-12 12:45:45 +01:00
|
|
|
}
|
|
|
|
|
2016-04-01 02:27:23 +02:00
|
|
|
template<typename P, typename T>
|
|
|
|
inline bool operator!=(const PrefixedList<P, T>& lhs, const PrefixedList<P, T>& rhs)
|
2015-12-12 12:45:45 +01:00
|
|
|
{
|
|
|
|
return not (lhs == rhs);
|
|
|
|
}
|
|
|
|
|
2016-04-01 02:27:23 +02:00
|
|
|
template<typename P, typename T>
|
|
|
|
inline String option_to_string(const PrefixedList<P, T>& opt)
|
2015-12-12 12:45:45 +01:00
|
|
|
{
|
2016-04-01 02:27:23 +02:00
|
|
|
return format("{}:{}", opt.prefix, option_to_string(opt.list));
|
2015-12-12 12:45:45 +01:00
|
|
|
}
|
|
|
|
|
2016-04-01 02:27:23 +02:00
|
|
|
template<typename P, typename T>
|
|
|
|
inline void option_from_string(StringView str, PrefixedList<P, T>& opt)
|
2015-12-12 12:45:45 +01:00
|
|
|
{
|
|
|
|
auto it = find(str, ':');
|
2016-04-01 02:27:23 +02:00
|
|
|
option_from_string(StringView{str.begin(), it}, opt.prefix);
|
2015-12-13 00:16:07 +01:00
|
|
|
if (it != str.end())
|
|
|
|
option_from_string({it+1, str.end()}, opt.list);
|
2015-12-12 12:45:45 +01:00
|
|
|
}
|
|
|
|
|
2016-04-01 02:27:23 +02:00
|
|
|
template<typename P, typename T>
|
|
|
|
inline bool option_add(PrefixedList<P, T>& opt, StringView str)
|
2015-12-12 12:45:45 +01:00
|
|
|
{
|
|
|
|
return option_add(opt.list, str);
|
|
|
|
}
|
|
|
|
|
2016-04-01 02:27:23 +02:00
|
|
|
template<typename T>
|
|
|
|
using TimestampedList = PrefixedList<size_t, T>;
|
|
|
|
|
2013-03-26 00:14:38 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
#endif // option_types_hh_INCLUDED
|