feat(client): add RefreshEditor API and CLI command
This commit is contained in:
parent
aa406927a5
commit
331910444d
|
|
@ -39,11 +39,11 @@ Legend:
|
|||
| Section | Proto Commands | Implemented | Coverage |
|
||||
| --- | ---: | ---: | ---: |
|
||||
| Common (base) | 6 | 4 | 67% |
|
||||
| Common editor/document | 23 | 11 | 48% |
|
||||
| Common editor/document | 23 | 12 | 52% |
|
||||
| Project manager | 5 | 3 | 60% |
|
||||
| Board editor (PCB) | 22 | 13 | 59% |
|
||||
| Schematic editor (dedicated proto commands) | 0 | 0 | n/a |
|
||||
| **Total** | **56** | **31** | **55%** |
|
||||
| **Total** | **56** | **32** | **57%** |
|
||||
|
||||
### Common (base)
|
||||
|
||||
|
|
@ -60,7 +60,7 @@ Legend:
|
|||
|
||||
| KiCad Command | Status | Rust API |
|
||||
| --- | --- | --- |
|
||||
| `RefreshEditor` | Not yet | - |
|
||||
| `RefreshEditor` | Implemented | `KiCadClient::refresh_editor` |
|
||||
| `GetOpenDocuments` | Implemented | `KiCadClient::get_open_documents`, `KiCadClient::get_current_project_path`, `KiCadClient::has_open_board` |
|
||||
| `SaveDocument` | Not yet | - |
|
||||
| `SaveCopyOfDocument` | Not yet | - |
|
||||
|
|
|
|||
|
|
@ -107,6 +107,14 @@ Show drill origin:
|
|||
cargo run --bin kicad-ipc-cli -- board-origin --type drill
|
||||
```
|
||||
|
||||
Refresh PCB editor:
|
||||
|
||||
```bash
|
||||
cargo run --bin kicad-ipc-cli -- refresh-editor --frame pcb
|
||||
```
|
||||
|
||||
If your KiCad build does not expose this handler yet, this call may return `AS_UNHANDLED`.
|
||||
|
||||
Start a staged commit and print commit ID:
|
||||
|
||||
```bash
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ use crate::model::board::{
|
|||
Vector2Nm,
|
||||
};
|
||||
use crate::model::common::{
|
||||
CommitAction, CommitSession, DocumentSpecifier, DocumentType, ItemBoundingBox,
|
||||
CommitAction, CommitSession, DocumentSpecifier, DocumentType, EditorFrameType, ItemBoundingBox,
|
||||
ItemHitTestResult, PcbObjectTypeCode, ProjectInfo, SelectionItemDetail, SelectionSummary,
|
||||
SelectionTypeCount, TextAsShapesEntry, TextAttributesSpec, TextBoxSpec, TextExtents,
|
||||
TextHorizontalAlignment, TextObjectSpec, TextShape, TextShapeGeometry, TextSpec,
|
||||
|
|
@ -42,6 +42,7 @@ const CMD_GET_TEXT_VARIABLES: &str = "kiapi.common.commands.GetTextVariables";
|
|||
const CMD_EXPAND_TEXT_VARIABLES: &str = "kiapi.common.commands.ExpandTextVariables";
|
||||
const CMD_GET_TEXT_EXTENTS: &str = "kiapi.common.commands.GetTextExtents";
|
||||
const CMD_GET_TEXT_AS_SHAPES: &str = "kiapi.common.commands.GetTextAsShapes";
|
||||
const CMD_REFRESH_EDITOR: &str = "kiapi.common.commands.RefreshEditor";
|
||||
const CMD_GET_OPEN_DOCUMENTS: &str = "kiapi.common.commands.GetOpenDocuments";
|
||||
const CMD_GET_NETS: &str = "kiapi.board.commands.GetNets";
|
||||
const CMD_GET_BOARD_ENABLED_LAYERS: &str = "kiapi.board.commands.GetBoardEnabledLayers";
|
||||
|
|
@ -293,6 +294,17 @@ impl KiCadClient {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn refresh_editor(&self, frame: EditorFrameType) -> Result<(), KiCadError> {
|
||||
let command = envelope::pack_any(
|
||||
&common_commands::RefreshEditor {
|
||||
frame: frame.to_proto(),
|
||||
},
|
||||
CMD_REFRESH_EDITOR,
|
||||
);
|
||||
self.send_command(command).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn get_version(&self) -> Result<VersionInfo, KiCadError> {
|
||||
let command = envelope::pack_any(&common_commands::GetVersion {}, CMD_GET_VERSION);
|
||||
let response = self.send_command(command).await?;
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ pub use crate::model::board::{
|
|||
Vector2Nm,
|
||||
};
|
||||
pub use crate::model::common::{
|
||||
CommitAction, CommitSession, DocumentSpecifier, DocumentType, ItemBoundingBox,
|
||||
CommitAction, CommitSession, DocumentSpecifier, DocumentType, EditorFrameType, ItemBoundingBox,
|
||||
ItemHitTestResult, PcbObjectTypeCode, SelectionItemDetail, SelectionSummary,
|
||||
SelectionTypeCount, TextAsShapesEntry, TextAttributesSpec, TextBoxSpec, TextExtents,
|
||||
TextHorizontalAlignment, TextObjectSpec, TextShape, TextShapeGeometry, TextSpec,
|
||||
|
|
|
|||
|
|
@ -12,6 +12,65 @@ pub struct VersionInfo {
|
|||
pub full_version: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
pub enum EditorFrameType {
|
||||
ProjectManager,
|
||||
SchematicEditor,
|
||||
PcbEditor,
|
||||
SpiceSimulator,
|
||||
SymbolEditor,
|
||||
FootprintEditor,
|
||||
DrawingSheetEditor,
|
||||
}
|
||||
|
||||
impl EditorFrameType {
|
||||
pub(crate) fn to_proto(self) -> i32 {
|
||||
match self {
|
||||
Self::ProjectManager => common_types::FrameType::FtProjectManager as i32,
|
||||
Self::SchematicEditor => common_types::FrameType::FtSchematicEditor as i32,
|
||||
Self::PcbEditor => common_types::FrameType::FtPcbEditor as i32,
|
||||
Self::SpiceSimulator => common_types::FrameType::FtSpiceSimulator as i32,
|
||||
Self::SymbolEditor => common_types::FrameType::FtSymbolEditor as i32,
|
||||
Self::FootprintEditor => common_types::FrameType::FtFootprintEditor as i32,
|
||||
Self::DrawingSheetEditor => common_types::FrameType::FtDrawingSheetEditor as i32,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for EditorFrameType {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
let value = match self {
|
||||
Self::ProjectManager => "project-manager",
|
||||
Self::SchematicEditor => "schematic",
|
||||
Self::PcbEditor => "pcb",
|
||||
Self::SpiceSimulator => "spice",
|
||||
Self::SymbolEditor => "symbol",
|
||||
Self::FootprintEditor => "footprint",
|
||||
Self::DrawingSheetEditor => "drawing-sheet",
|
||||
};
|
||||
write!(f, "{value}")
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for EditorFrameType {
|
||||
type Err = String;
|
||||
|
||||
fn from_str(value: &str) -> Result<Self, Self::Err> {
|
||||
match value {
|
||||
"project-manager" => Ok(Self::ProjectManager),
|
||||
"schematic" => Ok(Self::SchematicEditor),
|
||||
"pcb" => Ok(Self::PcbEditor),
|
||||
"spice" => Ok(Self::SpiceSimulator),
|
||||
"symbol" => Ok(Self::SymbolEditor),
|
||||
"footprint" => Ok(Self::FootprintEditor),
|
||||
"drawing-sheet" => Ok(Self::DrawingSheetEditor),
|
||||
_ => Err(format!(
|
||||
"unknown frame `{value}`; expected one of: project-manager, schematic, pcb, spice, symbol, footprint, drawing-sheet"
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
pub enum DocumentType {
|
||||
Schematic,
|
||||
|
|
@ -336,7 +395,7 @@ impl std::fmt::Display for ItemHitTestResult {
|
|||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::CommitAction;
|
||||
use super::{CommitAction, EditorFrameType};
|
||||
use std::str::FromStr;
|
||||
|
||||
#[test]
|
||||
|
|
@ -349,4 +408,21 @@ mod tests {
|
|||
fn commit_action_rejects_unknown_values() {
|
||||
assert!(CommitAction::from_str("rollback").is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn editor_frame_type_parses_known_values() {
|
||||
assert_eq!(
|
||||
EditorFrameType::from_str("pcb"),
|
||||
Ok(EditorFrameType::PcbEditor)
|
||||
);
|
||||
assert_eq!(
|
||||
EditorFrameType::from_str("project-manager"),
|
||||
Ok(EditorFrameType::ProjectManager)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn editor_frame_type_rejects_unknown_values() {
|
||||
assert!(EditorFrameType::from_str("layout").is_err());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,9 +6,9 @@ use std::str::FromStr;
|
|||
use std::time::Duration;
|
||||
|
||||
use kicad_ipc::{
|
||||
BoardOriginKind, ClientBuilder, CommitAction, CommitSession, DocumentType, KiCadClient,
|
||||
KiCadError, PadstackPresenceState, PcbObjectTypeCode, TextObjectSpec, TextShapeGeometry,
|
||||
TextSpec, Vector2Nm,
|
||||
BoardOriginKind, ClientBuilder, CommitAction, CommitSession, DocumentType, EditorFrameType,
|
||||
KiCadClient, KiCadError, PadstackPresenceState, PcbObjectTypeCode, TextObjectSpec,
|
||||
TextShapeGeometry, TextSpec, Vector2Nm,
|
||||
};
|
||||
|
||||
const REPORT_MAX_PAD_NET_ROWS: usize = 2_000;
|
||||
|
|
@ -52,6 +52,9 @@ enum Command {
|
|||
BoardOrigin {
|
||||
kind: BoardOriginKind,
|
||||
},
|
||||
RefreshEditor {
|
||||
frame: EditorFrameType,
|
||||
},
|
||||
BeginCommit,
|
||||
EndCommit {
|
||||
id: String,
|
||||
|
|
@ -320,6 +323,10 @@ async fn run() -> Result<(), KiCadError> {
|
|||
kind, origin.x_nm, origin.y_nm
|
||||
);
|
||||
}
|
||||
Command::RefreshEditor { frame } => {
|
||||
client.refresh_editor(frame).await?;
|
||||
println!("refresh_editor=ok frame={}", frame);
|
||||
}
|
||||
Command::BeginCommit => {
|
||||
let session = client.begin_commit().await?;
|
||||
println!("commit_id={}", session.id);
|
||||
|
|
@ -795,6 +802,23 @@ fn parse_args_from(mut args: Vec<String>) -> Result<(CliConfig, Command), KiCadE
|
|||
}
|
||||
Command::BoardOrigin { kind }
|
||||
}
|
||||
"refresh-editor" => {
|
||||
let mut frame = EditorFrameType::PcbEditor;
|
||||
let mut i = 1;
|
||||
while i < args.len() {
|
||||
if args[i] == "--frame" {
|
||||
let value = args.get(i + 1).ok_or_else(|| KiCadError::Config {
|
||||
reason: "missing value for refresh-editor --frame".to_string(),
|
||||
})?;
|
||||
frame = EditorFrameType::from_str(value)
|
||||
.map_err(|err| KiCadError::Config { reason: err })?;
|
||||
i += 2;
|
||||
continue;
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
Command::RefreshEditor { frame }
|
||||
}
|
||||
"begin-commit" => Command::BeginCommit,
|
||||
"end-commit" => {
|
||||
let mut id = None;
|
||||
|
|
@ -1154,7 +1178,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> [command options]\n\nCOMMANDS:\n ping Check IPC connectivity\n version Fetch KiCad version\n open-docs [--type <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 <value> (repeatable)\n text-extents Measure text bounding box\n Options: --text <value>\n text-as-shapes Convert text to rendered shapes\n Options: --text <value> (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 <uuid> ... Show parsed details for specific item IDs\n item-bbox --id <uuid> ... Show bounding boxes for item IDs\n hit-test --id <uuid> --x-nm <x> --y-nm <y> [--tolerance-nm <n>]\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 <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 <uuid> ... --layer-id <i32> [--debug]\n Dump pad polygons on a target layer\n padstack-presence --item-id <uuid> ... --layer-id <i32> ... [--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 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 active-layer Show active board layer\n visible-layers Show currently visible board layers\n board-origin [--type <t>] Show board origin (`grid` default, or `drill`)\n begin-commit Start staged commit and print commit ID\n end-commit --id <uuid> [--action <commit|drop>] [--message <text>]\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> [command options]\n\nCOMMANDS:\n ping Check IPC connectivity\n version Fetch KiCad version\n open-docs [--type <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 <value> (repeatable)\n text-extents Measure text bounding box\n Options: --text <value>\n text-as-shapes Convert text to rendered shapes\n Options: --text <value> (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 <uuid> ... Show parsed details for specific item IDs\n item-bbox --id <uuid> ... Show bounding boxes for item IDs\n hit-test --id <uuid> --x-nm <x> --y-nm <y> [--tolerance-nm <n>]\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 <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 <uuid> ... --layer-id <i32> [--debug]\n Dump pad polygons on a target layer\n padstack-presence --item-id <uuid> ... --layer-id <i32> ... [--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 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 active-layer Show active board layer\n visible-layers Show currently visible board layers\n board-origin [--type <t>] Show board origin (`grid` default, or `drill`)\n refresh-editor [--frame <f>] Refresh a specific editor frame (default: pcb)\n begin-commit Start staged commit and print commit ID\n end-commit --id <uuid> [--action <commit|drop>] [--message <text>]\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"
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -1748,4 +1772,21 @@ mod tests {
|
|||
other => panic!("unexpected command variant: {other:?}"),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_args_parses_refresh_editor_frame() {
|
||||
let (_, command) = parse_args_from(vec![
|
||||
"refresh-editor".to_string(),
|
||||
"--frame".to_string(),
|
||||
"schematic".to_string(),
|
||||
])
|
||||
.expect("refresh-editor args should parse");
|
||||
|
||||
match command {
|
||||
Command::RefreshEditor { frame } => {
|
||||
assert_eq!(frame.to_string(), "schematic");
|
||||
}
|
||||
other => panic!("unexpected command variant: {other:?}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue