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 }