|
|
@@ -43,13 +43,22 @@ CommandSystem::CommandSystem(EditorCore& core, MinibufferManager& minibuffer_man
|
|
|
}
|
|
|
|
|
|
void CommandSystem::register_command(const std::string& name, CommandFunction function,
|
|
|
- const std::string& doc_string, bool interactive, std::string interactive_spec) {
|
|
|
- // Check if command already exists
|
|
|
- if (commands_.count(name)) {
|
|
|
- // Log a warning or throw an error if overriding is not allowed
|
|
|
- // For now, new registration simply overwrites old one
|
|
|
+ const std::string& doc_string, bool interactive,
|
|
|
+ std::string interactive_spec, std::vector<std::string> aliases) {
|
|
|
+ // If the canonical command already exists, overwrite it.
|
|
|
+ commands_.insert_or_assign(name, Command(name, std::move(function), doc_string, interactive, std::move(interactive_spec), aliases));
|
|
|
+
|
|
|
+ // Register aliases
|
|
|
+ for (const auto& alias : aliases) {
|
|
|
+ // If an alias name clashes with an existing canonical command, prioritize the canonical command.
|
|
|
+ // Otherwise, map the alias to the canonical command name.
|
|
|
+ if (commands_.find(alias) == commands_.end()) {
|
|
|
+ alias_map_[alias] = name;
|
|
|
+ } else {
|
|
|
+ std::cerr << "[WARNING] Alias '" << alias << "' for command '" << name
|
|
|
+ << "' conflicts with existing canonical command. Alias ignored." << std::endl;
|
|
|
+ }
|
|
|
}
|
|
|
- commands_.emplace(name, Command(name, std::move(function), doc_string, interactive, std::move(interactive_spec)));
|
|
|
}
|
|
|
|
|
|
// Helper to split interactive_spec string into individual specifiers
|
|
|
@@ -131,34 +140,47 @@ CommandResult CommandSystem::process_next_interactive_argument() {
|
|
|
|
|
|
|
|
|
CommandResult CommandSystem::execute(const std::string& name, const std::vector<std::string>& args) {
|
|
|
- auto it = commands_.find(name);
|
|
|
+ std::string canonical_name = name;
|
|
|
+ auto alias_it = alias_map_.find(name);
|
|
|
+ if (alias_it != alias_map_.end()) {
|
|
|
+ canonical_name = alias_it->second;
|
|
|
+ }
|
|
|
+
|
|
|
+ auto it = commands_.find(canonical_name);
|
|
|
if (it != commands_.end()) {
|
|
|
try {
|
|
|
// For non-interactive execution, create a context with provided args
|
|
|
CommandContext context(core_, minibuffer_manager_, args); // Pass core_ as ICommandTarget&
|
|
|
return it->second.function(context);
|
|
|
} catch (const std::exception& e) {
|
|
|
- return {CommandStatus::Failure, "Command '" + name + "' failed: " + e.what()};
|
|
|
+ return {CommandStatus::Failure, "Command '" + canonical_name + "' failed: " + e.what()};
|
|
|
} catch (...) {
|
|
|
- return {CommandStatus::Failure, "Command '" + name + "' failed with unknown error."};
|
|
|
+ return {CommandStatus::Failure, "Command '" + canonical_name + "' failed with unknown error."};
|
|
|
}
|
|
|
}
|
|
|
- return {CommandStatus::Failure, "Unknown command: " + name};
|
|
|
+ return {CommandStatus::Failure, "Unknown command or alias: " + name};
|
|
|
}
|
|
|
|
|
|
CommandResult CommandSystem::execute_interactive(const std::string& name) {
|
|
|
+ // Resolve alias to canonical name first
|
|
|
+ std::string canonical_name = name;
|
|
|
+ auto alias_it = alias_map_.find(name);
|
|
|
+ if (alias_it != alias_map_.end()) {
|
|
|
+ canonical_name = alias_it->second;
|
|
|
+ }
|
|
|
+
|
|
|
// If an interactive command is already pending, we shouldn't start a new one.
|
|
|
// This is a simplification; a more robust system might queue or disallow.
|
|
|
if (current_interactive_command_) {
|
|
|
return {CommandStatus::Failure, "Another interactive command is already pending input."};
|
|
|
}
|
|
|
|
|
|
- auto it = commands_.find(name);
|
|
|
+ auto it = commands_.find(canonical_name);
|
|
|
if (it == commands_.end()) {
|
|
|
- return {CommandStatus::Failure, "Unknown command: " + name};
|
|
|
+ return {CommandStatus::Failure, "Unknown command or alias: " + name};
|
|
|
}
|
|
|
if (!it->second.interactive) {
|
|
|
- return {CommandStatus::Failure, "Command '" + name + "' is not interactive."};
|
|
|
+ return {CommandStatus::Failure, "Command '" + canonical_name + "' is not interactive."};
|
|
|
}
|
|
|
if (it->second.interactive_spec.empty()) {
|
|
|
// If interactive but no spec, just execute directly (no args, or uses default)
|
|
|
@@ -176,16 +198,25 @@ CommandResult CommandSystem::execute_interactive(const std::string& name) {
|
|
|
|
|
|
std::vector<std::string> CommandSystem::get_command_names() const {
|
|
|
std::vector<std::string> names;
|
|
|
- names.reserve(commands_.size());
|
|
|
+ names.reserve(commands_.size() + alias_map_.size());
|
|
|
for (const auto& pair : commands_) {
|
|
|
names.push_back(pair.first);
|
|
|
}
|
|
|
+ for (const auto& pair : alias_map_) {
|
|
|
+ names.push_back(pair.first);
|
|
|
+ }
|
|
|
std::sort(names.begin(), names.end());
|
|
|
return names;
|
|
|
}
|
|
|
|
|
|
std::optional<std::string> CommandSystem::get_command_doc_string(const std::string& name) const {
|
|
|
- auto it = commands_.find(name);
|
|
|
+ std::string canonical_name = name;
|
|
|
+ auto alias_it = alias_map_.find(name);
|
|
|
+ if (alias_it != alias_map_.end()) {
|
|
|
+ canonical_name = alias_it->second;
|
|
|
+ }
|
|
|
+
|
|
|
+ auto it = commands_.find(canonical_name);
|
|
|
if (it != commands_.end()) {
|
|
|
return it->second.doc_string;
|
|
|
}
|
|
|
@@ -193,7 +224,13 @@ std::optional<std::string> CommandSystem::get_command_doc_string(const std::stri
|
|
|
}
|
|
|
|
|
|
std::optional<std::string> CommandSystem::get_command_interactive_spec(const std::string& name) const {
|
|
|
- auto it = commands_.find(name);
|
|
|
+ std::string canonical_name = name;
|
|
|
+ auto alias_it = alias_map_.find(name);
|
|
|
+ if (alias_it != alias_map_.end()) {
|
|
|
+ canonical_name = alias_it->second;
|
|
|
+ }
|
|
|
+
|
|
|
+ auto it = commands_.find(canonical_name);
|
|
|
if (it != commands_.end()) {
|
|
|
if (it->second.interactive) {
|
|
|
return it->second.interactive_spec;
|
|
|
@@ -202,4 +239,4 @@ std::optional<std::string> CommandSystem::get_command_interactive_spec(const std
|
|
|
return std::nullopt;
|
|
|
}
|
|
|
|
|
|
-} // namespace lumacs
|
|
|
+} // namespace lumacs
|