Remove option checkers, handle that through the type system

Use a specific type for InsertCompleterDesc with checks in
the option_{from,to}_string functions
This commit is contained in:
Maxime Coste 2014-08-19 18:56:11 +01:00
parent a36aed94f1
commit bea53d09b2
4 changed files with 97 additions and 38 deletions

View File

@ -16,6 +16,48 @@ namespace Kakoune
using StringList = std::vector<String>; using StringList = std::vector<String>;
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<String>{};
return;
}
throw runtime_error("invalid completer description: " + str);;
}
namespace namespace
{ {
@ -272,26 +314,28 @@ bool InsertCompleter::setup_ifn()
using namespace std::placeholders; using namespace std::placeholders;
if (not m_completions.is_valid()) if (not m_completions.is_valid())
{ {
auto& completers = options()["completers"].get<StringList>(); auto& completers = options()["completers"].get<InsertCompleterDescList>();
for (auto& completer : completers) for (auto& completer : completers)
{ {
if (completer == "filename" and if (completer.mode == InsertCompleterDesc::Filename and
try_complete([this](const Buffer& buffer, ByteCoord cursor_pos) { try_complete([this](const Buffer& buffer, ByteCoord cursor_pos) {
return complete_filename<true>(buffer, cursor_pos, return complete_filename<true>(buffer, cursor_pos,
options()); options());
})) }))
return true; 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) { try_complete([&,this](const Buffer& buffer, ByteCoord cursor_pos) {
return complete_option(buffer, cursor_pos, return complete_option(buffer, cursor_pos,
options(), completer.substr(7_byte)); options(), *completer.param);
})) }))
return true; return true;
if (completer == "word=buffer" and if (completer.mode == InsertCompleterDesc::Word and
*completer.param == "buffer" and
(try_complete(complete_word<false, false>) or (try_complete(complete_word<false, false>) or
try_complete(complete_word<false, true>))) try_complete(complete_word<false, true>)))
return true; return true;
if (completer == "word=all" and if (completer.mode == InsertCompleterDesc::Word and
*completer.param == "all" and
(try_complete(complete_word<true, false>) or (try_complete(complete_word<true, false>) or
try_complete(complete_word<true, true>))) try_complete(complete_word<true, true>)))
return true; return true;
@ -323,12 +367,12 @@ void InsertCompleter::menu_show()
void InsertCompleter::on_option_changed(const Option& opt) void InsertCompleter::on_option_changed(const Option& opt)
{ {
auto& completers = options()["completers"].get<StringList>(); auto& completers = options()["completers"].get<InsertCompleterDescList>();
StringList option_names; std::vector<StringView> option_names;
for (auto& completer : completers) for (auto& completer : completers)
{ {
if (completer.substr(0_byte, 7_byte) == "option=") if (completer.mode == InsertCompleterDesc::Option)
option_names.emplace_back(completer.substr(7_byte)); option_names.emplace_back(*completer.param);
} }
if (contains(option_names, opt.name())) if (contains(option_names, opt.name()))
{ {

View File

@ -4,9 +4,41 @@
#include "buffer.hh" #include "buffer.hh"
#include "option_manager.hh" #include "option_manager.hh"
#include "optional.hh"
namespace Kakoune namespace Kakoune
{ {
struct InsertCompleterDesc
{
enum Mode
{
Word,
Option,
Filename
};
InsertCompleterDesc(Mode mode = Filename,
Optional<String> param = Optional<String>{})
: 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<String> param;
};
using InsertCompleterDescList = std::vector<InsertCompleterDesc>;
String option_to_string(const InsertCompleterDesc& opt);
void option_from_string(const String& str, InsertCompleterDesc& opt);
struct InsertCompletion struct InsertCompletion
{ {
ByteCoord begin; ByteCoord begin;

View File

@ -1,5 +1,7 @@
#include "option_manager.hh" #include "option_manager.hh"
#include "insert_completer.hh"
#include "assert.hh" #include "assert.hh"
#include <sstream> #include <sstream>
@ -159,18 +161,10 @@ GlobalOptions::GlobalOptions()
declare_option("path", "path to consider when trying to find a file", declare_option("path", "path to consider when trying to find a file",
std::vector<String>({ "./", "/usr/include" })); std::vector<String>({ "./", "/usr/include" }));
declare_option("completers", "insert mode completers to execute.", declare_option("completers", "insert mode completers to execute.",
std::vector<String>({"filename", "word=all"}), std::vector<InsertCompleterDesc>({
OptionFlags::None, InsertCompleterDesc{ InsertCompleterDesc::Filename },
OptionChecker<std::vector<String>>([](const std::vector<String>& s) { InsertCompleterDesc{ InsertCompleterDesc::Word, "all"_str }
static const auto values = {"word=buffer", "word=all", "filename"}; }), OptionFlags::None);
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");
}
}));
declare_option("autoreload", declare_option("autoreload",
"autoreload buffer when a filesystem modification is detected", "autoreload buffer when a filesystem modification is detected",
Ask); Ask);

View File

@ -117,23 +117,17 @@ private:
std::vector<OptionManagerWatcher*> m_watchers; std::vector<OptionManagerWatcher*> m_watchers;
}; };
template<typename T> using OptionChecker = std::function<void (const T&)>;
template<typename T> template<typename T>
class TypedOption : public Option class TypedOption : public Option
{ {
public: public:
TypedOption(OptionManager& manager, const OptionDesc& desc, TypedOption(OptionManager& manager, const OptionDesc& desc, const T& value)
const T& value, OptionChecker<T> checker) : Option(desc, manager), m_value(value) {}
: Option(desc, manager),
m_value(value), m_checker(std::move(checker)) {}
void set(T value) void set(T value)
{ {
if (m_value != value) if (m_value != value)
{ {
if (m_checker)
m_checker(value);
m_value = std::move(value); m_value = std::move(value);
manager().on_option_changed(*this); manager().on_option_changed(*this);
} }
@ -154,19 +148,16 @@ public:
{ {
T val; T val;
option_from_string(str, val); option_from_string(str, val);
if (m_checker)
m_checker(val);
if (option_add(m_value, val)) if (option_add(m_value, val))
m_manager.on_option_changed(*this); m_manager.on_option_changed(*this);
} }
Option* clone(OptionManager& manager) const override 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: private:
T m_value; T m_value;
OptionChecker<T> m_checker;
}; };
template<typename T> const T& Option::get() const template<typename T> const T& Option::get() const
@ -206,8 +197,7 @@ public:
template<typename T> template<typename T>
Option& declare_option(const String& name, const String& docstring, Option& declare_option(const String& name, const String& docstring,
const T& value, const T& value,
OptionFlags flags = OptionFlags::None, OptionFlags flags = OptionFlags::None)
OptionChecker<T> checker = OptionChecker<T>{})
{ {
auto it = find_option(m_options, name); auto it = find_option(m_options, name);
if (it != m_options.end()) if (it != m_options.end())
@ -217,8 +207,7 @@ public:
throw runtime_error("option " + name + " already declared with different type or flags"); throw runtime_error("option " + name + " already declared with different type or flags");
} }
m_descs.emplace_back(new OptionDesc{name, docstring, flags}); m_descs.emplace_back(new OptionDesc{name, docstring, flags});
m_options.emplace_back(new TypedOption<T>{*this, *m_descs.back(), m_options.emplace_back(new TypedOption<T>{*this, *m_descs.back(), value});
value, std::move(checker)});
return *m_options.back(); return *m_options.back();
} }