mirror of
https://github.com/storytold/gridcraft.git
synced 2026-10-24 10:46:50 -06:00
Merge pull request #184 from MarekSpodBiedry/issue-136
Honor search in the desktop engine.commands handler so connected list_commands filters (#136)
This commit is contained in:
@@ -2,7 +2,7 @@
|
|||||||
//!
|
//!
|
||||||
//! Methods (JSON lines over the host's transport, see `docs/control-protocol.md`):
|
//! Methods (JSON lines over the host's transport, see `docs/control-protocol.md`):
|
||||||
//! - `engine.execute {command, params}` — run any engine or UI command
|
//! - `engine.execute {command, params}` — run any engine or UI command
|
||||||
//! - `engine.commands` — every command with enablement and params docs
|
//! - `engine.commands {search?}` — every command with enablement and params docs
|
||||||
//! - `document.inspect`, `sheet.read {range?}`, `cell.get {cell?}` — read state
|
//! - `document.inspect`, `sheet.read {range?}`, `cell.get {cell?}` — read state
|
||||||
//! - `ui.inspect` — UI state (ribbon tab, editor, dialog, grid geometry, perf)
|
//! - `ui.inspect` — UI state (ribbon tab, editor, dialog, grid geometry, perf)
|
||||||
//! - `ui.click {x, y, button?, count?, shift?, cmd?, alt?}`, `ui.drag {x, y, toX, toY}`,
|
//! - `ui.click {x, y, button?, count?, shift?, cmd?, alt?}`, `ui.drag {x, y, toX, toY}`,
|
||||||
@@ -144,6 +144,17 @@ fn push_drag(app: &mut SheetApp, a: egui::Pos2, b: egui::Pos2, steps: usize, m:
|
|||||||
app.synthetic.push_back(vec![egui::Event::PointerButton { pos: b, button: egui::PointerButton::Primary, pressed: false, modifiers: m }]);
|
app.synthetic.push_back(vec![egui::Event::PointerButton { pos: b, button: egui::PointerButton::Primary, pressed: false, modifiers: m }]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Keeps the commands whose id, label or ribbon path contains `search` (case-insensitive); `None` keeps all.
|
||||||
|
fn filter_commands(commands: Vec<Json>, search: Option<&str>) -> Vec<Json> {
|
||||||
|
let Some(q) = search.map(str::to_ascii_lowercase) else { return commands };
|
||||||
|
let has = |c: &Json, k: &str| c.get(k).and_then(Json::as_str).is_some_and(|v| v.to_ascii_lowercase().contains(&q));
|
||||||
|
let in_menu = |c: &Json| {
|
||||||
|
let menu = c.get("menu").and_then(Json::as_array);
|
||||||
|
menu.is_some_and(|m| m.iter().filter_map(Json::as_str).any(|v| v.to_ascii_lowercase().contains(&q)))
|
||||||
|
};
|
||||||
|
commands.into_iter().filter(|c| has(c, "id") || has(c, "label") || in_menu(c)).collect()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn handle(app: &mut SheetApp, ctx: &egui::Context, method: &str, p: &Json) -> Outcome {
|
pub fn handle(app: &mut SheetApp, ctx: &egui::Context, method: &str, p: &Json) -> Outcome {
|
||||||
let s = |k: &str| p.get(k).and_then(Json::as_str);
|
let s = |k: &str| p.get(k).and_then(Json::as_str);
|
||||||
let f = |k: &str| p.get(k).and_then(Json::as_f64).unwrap_or(0.0) as f32;
|
let f = |k: &str| p.get(k).and_then(Json::as_f64).unwrap_or(0.0) as f32;
|
||||||
@@ -169,7 +180,7 @@ pub fn handle(app: &mut SheetApp, ctx: &egui::Context, method: &str, p: &Json) -
|
|||||||
] {
|
] {
|
||||||
v.push(json!({"id": id, "label": label, "params": params, "enabled": true, "ui": true}));
|
v.push(json!({"id": id, "label": label, "params": params, "enabled": true, "ui": true}));
|
||||||
}
|
}
|
||||||
ok(Json::Array(v))
|
ok(Json::Array(filter_commands(v, s("search"))))
|
||||||
}
|
}
|
||||||
"engine.journal" => ok(json!(app.session.journal.iter().map(|(id, p)| json!({"command": id, "params": p})).collect::<Vec<_>>())),
|
"engine.journal" => ok(json!(app.session.journal.iter().map(|(id, p)| json!({"command": id, "params": p})).collect::<Vec<_>>())),
|
||||||
"document.inspect" | "sheet.read" | "cell.get" | "selection.stats" => wrap(app.session.run(method, p.clone())),
|
"document.inspect" | "sheet.read" | "cell.get" | "selection.stats" => wrap(app.session.run(method, p.clone())),
|
||||||
@@ -433,3 +444,30 @@ pub fn save_image(image: &egui::ColorImage, path: Option<&str>) -> Json {
|
|||||||
None => json!({"ok": true, "result": {"base64": gridcraft_engine::io::base64_encode(&png), "width": w, "height": h}}),
|
None => json!({"ok": true, "result": {"base64": gridcraft_engine::io::base64_encode(&png), "width": w, "height": h}}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
fn sample() -> Vec<Json> {
|
||||||
|
vec![
|
||||||
|
json!({"id": "home.borders", "label": "Borders", "menu": ["Home", "Font"]}),
|
||||||
|
json!({"id": "home.bold", "label": "Bold", "menu": ["Home", "Font"]}),
|
||||||
|
json!({"id": "ui.ribbonTab", "label": "Ribbon Tab", "enabled": true, "ui": true}),
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ids(v: &[Json]) -> Vec<&str> {
|
||||||
|
v.iter().filter_map(|c| c.get("id").and_then(Json::as_str)).collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn search_filters_case_insensitively() {
|
||||||
|
assert_eq!(ids(&filter_commands(sample(), Some("border"))), ["home.borders"]);
|
||||||
|
assert_eq!(filter_commands(sample(), Some("BORDER")), filter_commands(sample(), Some("border")));
|
||||||
|
assert_eq!(ids(&filter_commands(sample(), Some("ribbon"))), ["ui.ribbonTab"]);
|
||||||
|
assert_eq!(ids(&filter_commands(sample(), Some("font"))), ["home.borders", "home.bold"]);
|
||||||
|
assert!(filter_commands(sample(), Some("catalog_no_match_7391")).is_empty());
|
||||||
|
assert_eq!(filter_commands(sample(), None).len(), 3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ Errors come back as `{"id": …, "ok": false, "error": "…"}`.
|
|||||||
| Method | Params | What it does |
|
| Method | Params | What it does |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| `engine.execute` | `{command, params}` | Runs any engine command (see `engine.commands` or `gridcraft-cli commands`) |
|
| `engine.execute` | `{command, params}` | Runs any engine command (see `engine.commands` or `gridcraft-cli commands`) |
|
||||||
| `engine.commands` | | Every command: id, label, ribbon path, shortcut, params doc, enabled |
|
| `engine.commands` | `{search?}` | Every command: id, label, ribbon path, shortcut, params doc, enabled; `search` keeps those whose id, label or ribbon path contains it (case-insensitive) |
|
||||||
| `engine.journal` | | Commands run so far (replayable) |
|
| `engine.journal` | | Commands run so far (replayable) |
|
||||||
| `document.inspect` | | Workbook summary: sheets, used ranges, tables, charts, names, selection, undo labels |
|
| `document.inspect` | | Workbook summary: sheets, used ranges, tables, charts, names, selection, undo labels |
|
||||||
| `sheet.read` | `{range?, sheet?, formulas?, formatted?}` | Values (or formulas / displayed text) of a range |
|
| `sheet.read` | `{range?, sheet?, formulas?, formatted?}` | Values (or formulas / displayed text) of a range |
|
||||||
|
|||||||
Reference in New Issue
Block a user