From feb29250d020d26e2d997d46bb530bb577d12419 Mon Sep 17 00:00:00 2001 From: Milind Sharma Date: Fri, 20 Feb 2026 18:00:37 +0800 Subject: [PATCH] feat(client): add RefillZones API and CLI command --- README.md | 6 ++--- docs/TEST_CLI.md | 6 +++++ src/client.rs | 18 ++++++++++++++ test-scripts/kicad-ipc-cli.rs | 46 +++++++++++++++++++++++++++++++++-- 4 files changed, 71 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index f4c47f7..6bad699 100644 --- a/README.md +++ b/README.md @@ -41,9 +41,9 @@ Legend: | Common (base) | 6 | 4 | 67% | | Common editor/document | 23 | 12 | 52% | | Project manager | 5 | 3 | 60% | -| Board editor (PCB) | 22 | 19 | 86% | +| Board editor (PCB) | 22 | 20 | 91% | | Schematic editor (dedicated proto commands) | 0 | 0 | n/a | -| **Total** | **56** | **38** | **68%** | +| **Total** | **56** | **39** | **70%** | ### Common (base) @@ -109,7 +109,7 @@ Legend: | `GetItemsByNet` | Implemented | `KiCadClient::get_items_by_net_raw`, `KiCadClient::get_items_by_net` | | `GetItemsByNetClass` | Implemented | `KiCadClient::get_items_by_net_class_raw`, `KiCadClient::get_items_by_net_class` | | `GetNetClassForNets` | Implemented | `KiCadClient::get_netclass_for_nets_raw`, `KiCadClient::get_netclass_for_nets` | -| `RefillZones` | Not yet | - | +| `RefillZones` | Implemented | `KiCadClient::refill_zones` | | `GetPadShapeAsPolygon` | Implemented | `KiCadClient::get_pad_shape_as_polygon_raw`, `KiCadClient::get_pad_shape_as_polygon` | | `CheckPadstackPresenceOnLayers` | Implemented | `KiCadClient::check_padstack_presence_on_layers_raw`, `KiCadClient::check_padstack_presence_on_layers` | | `InjectDrcError` | Implemented | `KiCadClient::inject_drc_error_raw`, `KiCadClient::inject_drc_error` | diff --git a/docs/TEST_CLI.md b/docs/TEST_CLI.md index a3bbb3b..de129cc 100644 --- a/docs/TEST_CLI.md +++ b/docs/TEST_CLI.md @@ -267,6 +267,12 @@ Inject DRC marker: cargo run --bin kicad-ipc-cli -- inject-drc-error --severity error --message "API marker test" --x-nm 1000000 --y-nm 1000000 ``` +Refill all zones: + +```bash +cargo run --bin kicad-ipc-cli -- refill-zones +``` + Show typed netclass map: ```bash diff --git a/src/client.rs b/src/client.rs index 639a6dd..b725508 100644 --- a/src/client.rs +++ b/src/client.rs @@ -62,6 +62,7 @@ const CMD_SET_BOARD_EDITOR_APPEARANCE_SETTINGS: &str = const CMD_GET_ITEMS_BY_NET: &str = "kiapi.board.commands.GetItemsByNet"; const CMD_GET_ITEMS_BY_NET_CLASS: &str = "kiapi.board.commands.GetItemsByNetClass"; const CMD_GET_NETCLASS_FOR_NETS: &str = "kiapi.board.commands.GetNetClassForNets"; +const CMD_REFILL_ZONES: &str = "kiapi.board.commands.RefillZones"; const CMD_GET_PAD_SHAPE_AS_POLYGON: &str = "kiapi.board.commands.GetPadShapeAsPolygon"; const CMD_CHECK_PADSTACK_PRESENCE_ON_LAYERS: &str = "kiapi.board.commands.CheckPadstackPresenceOnLayers"; @@ -903,6 +904,23 @@ impl KiCadClient { Ok(map_netclass_for_nets_response(response)) } + pub async fn refill_zones(&self, zone_ids: Vec) -> Result<(), KiCadError> { + let board = self.current_board_document_proto().await?; + let command = board_commands::RefillZones { + board: Some(board), + zones: zone_ids + .into_iter() + .map(|value| common_types::Kiid { value }) + .collect(), + }; + + let response = self + .send_command(envelope::pack_any(&command, CMD_REFILL_ZONES)) + .await?; + let _ = response_payload_as_any(response, RES_PROTOBUF_EMPTY)?; + Ok(()) + } + pub async fn get_pad_shape_as_polygon_raw( &self, pad_ids: Vec, diff --git a/test-scripts/kicad-ipc-cli.rs b/test-scripts/kicad-ipc-cli.rs index bf97cb1..5be4495 100644 --- a/test-scripts/kicad-ipc-cli.rs +++ b/test-scripts/kicad-ipc-cli.rs @@ -131,6 +131,9 @@ enum Command { board_flip: BoardFlipMode, ratsnest_display: RatsnestDisplayMode, }, + RefillZones { + zone_ids: Vec, + }, NetClass, BoardReadReport { output: PathBuf, @@ -701,6 +704,10 @@ async fn run() -> Result<(), KiCadError> { .await?; println!("{updated:#?}"); } + Command::RefillZones { zone_ids } => { + client.refill_zones(zone_ids).await?; + println!("refill_zones_dispatched=ok"); + } Command::NetClass => { let nets = client.get_nets().await?; let netclasses = client.get_netclass_for_nets(nets).await?; @@ -1496,9 +1503,25 @@ fn parse_args_from(mut args: Vec) -> Result<(CliConfig, Command), KiCadE reason: "set-appearance requires `--ratsnest-display `" .to_string(), - })?, + })?, } } + "refill-zones" => { + let mut zone_ids = Vec::new(); + let mut i = 1; + while i < args.len() { + if args[i] == "--zone-id" { + let value = args.get(i + 1).ok_or_else(|| KiCadError::Config { + reason: "missing value for refill-zones --zone-id".to_string(), + })?; + zone_ids.push(value.clone()); + i += 2; + continue; + } + i += 1; + } + Command::RefillZones { zone_ids } + } "netclass" => Command::NetClass, "proto-coverage-board-read" => Command::ProtoCoverageBoardRead, "board-read-report" => { @@ -1614,7 +1637,7 @@ fn default_config() -> CliConfig { fn print_help() { println!( - "kicad-ipc-cli\n\nUSAGE:\n cargo run --bin kicad-ipc-cli -- [--socket URI] [--token TOKEN] [--client-name NAME] [--timeout-ms N] [command options]\n\nCOMMANDS:\n ping Check IPC connectivity\n version Fetch KiCad version\n open-docs [--type ] List open docs (default type: pcb)\n project-path Get current project path from open PCB docs\n board-open Exit non-zero if no PCB doc is open\n net-classes List project netclass definitions\n text-variables List text variables for current board document\n expand-text-variables Expand variables in provided text values\n Options: --text (repeatable)\n text-extents Measure text bounding box\n Options: --text \n text-as-shapes Convert text to rendered shapes\n Options: --text (repeatable)\n nets List board nets (requires one open PCB)\n netlist-pads Emit pad-level netlist data (with footprint context)\n items-by-id --id ... Show parsed details for specific item IDs\n item-bbox --id ... Show bounding boxes for item IDs\n hit-test --id --x-nm --y-nm [--tolerance-nm ]\n Hit-test one item at a point\n types-pcb List PCB KiCad object type IDs from proto enum\n items-raw --type-id ... Dump raw Any payloads for requested item type IDs\n items-raw-all-pcb [--debug] Dump all PCB item payloads across all PCB object types\n pad-shape-polygon --pad-id ... --layer-id [--debug]\n Dump pad polygons on a target layer\n padstack-presence --item-id ... --layer-id ... [--debug]\n Check padstack shape presence matrix across layers\n title-block Show title block fields\n board-as-string Dump board as KiCad s-expression text\n selection-as-string Dump current selection as KiCad s-expression text\n stackup Show typed board stackup\n graphics-defaults Show typed graphics defaults\n appearance Show typed editor appearance settings\n set-appearance --inactive-layer-display \n --net-color-display \n --board-flip \n --ratsnest-display \n Set editor appearance settings\n inject-drc-error --severity --message [--x-nm --y-nm ] [--item-id ...]\n Inject a DRC marker (severity: warning|error|exclusion|ignore|info|action|debug|undefined)\n netclass Show typed netclass map for current board nets\n proto-coverage-board-read Print board-read command coverage vs proto\n board-read-report [--out P] Write markdown board reconstruction report\n enabled-layers List enabled board layers\n set-enabled-layers --copper-layer-count [--layer-id ...]\n Set enabled board layer set\n active-layer Show active board layer\n set-active-layer --layer-id \n Set active board layer\n visible-layers Show currently visible board layers\n set-visible-layers --layer-id ...\n Set visible board layers\n board-origin [--type ] Show board origin (`grid` default, or `drill`)\n set-board-origin --type --x-nm --y-nm \n Set board origin (`grid` or `drill`)\n refresh-editor [--frame ] Refresh a specific editor frame (default: pcb)\n begin-commit Start staged commit and print commit ID\n end-commit --id [--action ] [--message ]\n End staged commit with commit/drop action\n selection-summary Show current selection item type counts\n selection-details Show parsed details for selected items\n selection-raw Show raw Any payload bytes for selected items\n smoke ping + version + board-open summary\n help Show help\n\nTYPES:\n schematic | symbol | pcb | footprint | drawing-sheet | project\n" + "kicad-ipc-cli\n\nUSAGE:\n cargo run --bin kicad-ipc-cli -- [--socket URI] [--token TOKEN] [--client-name NAME] [--timeout-ms N] [command options]\n\nCOMMANDS:\n ping Check IPC connectivity\n version Fetch KiCad version\n open-docs [--type ] List open docs (default type: pcb)\n project-path Get current project path from open PCB docs\n board-open Exit non-zero if no PCB doc is open\n net-classes List project netclass definitions\n text-variables List text variables for current board document\n expand-text-variables Expand variables in provided text values\n Options: --text (repeatable)\n text-extents Measure text bounding box\n Options: --text \n text-as-shapes Convert text to rendered shapes\n Options: --text (repeatable)\n nets List board nets (requires one open PCB)\n netlist-pads Emit pad-level netlist data (with footprint context)\n items-by-id --id ... Show parsed details for specific item IDs\n item-bbox --id ... Show bounding boxes for item IDs\n hit-test --id --x-nm --y-nm [--tolerance-nm ]\n Hit-test one item at a point\n types-pcb List PCB KiCad object type IDs from proto enum\n items-raw --type-id ... Dump raw Any payloads for requested item type IDs\n items-raw-all-pcb [--debug] Dump all PCB item payloads across all PCB object types\n pad-shape-polygon --pad-id ... --layer-id [--debug]\n Dump pad polygons on a target layer\n padstack-presence --item-id ... --layer-id ... [--debug]\n Check padstack shape presence matrix across layers\n title-block Show title block fields\n board-as-string Dump board as KiCad s-expression text\n selection-as-string Dump current selection as KiCad s-expression text\n stackup Show typed board stackup\n graphics-defaults Show typed graphics defaults\n appearance Show typed editor appearance settings\n set-appearance --inactive-layer-display \n --net-color-display \n --board-flip \n --ratsnest-display \n Set editor appearance settings\n inject-drc-error --severity --message [--x-nm --y-nm ] [--item-id ...]\n Inject a DRC marker (severity: warning|error|exclusion|ignore|info|action|debug|undefined)\n refill-zones [--zone-id ...]\n Refill all zones or a provided subset\n netclass Show typed netclass map for current board nets\n proto-coverage-board-read Print board-read command coverage vs proto\n board-read-report [--out P] Write markdown board reconstruction report\n enabled-layers List enabled board layers\n set-enabled-layers --copper-layer-count [--layer-id ...]\n Set enabled board layer set\n active-layer Show active board layer\n set-active-layer --layer-id \n Set active board layer\n visible-layers Show currently visible board layers\n set-visible-layers --layer-id ...\n Set visible board layers\n board-origin [--type ] Show board origin (`grid` default, or `drill`)\n set-board-origin --type --x-nm --y-nm \n Set board origin (`grid` or `drill`)\n refresh-editor [--frame ] Refresh a specific editor frame (default: pcb)\n begin-commit Start staged commit and print commit ID\n end-commit --id [--action ] [--message ]\n End staged commit with commit/drop action\n selection-summary Show current selection item type counts\n selection-details Show parsed details for selected items\n selection-raw Show raw Any payload bytes for selected items\n smoke ping + version + board-open summary\n help Show help\n\nTYPES:\n schematic | symbol | pcb | footprint | drawing-sheet | project\n" ); } @@ -2372,4 +2395,23 @@ mod tests { other => panic!("unexpected command variant: {other:?}"), } } + + #[test] + fn parse_args_parses_refill_zones() { + let (_, command) = parse_args_from(vec![ + "refill-zones".to_string(), + "--zone-id".to_string(), + "zone-1".to_string(), + "--zone-id".to_string(), + "zone-2".to_string(), + ]) + .expect("refill-zones args should parse"); + + match command { + Command::RefillZones { zone_ids } => { + assert_eq!(zone_ids, vec!["zone-1".to_string(), "zone-2".to_string()]); + } + other => panic!("unexpected command variant: {other:?}"), + } + } }