refactor: derive Rust product versions from Cargo

This commit is contained in:
Kayshen-X 2026-07-15 21:10:08 +08:00
parent b542a7e5d1
commit e0a2bd4e69
5 changed files with 24 additions and 11 deletions

View file

@ -9,7 +9,11 @@ use std::time::{Duration, SystemTime, UNIX_EPOCH};
const PID_FILE_NAME: &str = "openpencil-mcp-server.pid";
const PORT_FILE_NAME: &str = "openpencil-mcp-server.port";
const TOKEN_FILE_NAME: &str = "openpencil-mcp-server.token";
const MINIMAL_DOCUMENT: &str = "{\n \"version\": \"0.8.0\",\n \"name\": \"OpenPencil CLI Session\",\n \"children\": []\n}\n";
const MINIMAL_DOCUMENT: &str = concat!(
"{\n \"version\": \"",
env!("CARGO_PKG_VERSION"),
"\",\n \"name\": \"OpenPencil CLI Session\",\n \"children\": []\n}\n"
);
/// Rust live-canvas discovery file (`~/.openpencil/.op-mcp-port`), written
/// by the running editor when its `McpLiveServer` binds. Deliberately

View file

@ -103,7 +103,10 @@ fn start_document_file_is_minimal_op_when_missing() {
assert_eq!(
std::fs::read_to_string(&path).expect("read document"),
"{\n \"version\": \"0.8.0\",\n \"name\": \"OpenPencil CLI Session\",\n \"children\": []\n}\n"
format!(
"{{\n \"version\": \"{}\",\n \"name\": \"OpenPencil CLI Session\",\n \"children\": []\n}}\n",
env!("CARGO_PKG_VERSION")
)
);
let _ = std::fs::remove_dir_all(&dir);
}

View file

@ -35,7 +35,7 @@ impl EditorState {
/// [`EditorState::starter`] (a single empty Frame) instead.
pub fn sample() -> Self {
let src = r##"{
"version": "0.8.0",
"version": "__OPENPENCIL_VERSION__",
"children": [
{"type":"frame","id":"n10","name":"Frame",
"x":40,"y":40,"width":360,"height":240,
@ -56,7 +56,8 @@ impl EditorState {
]}
]
}"##;
let doc = jian_ops_schema::load_str(src)
let src = src.replace("__OPENPENCIL_VERSION__", env!("CARGO_PKG_VERSION"));
let doc = jian_ops_schema::load_str(&src)
.expect("EditorState::sample() fixture parses")
.value;
let mut state = Self::from_document(doc);
@ -69,7 +70,7 @@ impl EditorState {
/// document geometry. No default selection and no demo decoration.
pub fn starter() -> Self {
let src = r##"{
"version": "0.8.0",
"version": "__OPENPENCIL_VERSION__",
"children": [
{"type":"frame","id":"n10","name":"Frame",
"x":0,"y":0,"width":1200,"height":800,
@ -77,7 +78,8 @@ impl EditorState {
"children":[]}
]
}"##;
let doc = jian_ops_schema::load_str(src)
let src = src.replace("__OPENPENCIL_VERSION__", env!("CARGO_PKG_VERSION"));
let doc = jian_ops_schema::load_str(&src)
.expect("EditorState::starter() fixture parses")
.value;
Self::from_document(doc)
@ -644,6 +646,7 @@ mod tests {
#[test]
fn sample_has_the_demo_tree_and_anchors_selection() {
let s = EditorState::sample();
assert_eq!(s.doc.version, env!("CARGO_PKG_VERSION"));
assert_eq!(s.doc.children.len(), 1);
assert_eq!(s.selection.anchor, NodeId::new("n11"));
// The frame + its two children are present.
@ -653,6 +656,7 @@ mod tests {
#[test]
fn starter_is_a_single_empty_frame_with_nothing_selected() {
let s = EditorState::starter();
assert_eq!(s.doc.version, env!("CARGO_PKG_VERSION"));
// Exactly one top-level node — the starter Frame. The
// `max_node_id() == 10` check proves no demo children:
// the n11..n14 sample tree would lift it to 14.
@ -754,14 +758,15 @@ mod tests {
#[test]
fn replace_paths_with_polyline_inherits_first_source_style() {
let src = r##"{
"version": "0.8.0",
"version": "__OPENPENCIL_VERSION__",
"children": [
{"type":"rectangle","id":"n10","x":0,"y":0,"width":20,"height":20,
"fill":[{"type":"solid","color":"#ff0000"}]},
{"type":"rectangle","id":"n11","x":10,"y":0,"width":20,"height":20}
]
}"##;
let doc = jian_ops_schema::load_str(src)
let src = src.replace("__OPENPENCIL_VERSION__", env!("CARGO_PKG_VERSION"));
let doc = jian_ops_schema::load_str(&src)
.expect("fixture parses")
.value;
let mut s = EditorState::from_document(doc);

View file

@ -165,7 +165,7 @@ impl EditorState {
}
/// Build an editor state around an empty single-page document.
/// `version` is set to the current `.op` format version literal;
/// `version` is set to the current Cargo package version;
/// `children` is empty (no nodes) and `pages` is left `None` so
/// the document uses the default single-page fallback.
pub fn new() -> Self {
@ -327,7 +327,7 @@ impl Default for EditorState {
/// An empty canonical document — `version` set, no nodes, no pages.
fn empty_document() -> jian_ops_schema::PenDocument {
jian_ops_schema::PenDocument {
version: "0.8.0".to_string(),
version: env!("CARGO_PKG_VERSION").to_owned(),
name: None,
themes: None,
variables: None,
@ -352,6 +352,7 @@ mod tests {
#[test]
fn new_state_is_empty_and_quiescent() {
let s = EditorState::new();
assert_eq!(s.doc.version, env!("CARGO_PKG_VERSION"));
assert!(s.doc.children.is_empty());
assert!(s.doc.pages.is_none());
// Persisted variables/themes live on `doc`, not duplicated.

View file

@ -62,7 +62,7 @@ role = "Editor"
# Phase 7.3 reorg: openpencil-shell-core dissolved — widget facade /
# render-backend / layout scene paths resolve through op-editor-ui.
op-editor-ui = { path = "../op-editor-ui" }
op-host-native = { path = "../op-host-native", version = "0.8.1", features = ["gl-host"] }
op-host-native = { path = "../op-host-native", features = ["gl-host"] }
# Phase 2: the headless daemon crate. The `--serve-web` closure migrates here
# over Phases 2-5; op-host-desktop's serve-web dispatch + GUI residuals call into
# it via `op_host_services::*`.