2021-12-07 22:47:41 +01:00
|
|
|
#include "content/views/view_command_palette.hpp"
|
2020-12-16 22:43:07 +01:00
|
|
|
|
2022-02-01 18:09:40 +01:00
|
|
|
#include <hex/api/content_registry.hpp>
|
|
|
|
|
2021-09-06 20:35:38 +02:00
|
|
|
#include <cstring>
|
2020-12-16 22:43:07 +01:00
|
|
|
|
2021-12-07 22:47:41 +01:00
|
|
|
namespace hex::plugin::builtin {
|
2020-12-16 22:43:07 +01:00
|
|
|
|
2021-12-07 22:47:41 +01:00
|
|
|
ViewCommandPalette::ViewCommandPalette() : View("hex.builtin.view.command_palette.name") {
|
2022-05-17 20:46:42 +02:00
|
|
|
this->m_commandBuffer = std::vector<char>(1024, 0x00);
|
2021-12-23 15:11:38 +01:00
|
|
|
|
|
|
|
ShortcutManager::addGlobalShortcut(CTRL + SHIFT + Keys::P, [this] {
|
|
|
|
EventManager::post<RequestOpenPopup>("hex.builtin.view.command_palette.name"_lang);
|
|
|
|
this->m_commandPaletteOpen = true;
|
2022-02-01 22:09:44 +01:00
|
|
|
this->m_justOpened = true;
|
2021-12-23 15:11:38 +01:00
|
|
|
});
|
2020-12-16 22:43:07 +01:00
|
|
|
}
|
|
|
|
|
2020-12-22 18:10:01 +01:00
|
|
|
void ViewCommandPalette::drawContent() {
|
2020-12-16 22:43:07 +01:00
|
|
|
|
2021-02-08 19:56:04 +01:00
|
|
|
if (!this->m_commandPaletteOpen) return;
|
2021-01-27 14:26:24 +01:00
|
|
|
|
2022-02-01 22:09:44 +01:00
|
|
|
auto windowPos = ImHexApi::System::getMainWindowPosition();
|
2022-02-01 18:09:40 +01:00
|
|
|
auto windowSize = ImHexApi::System::getMainWindowSize();
|
|
|
|
|
|
|
|
ImGui::SetNextWindowPos(ImVec2(windowPos.x + windowSize.x * 0.5F, windowPos.y), ImGuiCond_Always, ImVec2(0.5F, 0.0F));
|
2021-12-07 22:47:41 +01:00
|
|
|
if (ImGui::BeginPopup("hex.builtin.view.command_palette.name"_lang)) {
|
2020-12-16 22:43:07 +01:00
|
|
|
if (ImGui::IsKeyDown(ImGui::GetKeyIndex(ImGuiKey_Escape)))
|
|
|
|
ImGui::CloseCurrentPopup();
|
|
|
|
|
2022-07-02 21:38:58 +02:00
|
|
|
if (this->m_focusInputTextBox) {
|
|
|
|
auto textState = ImGui::GetInputTextState(ImGui::GetID("##command_input"));
|
|
|
|
if (textState != nullptr) {
|
|
|
|
textState->Stb.cursor = strlen(this->m_commandBuffer.data());
|
|
|
|
}
|
|
|
|
|
|
|
|
ImGui::SetKeyboardFocusHere(0);
|
|
|
|
this->m_focusInputTextBox = false;
|
|
|
|
}
|
|
|
|
|
2021-02-08 19:56:04 +01:00
|
|
|
ImGui::PushItemWidth(-1);
|
2022-07-02 21:38:58 +02:00
|
|
|
if (ImGui::InputText("##command_input", this->m_commandBuffer.data(), this->m_commandBuffer.size(), ImGuiInputTextFlags_CallbackEdit | ImGuiInputTextFlags_EnterReturnsTrue,
|
|
|
|
[](ImGuiInputTextCallbackData *callbackData) -> int {
|
|
|
|
auto _this = static_cast<ViewCommandPalette *>(callbackData->UserData);
|
|
|
|
_this->m_lastResults = _this->getCommandResults(callbackData->Buf);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}, this)) {
|
2021-02-08 19:56:04 +01:00
|
|
|
if (!this->m_lastResults.empty()) {
|
|
|
|
auto &[displayResult, matchedCommand, callback] = this->m_lastResults.front();
|
|
|
|
callback(matchedCommand);
|
|
|
|
}
|
2020-12-16 22:43:07 +01:00
|
|
|
ImGui::CloseCurrentPopup();
|
|
|
|
}
|
|
|
|
ImGui::PopItemWidth();
|
|
|
|
|
|
|
|
if (this->m_justOpened) {
|
2021-02-08 19:56:04 +01:00
|
|
|
focusInputTextBox();
|
|
|
|
this->m_lastResults = this->getCommandResults("");
|
|
|
|
std::memset(this->m_commandBuffer.data(), 0x00, this->m_commandBuffer.size());
|
2020-12-16 22:43:07 +01:00
|
|
|
this->m_justOpened = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
ImGui::Separator();
|
|
|
|
|
2021-02-08 19:56:04 +01:00
|
|
|
for (const auto &[displayResult, matchedCommand, callback] : this->m_lastResults) {
|
|
|
|
if (ImGui::Selectable(displayResult.c_str(), false, ImGuiSelectableFlags_DontClosePopups))
|
|
|
|
callback(matchedCommand);
|
2020-12-16 22:43:07 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
ImGui::EndPopup();
|
2021-01-27 14:26:24 +01:00
|
|
|
} else {
|
2021-02-08 19:56:04 +01:00
|
|
|
this->m_commandPaletteOpen = false;
|
2020-12-16 22:43:07 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-09-08 15:18:24 +02:00
|
|
|
std::vector<ViewCommandPalette::CommandResult> ViewCommandPalette::getCommandResults(const std::string &input) {
|
|
|
|
constexpr auto MatchCommand = [](const std::string &currCommand, const std::string &commandToMatch) -> std::pair<MatchType, std::string_view> {
|
2020-12-16 22:43:07 +01:00
|
|
|
if (currCommand.empty()) {
|
|
|
|
return { MatchType::InfoMatch, "" };
|
2022-01-24 20:53:17 +01:00
|
|
|
} else if (currCommand.size() <= commandToMatch.size()) {
|
2020-12-16 22:43:07 +01:00
|
|
|
if (commandToMatch.starts_with(currCommand))
|
|
|
|
return { MatchType::PartialMatch, currCommand };
|
|
|
|
else
|
2022-01-24 20:53:17 +01:00
|
|
|
return { MatchType::NoMatch, {} };
|
|
|
|
} else {
|
2020-12-16 22:43:07 +01:00
|
|
|
if (currCommand.starts_with(commandToMatch))
|
|
|
|
return { MatchType::PerfectMatch, currCommand.substr(commandToMatch.length()) };
|
|
|
|
else
|
2022-01-24 20:53:17 +01:00
|
|
|
return { MatchType::NoMatch, {} };
|
2020-12-16 22:43:07 +01:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2021-02-08 19:56:04 +01:00
|
|
|
std::vector<CommandResult> results;
|
|
|
|
|
2021-02-13 15:15:32 +01:00
|
|
|
for (const auto &[type, command, unlocalizedDescription, displayCallback, executeCallback] : ContentRegistry::CommandPaletteCommands::getEntries()) {
|
2020-12-16 22:43:07 +01:00
|
|
|
|
2021-02-08 19:56:04 +01:00
|
|
|
auto AutoComplete = [this, &currCommand = command](auto) {
|
|
|
|
focusInputTextBox();
|
|
|
|
std::strncpy(this->m_commandBuffer.data(), currCommand.data(), this->m_commandBuffer.size());
|
|
|
|
this->m_lastResults = this->getCommandResults(currCommand);
|
|
|
|
};
|
2021-01-11 23:02:55 +01:00
|
|
|
|
|
|
|
if (type == ContentRegistry::CommandPaletteCommands::Type::SymbolCommand) {
|
2021-02-08 19:56:04 +01:00
|
|
|
if (auto [match, value] = MatchCommand(input, command); match != MatchType::NoMatch) {
|
2021-01-11 23:02:55 +01:00
|
|
|
if (match != MatchType::PerfectMatch)
|
2021-02-13 15:15:32 +01:00
|
|
|
results.push_back({ command + " (" + LangEntry(unlocalizedDescription) + ")", "", AutoComplete });
|
2021-02-08 19:56:04 +01:00
|
|
|
else {
|
2021-09-08 15:18:24 +02:00
|
|
|
auto matchedCommand = input.substr(command.length());
|
2021-02-08 19:56:04 +01:00
|
|
|
results.push_back({ displayCallback(matchedCommand), matchedCommand, executeCallback });
|
|
|
|
}
|
2021-01-11 23:02:55 +01:00
|
|
|
}
|
|
|
|
} else if (type == ContentRegistry::CommandPaletteCommands::Type::KeywordCommand) {
|
2021-02-08 19:56:04 +01:00
|
|
|
if (auto [match, value] = MatchCommand(input, command + " "); match != MatchType::NoMatch) {
|
2021-01-11 23:02:55 +01:00
|
|
|
if (match != MatchType::PerfectMatch)
|
2021-02-13 15:15:32 +01:00
|
|
|
results.push_back({ command + " (" + LangEntry(unlocalizedDescription) + ")", "", AutoComplete });
|
2021-02-08 19:56:04 +01:00
|
|
|
else {
|
2021-09-08 15:18:24 +02:00
|
|
|
auto matchedCommand = input.substr(command.length() + 1);
|
2021-02-08 19:56:04 +01:00
|
|
|
results.push_back({ displayCallback(matchedCommand), matchedCommand, executeCallback });
|
|
|
|
}
|
2021-01-11 23:02:55 +01:00
|
|
|
}
|
2020-12-16 22:43:07 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return results;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|