Add scope class and encapsulate Options, Keymaps, Aliases and Hooks in it

This commit is contained in:
Maxime Coste 2014-10-30 14:00:42 +00:00
parent 8649371ff2
commit e38ba6ce3d
15 changed files with 201 additions and 241 deletions

View File

@ -21,16 +21,13 @@ public:
std::vector<StringView> aliases_for(StringView command) const;
private:
friend class GlobalAliases;
friend class Scope;
AliasRegistry() {}
safe_ptr<AliasRegistry> m_parent;
std::unordered_map<String, String> m_aliases;
};
class GlobalAliases : public AliasRegistry, public Singleton<GlobalAliases>
{};
}
#endif // alias_registry_hh_INCLUDED

View File

@ -16,18 +16,15 @@ namespace Kakoune
Buffer::Buffer(String name, Flags flags, std::vector<String> lines,
time_t fs_timestamp)
: m_name(flags & Flags::File ? real_path(parse_filename(name)) : std::move(name)),
: Scope(GlobalScope::instance()),
m_name(flags & Flags::File ? real_path(parse_filename(name)) : std::move(name)),
m_flags(flags | Flags::NoUndo),
m_history(), m_history_cursor(m_history.begin()),
m_last_save_undo_index(0),
m_fs_timestamp(fs_timestamp),
m_hooks(GlobalHooks::instance()),
m_options(GlobalOptions::instance()),
m_keymaps(GlobalKeymaps::instance()),
m_aliases(GlobalAliases::instance())
m_fs_timestamp(fs_timestamp)
{
BufferManager::instance().register_buffer(*this);
m_options.register_watcher(*this);
options().register_watcher(*this);
if (lines.empty())
lines.emplace_back("\n");
@ -57,7 +54,7 @@ Buffer::Buffer(String name, Flags flags, std::vector<String> lines,
// now we may begin to record undo data
m_flags = flags;
for (auto& option : m_options.flatten_options())
for (auto& option : options().flatten_options())
on_option_changed(*option);
}
@ -65,7 +62,7 @@ Buffer::~Buffer()
{
run_hook_in_own_context("BufClose", m_name);
m_options.unregister_watcher(*this);
options().unregister_watcher(*this);
BufferManager::instance().unregister_buffer(*this);
m_values.clear();
}
@ -520,7 +517,7 @@ void Buffer::on_option_changed(const Option& option)
void Buffer::run_hook_in_own_context(const String& hook_name, StringView param)
{
InputHandler hook_handler({ *this, Selection{} });
m_hooks.run_hook(hook_name, param, hook_handler.context());
hooks().run_hook(hook_name, param, hook_handler.context());
}
ByteCoord Buffer::last_modification_coord() const

View File

@ -1,13 +1,10 @@
#ifndef buffer_hh_INCLUDED
#define buffer_hh_INCLUDED
#include "alias_registry.hh"
#include "coord.hh"
#include "flags.hh"
#include "hook_manager.hh"
#include "option_manager.hh"
#include "keymap_manager.hh"
#include "safe_ptr.hh"
#include "scope.hh"
#include "interned_string.hh"
#include "value.hh"
@ -71,7 +68,7 @@ private:
// The Buffer class permits to read and mutate this file
// representation. It also manage modifications undo/redo and
// provides tools to deal with the line/column nature of text.
class Buffer : public SafeCountable, public OptionManagerWatcher
class Buffer : public SafeCountable, public OptionManagerWatcher, public Scope
{
public:
enum class Flags
@ -150,15 +147,6 @@ public:
// notify the buffer that it was saved in the current state
void notify_saved();
OptionManager& options() { return m_options; }
const OptionManager& options() const { return m_options; }
HookManager& hooks() { return m_hooks; }
const HookManager& hooks() const { return m_hooks; }
KeymapManager& keymaps() { return m_keymaps; }
const KeymapManager& keymaps() const { return m_keymaps; }
AliasRegistry& aliases() { return m_aliases; }
const AliasRegistry& aliases() const { return m_aliases; }
ValueMap& values() const { return m_values; }
void run_hook_in_own_context(const String& hook_name, StringView param);
@ -217,11 +205,6 @@ private:
time_t m_fs_timestamp;
OptionManager m_options;
HookManager m_hooks;
KeymapManager m_keymaps;
AliasRegistry m_aliases;
// Values are just data holding by the buffer, so it is part of its
// observable state
mutable ValueMap m_values;

View File

@ -84,6 +84,26 @@ const ParameterDesc single_optional_name_param{
static constexpr auto scopes = { "global", "buffer", "window" };
Scope* get_scope_ifp(const String& scope, const Context& context)
{
if (prefix_match("global", scope))
return &GlobalScope::instance();
else if (prefix_match("buffer", scope))
return &context.buffer();
else if (prefix_match("window", scope))
return &context.window();
else if (prefix_match(scope, "buffer="))
return &BufferManager::instance().get_buffer(scope.substr(7_byte));
return nullptr;
}
Scope& get_scope(const String& scope, const Context& context)
{
if (auto s = get_scope_ifp(scope, context))
return *s;
throw runtime_error("error: no such scope " + scope);
}
struct CommandDesc
{
const char* name;
@ -495,24 +515,6 @@ const CommandDesc rm_highlighter_cmd = {
}
};
HookManager* get_hook_manager_ifp(const String& scope, const Context& context)
{
if (prefix_match("global", scope))
return &GlobalHooks::instance();
else if (prefix_match("buffer", scope))
return &context.buffer().hooks();
else if (prefix_match("window", scope))
return &context.window().hooks();
return nullptr;
}
HookManager& get_hook_manager(const String& scope, const Context& context)
{
if (auto manager = get_hook_manager_ifp(scope, context))
return *manager;
throw runtime_error("error: no such hook container " + scope);
}
const CommandDesc add_hook_cmd = {
"hook",
nullptr,
@ -557,14 +559,14 @@ const CommandDesc add_hook_cmd = {
StringView group;
if (parser.has_option("group"))
group = parser.option_value("group");
get_hook_manager(parser[0], context).add_hook(parser[1], group, hook_func);
get_scope(parser[0], context).hooks().add_hook(parser[1], group, hook_func);
}
};
const CommandDesc rm_hook_cmd = {
"rmhooks",
nullptr,
"rmhooks <group>: remove all hooks whose group is <group>",
"rmhooks <scope> <group>: remove all hooks whose group is <group>",
ParameterDesc{ SwitchMap{}, ParameterDesc::Flags::None, 2, 2 },
CommandFlags::None,
[](const Context& context, CompletionFlags flags,
@ -576,15 +578,15 @@ const CommandDesc rm_hook_cmd = {
prefix_complete(params[0].substr(0_byte, pos_in_token), scopes) };
else if (token_to_complete == 1)
{
if (auto manager = get_hook_manager_ifp(params[0], context))
if (auto scope = get_scope_ifp(params[0], context))
return { 0_byte, params[0].length(),
manager->complete_hook_group(params[1], pos_in_token) };
scope->hooks().complete_hook_group(params[1], pos_in_token) };
}
return {};
},
[](const ParametersParser& parser, Context& context)
{
get_hook_manager(parser[0], context).remove_hooks(parser[1]);
get_scope(parser[0], context).hooks().remove_hooks(parser[1]);
}
};
@ -712,17 +714,6 @@ const CommandDesc define_command_cmd = {
define_command
};
AliasRegistry& get_aliases(const String& scope, const Context& context)
{
if (prefix_match("global", scope))
return GlobalAliases::instance();
else if (prefix_match("buffer", scope))
return context.buffer().aliases();
else if (prefix_match("window", scope))
return context.window().aliases();
throw runtime_error("error: no such scope " + scope);
}
const CommandDesc alias_cmd = {
"alias",
nullptr,
@ -732,7 +723,7 @@ const CommandDesc alias_cmd = {
CommandCompleter{},
[](const ParametersParser& parser, Context& context)
{
AliasRegistry& aliases = get_aliases(parser[0], context);
AliasRegistry& aliases = get_scope(parser[0], context).aliases();
aliases.add_alias(parser[1], parser[2]);
}
};
@ -747,7 +738,7 @@ const CommandDesc unalias_cmd = {
CommandCompleter{},
[](const ParametersParser& parser, Context& context)
{
AliasRegistry& aliases = get_aliases(parser[0], context);
AliasRegistry& aliases = get_scope(parser[0], context).aliases();
if (parser.positional_count() == 3 and
aliases[parser[1]] != parser[2])
return;
@ -831,19 +822,6 @@ const CommandDesc source_cmd = {
}
};
OptionManager& get_options(const String& scope, const Context& context)
{
if (prefix_match("global", scope))
return GlobalOptions::instance();
else if (prefix_match("buffer", scope))
return context.buffer().options();
else if (prefix_match("window", scope))
return context.window().options();
else if (prefix_match(scope, "buffer="))
return BufferManager::instance().get_buffer(scope.substr(7_byte)).options();
throw runtime_error("error: no such option container " + scope);
}
const CommandDesc set_option_cmd = {
"set",
nullptr,
@ -863,14 +841,14 @@ const CommandDesc set_option_cmd = {
prefix_complete(params[0].substr(0_byte, pos_in_token), scopes) };
else if (token_to_complete == 1)
{
OptionManager& options = get_options(params[0], context);
OptionManager& options = get_scope(params[0], context).options();
return { 0_byte, params[1].length(),
options.complete_option_name(params[1], pos_in_token) };
}
else if (token_to_complete == 2 and
GlobalOptions::instance().option_exists(params[1]))
GlobalScope::instance().option_registry().option_exists(params[1]))
{
OptionManager& options = get_options(params[0], context);
OptionManager& options = get_scope(params[0], context).options();
String val = options[params[1]].get_as_string();
if (prefix_match(val, params[2]))
return { 0_byte, params[2].length(), { std::move(val) } };
@ -879,7 +857,7 @@ const CommandDesc set_option_cmd = {
},
[](const ParametersParser& parser, Context& context)
{
Option& opt = get_options(parser[0], context).get_local_option(parser[1]);
Option& opt = get_scope(parser[0], context).options().get_local_option(parser[1]);
if (parser.has_option("add"))
opt.add_from_string(parser[2]);
else
@ -920,22 +898,22 @@ const CommandDesc declare_option_cmd = {
if (parser.has_option("docstring"))
docstring = parser.option_value("docstring");
GlobalOptions& opts = GlobalOptions::instance();
OptionsRegistry& reg = GlobalScope::instance().option_registry();
if (parser[0] == "int")
opt = &opts.declare_option<int>(parser[1], docstring, 0, flags);
opt = &reg.declare_option<int>(parser[1], docstring, 0, flags);
else if (parser[0] == "bool")
opt = &opts.declare_option<bool>(parser[1], docstring, 0, flags);
opt = &reg.declare_option<bool>(parser[1], docstring, 0, flags);
else if (parser[0] == "str")
opt = &opts.declare_option<String>(parser[1], docstring, "", flags);
opt = &reg.declare_option<String>(parser[1], docstring, "", flags);
else if (parser[0] == "regex")
opt = &opts.declare_option<Regex>(parser[1], docstring, Regex{}, flags);
opt = &reg.declare_option<Regex>(parser[1], docstring, Regex{}, flags);
else if (parser[0] == "int-list")
opt = &opts.declare_option<std::vector<int>>(parser[1], docstring, {}, flags);
opt = &reg.declare_option<std::vector<int>>(parser[1], docstring, {}, flags);
else if (parser[0] == "str-list")
opt = &opts.declare_option<std::vector<String>>(parser[1], docstring, {}, flags);
opt = &reg.declare_option<std::vector<String>>(parser[1], docstring, {}, flags);
else if (parser[0] == "line-flag-list")
opt = &opts.declare_option<std::vector<LineAndFlag>>(parser[1], docstring, {}, flags);
opt = &reg.declare_option<std::vector<LineAndFlag>>(parser[1], docstring, {}, flags);
else
throw runtime_error("unknown type " + parser[0]);
@ -944,15 +922,6 @@ const CommandDesc declare_option_cmd = {
}
};
KeymapManager& get_keymap_manager(const String& scope, Context& context)
{
if (prefix_match("global", scope)) return GlobalKeymaps::instance();
if (prefix_match("buffer", scope)) return context.buffer().keymaps();
if (prefix_match("window", scope)) return context.window().keymaps();
throw runtime_error("error: no such keymap container " + scope);
}
KeymapMode parse_keymap_mode(const String& str)
{
if (prefix_match("normal", str)) return KeymapMode::Normal;
@ -997,7 +966,7 @@ const CommandDesc map_key_cmd = {
},
[](const ParametersParser& parser, Context& context)
{
KeymapManager& keymaps = get_keymap_manager(parser[0], context);
KeymapManager& keymaps = get_scope(parser[0], context).keymaps();
KeymapMode keymap_mode = parse_keymap_mode(parser[1]);
KeyList key = parse_keys(parser[2]);
@ -1419,7 +1388,7 @@ static void register_command(CommandManager& cm, const CommandDesc& c)
{
cm.register_command(c.name, c.func, c.docstring, c.params, c.flags, c.completer);
if (c.alias)
GlobalAliases::instance().add_alias(c.alias, c.name);
GlobalScope::instance().aliases().add_alias(c.alias, c.name);
}
void register_commands()

View File

@ -54,40 +54,33 @@ UserInterface& Context::ui() const
return client().ui();
}
OptionManager& Context::options() const
Scope& Context::scope() const
{
if (has_window())
return window().options();
return window();
if (has_buffer())
return buffer().options();
return GlobalOptions::instance();
return buffer();
return GlobalScope::instance();
}
OptionManager& Context::options() const
{
return scope().options();
}
HookManager& Context::hooks() const
{
if (has_window())
return window().hooks();
if (has_buffer())
return buffer().hooks();
return GlobalHooks::instance();
return scope().hooks();
}
KeymapManager& Context::keymaps() const
{
if (has_window())
return window().keymaps();
if (has_buffer())
return buffer().keymaps();
return GlobalKeymaps::instance();
return scope().keymaps();
}
AliasRegistry& Context::aliases() const
{
if (has_window())
return window().aliases();
if (has_buffer())
return buffer().aliases();
return GlobalAliases::instance();
return scope().aliases();
}
void Context::set_client(Client& client)

View File

@ -10,6 +10,7 @@ namespace Kakoune
class Window;
class Buffer;
class Client;
class Scope;
class InputHandler;
class UserInterface;
class DisplayLine;
@ -58,6 +59,8 @@ public:
void set_client(Client& client);
void set_window(Window& window);
Scope& scope() const;
OptionManager& options() const;
HookManager& hooks() const;
KeymapManager& keymaps() const;

View File

@ -395,7 +395,7 @@ HighlighterAndId create_regex_option_highlighter(HighlighterParameters params)
String option_name = params[0];
// verify option type now
GlobalOptions::instance()[option_name].get<Regex>();
GlobalScope::instance().options()[option_name].get<Regex>();
auto get_regex = [option_name](const Context& context){
return context.options()[option_name].get<Regex>();
@ -412,7 +412,7 @@ HighlighterAndId create_line_option_highlighter(HighlighterParameters params)
String option_name = params[0];
get_face(facespec); // validate facespec
GlobalOptions::instance()[option_name].get<int>(); // verify option type now
GlobalScope::instance().options()[option_name].get<int>(); // verify option type now
auto func = [=](const Context& context, HighlightFlags flags,
DisplayBuffer& display_buffer)
@ -645,7 +645,7 @@ HighlighterAndId create_flag_lines_highlighter(HighlighterParameters params)
Color bg = str_to_color(params[0]);
// throw if wrong option type
GlobalOptions::instance()[option_name].get<std::vector<LineAndFlag>>();
GlobalScope::instance().options()[option_name].get<std::vector<LineAndFlag>>();
auto func = [=](const Context& context, HighlightFlags flags,
DisplayBuffer& display_buffer)

View File

@ -27,17 +27,12 @@ private:
HookManager()
: m_parent(nullptr) {}
// the only one allowed to construct a root hook manager
friend class GlobalHooks;
friend class Scope;
HookManager* m_parent;
std::unordered_map<String, id_map<HookFunc>> m_hook;
};
class GlobalHooks : public HookManager,
public Singleton<GlobalHooks>
{
};
}
#endif // hook_manager_hh_INCLUDED

View File

@ -34,7 +34,7 @@ private:
KeymapManager()
: m_parent(nullptr) {}
// the only one allowed to construct a root map manager
friend class GlobalKeymaps;
friend class Scope;
KeymapManager* m_parent;
@ -43,11 +43,6 @@ private:
Keymap m_mapping;
};
class GlobalKeymaps : public KeymapManager,
public Singleton<GlobalKeymaps>
{
};
}
#endif // keymap_manager_hh_INCLUDED

View File

@ -1,5 +1,4 @@
#include "assert.hh"
#include "alias_registry.hh"
#include "buffer.hh"
#include "buffer_manager.hh"
#include "buffer_utils.hh"
@ -12,15 +11,14 @@
#include "face_registry.hh"
#include "file.hh"
#include "highlighters.hh"
#include "hook_manager.hh"
#include "keymap_manager.hh"
#include "ncurses.hh"
#include "option_manager.hh"
#include "parameters_parser.hh"
#include "register_manager.hh"
#include "remote.hh"
#include "shell_manager.hh"
#include "scope.hh"
#include "string.hh"
#include "insert_completer.hh"
#include "interned_string.hh"
#include "window.hh"
@ -187,6 +185,52 @@ void register_registers()
}
}
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("eolformat", "end of line format: 'crlf' or 'lf'", "lf"_str);
reg.declare_option("BOM", "insert a byte order mark when writing buffer",
"no"_str);
reg.declare_option("complete_prefix",
"complete up to common prefix in tab completion",
true);
reg.declare_option("incsearch",
"incrementaly apply search/select/split regex",
true);
reg.declare_option("autoinfo",
"automatically display contextual help",
1);
reg.declare_option("autoshowcompl",
"automatically display possible completions for prompts",
true);
reg.declare_option("aligntab",
"use tab characters when possible for alignement",
false);
reg.declare_option("ignored_files",
"patterns to ignore when completing filenames",
Regex{R"(^(\..*|.*\.(o|so|a))$)"});
reg.declare_option("disabled_hooks",
"patterns to disable hooks whose group is matched",
Regex{});
reg.declare_option("filetype", "buffer filetype", ""_str);
reg.declare_option("path", "path to consider when trying to find a file",
std::vector<String>({ "./", "/usr/include" }));
reg.declare_option("completers", "insert mode completers to execute.",
std::vector<InsertCompleterDesc>({
InsertCompleterDesc{ InsertCompleterDesc::Filename },
InsertCompleterDesc{ InsertCompleterDesc::Word, "all"_str }
}), OptionFlags::None);
reg.declare_option("autoreload",
"autoreload buffer when a filesystem modification is detected",
Ask);
}
void create_local_client(const String& init_command)
{
class LocalNCursesUI : public NCursesUI
@ -298,10 +342,7 @@ int run_server(StringView session, StringView init_command,
StringRegistry string_registry;
EventManager event_manager;
GlobalOptions global_options;
GlobalHooks global_hooks;
GlobalKeymaps global_keymaps;
GlobalAliases global_aliases;
GlobalScope global_scope;
ShellManager shell_manager;
CommandManager command_manager;
BufferManager buffer_manager;
@ -313,6 +354,7 @@ int run_server(StringView session, StringView init_command,
run_unit_tests();
register_options();
register_env_vars();
register_registers();
register_commands();
@ -339,7 +381,7 @@ int run_server(StringView session, StringView init_command,
{
Context empty_context;
global_hooks.run_hook("KakBegin", "", empty_context);
global_scope.hooks().run_hook("KakBegin", "", empty_context);
}
if (not files.empty()) try
@ -372,7 +414,7 @@ int run_server(StringView session, StringView init_command,
{
Context empty_context;
global_hooks.run_hook("KakEnd", "", empty_context);
global_scope.hooks().run_hook("KakEnd", "", empty_context);
}
return 0;
@ -381,14 +423,12 @@ int run_server(StringView session, StringView init_command,
int run_filter(StringView keystr, memoryview<StringView> files)
{
StringRegistry string_registry;
GlobalOptions global_options;
GlobalHooks global_hooks;
GlobalKeymaps global_keymaps;
GlobalAliases global_aliases;
GlobalScope global_scope;
ShellManager shell_manager;
BufferManager buffer_manager;
RegisterManager register_manager;
register_options();
register_env_vars();
register_registers();

View File

@ -1,11 +1,7 @@
#include "option_manager.hh"
#include "insert_completer.hh"
#include "assert.hh"
#include <sstream>
namespace Kakoune
{
@ -128,49 +124,4 @@ void OptionManager::on_option_changed(const Option& option)
watcher->on_option_changed(option);
}
GlobalOptions::GlobalOptions()
: OptionManager()
{
declare_option("tabstop", "size of a tab character", 8);
declare_option("indentwidth", "indentation width", 4);
declare_option("scrolloff",
"number of lines and columns to keep visible main cursor when scrolling",
CharCoord{0,0});
declare_option("eolformat", "end of line format: 'crlf' or 'lf'", "lf"_str);
declare_option("BOM", "insert a byte order mark when writing buffer",
"no"_str);
declare_option("complete_prefix",
"complete up to common prefix in tab completion",
true);
declare_option("incsearch",
"incrementaly apply search/select/split regex",
true);
declare_option("autoinfo",
"automatically display contextual help",
1);
declare_option("autoshowcompl",
"automatically display possible completions for prompts",
true);
declare_option("aligntab",
"use tab characters when possible for alignement",
false);
declare_option("ignored_files",
"patterns to ignore when completing filenames",
Regex{R"(^(\..*|.*\.(o|so|a))$)"});
declare_option("disabled_hooks",
"patterns to disable hooks whose group is matched",
Regex{});
declare_option("filetype", "buffer filetype", ""_str);
declare_option("path", "path to consider when trying to find a file",
std::vector<String>({ "./", "/usr/include" }));
declare_option("completers", "insert mode completers to execute.",
std::vector<InsertCompleterDesc>({
InsertCompleterDesc{ InsertCompleterDesc::Filename },
InsertCompleterDesc{ InsertCompleterDesc::Word, "all"_str }
}), OptionFlags::None);
declare_option("autoreload",
"autoreload buffer when a filesystem modification is detected",
Ask);
}
}

View File

@ -104,7 +104,8 @@ private:
OptionManager()
: m_parent(nullptr) {}
// the only one allowed to construct a root option manager
friend class GlobalOptions;
friend class Scope;
friend class OptionsRegistry;
template<typename MatchingFunc>
CandidateList get_matching_names(MatchingFunc func);
@ -186,34 +187,37 @@ auto find_option(T& container, const String& name) -> decltype(container.begin()
return find_if(container, [&name](const ptr_type& opt) { return opt->name() == name; });
}
class GlobalOptions : public OptionManager,
public Singleton<GlobalOptions>
class OptionsRegistry
{
public:
GlobalOptions();
OptionsRegistry(OptionManager& global_manager) : m_global_manager(global_manager) {}
template<typename T>
Option& declare_option(const String& name, const String& docstring,
const T& value,
OptionFlags flags = OptionFlags::None)
{
auto it = find_option(m_options, name);
if (it != m_options.end())
auto& opts = m_global_manager.m_options;
auto it = find_option(opts, name);
if (it != opts.end())
{
if ((*it)->is_of_type<T>() and (*it)->flags() == flags)
return **it;
throw runtime_error("option " + name + " already declared with different type or flags");
}
m_descs.emplace_back(new OptionDesc{name, docstring, flags});
m_options.emplace_back(new TypedOption<T>{*this, *m_descs.back(), value});
return *m_options.back();
opts.emplace_back(new TypedOption<T>{m_global_manager, *m_descs.back(), value});
return *opts.back();
}
bool option_exists(const String& name) const
{
return find_option(m_options, name) != m_options.end();
return find_if(m_descs, [&name](const std::unique_ptr<OptionDesc>& opt) {
return opt->name() == name;
}) != m_descs.end();
}
private:
OptionManager& m_global_manager;
std::vector<std::unique_ptr<OptionDesc>> m_descs;
};

53
src/scope.hh Normal file
View File

@ -0,0 +1,53 @@
#ifndef scope_hh_INCLUDED
#define scope_hh_INCLUDED
#include "alias_registry.hh"
#include "hook_manager.hh"
#include "keymap_manager.hh"
#include "option_manager.hh"
namespace Kakoune
{
class Scope
{
public:
Scope(Scope& parent)
: m_options(parent.options()),
m_hooks(parent.hooks()),
m_keymaps(parent.keymaps()),
m_aliases(parent.aliases()) {}
OptionManager& options() { return m_options; }
const OptionManager& options() const { return m_options; }
HookManager& hooks() { return m_hooks; }
const HookManager& hooks() const { return m_hooks; }
KeymapManager& keymaps() { return m_keymaps; }
const KeymapManager& keymaps() const { return m_keymaps; }
AliasRegistry& aliases() { return m_aliases; }
const AliasRegistry& aliases() const { return m_aliases; }
private:
friend class GlobalScope;
Scope() = default;
OptionManager m_options;
HookManager m_hooks;
KeymapManager m_keymaps;
AliasRegistry m_aliases;
};
class GlobalScope : public Scope, public Singleton<GlobalScope>
{
public:
GlobalScope() : m_option_registry(m_options) {}
OptionsRegistry& option_registry() { return m_option_registry; }
const OptionsRegistry& option_registry() const { return m_option_registry; }
private:
OptionsRegistry m_option_registry;
};
}
#endif // scope_hh_INCLUDED

View File

@ -18,22 +18,19 @@ void expand_tabulations(const Context& context, HighlightFlags flags, DisplayBuf
void expand_unprintable(const Context& context, HighlightFlags flags, DisplayBuffer& display_buffer);
Window::Window(Buffer& buffer)
: m_buffer(&buffer),
m_hooks(buffer.hooks()),
m_options(buffer.options()),
m_keymaps(buffer.keymaps()),
m_aliases(buffer.aliases())
: Scope(buffer),
m_buffer(&buffer)
{
InputHandler hook_handler{{ *m_buffer, Selection{} }};
hook_handler.context().set_window(*this);
m_hooks.run_hook("WinCreate", buffer.name(), hook_handler.context());
m_options.register_watcher(*this);
hooks().run_hook("WinCreate", buffer.name(), hook_handler.context());
options().register_watcher(*this);
m_builtin_highlighters.add_child({"tabulations"_str, make_simple_highlighter(expand_tabulations)});
m_builtin_highlighters.add_child({"unprintable"_str, make_simple_highlighter(expand_unprintable)});
m_builtin_highlighters.add_child({"selections"_str, make_simple_highlighter(highlight_selections)});
for (auto& option : m_options.flatten_options())
for (auto& option : options().flatten_options())
on_option_changed(*option);
}
@ -41,8 +38,8 @@ Window::~Window()
{
InputHandler hook_handler{{ *m_buffer, Selection{} }};
hook_handler.context().set_window(*this);
m_hooks.run_hook("WinClose", buffer().name(), hook_handler.context());
m_options.unregister_watcher(*this);
hooks().run_hook("WinClose", buffer().name(), hook_handler.context());
options().unregister_watcher(*this);
}
void Window::display_line_at(LineCount buffer_line, LineCount display_line)
@ -279,7 +276,7 @@ void Window::on_option_changed(const Option& option)
String desc = option.name() + "=" + option.get_as_string();
InputHandler hook_handler{{ *m_buffer, Selection{} }};
hook_handler.context().set_window(*this);
m_hooks.run_hook("WinSetOption", desc, hook_handler.context());
hooks().run_hook("WinSetOption", desc, hook_handler.context());
// an highlighter might depend on the option, so we need to redraw
forget_timestamp();

View File

@ -1,21 +1,18 @@
#ifndef window_hh_INCLUDED
#define window_hh_INCLUDED
#include "alias_registry.hh"
#include "completion.hh"
#include "display_buffer.hh"
#include "highlighter_group.hh"
#include "selection.hh"
#include "hook_manager.hh"
#include "option_manager.hh"
#include "keymap_manager.hh"
#include "safe_ptr.hh"
#include "scope.hh"
namespace Kakoune
{
// A Window is a view onto a Buffer
class Window : public SafeCountable, public OptionManagerWatcher
class Window : public SafeCountable, public OptionManagerWatcher, public Scope
{
public:
Window(Buffer& buffer);
@ -39,15 +36,6 @@ public:
Highlighter& highlighters() { return m_highlighters; }
OptionManager& options() { return m_options; }
const OptionManager& options() const { return m_options; }
HookManager& hooks() { return m_hooks; }
const HookManager& hooks() const { return m_hooks; }
KeymapManager& keymaps() { return m_keymaps; }
const KeymapManager& keymaps() const { return m_keymaps; }
AliasRegistry& aliases() { return m_aliases; }
const AliasRegistry& aliases() const { return m_aliases; }
Buffer& buffer() const { return *m_buffer; }
size_t timestamp() const { return m_timestamp; }
@ -67,11 +55,6 @@ private:
CharCoord m_dimensions;
DisplayBuffer m_display_buffer;
HookManager m_hooks;
OptionManager m_options;
KeymapManager m_keymaps;
AliasRegistry m_aliases;
HighlighterGroup m_highlighters;
HighlighterGroup m_builtin_highlighters;