Refactor OptionManager, add OptionManagerWatcher
- use set_option to set an option, instead of operator[] (no-const) - keeps a list of OptionManagerWatcher to notify when an option change it also notifies when an option changes in his parent and the option is not overridden.
This commit is contained in:
parent
109c11f29c
commit
a943e08dc7
|
@ -640,13 +640,12 @@ void exec_commands_in_runtime_file(const CommandParameters& params,
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_option(OptionManager& option_manager, const CommandParameters& params,
|
void set_option(OptionManager& option_manager, const CommandParameters& params,
|
||||||
HookManager& hook_manager, const Context& context)
|
const Context& context)
|
||||||
{
|
{
|
||||||
if (params.size() != 2)
|
if (params.size() != 2)
|
||||||
throw wrong_argument_count();
|
throw wrong_argument_count();
|
||||||
|
|
||||||
option_manager[params[0]] = params[1];
|
option_manager.set_option(params[0], Option(params[1]));
|
||||||
hook_manager.run_hook("SetOption", params[0] + "=" + params[1], context);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class RegisterRestorer
|
class RegisterRestorer
|
||||||
|
@ -920,7 +919,7 @@ void register_commands()
|
||||||
|
|
||||||
cm.register_commands({ "setg", "setglobal" },
|
cm.register_commands({ "setg", "setglobal" },
|
||||||
[](const CommandParameters& params, const Context& context)
|
[](const CommandParameters& params, const Context& context)
|
||||||
{ set_option(GlobalOptionManager::instance(), params, GlobalHookManager::instance(), context); },
|
{ set_option(GlobalOptionManager::instance(), params, context); },
|
||||||
CommandManager::None,
|
CommandManager::None,
|
||||||
PerArgumentCommandCompleter({
|
PerArgumentCommandCompleter({
|
||||||
[](const String& prefix, size_t cursor_pos)
|
[](const String& prefix, size_t cursor_pos)
|
||||||
|
@ -928,7 +927,7 @@ void register_commands()
|
||||||
}));
|
}));
|
||||||
cm.register_commands({ "setb", "setbuffer" },
|
cm.register_commands({ "setb", "setbuffer" },
|
||||||
[](const CommandParameters& params, const Context& context)
|
[](const CommandParameters& params, const Context& context)
|
||||||
{ set_option(context.buffer().option_manager(), params, context.buffer().hook_manager(), context); },
|
{ set_option(context.buffer().option_manager(), params, context); },
|
||||||
CommandManager::None,
|
CommandManager::None,
|
||||||
PerArgumentCommandCompleter({
|
PerArgumentCommandCompleter({
|
||||||
[](const String& prefix, size_t cursor_pos)
|
[](const String& prefix, size_t cursor_pos)
|
||||||
|
@ -936,7 +935,7 @@ void register_commands()
|
||||||
}));
|
}));
|
||||||
cm.register_commands({ "setw", "setwindow" },
|
cm.register_commands({ "setw", "setwindow" },
|
||||||
[](const CommandParameters& params, const Context& context)
|
[](const CommandParameters& params, const Context& context)
|
||||||
{ set_option(context.window().option_manager(), params, context.window().hook_manager(), context); },
|
{ set_option(context.window().option_manager(), params, context); },
|
||||||
CommandManager::None,
|
CommandManager::None,
|
||||||
PerArgumentCommandCompleter({
|
PerArgumentCommandCompleter({
|
||||||
[](const String& prefix, size_t cursor_pos)
|
[](const String& prefix, size_t cursor_pos)
|
||||||
|
|
|
@ -1,31 +1,47 @@
|
||||||
#include "option_manager.hh"
|
#include "option_manager.hh"
|
||||||
|
#include "assert.hh"
|
||||||
|
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
namespace Kakoune
|
namespace Kakoune
|
||||||
{
|
{
|
||||||
|
|
||||||
Option& OptionManager::operator[] (const String& name)
|
OptionManager::OptionManager(OptionManager& parent)
|
||||||
|
: m_parent(&parent)
|
||||||
{
|
{
|
||||||
auto it = m_options.find(name);
|
parent.register_watcher(*this);
|
||||||
if (it != m_options.end())
|
|
||||||
return it->second;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Option& res = m_options[name];
|
|
||||||
OptionManager* parent = m_parent;
|
|
||||||
while (parent)
|
|
||||||
{
|
|
||||||
auto parent_it = parent->m_options.find(name);
|
|
||||||
if (parent_it != parent->m_options.end())
|
|
||||||
{
|
|
||||||
res = parent_it->second;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
parent = parent->m_parent;
|
OptionManager::~OptionManager()
|
||||||
|
{
|
||||||
|
if (m_parent)
|
||||||
|
m_parent->unregister_watcher(*this);
|
||||||
|
|
||||||
|
assert(m_watchers.empty());
|
||||||
}
|
}
|
||||||
return res;
|
|
||||||
|
void OptionManager::register_watcher(OptionManagerWatcher& watcher)
|
||||||
|
{
|
||||||
|
assert(not contains(m_watchers, &watcher));
|
||||||
|
m_watchers.push_back(&watcher);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OptionManager::unregister_watcher(OptionManagerWatcher& watcher)
|
||||||
|
{
|
||||||
|
auto it = find(m_watchers.begin(), m_watchers.end(), &watcher);
|
||||||
|
assert(it != m_watchers.end());
|
||||||
|
m_watchers.erase(it);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OptionManager::set_option(const String& name, const Option& value)
|
||||||
|
{
|
||||||
|
Option old_value = m_options[name];
|
||||||
|
m_options[name] = value;
|
||||||
|
|
||||||
|
if (old_value != value)
|
||||||
|
{
|
||||||
|
for (auto watcher : m_watchers)
|
||||||
|
watcher->on_option_changed(name, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,10 +72,28 @@ CandidateList OptionManager::complete_option_name(const String& prefix,
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
OptionManager::OptionMap OptionManager::flatten_options() const
|
||||||
|
{
|
||||||
|
OptionMap res = m_parent ? m_parent->flatten_options() : OptionMap();
|
||||||
|
for (auto& option : m_options)
|
||||||
|
res.insert(option);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
void OptionManager::on_option_changed(const String& name, const Option& value)
|
||||||
|
{
|
||||||
|
// if parent option changed, but we overrided it, it's like nothing happened
|
||||||
|
if (m_options.find(name) != m_options.end())
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (auto watcher : m_watchers)
|
||||||
|
watcher->on_option_changed(name, value);
|
||||||
|
}
|
||||||
|
|
||||||
GlobalOptionManager::GlobalOptionManager()
|
GlobalOptionManager::GlobalOptionManager()
|
||||||
: OptionManager()
|
: OptionManager()
|
||||||
{
|
{
|
||||||
(*this)["tabstop"] = 8;
|
set_option("tabstop", Option(8));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,32 +28,56 @@ public:
|
||||||
Option& operator=(int value) { m_value = int_to_str(value); return *this; }
|
Option& operator=(int value) { m_value = int_to_str(value); return *this; }
|
||||||
Option& operator=(const String& value) { m_value = value; return *this; }
|
Option& operator=(const String& value) { m_value = value; return *this; }
|
||||||
|
|
||||||
|
bool operator==(const Option& other) const { return m_value == other.m_value; }
|
||||||
|
bool operator!=(const Option& other) const { return m_value != other.m_value; }
|
||||||
|
|
||||||
int as_int() const { return atoi(m_value.c_str()); }
|
int as_int() const { return atoi(m_value.c_str()); }
|
||||||
String as_string() const { return m_value; }
|
String as_string() const { return m_value; }
|
||||||
private:
|
private:
|
||||||
String m_value;
|
String m_value;
|
||||||
};
|
};
|
||||||
|
|
||||||
class OptionManager
|
class OptionManagerWatcher
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
OptionManager(OptionManager& parent)
|
virtual ~OptionManagerWatcher() {}
|
||||||
: m_parent(&parent) {}
|
|
||||||
|
virtual void on_option_changed(const String& name,
|
||||||
|
const Option& option) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class OptionManager : private OptionManagerWatcher
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
OptionManager(OptionManager& parent);
|
||||||
|
~OptionManager();
|
||||||
|
|
||||||
Option& operator[] (const String& name);
|
|
||||||
const Option& operator[] (const String& name) const;
|
const Option& operator[] (const String& name) const;
|
||||||
|
|
||||||
|
void set_option(const String& name, const Option& value);
|
||||||
|
|
||||||
CandidateList complete_option_name(const String& prefix,
|
CandidateList complete_option_name(const String& prefix,
|
||||||
size_t cursor_pos);
|
size_t cursor_pos);
|
||||||
|
|
||||||
|
typedef std::unordered_map<String, Option> OptionMap;
|
||||||
|
OptionMap flatten_options() const;
|
||||||
|
|
||||||
|
void register_watcher(OptionManagerWatcher& watcher);
|
||||||
|
void unregister_watcher(OptionManagerWatcher& watcher);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
OptionManager()
|
OptionManager()
|
||||||
: m_parent(nullptr) {}
|
: m_parent(nullptr) {}
|
||||||
// the only one allowed to construct a root option manager
|
// the only one allowed to construct a root option manager
|
||||||
friend class GlobalOptionManager;
|
friend class GlobalOptionManager;
|
||||||
|
|
||||||
std::unordered_map<String, Option> m_options;
|
OptionMap m_options;
|
||||||
OptionManager* m_parent;
|
OptionManager* m_parent;
|
||||||
|
|
||||||
|
void on_option_changed(const String& name,
|
||||||
|
const Option& value);
|
||||||
|
|
||||||
|
std::vector<OptionManagerWatcher*> m_watchers;
|
||||||
};
|
};
|
||||||
|
|
||||||
class GlobalOptionManager : public OptionManager,
|
class GlobalOptionManager : public OptionManager,
|
||||||
|
|
Loading…
Reference in New Issue
Block a user