From bea53d09b21de050841dee75fa4cc58e71532afb Mon Sep 17 00:00:00 2001 From: Maxime Coste Date: Tue, 19 Aug 2014 18:56:11 +0100 Subject: [PATCH] Remove option checkers, handle that through the type system Use a specific type for InsertCompleterDesc with checks in the option_{from,to}_string functions --- src/insert_completer.cc | 64 ++++++++++++++++++++++++++++++++++------- src/insert_completer.hh | 32 +++++++++++++++++++++ src/option_manager.cc | 18 ++++-------- src/option_manager.hh | 21 ++++---------- 4 files changed, 97 insertions(+), 38 deletions(-) diff --git a/src/insert_completer.cc b/src/insert_completer.cc index 205b99e8..b5be9c95 100644 --- a/src/insert_completer.cc +++ b/src/insert_completer.cc @@ -16,6 +16,48 @@ namespace Kakoune using StringList = std::vector; +String option_to_string(const InsertCompleterDesc& opt) +{ + switch (opt.mode) + { + case InsertCompleterDesc::Word: + return "word=" + (opt.param ? *opt.param : ""); + case InsertCompleterDesc::Filename: + return "filename"; + case InsertCompleterDesc::Option: + return "option=" + (opt.param ? *opt.param : ""); + } + kak_assert(false); + return ""; +} + +void option_from_string(const String& str, InsertCompleterDesc& opt) +{ + if (str.substr(0_byte, 7_byte) == "option=") + { + opt.mode = InsertCompleterDesc::Option; + opt.param = str.substr(7_byte).str(); + return; + } + else if (str.substr(0_byte, 5_byte) == "word=") + { + auto param = str.substr(5_byte); + if (param == "all" or param == "buffer") + { + opt.mode = InsertCompleterDesc::Word; + opt.param = param.str(); + return; + } + } + else if (str == "filename") + { + opt.mode = InsertCompleterDesc::Filename; + opt.param = Optional{}; + return; + } + throw runtime_error("invalid completer description: " + str);; +} + namespace { @@ -272,26 +314,28 @@ bool InsertCompleter::setup_ifn() using namespace std::placeholders; if (not m_completions.is_valid()) { - auto& completers = options()["completers"].get(); + auto& completers = options()["completers"].get(); for (auto& completer : completers) { - if (completer == "filename" and + if (completer.mode == InsertCompleterDesc::Filename and try_complete([this](const Buffer& buffer, ByteCoord cursor_pos) { return complete_filename(buffer, cursor_pos, options()); })) return true; - if (completer.substr(0_byte, 7_byte) == "option=" and + if (completer.mode == InsertCompleterDesc::Option and try_complete([&,this](const Buffer& buffer, ByteCoord cursor_pos) { return complete_option(buffer, cursor_pos, - options(), completer.substr(7_byte)); + options(), *completer.param); })) return true; - if (completer == "word=buffer" and + if (completer.mode == InsertCompleterDesc::Word and + *completer.param == "buffer" and (try_complete(complete_word) or try_complete(complete_word))) return true; - if (completer == "word=all" and + if (completer.mode == InsertCompleterDesc::Word and + *completer.param == "all" and (try_complete(complete_word) or try_complete(complete_word))) return true; @@ -323,12 +367,12 @@ void InsertCompleter::menu_show() void InsertCompleter::on_option_changed(const Option& opt) { - auto& completers = options()["completers"].get(); - StringList option_names; + auto& completers = options()["completers"].get(); + std::vector option_names; for (auto& completer : completers) { - if (completer.substr(0_byte, 7_byte) == "option=") - option_names.emplace_back(completer.substr(7_byte)); + if (completer.mode == InsertCompleterDesc::Option) + option_names.emplace_back(*completer.param); } if (contains(option_names, opt.name())) { diff --git a/src/insert_completer.hh b/src/insert_completer.hh index dcbf3ba1..88759edf 100644 --- a/src/insert_completer.hh +++ b/src/insert_completer.hh @@ -4,9 +4,41 @@ #include "buffer.hh" #include "option_manager.hh" +#include "optional.hh" + namespace Kakoune { +struct InsertCompleterDesc +{ + enum Mode + { + Word, + Option, + Filename + }; + + InsertCompleterDesc(Mode mode = Filename, + Optional param = Optional{}) + : mode{mode}, param{std::move(param)} + {} + + bool operator==(const InsertCompleterDesc& other) const + { return mode == other.mode && param == other.param; } + + bool operator!=(const InsertCompleterDesc& other) const + { return !(*this == other); } + + Mode mode; + Optional param; +}; + +using InsertCompleterDescList = std::vector; + + +String option_to_string(const InsertCompleterDesc& opt); +void option_from_string(const String& str, InsertCompleterDesc& opt); + struct InsertCompletion { ByteCoord begin; diff --git a/src/option_manager.cc b/src/option_manager.cc index 5ad35387..f66de005 100644 --- a/src/option_manager.cc +++ b/src/option_manager.cc @@ -1,5 +1,7 @@ #include "option_manager.hh" +#include "insert_completer.hh" + #include "assert.hh" #include @@ -159,18 +161,10 @@ GlobalOptions::GlobalOptions() declare_option("path", "path to consider when trying to find a file", std::vector({ "./", "/usr/include" })); declare_option("completers", "insert mode completers to execute.", - std::vector({"filename", "word=all"}), - OptionFlags::None, - OptionChecker>([](const std::vector& s) { - static const auto values = {"word=buffer", "word=all", "filename"}; - for (auto& v : s) - { - if (v.substr(0_byte, 7_byte) == "option=") - continue; - if (not contains(values, v)) - throw runtime_error(v + " is not a recognised value for completers"); - } - })); + std::vector({ + InsertCompleterDesc{ InsertCompleterDesc::Filename }, + InsertCompleterDesc{ InsertCompleterDesc::Word, "all"_str } + }), OptionFlags::None); declare_option("autoreload", "autoreload buffer when a filesystem modification is detected", Ask); diff --git a/src/option_manager.hh b/src/option_manager.hh index 92c3ac7b..93e6a943 100644 --- a/src/option_manager.hh +++ b/src/option_manager.hh @@ -117,23 +117,17 @@ private: std::vector m_watchers; }; -template using OptionChecker = std::function; - template class TypedOption : public Option { public: - TypedOption(OptionManager& manager, const OptionDesc& desc, - const T& value, OptionChecker checker) - : Option(desc, manager), - m_value(value), m_checker(std::move(checker)) {} + TypedOption(OptionManager& manager, const OptionDesc& desc, const T& value) + : Option(desc, manager), m_value(value) {} void set(T value) { if (m_value != value) { - if (m_checker) - m_checker(value); m_value = std::move(value); manager().on_option_changed(*this); } @@ -154,19 +148,16 @@ public: { T val; option_from_string(str, val); - if (m_checker) - m_checker(val); if (option_add(m_value, val)) m_manager.on_option_changed(*this); } Option* clone(OptionManager& manager) const override { - return new TypedOption{manager, m_desc, m_value, m_checker}; + return new TypedOption{manager, m_desc, m_value}; } private: T m_value; - OptionChecker m_checker; }; template const T& Option::get() const @@ -206,8 +197,7 @@ public: template Option& declare_option(const String& name, const String& docstring, const T& value, - OptionFlags flags = OptionFlags::None, - OptionChecker checker = OptionChecker{}) + OptionFlags flags = OptionFlags::None) { auto it = find_option(m_options, name); if (it != m_options.end()) @@ -217,8 +207,7 @@ public: throw runtime_error("option " + name + " already declared with different type or flags"); } m_descs.emplace_back(new OptionDesc{name, docstring, flags}); - m_options.emplace_back(new TypedOption{*this, *m_descs.back(), - value, std::move(checker)}); + m_options.emplace_back(new TypedOption{*this, *m_descs.back(), value}); return *m_options.back(); }