yaze 0.3.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
command_palette.cc
Go to the documentation of this file.
2
3#include <algorithm>
4#include <cctype>
5#include <chrono>
6
7namespace yaze {
8namespace editor {
9
10void CommandPalette::AddCommand(const std::string& name,
11 const std::string& category,
12 const std::string& description,
13 const std::string& shortcut,
14 std::function<void()> callback) {
15 CommandEntry entry;
16 entry.name = name;
17 entry.category = category;
18 entry.description = description;
19 entry.shortcut = shortcut;
20 entry.callback = callback;
21 commands_[name] = entry;
22}
23
24void CommandPalette::RecordUsage(const std::string& name) {
25 auto it = commands_.find(name);
26 if (it != commands_.end()) {
27 it->second.usage_count++;
28 it->second.last_used_ms =
29 std::chrono::duration_cast<std::chrono::milliseconds>(
30 std::chrono::system_clock::now().time_since_epoch())
31 .count();
32 }
33}
34
35int CommandPalette::FuzzyScore(const std::string& text,
36 const std::string& query) {
37 if (query.empty())
38 return 0;
39
40 int score = 0;
41 size_t text_idx = 0;
42 size_t query_idx = 0;
43
44 std::string text_lower = text;
45 std::string query_lower = query;
46 std::transform(text_lower.begin(), text_lower.end(), text_lower.begin(),
47 ::tolower);
48 std::transform(query_lower.begin(), query_lower.end(), query_lower.begin(),
49 ::tolower);
50
51 // Exact match bonus
52 if (text_lower == query_lower)
53 return 1000;
54
55 // Starts with bonus
56 if (text_lower.find(query_lower) == 0)
57 return 500;
58
59 // Contains bonus
60 if (text_lower.find(query_lower) != std::string::npos)
61 return 250;
62
63 // Fuzzy match - characters in order
64 while (text_idx < text_lower.length() && query_idx < query_lower.length()) {
65 if (text_lower[text_idx] == query_lower[query_idx]) {
66 score += 10;
67 query_idx++;
68 }
69 text_idx++;
70 }
71
72 // Penalty if not all characters matched
73 if (query_idx != query_lower.length())
74 return 0;
75
76 return score;
77}
78
79std::vector<CommandEntry> CommandPalette::SearchCommands(
80 const std::string& query) {
81 std::vector<std::pair<int, CommandEntry>> scored;
82
83 for (const auto& [name, entry] : commands_) {
84 int score = FuzzyScore(entry.name, query);
85
86 // Also check category and description
87 score += FuzzyScore(entry.category, query) / 2;
88 score += FuzzyScore(entry.description, query) / 4;
89
90 // Frecency bonus (frequency + recency)
91 score += entry.usage_count * 2;
92
93 auto now_ms = std::chrono::duration_cast<std::chrono::milliseconds>(
94 std::chrono::system_clock::now().time_since_epoch())
95 .count();
96 int64_t age_ms = now_ms - entry.last_used_ms;
97 if (age_ms < 60000) { // Used in last minute
98 score += 50;
99 } else if (age_ms < 3600000) { // Last hour
100 score += 25;
101 }
102
103 if (score > 0) {
104 scored.push_back({score, entry});
105 }
106 }
107
108 // Sort by score descending
109 std::sort(scored.begin(), scored.end(),
110 [](const auto& a, const auto& b) { return a.first > b.first; });
111
112 std::vector<CommandEntry> results;
113 for (const auto& [score, entry] : scored) {
114 results.push_back(entry);
115 }
116
117 return results;
118}
119
120std::vector<CommandEntry> CommandPalette::GetRecentCommands(int limit) {
121 std::vector<CommandEntry> recent;
122
123 for (const auto& [name, entry] : commands_) {
124 if (entry.usage_count > 0) {
125 recent.push_back(entry);
126 }
127 }
128
129 std::sort(recent.begin(), recent.end(),
130 [](const CommandEntry& a, const CommandEntry& b) {
131 return a.last_used_ms > b.last_used_ms;
132 });
133
134 if (recent.size() > static_cast<size_t>(limit)) {
135 recent.resize(limit);
136 }
137
138 return recent;
139}
140
141std::vector<CommandEntry> CommandPalette::GetFrequentCommands(int limit) {
142 std::vector<CommandEntry> frequent;
143
144 for (const auto& [name, entry] : commands_) {
145 if (entry.usage_count > 0) {
146 frequent.push_back(entry);
147 }
148 }
149
150 std::sort(frequent.begin(), frequent.end(),
151 [](const CommandEntry& a, const CommandEntry& b) {
152 return a.usage_count > b.usage_count;
153 });
154
155 if (frequent.size() > static_cast<size_t>(limit)) {
156 frequent.resize(limit);
157 }
158
159 return frequent;
160}
161
162void CommandPalette::SaveHistory(const std::string& filepath) {
163 // TODO: Implement JSON serialization of command history
164}
165
166void CommandPalette::LoadHistory(const std::string& filepath) {
167 // TODO: Implement JSON deserialization of command history
168}
169
170} // namespace editor
171} // namespace yaze
std::vector< CommandEntry > SearchCommands(const std::string &query)
void SaveHistory(const std::string &filepath)
void AddCommand(const std::string &name, const std::string &category, const std::string &description, const std::string &shortcut, std::function< void()> callback)
void LoadHistory(const std::string &filepath)
void RecordUsage(const std::string &name)
std::unordered_map< std::string, CommandEntry > commands_
std::vector< CommandEntry > GetRecentCommands(int limit=10)
std::vector< CommandEntry > GetFrequentCommands(int limit=10)
int FuzzyScore(const std::string &text, const std::string &query)
std::function< void()> callback