diff --git a/src/option_manager.cc b/src/option_manager.cc index 46bfce9e..a06177d7 100644 --- a/src/option_manager.cc +++ b/src/option_manager.cc @@ -1,154 +1,14 @@ #include "option_manager.hh" #include "assert.hh" -#include "option_types.hh" - #include namespace Kakoune { -namespace -{ - -String option_to_string(const String& opt) { return opt; } -void option_from_string(const String& str, String& opt) { opt = str; } - -String option_to_string(int opt) { return int_to_str(opt); } -void option_from_string(const String& str, int& opt) { opt = str_to_int(str); } - -String option_to_string(bool opt) { return opt ? "true" : "false"; } -void option_from_string(const String& str, bool& opt) -{ - 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"); -} - -template -String option_to_string(const std::vector& opt) -{ - String res; - for (size_t i = 0; i < opt.size(); ++i) - { - res += option_to_string(opt[i]); - if (i != opt.size() - 1) - res += ","; - } - return res; -} - -template -void option_from_string(const String& str, std::vector& opt) -{ - opt.clear(); - std::vector elems = split(str, ','); - for (auto& elem: elems) - { - T opt_elem; - option_from_string(elem, opt_elem); - opt.push_back(opt_elem); - } -} - -String option_to_string(const Regex& re) -{ - return String{re.str()}; -} - -void option_from_string(const String& str, Regex& re) -{ - try - { - re = Regex{str.begin(), str.end()}; - } - catch (boost::regex_error& err) - { - throw runtime_error("unable to create regex: "_str + err.what()); - } -} - -} - -template -class TypedOption : public Option -{ -public: - TypedOption(OptionManager& manager, String name, const T& value) - : Option(manager, std::move(name)), m_value(value) {} - - void set(const T& value) - { - if (m_value != value) - { - m_value = value; - m_manager.on_option_changed(*this); - } - } - const T& get() const { return m_value; } - - String get_as_string() const override - { - return option_to_string(m_value); - } - void set_from_string(const String& str) override - { - T val; - option_from_string(str, val); - set(val); - } - - Option* clone(OptionManager& manager) const override - { - return new TypedOption{manager, name(), m_value}; - } -private: - T m_value; -}; - Option::Option(OptionManager& manager, String name) : m_manager(manager), m_name(std::move(name)) {} -template const T& Option::get() const -{ - auto* typed_opt = dynamic_cast*>(this); - if (not typed_opt) - throw runtime_error("option " + name() + " is not of type " + typeid(T).name()); - return typed_opt->get(); -} - -template void Option::set(const T& val) -{ - auto* typed_opt = dynamic_cast*>(this); - if (not typed_opt) - throw runtime_error("option " + name() + " is not of type " + typeid(T).name()); - return typed_opt->set(val); -} - -template const String& Option::get() const; -template void Option::set(const String&); - -template const int& Option::get() const; -template void Option::set(const int&); - -template const bool& Option::get() const; -template void Option::set(const bool&); - -template const std::vector& Option::get>() const; -template void Option::set>(const std::vector&); - -template const std::vector& Option::get>() const; -template void Option::set>(const std::vector&); - -template const Regex& Option::get() const; -template void Option::set(const Regex&); - -template const std::vector& Option::get>() const; -template void Option::set>(const std::vector&); - OptionManager::OptionManager(OptionManager& parent) : m_parent(&parent) { @@ -176,13 +36,6 @@ void OptionManager::unregister_watcher(OptionManagerWatcher& watcher) m_watchers.erase(it); } -template -auto find_option(T& container, const String& name) -> decltype(container.begin()) -{ - using ptr_type = decltype(*container.begin()); - return find_if(container, [&name](const ptr_type& opt) { return opt->name() == name; }); -} - Option& OptionManager::get_local_option(const String& name) { auto it = find_option(m_options, name); @@ -268,16 +121,4 @@ GlobalOptions::GlobalOptions() declare_option("insert_hide_sel", false); } -template -Option& GlobalOptions::declare_option(const String& name, const T& value) -{ - if (find_option(m_options, name) != m_options.end()) - throw runtime_error("option " + name + " already declared"); - m_options.emplace_back(new TypedOption{*this, name, value}); - return *m_options.back(); -} - -template Option& GlobalOptions::declare_option<>(const String&, const std::vector&); -template Option& GlobalOptions::declare_option<>(const String&, const std::vector&); - } diff --git a/src/option_manager.hh b/src/option_manager.hh index 80443323..96271b0d 100644 --- a/src/option_manager.hh +++ b/src/option_manager.hh @@ -4,6 +4,7 @@ #include "utils.hh" #include "exception.hh" #include "completion.hh" +#include "option_types.hh" #include @@ -78,6 +79,65 @@ private: std::vector m_watchers; }; +template +class TypedOption : public Option +{ +public: + TypedOption(OptionManager& manager, String name, const T& value) + : Option(manager, std::move(name)), m_value(value) {} + + void set(const T& value) + { + if (m_value != value) + { + m_value = value; + m_manager.on_option_changed(*this); + } + } + const T& get() const { return m_value; } + + String get_as_string() const override + { + return option_to_string(m_value); + } + void set_from_string(const String& str) override + { + T val; + option_from_string(str, val); + set(val); + } + + Option* clone(OptionManager& manager) const override + { + return new TypedOption{manager, name(), m_value}; + } +private: + T m_value; +}; + +template const T& Option::get() const +{ + auto* typed_opt = dynamic_cast*>(this); + if (not typed_opt) + throw runtime_error("option " + name() + " is not of type " + typeid(T).name()); + return typed_opt->get(); +} + +template void Option::set(const T& val) +{ + auto* typed_opt = dynamic_cast*>(this); + if (not typed_opt) + throw runtime_error("option " + name() + " is not of type " + typeid(T).name()); + return typed_opt->set(val); +} + +template +auto find_option(T& container, const String& name) -> decltype(container.begin()) +{ + using ptr_type = decltype(*container.begin()); + return find_if(container, [&name](const ptr_type& opt) { return opt->name() == name; }); +} + class GlobalOptions : public OptionManager, public Singleton { @@ -85,7 +145,13 @@ public: GlobalOptions(); template - Option& declare_option(const String& name, const T& inital_value); + Option& declare_option(const String& name, const T& value) + { + if (find_option(m_options, name) != m_options.end()) + throw runtime_error("option " + name + " already declared"); + m_options.emplace_back(new TypedOption{*this, name, value}); + return *m_options.back(); + } }; } diff --git a/src/option_types.cc b/src/option_types.cc index 29d21e8f..89289752 100644 --- a/src/option_types.cc +++ b/src/option_types.cc @@ -5,6 +5,23 @@ namespace Kakoune { +String option_to_string(const Regex& re) +{ + return String{re.str()}; +} + +void option_from_string(const String& str, Regex& re) +{ + try + { + re = Regex{str.begin(), str.end()}; + } + catch (boost::regex_error& err) + { + throw runtime_error("unable to create regex: "_str + err.what()); + } +} + String option_to_string(const LineAndFlag& opt) { return int_to_str((int)opt.line) + ":" + color_to_str(opt.color) + ":" + opt.flag; diff --git a/src/option_types.hh b/src/option_types.hh index b34d16e0..73cbf315 100644 --- a/src/option_types.hh +++ b/src/option_types.hh @@ -4,10 +4,57 @@ #include "units.hh" #include "string.hh" #include "color.hh" +#include "exception.hh" namespace Kakoune { +inline String option_to_string(const String& opt) { return opt; } +inline void option_from_string(const String& str, String& opt) { opt = str; } + +inline String option_to_string(int opt) { return int_to_str(opt); } +inline void option_from_string(const String& str, int& opt) { opt = str_to_int(str); } + +inline String option_to_string(bool opt) { return opt ? "true" : "false"; } +inline void option_from_string(const String& str, bool& opt) +{ + 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"); +} + +template +String option_to_string(const std::vector& opt) +{ + String res; + for (size_t i = 0; i < opt.size(); ++i) + { + res += option_to_string(opt[i]); + if (i != opt.size() - 1) + res += ','; + } + return res; +} + +template +void option_from_string(const String& str, std::vector& opt) +{ + opt.clear(); + std::vector elems = split(str, ','); + for (auto& elem: elems) + { + T opt_elem; + option_from_string(elem, opt_elem); + opt.push_back(opt_elem); + } +} + +String option_to_string(const Regex& re); +void option_from_string(const String& str, Regex& re); + struct LineAndFlag { LineCount line;