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