summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMaxime Coste <mawww@kakoune.org>2019-04-25 11:59:42 +0100
committerMaxime Coste <mawww@kakoune.org>2019-04-25 11:59:42 +0100
commit0cc89b2b9f3cdeff960bd55a865ee0f52fa98d25 (patch)
treebd4860272e271f215e4d9ba7d2049be9f44ac211 /src
parent429eeb252c6e7ac8512c2bd98ed3b18c62d7f37b (diff)
parentf49644e8ee8b2450f28b82d74fcf823d81f2ae1c (diff)
Merge remote-tracking branch 'laelath/provides-requires'
Diffstat (limited to 'src')
-rw-r--r--src/command_manager.cc30
-rw-r--r--src/command_manager.hh14
-rw-r--r--src/commands.cc42
-rw-r--r--src/hook_manager.hh6
4 files changed, 90 insertions, 2 deletions
diff --git a/src/command_manager.cc b/src/command_manager.cc
index 5e8c8196..1fdfa34d 100644
--- a/src/command_manager.cc
+++ b/src/command_manager.cc
@@ -40,6 +40,36 @@ void CommandManager::register_command(String command_name,
std::move(completer) };
}
+bool CommandManager::module_defined(StringView module_name) const
+{
+ return m_modules.find(module_name) != m_modules.end();
+}
+
+void CommandManager::register_module(String module_name, String commands)
+{
+ auto module = m_modules.find(module_name);
+ if (module != m_modules.end() and module->value.loaded)
+ throw runtime_error{format("module already loaded: '{}'", module_name)};
+
+ m_modules[module_name] = { false, std::move(commands) };
+}
+
+void CommandManager::load_module(StringView module_name, Context& context)
+{
+ auto module = m_modules.find(module_name);
+ if (module == m_modules.end())
+ throw runtime_error{format("no such module: '{}'", module_name)};
+ if (module->value.loaded)
+ return;
+
+ module->value.loaded = true;
+ Context empty_context{Context::EmptyContextFlag{}};
+ execute(module->value.commands, empty_context);
+ module->value.commands.clear();
+
+ context.hooks().run_hook(Hook::ModuleLoad, module_name, context);
+}
+
struct parse_error : runtime_error
{
parse_error(StringView error)
diff --git a/src/command_manager.hh b/src/command_manager.hh
index 0468a1fc..329c24f2 100644
--- a/src/command_manager.hh
+++ b/src/command_manager.hh
@@ -123,6 +123,12 @@ public:
void clear_last_complete_command() { m_last_complete_command = String{}; }
+ bool module_defined(StringView module_name) const;
+
+ void register_module(String module_name, String commands);
+
+ void load_module(StringView module_name, Context& context);
+
private:
void execute_single_command(CommandParameters params,
Context& context,
@@ -143,6 +149,14 @@ private:
String m_last_complete_command;
int m_command_depth = 0;
+ struct Module
+ {
+ bool loaded;
+ String commands;
+ };
+ using ModuleMap = HashMap<String, Module, MemoryDomain::Commands>;
+ ModuleMap m_modules;
+
CommandMap::const_iterator find_command(const Context& context,
StringView name) const;
};
diff --git a/src/commands.cc b/src/commands.cc
index 559fe90b..51adb80c 100644
--- a/src/commands.cc
+++ b/src/commands.cc
@@ -2403,6 +2403,46 @@ const CommandDesc enter_user_mode_cmd = {
}
};
+const CommandDesc provide_module_cmd = {
+ "provide-module",
+ nullptr,
+ "provide-module [<switches>] <name> <cmds>: declares a module <name> provided by <cmds>",
+ ParameterDesc{
+ { { "override", { false, "allow overriding an existing module" } } },
+ ParameterDesc::Flags::None,
+ 2, 2
+ },
+ CommandFlags::None,
+ CommandHelper{},
+ CommandCompleter{},
+ [](const ParametersParser& parser, Context& context, const ShellContext&)
+ {
+ const String& module_name = parser[0];
+ auto& cm = CommandManager::instance();
+
+ if (not all_of(module_name, is_identifier))
+ throw runtime_error(format("invalid module name: '{}'", module_name));
+
+ if (cm.module_defined(module_name) and not parser.get_switch("override"))
+ throw runtime_error(format("module '{}' already defined", module_name));
+ cm.register_module(module_name, parser[1]);
+ }
+};
+
+const CommandDesc require_module_cmd = {
+ "require-module",
+ nullptr,
+ "require-module <name>: ensures that <name> module has been loaded",
+ ParameterDesc{ {}, ParameterDesc::Flags::None, 1, 1 },
+ CommandFlags::None,
+ CommandHelper{},
+ CommandCompleter{},
+ [](const ParametersParser& parser, Context& context, const ShellContext&)
+ {
+ CommandManager::instance().load_module(parser[0], context);
+ }
+};
+
}
void register_commands()
@@ -2468,6 +2508,8 @@ void register_commands()
register_command(fail_cmd);
register_command(declare_user_mode_cmd);
register_command(enter_user_mode_cmd);
+ register_command(provide_module_cmd);
+ register_command(require_module_cmd);
}
}
diff --git a/src/hook_manager.hh b/src/hook_manager.hh
index 909d24bc..f1e6667b 100644
--- a/src/hook_manager.hh
+++ b/src/hook_manager.hh
@@ -56,12 +56,13 @@ enum class Hook
WinCreate,
WinDisplay,
WinResize,
- WinSetOption
+ WinSetOption,
+ ModuleLoad
};
constexpr auto enum_desc(Meta::Type<Hook>)
{
- return make_array<EnumDesc<Hook>, 40>({
+ return make_array<EnumDesc<Hook>, 41>({
{Hook::BufCreate, "BufCreate"},
{Hook::BufNewFile, "BufNewFile"},
{Hook::BufOpenFile, "BufOpenFile"},
@@ -102,6 +103,7 @@ constexpr auto enum_desc(Meta::Type<Hook>)
{Hook::WinDisplay, "WinDisplay"},
{Hook::WinResize, "WinResize"},
{Hook::WinSetOption, "WinSetOption"},
+ {Hook::ModuleLoad, "ModuleLoad"}
});
}