1 #include "views/view_command_palette.hpp" 2 3 #include <GLFW/glfw3.h> 4 5 namespace hex { 6 ViewCommandPalette()7 ViewCommandPalette::ViewCommandPalette() : View("hex.view.command_palette.name"_lang) { 8 this->m_commandBuffer.resize(1024, 0x00); 9 } 10 ~ViewCommandPalette()11 ViewCommandPalette::~ViewCommandPalette() { 12 13 } 14 drawContent()15 void ViewCommandPalette::drawContent() { 16 17 if (!this->m_commandPaletteOpen) return; 18 19 ImGui::SetNextWindowPos(ImVec2(SharedData::windowPos.x + SharedData::windowSize.x * 0.5F, SharedData::windowPos.y), ImGuiCond_Always, ImVec2(0.5F,0.0F)); 20 if (ImGui::BeginPopup("hex.view.command_palette.name"_lang)) { 21 if (ImGui::IsKeyDown(ImGui::GetKeyIndex(ImGuiKey_Escape))) 22 ImGui::CloseCurrentPopup(); 23 24 ImGui::PushItemWidth(-1); 25 if (ImGui::InputText("##nolabel", this->m_commandBuffer.data(), this->m_commandBuffer.size(), ImGuiInputTextFlags_CallbackEdit | ImGuiInputTextFlags_EnterReturnsTrue, 26 [](ImGuiInputTextCallbackData *callbackData) -> int { 27 auto _this = static_cast<ViewCommandPalette*>(callbackData->UserData); 28 _this->m_lastResults = _this->getCommandResults(callbackData->Buf); 29 30 return 0; 31 }, this)) { 32 if (!this->m_lastResults.empty()) { 33 auto &[displayResult, matchedCommand, callback] = this->m_lastResults.front(); 34 callback(matchedCommand); 35 } 36 ImGui::CloseCurrentPopup(); 37 } 38 ImGui::PopItemWidth(); 39 40 if (this->m_justOpened) { 41 focusInputTextBox(); 42 this->m_lastResults = this->getCommandResults(""); 43 std::memset(this->m_commandBuffer.data(), 0x00, this->m_commandBuffer.size()); 44 this->m_justOpened = false; 45 } 46 47 if (this->m_focusInputTextBox) { 48 ImGui::SetKeyboardFocusHere(0); 49 this->m_focusInputTextBox = false; 50 } 51 52 ImGui::Separator(); 53 54 for (const auto &[displayResult, matchedCommand, callback] : this->m_lastResults) { 55 if (ImGui::Selectable(displayResult.c_str(), false, ImGuiSelectableFlags_DontClosePopups)) 56 callback(matchedCommand); 57 } 58 59 ImGui::EndPopup(); 60 } else { 61 this->m_commandPaletteOpen = false; 62 } 63 64 } 65 drawMenu()66 void ViewCommandPalette::drawMenu() { 67 68 } 69 handleShortcut(int key,int mods)70 bool ViewCommandPalette::handleShortcut(int key, int mods) { 71 if (key == GLFW_KEY_P && mods == (GLFW_MOD_SHIFT | GLFW_MOD_CONTROL)) { 72 View::doLater([this] { 73 ImGui::OpenPopup("hex.view.command_palette.name"_lang); 74 this->m_commandPaletteOpen = true; 75 this->m_justOpened = true; 76 }); 77 return true; 78 } 79 80 return false; 81 } 82 getCommandResults(std::string_view input)83 std::vector<ViewCommandPalette::CommandResult> ViewCommandPalette::getCommandResults(std::string_view input) { 84 constexpr auto MatchCommand = [](std::string_view currCommand, std::string_view commandToMatch) -> std::pair<MatchType, std::string_view> { 85 if (currCommand.empty()) { 86 return { MatchType::InfoMatch, "" }; 87 } 88 else if (currCommand.size() <= commandToMatch.size()) { 89 if (commandToMatch.starts_with(currCommand)) 90 return { MatchType::PartialMatch, currCommand }; 91 else 92 return { MatchType::NoMatch, { } }; 93 } 94 else { 95 if (currCommand.starts_with(commandToMatch)) 96 return { MatchType::PerfectMatch, currCommand.substr(commandToMatch.length()) }; 97 else 98 return { MatchType::NoMatch, { } }; 99 } 100 }; 101 102 std::vector<CommandResult> results; 103 104 for (const auto &[type, command, unlocalizedDescription, displayCallback, executeCallback] : ContentRegistry::CommandPaletteCommands::getEntries()) { 105 106 auto AutoComplete = [this, &currCommand = command](auto) { 107 focusInputTextBox(); 108 std::strncpy(this->m_commandBuffer.data(), currCommand.data(), this->m_commandBuffer.size()); 109 this->m_lastResults = this->getCommandResults(currCommand); 110 }; 111 112 if (type == ContentRegistry::CommandPaletteCommands::Type::SymbolCommand) { 113 if (auto [match, value] = MatchCommand(input, command); match != MatchType::NoMatch) { 114 if (match != MatchType::PerfectMatch) 115 results.push_back({ command + " (" + LangEntry(unlocalizedDescription) + ")", "", AutoComplete }); 116 else { 117 auto matchedCommand = input.substr(command.length()).data(); 118 results.push_back({ displayCallback(matchedCommand), matchedCommand, executeCallback }); 119 } 120 } 121 } else if (type == ContentRegistry::CommandPaletteCommands::Type::KeywordCommand) { 122 if (auto [match, value] = MatchCommand(input, command + " "); match != MatchType::NoMatch) { 123 if (match != MatchType::PerfectMatch) 124 results.push_back({ command + " (" + LangEntry(unlocalizedDescription) + ")", "", AutoComplete }); 125 else { 126 auto matchedCommand = input.substr(command.length() + 1).data(); 127 results.push_back({ displayCallback(matchedCommand), matchedCommand, executeCallback }); 128 } 129 } 130 } 131 132 } 133 134 return results; 135 } 136 137 }