49 std::string status_msg;
57 std::function<absl::Status()> exec;
61 auto state = std::make_shared<PaletteState>();
63 static std::vector<Cmd> cmds = {
64 {
"hex-read",
"🔢 Hex",
"Read ROM bytes",
65 "--address=0x1C800 --length=16 --format=both",
67 return absl::OkStatus();
70 {
"hex-write",
"🔢 Hex",
"Write ROM bytes",
71 "--address=0x1C800 --data=\"FF 00\"",
73 return absl::OkStatus();
76 {
"hex-search",
"🔢 Hex",
"Search byte pattern",
77 "--pattern=\"FF 00 ?? 12\"",
79 return absl::OkStatus();
82 {
"palette-get",
"🎨 Palette",
"Get palette colors",
83 "--group=0 --palette=0 --format=hex",
85 return absl::OkStatus();
88 {
"palette-set",
"🎨 Palette",
"Set palette color",
89 "--group=0 --palette=0 --index=5 --color=FF0000",
91 return absl::OkStatus();
94 {
"palette-analyze",
"🎨 Palette",
"Analyze palette",
95 "--type=palette --id=0/0",
97 return absl::OkStatus();
101 auto search_input = Input(&state->query,
"Search commands...");
103 auto menu = Renderer([state] {
104 std::vector<int> filtered_idx;
105 if (state->query.empty()) {
106 for (size_t i = 0; i < cmds.size(); ++i) {
107 filtered_idx.push_back(i);
110 for (
size_t i = 0; i < cmds.size(); ++i) {
111 cmds[i].score = fuzzy_match(state->query, cmds[i].name);
112 if (cmds[i].score > 0) {
113 filtered_idx.push_back(i);
116 std::sort(filtered_idx.begin(), filtered_idx.end(),
117 [](
int a,
int b) { return cmds[a].score > cmds[b].score; });
120 for (
size_t i = 0; i < filtered_idx.size(); ++i) {
121 int idx = filtered_idx[i];
123 text(cmds[idx].cat) | color(Color::GrayLight),
125 text(cmds[idx].name) | bold,
127 if (
static_cast<int>(i) == state->selected) {
128 item = item | inverted | focus;
130 items.push_back(item);
132 return vbox(items) | vscroll_indicator | frame;
135 auto execute_command = [state] {
136 std::vector<int> filtered_idx;
137 if (state->query.empty()) {
138 for (
size_t i = 0; i < cmds.size(); ++i) {
139 filtered_idx.push_back(i);
142 for (
size_t i = 0; i < cmds.size(); ++i) {
143 cmds[i].score = fuzzy_match(state->query, cmds[i].name);
144 if (cmds[i].score > 0) {
145 filtered_idx.push_back(i);
148 std::sort(filtered_idx.begin(), filtered_idx.end(),
149 [](
int a,
int b) { return cmds[a].score > cmds[b].score; });
152 if (state->selected <
static_cast<int>(filtered_idx.size())) {
153 int cmd_idx = filtered_idx[state->selected];
154 auto status = cmds[cmd_idx].exec();
155 state->status_msg = status.ok()
156 ?
"✓ Success: Command executed."
157 :
"✗ Error: " + std::string(status.message().data(), status.message().size());
161 auto back_btn = Button(
"Back", [] {
163 ScreenInteractive::Active()->ExitLoopClosure()();
166 auto container = Container::Vertical({search_input, menu, back_btn});
170 [container, search_input, menu, back_btn, state] {
171 std::vector<int> filtered_idx;
172 if (state->query.empty()) {
173 for (size_t i = 0; i < cmds.size(); ++i) {
174 filtered_idx.push_back(i);
177 for (
size_t i = 0; i < cmds.size(); ++i) {
178 cmds[i].score =
fuzzy_match(state->query, cmds[i].name);
179 if (cmds[i].score > 0) {
180 filtered_idx.push_back(i);
183 std::sort(filtered_idx.begin(), filtered_idx.end(),
185 return cmds[a].score > cmds[b].score;
189 Element details = text(
"Select a command to see details.") | dim;
190 if (state->selected <
static_cast<int>(filtered_idx.size())) {
191 int idx = filtered_idx[state->selected];
193 text(cmds[idx].desc) | bold,
195 text(
"Usage: " + cmds[idx].name +
" " + cmds[idx].usage) |
201 text(
"⚡ Command Palette") | bold | center |
203 text(app_context.rom.is_loaded()
204 ?
"ROM: " + app_context.rom.title()
208 hbox({text(
"🔍 "), search_input->Render() | flex}),
211 menu->Render() | flex,
216 hbox({back_btn->Render()}) | center,
218 text(state->status_msg) | center |
219 (state->status_msg.find(
"✓") != 0
220 ? color(Color::Green)
221 : color(Color::Red)),
222 text(
"↑↓: Navigate | Enter: Execute | Esc: Back") |
227 CatchEvent([state, execute_command](
const Event& e) {
228 if (e == Event::Return) {
232 if (e == Event::ArrowUp) {
233 if (state->selected > 0)
237 if (e == Event::ArrowDown) {
239 std::vector<int> filtered_idx;
240 if (state->query.empty()) {
241 for (
size_t i = 0; i < cmds.size(); ++i) {
242 filtered_idx.push_back(i);
245 for (
size_t i = 0; i < cmds.size(); ++i) {
246 cmds[i].score =
fuzzy_match(state->query, cmds[i].name);
247 if (cmds[i].score > 0) {
248 filtered_idx.push_back(i);
252 if (state->selected <
static_cast<int>(filtered_idx.size()) - 1)