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; std::vector<StringView> aliases_for(StringView command) const;
private: private:
friend class GlobalAliases; friend class Scope;
AliasRegistry() {} AliasRegistry() {}
safe_ptr<AliasRegistry> m_parent; safe_ptr<AliasRegistry> m_parent;
std::unordered_map<String, String> m_aliases; std::unordered_map<String, String> m_aliases;
}; };
class GlobalAliases : public AliasRegistry, public Singleton<GlobalAliases>
{};
} }
#endif // alias_registry_hh_INCLUDED #endif // alias_registry_hh_INCLUDED

View File

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

View File

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

View File

@ -84,6 +84,26 @@ const ParameterDesc single_optional_name_param{
static constexpr auto scopes = { "global", "buffer", "window" }; 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 struct CommandDesc
{ {
const char* name; 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 = { const CommandDesc add_hook_cmd = {
"hook", "hook",
nullptr, nullptr,
@ -557,14 +559,14 @@ const CommandDesc add_hook_cmd = {
StringView group; StringView group;
if (parser.has_option("group")) if (parser.has_option("group"))
group = parser.option_value("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 = { const CommandDesc rm_hook_cmd = {
"rmhooks", "rmhooks",
nullptr, 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 }, ParameterDesc{ SwitchMap{}, ParameterDesc::Flags::None, 2, 2 },
CommandFlags::None, CommandFlags::None,
[](const Context& context, CompletionFlags flags, [](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) }; prefix_complete(params[0].substr(0_byte, pos_in_token), scopes) };
else if (token_to_complete == 1) 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(), 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 {}; return {};
}, },
[](const ParametersParser& parser, Context& context) [](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 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 = { const CommandDesc alias_cmd = {
"alias", "alias",
nullptr, nullptr,
@ -732,7 +723,7 @@ const CommandDesc alias_cmd = {
CommandCompleter{}, CommandCompleter{},
[](const ParametersParser& parser, Context& context) [](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]); aliases.add_alias(parser[1], parser[2]);
} }
}; };
@ -747,7 +738,7 @@ const CommandDesc unalias_cmd = {
CommandCompleter{}, CommandCompleter{},
[](const ParametersParser& parser, Context& context) [](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 if (parser.positional_count() == 3 and
aliases[parser[1]] != parser[2]) aliases[parser[1]] != parser[2])
return; 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 = { const CommandDesc set_option_cmd = {
"set", "set",
nullptr, nullptr,
@ -863,14 +841,14 @@ const CommandDesc set_option_cmd = {
prefix_complete(params[0].substr(0_byte, pos_in_token), scopes) }; prefix_complete(params[0].substr(0_byte, pos_in_token), scopes) };
else if (token_to_complete == 1) 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(), return { 0_byte, params[1].length(),
options.complete_option_name(params[1], pos_in_token) }; options.complete_option_name(params[1], pos_in_token) };
} }
else if (token_to_complete == 2 and 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(); String val = options[params[1]].get_as_string();
if (prefix_match(val, params[2])) if (prefix_match(val, params[2]))
return { 0_byte, params[2].length(), { std::move(val) } }; return { 0_byte, params[2].length(), { std::move(val) } };
@ -879,7 +857,7 @@ const CommandDesc set_option_cmd = {
}, },
[](const ParametersParser& parser, Context& context) [](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")) if (parser.has_option("add"))
opt.add_from_string(parser[2]); opt.add_from_string(parser[2]);
else else
@ -920,22 +898,22 @@ const CommandDesc declare_option_cmd = {
if (parser.has_option("docstring")) if (parser.has_option("docstring"))
docstring = parser.option_value("docstring"); docstring = parser.option_value("docstring");
GlobalOptions& opts = GlobalOptions::instance(); OptionsRegistry& reg = GlobalScope::instance().option_registry();
if (parser[0] == "int") 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") 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") 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") 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") 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") 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") 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 else
throw runtime_error("unknown type " + parser[0]); 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) KeymapMode parse_keymap_mode(const String& str)
{ {
if (prefix_match("normal", str)) return KeymapMode::Normal; if (prefix_match("normal", str)) return KeymapMode::Normal;
@ -997,7 +966,7 @@ const CommandDesc map_key_cmd = {
}, },
[](const ParametersParser& parser, Context& context) [](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]); KeymapMode keymap_mode = parse_keymap_mode(parser[1]);
KeyList key = parse_keys(parser[2]); 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); cm.register_command(c.name, c.func, c.docstring, c.params, c.flags, c.completer);
if (c.alias) if (c.alias)
GlobalAliases::instance().add_alias(c.alias, c.name); GlobalScope::instance().aliases().add_alias(c.alias, c.name);
} }
void register_commands() void register_commands()

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,5 +1,4 @@
#include "assert.hh" #include "assert.hh"
#include "alias_registry.hh"
#include "buffer.hh" #include "buffer.hh"
#include "buffer_manager.hh" #include "buffer_manager.hh"
#include "buffer_utils.hh" #include "buffer_utils.hh"
@ -12,15 +11,14 @@
#include "face_registry.hh" #include "face_registry.hh"
#include "file.hh" #include "file.hh"
#include "highlighters.hh" #include "highlighters.hh"
#include "hook_manager.hh"
#include "keymap_manager.hh"
#include "ncurses.hh" #include "ncurses.hh"
#include "option_manager.hh"
#include "parameters_parser.hh" #include "parameters_parser.hh"
#include "register_manager.hh" #include "register_manager.hh"
#include "remote.hh" #include "remote.hh"
#include "shell_manager.hh" #include "shell_manager.hh"
#include "scope.hh"
#include "string.hh" #include "string.hh"
#include "insert_completer.hh"
#include "interned_string.hh" #include "interned_string.hh"
#include "window.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) void create_local_client(const String& init_command)
{ {
class LocalNCursesUI : public NCursesUI class LocalNCursesUI : public NCursesUI
@ -298,10 +342,7 @@ int run_server(StringView session, StringView init_command,
StringRegistry string_registry; StringRegistry string_registry;
EventManager event_manager; EventManager event_manager;
GlobalOptions global_options; GlobalScope global_scope;
GlobalHooks global_hooks;
GlobalKeymaps global_keymaps;
GlobalAliases global_aliases;
ShellManager shell_manager; ShellManager shell_manager;
CommandManager command_manager; CommandManager command_manager;
BufferManager buffer_manager; BufferManager buffer_manager;
@ -313,6 +354,7 @@ int run_server(StringView session, StringView init_command,
run_unit_tests(); run_unit_tests();
register_options();
register_env_vars(); register_env_vars();
register_registers(); register_registers();
register_commands(); register_commands();
@ -339,7 +381,7 @@ int run_server(StringView session, StringView init_command,
{ {
Context empty_context; Context empty_context;
global_hooks.run_hook("KakBegin", "", empty_context); global_scope.hooks().run_hook("KakBegin", "", empty_context);
} }
if (not files.empty()) try if (not files.empty()) try
@ -372,7 +414,7 @@ int run_server(StringView session, StringView init_command,
{ {
Context empty_context; Context empty_context;
global_hooks.run_hook("KakEnd", "", empty_context); global_scope.hooks().run_hook("KakEnd", "", empty_context);
} }
return 0; return 0;
@ -381,14 +423,12 @@ int run_server(StringView session, StringView init_command,
int run_filter(StringView keystr, memoryview<StringView> files) int run_filter(StringView keystr, memoryview<StringView> files)
{ {
StringRegistry string_registry; StringRegistry string_registry;
GlobalOptions global_options; GlobalScope global_scope;
GlobalHooks global_hooks;
GlobalKeymaps global_keymaps;
GlobalAliases global_aliases;
ShellManager shell_manager; ShellManager shell_manager;
BufferManager buffer_manager; BufferManager buffer_manager;
RegisterManager register_manager; RegisterManager register_manager;
register_options();
register_env_vars(); register_env_vars();
register_registers(); register_registers();

View File

@ -1,11 +1,7 @@
#include "option_manager.hh" #include "option_manager.hh"
#include "insert_completer.hh"
#include "assert.hh" #include "assert.hh"
#include <sstream>
namespace Kakoune namespace Kakoune
{ {
@ -128,49 +124,4 @@ void OptionManager::on_option_changed(const Option& option)
watcher->on_option_changed(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() 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 GlobalOptions; friend class Scope;
friend class OptionsRegistry;
template<typename MatchingFunc> template<typename MatchingFunc>
CandidateList get_matching_names(MatchingFunc func); 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; }); return find_if(container, [&name](const ptr_type& opt) { return opt->name() == name; });
} }
class GlobalOptions : public OptionManager, class OptionsRegistry
public Singleton<GlobalOptions>
{ {
public: public:
GlobalOptions(); OptionsRegistry(OptionManager& global_manager) : m_global_manager(global_manager) {}
template<typename T> template<typename T>
Option& declare_option(const String& name, const String& docstring, Option& declare_option(const String& name, const String& docstring,
const T& value, const T& value,
OptionFlags flags = OptionFlags::None) OptionFlags flags = OptionFlags::None)
{ {
auto it = find_option(m_options, name); auto& opts = m_global_manager.m_options;
if (it != m_options.end()) auto it = find_option(opts, name);
if (it != opts.end())
{ {
if ((*it)->is_of_type<T>() and (*it)->flags() == flags) if ((*it)->is_of_type<T>() and (*it)->flags() == flags)
return **it; return **it;
throw runtime_error("option " + name + " already declared with different type or flags"); throw runtime_error("option " + name + " already declared with different type or flags");
} }
m_descs.emplace_back(new OptionDesc{name, docstring, flags}); m_descs.emplace_back(new OptionDesc{name, docstring, flags});
m_options.emplace_back(new TypedOption<T>{*this, *m_descs.back(), value}); opts.emplace_back(new TypedOption<T>{m_global_manager, *m_descs.back(), value});
return *m_options.back(); return *opts.back();
} }
bool option_exists(const String& name) const 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: private:
OptionManager& m_global_manager;
std::vector<std::unique_ptr<OptionDesc>> m_descs; 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); void expand_unprintable(const Context& context, HighlightFlags flags, DisplayBuffer& display_buffer);
Window::Window(Buffer& buffer) Window::Window(Buffer& buffer)
: m_buffer(&buffer), : Scope(buffer),
m_hooks(buffer.hooks()), m_buffer(&buffer)
m_options(buffer.options()),
m_keymaps(buffer.keymaps()),
m_aliases(buffer.aliases())
{ {
InputHandler hook_handler{{ *m_buffer, Selection{} }}; InputHandler hook_handler{{ *m_buffer, Selection{} }};
hook_handler.context().set_window(*this); hook_handler.context().set_window(*this);
m_hooks.run_hook("WinCreate", buffer.name(), hook_handler.context()); hooks().run_hook("WinCreate", buffer.name(), hook_handler.context());
m_options.register_watcher(*this); options().register_watcher(*this);
m_builtin_highlighters.add_child({"tabulations"_str, make_simple_highlighter(expand_tabulations)}); 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({"unprintable"_str, make_simple_highlighter(expand_unprintable)});
m_builtin_highlighters.add_child({"selections"_str, make_simple_highlighter(highlight_selections)}); 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); on_option_changed(*option);
} }
@ -41,8 +38,8 @@ Window::~Window()
{ {
InputHandler hook_handler{{ *m_buffer, Selection{} }}; InputHandler hook_handler{{ *m_buffer, Selection{} }};
hook_handler.context().set_window(*this); hook_handler.context().set_window(*this);
m_hooks.run_hook("WinClose", buffer().name(), hook_handler.context()); hooks().run_hook("WinClose", buffer().name(), hook_handler.context());
m_options.unregister_watcher(*this); options().unregister_watcher(*this);
} }
void Window::display_line_at(LineCount buffer_line, LineCount display_line) 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(); String desc = option.name() + "=" + option.get_as_string();
InputHandler hook_handler{{ *m_buffer, Selection{} }}; InputHandler hook_handler{{ *m_buffer, Selection{} }};
hook_handler.context().set_window(*this); 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 // an highlighter might depend on the option, so we need to redraw
forget_timestamp(); forget_timestamp();

View File

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