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
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)
$(CXX) $(LDFLAGS) $(CXXFLAGS) $(objects) $(LIBS) -o $@

View File

@ -178,15 +178,27 @@ void register_registers()
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()
{
OptionsRegistry& reg = GlobalScope::instance().option_registry();
reg.declare_option("tabstop", "size of a tab character", 8);
reg.declare_option("indentwidth", "indentation width", 4);
reg.declare_option("scrolloff",
"number of lines and columns to keep visible main cursor when scrolling",
CharCoord{0,0});
reg.declare_option<int, check_positive>("tabstop", "size of a tab character", 8);
reg.declare_option<int, check_positive>("indentwidth", "indentation width", 4);
reg.declare_option<CharCoord, check_scrolloff>(
"scrolloff", "number of lines and columns to keep visible main cursor when scrolling",
{0,0});
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)",
ByteOrderMark::None);

View File

@ -115,6 +115,7 @@ public:
void set(T value, bool notify = true)
{
validate(value);
if (m_value != value)
{
m_value = std::move(value);
@ -141,11 +142,6 @@ public:
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>;
static void* operator new (std::size_t sz)
{
@ -158,9 +154,23 @@ public:
return Alloc{}.deallocate(reinterpret_cast<TypedOption*>(ptr), 1);
}
private:
virtual void validate(const T& value) const {}
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
{
auto* typed_opt = dynamic_cast<const TypedOption<T>*>(this);
@ -199,7 +209,7 @@ class OptionsRegistry
public:
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,
const T& value,
OptionFlags flags = OptionFlags::None)
@ -213,7 +223,7 @@ public:
throw runtime_error(format("option '{}' already declared with different type or flags", name));
}
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();
}