Support validating some options values before setting them

Fixes #583
This commit is contained in:
Maxime Coste 2016-02-11 22:07:18 +00:00
parent 9cdfa4a81c
commit 986c91a835
3 changed files with 35 additions and 13 deletions

View File

@ -60,7 +60,7 @@ endif
# Picking the right name is done in the system detection switch above # Picking the right name is done in the system detection switch above
A2X ?= a2x A2X ?= a2x
CXXFLAGS += -std=gnu++11 -g -Wall -Wno-reorder -Wno-sign-compare CXXFLAGS += -std=gnu++11 -g -Wall -Wno-reorder -Wno-sign-compare -Wno-address
kak : $(objects) kak : $(objects)
$(CXX) $(LDFLAGS) $(CXXFLAGS) $(objects) $(LIBS) -o $@ $(CXX) $(LDFLAGS) $(CXXFLAGS) $(objects) $(LIBS) -o $@

View File

@ -178,15 +178,27 @@ void register_registers()
register_manager.add_register('_', make_unique<NullRegister>()); register_manager.add_register('_', make_unique<NullRegister>());
} }
static void check_positive(const int& val)
{
if (val < 1)
throw runtime_error{"value should be strictly positive"};
}
static void check_scrolloff(const CharCoord& so)
{
if (so.line < 0 or so.column < 0)
throw runtime_error{"scroll offset must be positive or zero"};
}
void register_options() void register_options()
{ {
OptionsRegistry& reg = GlobalScope::instance().option_registry(); OptionsRegistry& reg = GlobalScope::instance().option_registry();
reg.declare_option("tabstop", "size of a tab character", 8); reg.declare_option<int, check_positive>("tabstop", "size of a tab character", 8);
reg.declare_option("indentwidth", "indentation width", 4); reg.declare_option<int, check_positive>("indentwidth", "indentation width", 4);
reg.declare_option("scrolloff", reg.declare_option<CharCoord, check_scrolloff>(
"number of lines and columns to keep visible main cursor when scrolling", "scrolloff", "number of lines and columns to keep visible main cursor when scrolling",
CharCoord{0,0}); {0,0});
reg.declare_option("eolformat", "end of line format: crlf or lf", EolFormat::Lf); reg.declare_option("eolformat", "end of line format: crlf or lf", EolFormat::Lf);
reg.declare_option("BOM", "insert a byte order mark when writing buffer (none or utf8)", reg.declare_option("BOM", "insert a byte order mark when writing buffer (none or utf8)",
ByteOrderMark::None); ByteOrderMark::None);

View File

@ -115,6 +115,7 @@ public:
void set(T value, bool notify = true) void set(T value, bool notify = true)
{ {
validate(value);
if (m_value != value) if (m_value != value)
{ {
m_value = std::move(value); m_value = std::move(value);
@ -141,11 +142,6 @@ public:
m_manager.on_option_changed(*this); m_manager.on_option_changed(*this);
} }
Option* clone(OptionManager& manager) const override
{
return new TypedOption{manager, m_desc, m_value};
}
using Alloc = Allocator<TypedOption, MemoryDomain::Options>; using Alloc = Allocator<TypedOption, MemoryDomain::Options>;
static void* operator new (std::size_t sz) static void* operator new (std::size_t sz)
{ {
@ -158,9 +154,23 @@ public:
return Alloc{}.deallocate(reinterpret_cast<TypedOption*>(ptr), 1); return Alloc{}.deallocate(reinterpret_cast<TypedOption*>(ptr), 1);
} }
private: private:
virtual void validate(const T& value) const {}
T m_value; T m_value;
}; };
template<typename T, void (*validator)(const T&)>
class TypedCheckedOption : public TypedOption<T>
{
using TypedOption<T>::TypedOption;
Option* clone(OptionManager& manager) const override
{
return new TypedCheckedOption{manager, this->m_desc, this->get()};
}
void validate(const T& value) const override { if (validator != nullptr) validator(value); }
};
template<typename T> const T& Option::get() const template<typename T> const T& Option::get() const
{ {
auto* typed_opt = dynamic_cast<const TypedOption<T>*>(this); auto* typed_opt = dynamic_cast<const TypedOption<T>*>(this);
@ -199,7 +209,7 @@ class OptionsRegistry
public: public:
OptionsRegistry(OptionManager& global_manager) : m_global_manager(global_manager) {} OptionsRegistry(OptionManager& global_manager) : m_global_manager(global_manager) {}
template<typename T> template<typename T, void (*validator)(const T&) = nullptr>
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)
@ -213,7 +223,7 @@ public:
throw runtime_error(format("option '{}' already declared with different type or flags", name)); throw runtime_error(format("option '{}' already declared with different type or flags", name));
} }
m_descs.emplace_back(new OptionDesc{name, docstring, flags}); m_descs.emplace_back(new OptionDesc{name, docstring, flags});
opts.emplace_back(new TypedOption<T>{m_global_manager, *m_descs.back(), value}); opts.emplace_back(new TypedCheckedOption<T, validator>{m_global_manager, *m_descs.back(), value});
return *opts.back(); return *opts.back();
} }