feat(base): add GetTextAsShapes API bindings
This commit is contained in:
parent
5fb0bdccdb
commit
e644eb0ac5
|
|
@ -38,12 +38,12 @@ Legend:
|
|||
|
||||
| Section | Proto Commands | Implemented | Coverage |
|
||||
| --- | ---: | ---: | ---: |
|
||||
| Common (base) | 6 | 3 | 50% |
|
||||
| Common (base) | 6 | 4 | 67% |
|
||||
| Common editor/document | 23 | 9 | 39% |
|
||||
| Project manager | 5 | 3 | 60% |
|
||||
| Board editor (PCB) | 22 | 13 | 59% |
|
||||
| Schematic editor (dedicated proto commands) | 0 | 0 | n/a |
|
||||
| **Total** | **56** | **28** | **50%** |
|
||||
| **Total** | **56** | **29** | **52%** |
|
||||
|
||||
### Common (base)
|
||||
|
||||
|
|
@ -53,7 +53,7 @@ Legend:
|
|||
| `GetVersion` | Implemented | `KiCadClient::get_version` |
|
||||
| `GetKiCadBinaryPath` | Not yet | - |
|
||||
| `GetTextExtents` | Implemented | `KiCadClient::get_text_extents_raw`, `KiCadClient::get_text_extents` |
|
||||
| `GetTextAsShapes` | Not yet | - |
|
||||
| `GetTextAsShapes` | Implemented | `KiCadClient::get_text_as_shapes_raw`, `KiCadClient::get_text_as_shapes` |
|
||||
| `GetPluginSettingsPath` | Not yet | - |
|
||||
|
||||
### Common editor/document
|
||||
|
|
|
|||
|
|
@ -71,6 +71,12 @@ Measure text extents:
|
|||
cargo run --bin kicad-ipc-cli -- text-extents --text "R1"
|
||||
```
|
||||
|
||||
Convert text to shape primitives:
|
||||
|
||||
```bash
|
||||
cargo run --bin kicad-ipc-cli -- text-as-shapes --text "R1" --text "C5"
|
||||
```
|
||||
|
||||
List enabled board layers:
|
||||
|
||||
```bash
|
||||
|
|
|
|||
221
src/client.rs
221
src/client.rs
|
|
@ -19,9 +19,9 @@ use crate::model::board::{
|
|||
};
|
||||
use crate::model::common::{
|
||||
DocumentSpecifier, DocumentType, ItemBoundingBox, ItemHitTestResult, PcbObjectTypeCode,
|
||||
ProjectInfo, SelectionItemDetail, SelectionSummary, SelectionTypeCount, TextAttributesSpec,
|
||||
TextExtents, TextHorizontalAlignment, TextSpec, TextVerticalAlignment, TitleBlockInfo,
|
||||
VersionInfo,
|
||||
ProjectInfo, SelectionItemDetail, SelectionSummary, SelectionTypeCount, TextAsShapesEntry,
|
||||
TextAttributesSpec, TextBoxSpec, TextExtents, TextHorizontalAlignment, TextObjectSpec,
|
||||
TextShape, TextShapeGeometry, TextSpec, TextVerticalAlignment, TitleBlockInfo, VersionInfo,
|
||||
};
|
||||
use crate::proto::kiapi::board as board_proto;
|
||||
use crate::proto::kiapi::board::commands as board_commands;
|
||||
|
|
@ -40,6 +40,7 @@ const CMD_GET_NET_CLASSES: &str = "kiapi.common.commands.GetNetClasses";
|
|||
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_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";
|
||||
|
|
@ -71,6 +72,7 @@ const RES_TEXT_VARIABLES: &str = "kiapi.common.project.TextVariables";
|
|||
const RES_EXPAND_TEXT_VARIABLES_RESPONSE: &str =
|
||||
"kiapi.common.commands.ExpandTextVariablesResponse";
|
||||
const RES_BOX2: &str = "kiapi.common.types.Box2";
|
||||
const RES_GET_TEXT_AS_SHAPES_RESPONSE: &str = "kiapi.common.commands.GetTextAsShapesResponse";
|
||||
const RES_GET_OPEN_DOCUMENTS: &str = "kiapi.common.commands.GetOpenDocumentsResponse";
|
||||
const RES_GET_NETS: &str = "kiapi.board.commands.NetsResponse";
|
||||
const RES_GET_BOARD_ENABLED_LAYERS: &str = "kiapi.board.commands.BoardEnabledLayersResponse";
|
||||
|
|
@ -422,6 +424,34 @@ impl KiCadClient {
|
|||
})
|
||||
}
|
||||
|
||||
pub async fn get_text_as_shapes_raw(
|
||||
&self,
|
||||
text: Vec<TextObjectSpec>,
|
||||
) -> Result<prost_types::Any, KiCadError> {
|
||||
let command = common_commands::GetTextAsShapes {
|
||||
text: text.into_iter().map(text_object_spec_to_proto).collect(),
|
||||
};
|
||||
let response = self
|
||||
.send_command(envelope::pack_any(&command, CMD_GET_TEXT_AS_SHAPES))
|
||||
.await?;
|
||||
response_payload_as_any(response, RES_GET_TEXT_AS_SHAPES_RESPONSE)
|
||||
}
|
||||
|
||||
pub async fn get_text_as_shapes(
|
||||
&self,
|
||||
text: Vec<TextObjectSpec>,
|
||||
) -> Result<Vec<TextAsShapesEntry>, KiCadError> {
|
||||
let payload = self.get_text_as_shapes_raw(text).await?;
|
||||
let response: common_commands::GetTextAsShapesResponse =
|
||||
decode_any(&payload, RES_GET_TEXT_AS_SHAPES_RESPONSE)?;
|
||||
|
||||
response
|
||||
.text_with_shapes
|
||||
.into_iter()
|
||||
.map(map_text_with_shapes)
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub async fn get_current_project_path(&self) -> Result<PathBuf, KiCadError> {
|
||||
let docs = self.get_open_documents(DocumentType::Pcb).await?;
|
||||
select_single_project_path(&docs)
|
||||
|
|
@ -1286,6 +1316,191 @@ fn text_vertical_alignment_to_proto(value: TextVerticalAlignment) -> i32 {
|
|||
}
|
||||
}
|
||||
|
||||
fn text_box_spec_to_proto(text: TextBoxSpec) -> common_types::TextBox {
|
||||
common_types::TextBox {
|
||||
top_left: text.top_left_nm.map(vector2_nm_to_proto),
|
||||
bottom_right: text.bottom_right_nm.map(vector2_nm_to_proto),
|
||||
attributes: text.attributes.map(text_attributes_spec_to_proto),
|
||||
text: text.text,
|
||||
}
|
||||
}
|
||||
|
||||
fn text_object_spec_to_proto(text: TextObjectSpec) -> common_commands::TextOrTextBox {
|
||||
let inner = match text {
|
||||
TextObjectSpec::Text(value) => {
|
||||
common_commands::text_or_text_box::Inner::Text(text_spec_to_proto(value))
|
||||
}
|
||||
TextObjectSpec::TextBox(value) => {
|
||||
common_commands::text_or_text_box::Inner::Textbox(text_box_spec_to_proto(value))
|
||||
}
|
||||
};
|
||||
common_commands::TextOrTextBox { inner: Some(inner) }
|
||||
}
|
||||
|
||||
fn map_text_horizontal_alignment_from_proto(value: i32) -> TextHorizontalAlignment {
|
||||
match common_types::HorizontalAlignment::try_from(value) {
|
||||
Ok(common_types::HorizontalAlignment::HaLeft) => TextHorizontalAlignment::Left,
|
||||
Ok(common_types::HorizontalAlignment::HaCenter) => TextHorizontalAlignment::Center,
|
||||
Ok(common_types::HorizontalAlignment::HaRight) => TextHorizontalAlignment::Right,
|
||||
Ok(common_types::HorizontalAlignment::HaIndeterminate) => {
|
||||
TextHorizontalAlignment::Indeterminate
|
||||
}
|
||||
_ => TextHorizontalAlignment::Unknown,
|
||||
}
|
||||
}
|
||||
|
||||
fn map_text_vertical_alignment_from_proto(value: i32) -> TextVerticalAlignment {
|
||||
match common_types::VerticalAlignment::try_from(value) {
|
||||
Ok(common_types::VerticalAlignment::VaTop) => TextVerticalAlignment::Top,
|
||||
Ok(common_types::VerticalAlignment::VaCenter) => TextVerticalAlignment::Center,
|
||||
Ok(common_types::VerticalAlignment::VaBottom) => TextVerticalAlignment::Bottom,
|
||||
Ok(common_types::VerticalAlignment::VaIndeterminate) => {
|
||||
TextVerticalAlignment::Indeterminate
|
||||
}
|
||||
_ => TextVerticalAlignment::Unknown,
|
||||
}
|
||||
}
|
||||
|
||||
fn map_text_attributes_spec_from_proto(
|
||||
attributes: common_types::TextAttributes,
|
||||
) -> TextAttributesSpec {
|
||||
TextAttributesSpec {
|
||||
font_name: if attributes.font_name.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(attributes.font_name)
|
||||
},
|
||||
horizontal_alignment: map_text_horizontal_alignment_from_proto(
|
||||
attributes.horizontal_alignment,
|
||||
),
|
||||
vertical_alignment: map_text_vertical_alignment_from_proto(attributes.vertical_alignment),
|
||||
angle_degrees: attributes.angle.map(|value| value.value_degrees),
|
||||
line_spacing: Some(attributes.line_spacing),
|
||||
stroke_width_nm: map_optional_distance_nm(attributes.stroke_width),
|
||||
italic: attributes.italic,
|
||||
bold: attributes.bold,
|
||||
underlined: attributes.underlined,
|
||||
mirrored: attributes.mirrored,
|
||||
multiline: attributes.multiline,
|
||||
keep_upright: attributes.keep_upright,
|
||||
size_nm: attributes.size.map(map_vector2_nm),
|
||||
}
|
||||
}
|
||||
|
||||
fn map_text_spec_from_proto(text: common_types::Text) -> TextSpec {
|
||||
TextSpec {
|
||||
text: text.text,
|
||||
position_nm: text.position.map(map_vector2_nm),
|
||||
attributes: text.attributes.map(map_text_attributes_spec_from_proto),
|
||||
hyperlink: if text.hyperlink.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(text.hyperlink)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn map_text_box_spec_from_proto(text: common_types::TextBox) -> TextBoxSpec {
|
||||
TextBoxSpec {
|
||||
text: text.text,
|
||||
top_left_nm: text.top_left.map(map_vector2_nm),
|
||||
bottom_right_nm: text.bottom_right.map(map_vector2_nm),
|
||||
attributes: text.attributes.map(map_text_attributes_spec_from_proto),
|
||||
}
|
||||
}
|
||||
|
||||
fn map_text_object_spec_from_proto(text: common_commands::TextOrTextBox) -> Option<TextObjectSpec> {
|
||||
match text.inner {
|
||||
Some(common_commands::text_or_text_box::Inner::Text(value)) => {
|
||||
Some(TextObjectSpec::Text(map_text_spec_from_proto(value)))
|
||||
}
|
||||
Some(common_commands::text_or_text_box::Inner::Textbox(value)) => {
|
||||
Some(TextObjectSpec::TextBox(map_text_box_spec_from_proto(value)))
|
||||
}
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn map_text_shape_geometry(
|
||||
shape: common_types::GraphicShape,
|
||||
) -> Result<TextShapeGeometry, KiCadError> {
|
||||
match shape.geometry {
|
||||
Some(common_types::graphic_shape::Geometry::Segment(segment)) => {
|
||||
Ok(TextShapeGeometry::Segment {
|
||||
start_nm: segment.start.map(map_vector2_nm),
|
||||
end_nm: segment.end.map(map_vector2_nm),
|
||||
})
|
||||
}
|
||||
Some(common_types::graphic_shape::Geometry::Rectangle(rectangle)) => {
|
||||
Ok(TextShapeGeometry::Rectangle {
|
||||
top_left_nm: rectangle.top_left.map(map_vector2_nm),
|
||||
bottom_right_nm: rectangle.bottom_right.map(map_vector2_nm),
|
||||
corner_radius_nm: map_optional_distance_nm(rectangle.corner_radius),
|
||||
})
|
||||
}
|
||||
Some(common_types::graphic_shape::Geometry::Arc(arc)) => Ok(TextShapeGeometry::Arc {
|
||||
start_nm: arc.start.map(map_vector2_nm),
|
||||
mid_nm: arc.mid.map(map_vector2_nm),
|
||||
end_nm: arc.end.map(map_vector2_nm),
|
||||
}),
|
||||
Some(common_types::graphic_shape::Geometry::Circle(circle)) => {
|
||||
Ok(TextShapeGeometry::Circle {
|
||||
center_nm: circle.center.map(map_vector2_nm),
|
||||
radius_point_nm: circle.radius_point.map(map_vector2_nm),
|
||||
})
|
||||
}
|
||||
Some(common_types::graphic_shape::Geometry::Polygon(polygon)) => {
|
||||
let polygons = polygon
|
||||
.polygons
|
||||
.into_iter()
|
||||
.map(map_polygon_with_holes)
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
Ok(TextShapeGeometry::Polygon { polygons })
|
||||
}
|
||||
Some(common_types::graphic_shape::Geometry::Bezier(bezier)) => {
|
||||
Ok(TextShapeGeometry::Bezier {
|
||||
start_nm: bezier.start.map(map_vector2_nm),
|
||||
control1_nm: bezier.control1.map(map_vector2_nm),
|
||||
control2_nm: bezier.control2.map(map_vector2_nm),
|
||||
end_nm: bezier.end.map(map_vector2_nm),
|
||||
})
|
||||
}
|
||||
None => Ok(TextShapeGeometry::Unknown),
|
||||
}
|
||||
}
|
||||
|
||||
fn map_text_shape(shape: common_types::GraphicShape) -> Result<TextShape, KiCadError> {
|
||||
let geometry = map_text_shape_geometry(shape.clone())?;
|
||||
let attributes = shape.attributes.unwrap_or_default();
|
||||
let stroke = attributes.stroke;
|
||||
let fill = attributes.fill;
|
||||
|
||||
Ok(TextShape {
|
||||
geometry,
|
||||
stroke_width_nm: stroke
|
||||
.clone()
|
||||
.and_then(|value| map_optional_distance_nm(value.width)),
|
||||
stroke_style: stroke.as_ref().map(|value| value.style),
|
||||
stroke_color: stroke.and_then(|value| map_optional_color(value.color)),
|
||||
fill_type: fill.as_ref().map(|value| value.fill_type),
|
||||
fill_color: fill.and_then(|value| map_optional_color(value.color)),
|
||||
})
|
||||
}
|
||||
|
||||
fn map_text_with_shapes(
|
||||
row: common_commands::TextWithShapes,
|
||||
) -> Result<TextAsShapesEntry, KiCadError> {
|
||||
let source = row.text.and_then(map_text_object_spec_from_proto);
|
||||
let shapes = row
|
||||
.shapes
|
||||
.unwrap_or_default()
|
||||
.shapes
|
||||
.into_iter()
|
||||
.map(map_text_shape)
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
Ok(TextAsShapesEntry { source, shapes })
|
||||
}
|
||||
|
||||
fn layer_to_model(layer_id: i32) -> BoardLayerInfo {
|
||||
let name = board_types::BoardLayer::try_from(layer_id)
|
||||
.map(|layer| layer.as_str_name().to_string())
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ pub use crate::model::board::{
|
|||
};
|
||||
pub use crate::model::common::{
|
||||
DocumentSpecifier, DocumentType, ItemBoundingBox, ItemHitTestResult, PcbObjectTypeCode,
|
||||
SelectionItemDetail, SelectionSummary, SelectionTypeCount, TextAttributesSpec, TextExtents,
|
||||
TextHorizontalAlignment, TextSpec, TextVerticalAlignment, TitleBlockInfo, VersionInfo,
|
||||
SelectionItemDetail, SelectionSummary, SelectionTypeCount, TextAsShapesEntry,
|
||||
TextAttributesSpec, TextBoxSpec, TextExtents, TextHorizontalAlignment, TextObjectSpec,
|
||||
TextShape, TextShapeGeometry, TextSpec, TextVerticalAlignment, TitleBlockInfo, VersionInfo,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
use std::path::PathBuf;
|
||||
use std::str::FromStr;
|
||||
|
||||
use crate::model::board::Vector2Nm;
|
||||
use crate::model::board::{ColorRgba, PolygonWithHolesNm, Vector2Nm};
|
||||
use crate::proto::kiapi::common::types as common_types;
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
|
|
@ -226,6 +226,68 @@ pub struct TextExtents {
|
|||
pub height_nm: i64,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct TextBoxSpec {
|
||||
pub text: String,
|
||||
pub top_left_nm: Option<Vector2Nm>,
|
||||
pub bottom_right_nm: Option<Vector2Nm>,
|
||||
pub attributes: Option<TextAttributesSpec>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub enum TextObjectSpec {
|
||||
Text(TextSpec),
|
||||
TextBox(TextBoxSpec),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub enum TextShapeGeometry {
|
||||
Segment {
|
||||
start_nm: Option<Vector2Nm>,
|
||||
end_nm: Option<Vector2Nm>,
|
||||
},
|
||||
Rectangle {
|
||||
top_left_nm: Option<Vector2Nm>,
|
||||
bottom_right_nm: Option<Vector2Nm>,
|
||||
corner_radius_nm: Option<i64>,
|
||||
},
|
||||
Arc {
|
||||
start_nm: Option<Vector2Nm>,
|
||||
mid_nm: Option<Vector2Nm>,
|
||||
end_nm: Option<Vector2Nm>,
|
||||
},
|
||||
Circle {
|
||||
center_nm: Option<Vector2Nm>,
|
||||
radius_point_nm: Option<Vector2Nm>,
|
||||
},
|
||||
Polygon {
|
||||
polygons: Vec<PolygonWithHolesNm>,
|
||||
},
|
||||
Bezier {
|
||||
start_nm: Option<Vector2Nm>,
|
||||
control1_nm: Option<Vector2Nm>,
|
||||
control2_nm: Option<Vector2Nm>,
|
||||
end_nm: Option<Vector2Nm>,
|
||||
},
|
||||
Unknown,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct TextShape {
|
||||
pub geometry: TextShapeGeometry,
|
||||
pub stroke_width_nm: Option<i64>,
|
||||
pub stroke_style: Option<i32>,
|
||||
pub stroke_color: Option<ColorRgba>,
|
||||
pub fill_type: Option<i32>,
|
||||
pub fill_color: Option<ColorRgba>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct TextAsShapesEntry {
|
||||
pub source: Option<TextObjectSpec>,
|
||||
pub shapes: Vec<TextShape>,
|
||||
}
|
||||
|
||||
impl std::fmt::Display for ItemHitTestResult {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
let value = match self {
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ use std::time::Duration;
|
|||
|
||||
use kicad_ipc::{
|
||||
BoardOriginKind, ClientBuilder, DocumentType, KiCadClient, KiCadError, PadstackPresenceState,
|
||||
PcbObjectTypeCode, TextSpec, Vector2Nm,
|
||||
PcbObjectTypeCode, TextObjectSpec, TextShapeGeometry, TextSpec, Vector2Nm,
|
||||
};
|
||||
|
||||
const REPORT_MAX_PAD_NET_ROWS: usize = 2_000;
|
||||
|
|
@ -40,6 +40,9 @@ enum Command {
|
|||
TextExtents {
|
||||
text: String,
|
||||
},
|
||||
TextAsShapes {
|
||||
text: Vec<String>,
|
||||
},
|
||||
Nets,
|
||||
EnabledLayers,
|
||||
ActiveLayer,
|
||||
|
|
@ -224,6 +227,47 @@ async fn run() -> Result<(), KiCadError> {
|
|||
extents.x_nm, extents.y_nm, extents.width_nm, extents.height_nm
|
||||
);
|
||||
}
|
||||
Command::TextAsShapes { text } => {
|
||||
let entries = client
|
||||
.get_text_as_shapes(
|
||||
text.into_iter()
|
||||
.map(|value| TextObjectSpec::Text(TextSpec::plain(value)))
|
||||
.collect(),
|
||||
)
|
||||
.await?;
|
||||
println!("text_with_shapes_count={}", entries.len());
|
||||
for (index, entry) in entries.iter().enumerate() {
|
||||
let mut segment_count = 0;
|
||||
let mut rectangle_count = 0;
|
||||
let mut arc_count = 0;
|
||||
let mut circle_count = 0;
|
||||
let mut polygon_count = 0;
|
||||
let mut bezier_count = 0;
|
||||
let mut unknown_count = 0;
|
||||
for shape in &entry.shapes {
|
||||
match shape.geometry {
|
||||
TextShapeGeometry::Segment { .. } => segment_count += 1,
|
||||
TextShapeGeometry::Rectangle { .. } => rectangle_count += 1,
|
||||
TextShapeGeometry::Arc { .. } => arc_count += 1,
|
||||
TextShapeGeometry::Circle { .. } => circle_count += 1,
|
||||
TextShapeGeometry::Polygon { .. } => polygon_count += 1,
|
||||
TextShapeGeometry::Bezier { .. } => bezier_count += 1,
|
||||
TextShapeGeometry::Unknown => unknown_count += 1,
|
||||
}
|
||||
}
|
||||
println!(
|
||||
"[{index}] shape_count={} segment={} rectangle={} arc={} circle={} polygon={} bezier={} unknown={}",
|
||||
entry.shapes.len(),
|
||||
segment_count,
|
||||
rectangle_count,
|
||||
arc_count,
|
||||
circle_count,
|
||||
polygon_count,
|
||||
bezier_count,
|
||||
unknown_count
|
||||
);
|
||||
}
|
||||
}
|
||||
Command::Nets => {
|
||||
let nets = client.get_nets().await?;
|
||||
if nets.is_empty() {
|
||||
|
|
@ -669,6 +713,33 @@ fn parse_args() -> Result<(CliConfig, Command), KiCadError> {
|
|||
})?,
|
||||
}
|
||||
}
|
||||
"text-as-shapes" => {
|
||||
let mut text = Vec::new();
|
||||
let mut i = 1;
|
||||
while i < args.len() {
|
||||
match args[i].as_str() {
|
||||
"--text" => {
|
||||
let value = args.get(i + 1).ok_or_else(|| KiCadError::Config {
|
||||
reason: "missing value for text-as-shapes --text".to_string(),
|
||||
})?;
|
||||
text.push(value.clone());
|
||||
i += 2;
|
||||
}
|
||||
_ => {
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if text.is_empty() {
|
||||
return Err(KiCadError::Config {
|
||||
reason: "text-as-shapes requires one or more `--text <value>` arguments"
|
||||
.to_string(),
|
||||
});
|
||||
}
|
||||
|
||||
Command::TextAsShapes { text }
|
||||
}
|
||||
"nets" => Command::Nets,
|
||||
"enabled-layers" => Command::EnabledLayers,
|
||||
"active-layer" => Command::ActiveLayer,
|
||||
|
|
@ -1004,7 +1075,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] [--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 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 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] [--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 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"
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -1427,6 +1498,11 @@ fn proto_coverage_board_read_rows() -> Vec<(&'static str, &'static str, &'static
|
|||
"implemented",
|
||||
"get_text_extents_raw/get_text_extents",
|
||||
),
|
||||
(
|
||||
"kiapi.common.commands.GetTextAsShapes",
|
||||
"implemented",
|
||||
"get_text_as_shapes_raw/get_text_as_shapes",
|
||||
),
|
||||
(
|
||||
"kiapi.common.commands.GetItems",
|
||||
"implemented",
|
||||
|
|
|
|||
Loading…
Reference in New Issue