2012-04-03 15:39:20 +02:00
|
|
|
#include "option_manager.hh"
|
2013-04-09 20:05:40 +02:00
|
|
|
|
2012-06-14 15:16:44 +02:00
|
|
|
#include "assert.hh"
|
2017-03-15 18:55:34 +01:00
|
|
|
#include "flags.hh"
|
2012-04-03 15:39:20 +02:00
|
|
|
|
|
|
|
namespace Kakoune
|
|
|
|
{
|
|
|
|
|
2014-04-12 21:03:26 +02:00
|
|
|
OptionDesc::OptionDesc(String name, String docstring, OptionFlags flags)
|
|
|
|
: m_name(std::move(name)), m_docstring(std::move(docstring)),
|
|
|
|
m_flags(flags) {}
|
|
|
|
|
|
|
|
Option::Option(const OptionDesc& desc, OptionManager& manager)
|
|
|
|
: m_manager(manager), m_desc(desc) {}
|
2013-03-03 17:25:40 +01:00
|
|
|
|
2012-06-14 15:16:44 +02:00
|
|
|
OptionManager::OptionManager(OptionManager& parent)
|
|
|
|
: m_parent(&parent)
|
2012-04-03 20:25:27 +02:00
|
|
|
{
|
2012-06-14 15:16:44 +02:00
|
|
|
parent.register_watcher(*this);
|
|
|
|
}
|
|
|
|
|
|
|
|
OptionManager::~OptionManager()
|
|
|
|
{
|
|
|
|
if (m_parent)
|
|
|
|
m_parent->unregister_watcher(*this);
|
|
|
|
|
2013-04-09 20:04:11 +02:00
|
|
|
kak_assert(m_watchers.empty());
|
2012-06-14 15:16:44 +02:00
|
|
|
}
|
|
|
|
|
2016-08-21 21:24:18 +02:00
|
|
|
void OptionManager::register_watcher(OptionManagerWatcher& watcher) const
|
2012-06-14 15:16:44 +02:00
|
|
|
{
|
2013-04-09 20:04:11 +02:00
|
|
|
kak_assert(not contains(m_watchers, &watcher));
|
2012-06-14 15:16:44 +02:00
|
|
|
m_watchers.push_back(&watcher);
|
|
|
|
}
|
|
|
|
|
2016-08-21 21:24:18 +02:00
|
|
|
void OptionManager::unregister_watcher(OptionManagerWatcher& watcher) const
|
2012-06-14 15:16:44 +02:00
|
|
|
{
|
|
|
|
auto it = find(m_watchers.begin(), m_watchers.end(), &watcher);
|
2013-04-09 20:04:11 +02:00
|
|
|
kak_assert(it != m_watchers.end());
|
2012-06-14 15:16:44 +02:00
|
|
|
m_watchers.erase(it);
|
|
|
|
}
|
|
|
|
|
2015-04-26 21:40:32 +02:00
|
|
|
struct option_not_found : public runtime_error
|
|
|
|
{
|
|
|
|
option_not_found(StringView name)
|
2018-03-27 19:14:41 +02:00
|
|
|
: runtime_error(format("option not found: '{}'. Use declare-option first", name)) {}
|
2015-04-26 21:40:32 +02:00
|
|
|
};
|
|
|
|
|
2014-11-16 21:55:36 +01:00
|
|
|
Option& OptionManager::get_local_option(StringView name)
|
2013-03-03 17:25:40 +01:00
|
|
|
{
|
2017-06-23 10:54:21 +02:00
|
|
|
auto it = m_options.find(name);
|
2013-03-03 17:25:40 +01:00
|
|
|
if (it != m_options.end())
|
2017-06-23 10:54:21 +02:00
|
|
|
return *(it->value);
|
2013-03-03 17:25:40 +01:00
|
|
|
else if (m_parent)
|
2012-06-12 20:28:25 +02:00
|
|
|
{
|
2017-06-23 10:54:21 +02:00
|
|
|
auto* clone = (*m_parent)[name].clone(*this);
|
|
|
|
return *m_options.insert({clone->name(), std::unique_ptr<Option>{clone}});
|
2012-06-12 20:28:25 +02:00
|
|
|
}
|
2013-03-03 17:25:40 +01:00
|
|
|
else
|
|
|
|
throw option_not_found(name);
|
|
|
|
|
2012-04-03 20:25:27 +02:00
|
|
|
}
|
|
|
|
|
2014-11-16 21:55:36 +01:00
|
|
|
Option& OptionManager::operator[](StringView name)
|
2012-04-03 20:25:27 +02:00
|
|
|
{
|
2017-06-23 10:54:21 +02:00
|
|
|
auto it = m_options.find(name);
|
2012-04-03 20:25:27 +02:00
|
|
|
if (it != m_options.end())
|
2017-06-23 10:54:21 +02:00
|
|
|
return *it->value;
|
2012-04-03 20:25:27 +02:00
|
|
|
else if (m_parent)
|
|
|
|
return (*m_parent)[name];
|
|
|
|
else
|
|
|
|
throw option_not_found(name);
|
|
|
|
}
|
|
|
|
|
2014-11-16 21:55:36 +01:00
|
|
|
const Option& OptionManager::operator[](StringView name) const
|
2014-05-25 18:36:12 +02:00
|
|
|
{
|
|
|
|
return const_cast<OptionManager&>(*this)[name];
|
|
|
|
}
|
|
|
|
|
2015-08-10 14:54:52 +02:00
|
|
|
void OptionManager::unset_option(StringView name)
|
|
|
|
{
|
|
|
|
kak_assert(m_parent); // cannot unset option on global manager
|
2018-11-28 11:45:40 +01:00
|
|
|
auto it = m_options.find(name);
|
|
|
|
if (it != m_options.end())
|
2015-08-10 14:54:52 +02:00
|
|
|
{
|
2018-11-28 11:45:40 +01:00
|
|
|
auto& parent_option = (*m_parent)[name];
|
|
|
|
const bool changed = not parent_option.has_same_value(*it->value);
|
2017-06-23 10:54:21 +02:00
|
|
|
m_options.erase(name);
|
2018-11-28 11:45:40 +01:00
|
|
|
if (changed)
|
|
|
|
on_option_changed(parent_option);
|
2015-08-10 14:54:52 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-03-03 17:25:40 +01:00
|
|
|
void OptionManager::on_option_changed(const Option& option)
|
2012-06-14 15:16:44 +02:00
|
|
|
{
|
|
|
|
// if parent option changed, but we overrided it, it's like nothing happened
|
2017-06-23 10:54:21 +02:00
|
|
|
if (&option.manager() != this and m_options.contains(option.name()))
|
2012-06-14 15:16:44 +02:00
|
|
|
return;
|
|
|
|
|
2017-02-20 14:44:08 +01:00
|
|
|
// The watcher list might get mutated during calls to on_option_changed
|
|
|
|
auto watchers = m_watchers;
|
|
|
|
for (auto* watcher : watchers)
|
|
|
|
{
|
|
|
|
if (contains(m_watchers, watcher)) // make sure this watcher is still alive
|
|
|
|
watcher->on_option_changed(option);
|
|
|
|
}
|
2012-06-14 15:16:44 +02:00
|
|
|
}
|
|
|
|
|
2015-08-10 14:38:06 +02:00
|
|
|
CandidateList OptionsRegistry::complete_option_name(StringView prefix,
|
|
|
|
ByteCount cursor_pos) const
|
|
|
|
{
|
2016-09-26 23:59:02 +02:00
|
|
|
using OptionPtr = std::unique_ptr<const OptionDesc>;
|
2016-04-17 20:21:08 +02:00
|
|
|
return complete(prefix, cursor_pos, m_descs |
|
|
|
|
filter([](const OptionPtr& desc)
|
|
|
|
{ return not (desc->flags() & OptionFlags::Hidden); }) |
|
2018-03-13 04:24:03 +01:00
|
|
|
transform(&OptionDesc::name));
|
2015-08-10 14:38:06 +02:00
|
|
|
}
|
|
|
|
|
2012-04-03 15:39:20 +02:00
|
|
|
}
|