FlagLines: use a shared updaters for options

previously, having two windows showing the same buffer with
the same line flags would have updated the options twice, resulting
in wrong lines in option. Now line flags options are updated only
once by a shared object along all FlagLines highlighter using the
same option.
This commit is contained in:
Maxime Coste 2013-04-29 14:20:42 +02:00
parent ba562367f0
commit 11bc24f992
2 changed files with 67 additions and 39 deletions

View File

@ -332,22 +332,22 @@ void expand_unprintable(DisplayBuffer& display_buffer)
} }
} }
class FlagLines : public BufferChangeListener_AutoRegister, class FlagLines : public OptionManagerWatcher_AutoRegister
public OptionManagerWatcher_AutoRegister
{ {
public: public:
FlagLines(Color bg, String option_name, Window& window) FlagLines(Color bg, String option_name, Window& window)
: BufferChangeListener_AutoRegister(window.buffer()), : OptionManagerWatcher_AutoRegister(window.options()),
OptionManagerWatcher_AutoRegister(window.options()),
m_bg(bg), m_option_name(std::move(option_name)), m_bg(bg), m_option_name(std::move(option_name)),
m_window(window) m_window(window)
{ {
// trigger an exception if option is not of right type. // trigger an exception if option is not of right type.
m_window.options()[m_option_name].get<std::vector<LineAndFlag>>(); m_window.options()[m_option_name].get<std::vector<LineAndFlag>>();
update_shared_option_updater();
} }
void operator()(DisplayBuffer& display_buffer) void operator()(DisplayBuffer& display_buffer)
{ {
update_shared_option_updater();
auto& lines = m_window.options()[m_option_name].get<std::vector<LineAndFlag>>(); auto& lines = m_window.options()[m_option_name].get<std::vector<LineAndFlag>>();
CharCount width = 0; CharCount width = 0;
@ -366,54 +366,82 @@ public:
} }
} }
void on_option_changed(const Option& option) private:
void on_option_changed(const Option& option) override
{ {
if (option.name() == m_option_name) if (option.name() == m_option_name)
m_window.forget_timestamp(); m_window.forget_timestamp();
} }
void on_insert(const BufferIterator& begin, const BufferIterator& end) override struct OptionUpdater : BufferChangeListener_AutoRegister
{ {
LineCount new_lines = end.line() - begin.line(); OptionUpdater(Buffer& buffer, Option& option)
if (new_lines == 0) : BufferChangeListener_AutoRegister(buffer), m_option(&option)
return;
const Option& opt = m_window.options()[m_option_name];
if (&opt.manager() == &GlobalOptions::instance())
return;
auto lines = opt.get<std::vector<LineAndFlag>>();
for (auto& line : lines)
{ {
if (std::get<0>(line) > begin.line()) // sanity checks
std::get<0>(line) += new_lines; kak_assert(&m_option->manager() != &GlobalOptions::instance());
m_option->get<std::vector<LineAndFlag>>();
} }
opt.manager().get_local_option(m_option_name).set(lines);
void on_insert(const BufferIterator& begin, const BufferIterator& end) override
{
LineCount new_lines = end.line() - begin.line();
if (new_lines == 0)
return;
auto lines = m_option->get<std::vector<LineAndFlag>>();
for (auto& line : lines)
{
if (std::get<0>(line) > begin.line())
std::get<0>(line) += new_lines;
}
m_option->set(lines);
}
void on_erase(const BufferIterator& begin, const BufferIterator& end) override
{
LineCount removed_lines = end.line() - begin.line();
if (removed_lines == 0)
return;
auto lines = m_option->get<std::vector<LineAndFlag>>();
for (auto& line : lines)
{
if (std::get<0>(line) > begin.line())
std::get<0>(line) -= removed_lines;
}
m_option->set(lines);
}
const Option& option() const { return *m_option; }
private:
safe_ptr<Option> m_option;
};
static std::unordered_map<const Option*, std::weak_ptr<OptionUpdater>> ms_updaters;
void update_shared_option_updater()
{
const Option& option = m_window.options()[m_option_name];
if (&option.manager() == &GlobalOptions::instance() or
(m_updater and &option == &m_updater->option()))
return;
auto& shared_updater = ms_updaters[&option];
if (shared_updater.expired())
{
m_updater = std::make_shared<OptionUpdater>(
m_window.buffer(), option.manager().get_local_option(option.name()));
shared_updater = m_updater;
}
else
m_updater = shared_updater.lock();
} }
void on_erase(const BufferIterator& begin, const BufferIterator& end) override
{
LineCount removed_lines = end.line() - begin.line();
if (removed_lines == 0)
return;
const Option& opt = m_window.options()[m_option_name];
// only update
if (&opt.manager() == &GlobalOptions::instance())
return;
auto lines = opt.get<std::vector<LineAndFlag>>();
for (auto& line : lines)
{
if (std::get<0>(line) > begin.line())
std::get<0>(line) -= removed_lines;
}
opt.manager().get_local_option(m_option_name).set(lines);
}
private:
Color m_bg; Color m_bg;
String m_option_name; String m_option_name;
Window& m_window; Window& m_window;
std::shared_ptr<OptionUpdater> m_updater;
}; };
std::unordered_map<const Option*, std::weak_ptr<FlagLines::OptionUpdater>> FlagLines::ms_updaters;
HighlighterAndId flag_lines_factory(const HighlighterParameters& params, Window& window) HighlighterAndId flag_lines_factory(const HighlighterParameters& params, Window& window)
{ {

View File

@ -19,7 +19,7 @@ struct option_not_found : public runtime_error
class OptionManager; class OptionManager;
class Option class Option : public SafeCountable
{ {
public: public:
Option(OptionManager& manager, String name); Option(OptionManager& manager, String name);