From e38ba6ce3d62c2629ebdaad41258d5e4b48f5296 Mon Sep 17 00:00:00 2001 From: Maxime Coste Date: Thu, 30 Oct 2014 14:00:42 +0000 Subject: [PATCH] Add scope class and encapsulate Options, Keymaps, Aliases and Hooks in it --- src/alias_registry.hh | 5 +- src/buffer.cc | 17 +++---- src/buffer.hh | 21 +------- src/commands.cc | 113 +++++++++++++++--------------------------- src/context.cc | 31 +++++------- src/context.hh | 3 ++ src/highlighters.cc | 6 +-- src/hook_manager.hh | 7 +-- src/keymap_manager.hh | 7 +-- src/main.cc | 68 +++++++++++++++++++------ src/option_manager.cc | 49 ------------------ src/option_manager.hh | 22 ++++---- src/scope.hh | 53 ++++++++++++++++++++ src/window.cc | 19 +++---- src/window.hh | 21 +------- 15 files changed, 201 insertions(+), 241 deletions(-) create mode 100644 src/scope.hh diff --git a/src/alias_registry.hh b/src/alias_registry.hh index 97f52ee3..ae879eef 100644 --- a/src/alias_registry.hh +++ b/src/alias_registry.hh @@ -21,16 +21,13 @@ public: std::vector aliases_for(StringView command) const; private: - friend class GlobalAliases; + friend class Scope; AliasRegistry() {} safe_ptr m_parent; std::unordered_map m_aliases; }; -class GlobalAliases : public AliasRegistry, public Singleton -{}; - } #endif // alias_registry_hh_INCLUDED diff --git a/src/buffer.cc b/src/buffer.cc index 9bdc76df..6956c121 100644 --- a/src/buffer.cc +++ b/src/buffer.cc @@ -16,18 +16,15 @@ namespace Kakoune Buffer::Buffer(String name, Flags flags, std::vector 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 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 diff --git a/src/buffer.hh b/src/buffer.hh index 63b2e7cd..4715ddc1 100644 --- a/src/buffer.hh +++ b/src/buffer.hh @@ -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; diff --git a/src/commands.cc b/src/commands.cc index 9bb6d8e1..240daea1 100644 --- a/src/commands.cc +++ b/src/commands.cc @@ -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 : remove all hooks whose group is ", + "rmhooks : remove all hooks whose group is ", 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(parser[1], docstring, 0, flags); + opt = ®.declare_option(parser[1], docstring, 0, flags); else if (parser[0] == "bool") - opt = &opts.declare_option(parser[1], docstring, 0, flags); + opt = ®.declare_option(parser[1], docstring, 0, flags); else if (parser[0] == "str") - opt = &opts.declare_option(parser[1], docstring, "", flags); + opt = ®.declare_option(parser[1], docstring, "", flags); else if (parser[0] == "regex") - opt = &opts.declare_option(parser[1], docstring, Regex{}, flags); + opt = ®.declare_option(parser[1], docstring, Regex{}, flags); else if (parser[0] == "int-list") - opt = &opts.declare_option>(parser[1], docstring, {}, flags); + opt = ®.declare_option>(parser[1], docstring, {}, flags); else if (parser[0] == "str-list") - opt = &opts.declare_option>(parser[1], docstring, {}, flags); + opt = ®.declare_option>(parser[1], docstring, {}, flags); else if (parser[0] == "line-flag-list") - opt = &opts.declare_option>(parser[1], docstring, {}, flags); + opt = ®.declare_option>(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() diff --git a/src/context.cc b/src/context.cc index 883df5ee..4c72c2bf 100644 --- a/src/context.cc +++ b/src/context.cc @@ -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) diff --git a/src/context.hh b/src/context.hh index ad54773f..cd7abb23 100644 --- a/src/context.hh +++ b/src/context.hh @@ -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; diff --git a/src/highlighters.cc b/src/highlighters.cc index 8acd83c8..be795e4f 100644 --- a/src/highlighters.cc +++ b/src/highlighters.cc @@ -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(); + GlobalScope::instance().options()[option_name].get(); auto get_regex = [option_name](const Context& context){ return context.options()[option_name].get(); @@ -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(); // verify option type now + GlobalScope::instance().options()[option_name].get(); // 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>(); + GlobalScope::instance().options()[option_name].get>(); auto func = [=](const Context& context, HighlightFlags flags, DisplayBuffer& display_buffer) diff --git a/src/hook_manager.hh b/src/hook_manager.hh index dd1c6eeb..21aade05 100644 --- a/src/hook_manager.hh +++ b/src/hook_manager.hh @@ -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> m_hook; }; -class GlobalHooks : public HookManager, - public Singleton -{ -}; - } #endif // hook_manager_hh_INCLUDED diff --git a/src/keymap_manager.hh b/src/keymap_manager.hh index 489ad301..6521f69c 100644 --- a/src/keymap_manager.hh +++ b/src/keymap_manager.hh @@ -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 -{ -}; - } #endif // keymap_manager_hh_INCLUDED diff --git a/src/main.cc b/src/main.cc index 4402d53c..f6154404 100644 --- a/src/main.cc +++ b/src/main.cc @@ -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({ "./", "/usr/include" })); + reg.declare_option("completers", "insert mode completers to execute.", + std::vector({ + 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 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(); diff --git a/src/option_manager.cc b/src/option_manager.cc index 8b7c2f76..5330e05a 100644 --- a/src/option_manager.cc +++ b/src/option_manager.cc @@ -1,11 +1,7 @@ #include "option_manager.hh" -#include "insert_completer.hh" - #include "assert.hh" -#include - 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({ "./", "/usr/include" })); - declare_option("completers", "insert mode completers to execute.", - std::vector({ - InsertCompleterDesc{ InsertCompleterDesc::Filename }, - InsertCompleterDesc{ InsertCompleterDesc::Word, "all"_str } - }), OptionFlags::None); - declare_option("autoreload", - "autoreload buffer when a filesystem modification is detected", - Ask); -} - } diff --git a/src/option_manager.hh b/src/option_manager.hh index 00cd0370..058c8ea6 100644 --- a/src/option_manager.hh +++ b/src/option_manager.hh @@ -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 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 +class OptionsRegistry { public: - GlobalOptions(); + OptionsRegistry(OptionManager& global_manager) : m_global_manager(global_manager) {} template 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() 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{*this, *m_descs.back(), value}); - return *m_options.back(); + opts.emplace_back(new TypedOption{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& opt) { + return opt->name() == name; + }) != m_descs.end(); } private: + OptionManager& m_global_manager; std::vector> m_descs; }; diff --git a/src/scope.hh b/src/scope.hh new file mode 100644 index 00000000..0fb99f8d --- /dev/null +++ b/src/scope.hh @@ -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 +{ + 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 diff --git a/src/window.cc b/src/window.cc index 5adf685c..c7eaf686 100644 --- a/src/window.cc +++ b/src/window.cc @@ -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(); diff --git a/src/window.hh b/src/window.hh index 8a51ad4a..e2bb91b1 100644 --- a/src/window.hh +++ b/src/window.hh @@ -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;