mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-10-24 17:56:50 -06:00
Dimensions: a file whose dimensions carry options this version doesn't know still opens; commands still refuse unknown options
This commit is contained in:
@@ -123,7 +123,7 @@ pub enum TextAlignment {
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(default, rename_all = "camelCase", deny_unknown_fields)]
|
||||
#[serde(default, rename_all = "camelCase")]
|
||||
pub struct DimensionOptions {
|
||||
pub units: LengthUnit,
|
||||
pub precision: usize,
|
||||
@@ -182,6 +182,18 @@ impl Default for DimensionOptions {
|
||||
}
|
||||
|
||||
impl DimensionOptions {
|
||||
/// Options given to a command or a tool: unknown keys are refused there, while files load
|
||||
/// tolerantly so a newer version's options don't stop a document opening.
|
||||
pub fn from_params(v: serde_json::Value) -> Result<Self, String> {
|
||||
if let (Some(given), Ok(serde_json::Value::Object(known))) = (v.as_object(), serde_json::to_value(Self::default()))
|
||||
&& let Some(k) = given.keys().find(|k| !known.contains_key(*k))
|
||||
{
|
||||
return Err(format!("Unknown dimension option {k}"));
|
||||
}
|
||||
let o: Self = serde_json::from_value(v).map_err(|e| e.to_string())?;
|
||||
o.validate()?;
|
||||
Ok(o)
|
||||
}
|
||||
pub fn factor(&self) -> Result<f64, String> {
|
||||
let (a, b) = self.scale.split_once(':').ok_or("Scale must be drawing:real, for example 1:10")?;
|
||||
let parse = |s: &str| s.trim().parse::<f64>().ok().filter(|n| n.is_finite() && *n > 0.0 && *n <= 1e9);
|
||||
@@ -236,7 +248,7 @@ impl DimensionOptions {
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase", deny_unknown_fields)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SegmentRef {
|
||||
pub node: NodeId,
|
||||
pub subpath: usize,
|
||||
@@ -263,7 +275,7 @@ impl SegmentRef {
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(tag = "kind", rename_all = "camelCase", deny_unknown_fields)]
|
||||
#[serde(tag = "kind", rename_all = "camelCase")]
|
||||
pub enum DimensionSource {
|
||||
Segment {
|
||||
edge: SegmentRef,
|
||||
@@ -312,7 +324,7 @@ impl DimensionSource {
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase", deny_unknown_fields)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct PointRef {
|
||||
pub node: NodeId,
|
||||
pub subpath: usize,
|
||||
@@ -326,7 +338,7 @@ impl PointRef {
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase", deny_unknown_fields)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Dimension {
|
||||
pub mode: DimensionMode,
|
||||
pub a: Point,
|
||||
|
||||
@@ -46,9 +46,7 @@ fn error(s: impl ToString) -> EngineError {
|
||||
fn options(s: &Session, p: &Value) -> Result<DimensionOptions> {
|
||||
let default = s.tool_options_of("dimension");
|
||||
let value = p.get("options").cloned().unwrap_or_else(|| default.get("style").cloned().unwrap_or(json!({})));
|
||||
let o: DimensionOptions = serde_json::from_value(value).map_err(error)?;
|
||||
o.validate().map_err(error)?;
|
||||
Ok(o)
|
||||
DimensionOptions::from_params(value).map_err(error)
|
||||
}
|
||||
|
||||
fn point(p: &Value, key: &str) -> Result<Point> {
|
||||
|
||||
@@ -455,8 +455,7 @@ impl Session {
|
||||
}
|
||||
if tool.unwrap_or(self.tool_id()) == "dimension" {
|
||||
if let Some(style) = values.get("style") {
|
||||
let options: vectorcraft_doc::dimension::DimensionOptions = serde_json::from_value(style.clone()).map_err(|e| e.to_string())?;
|
||||
options.validate()?;
|
||||
vectorcraft_doc::dimension::DimensionOptions::from_params(style.clone())?;
|
||||
}
|
||||
if let Some(mode) = values.get("mode")
|
||||
&& !mode.as_str().is_some_and(|m| ["linear", "angular", "radial", "radius", "diameter"].contains(&m))
|
||||
|
||||
@@ -357,3 +357,35 @@ fn dimension_cannot_measure_its_own_generated_art() {
|
||||
let child = s.doc().unwrap().doc.node(NodeId(id)).unwrap().children().unwrap()[0].id;
|
||||
assert!(s.execute("dimension.create", &json!({"source":{"kind":"segment","edge":{"node":child,"subpath":0,"segment":0}}})).is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unknown_dimension_options_are_refused_by_commands_but_a_newer_file_still_opens() {
|
||||
let mut s = session();
|
||||
let line = edge(&mut s);
|
||||
let source = json!({"kind":"segment","edge":{"node":line,"subpath":0,"segment":0}});
|
||||
let bad = s.execute("dimension.create", &json!({"source":source,"options":{"units":"in","color":"red"}}));
|
||||
assert!(bad.unwrap_err().to_string().contains("Unknown dimension option color"));
|
||||
assert!(s.set_tool_option_cmd(&json!({"tool":"dimension","values":{"style":{"precison":2}}})).is_err());
|
||||
let id = dim(&mut s, line);
|
||||
let saved = vectorcraft_format::save(&s.doc().unwrap().doc, false);
|
||||
let mut v: Value = serde_json::from_slice(&saved).unwrap();
|
||||
// A later version's dimension carries fields this one doesn't know.
|
||||
fn add_unknown(v: &mut Value) {
|
||||
match v {
|
||||
Value::Object(m) => {
|
||||
if let Some(Value::Object(d)) = m.get_mut("dimension") {
|
||||
d.insert("later".into(), json!(1));
|
||||
if let Some(Value::Object(o)) = d.get_mut("options") {
|
||||
o.insert("later".into(), json!(true));
|
||||
}
|
||||
}
|
||||
m.values_mut().for_each(add_unknown);
|
||||
}
|
||||
Value::Array(a) => a.iter_mut().for_each(add_unknown),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
add_unknown(&mut v);
|
||||
let doc = vectorcraft_format::load(&serde_json::to_vec(&v).unwrap()).unwrap();
|
||||
assert!(doc.node(NodeId(id)).unwrap().extras().dimension.is_some());
|
||||
}
|
||||
|
||||
@@ -4851,6 +4851,7 @@ mark-style Japanese Japonské
|
||||
@msg Scale ratio must be between 1:1000000 and 1000000:1 Poměr měřítka musí být mezi 1:1000000 a 1000000:1
|
||||
@msg Second measured segment no longer exists Druhý měřený segment už neexistuje
|
||||
@msg Unknown dimension mode Neznámý režim kóty
|
||||
@msg Unknown dimension option {k} Neznámá volba kóty {k}
|
||||
@msg Unknown dimension style Neznámý styl kóty
|
||||
@msg Unknown unit Neznámá jednotka
|
||||
# Revolve cap description
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -4380,6 +4380,7 @@ theme Appearance Erscheinungsbild
|
||||
@msg Scale ratio must be between 1:1000000 and 1000000:1 Das Maßstabsverhältnis muss zwischen 1:1000000 und 1000000:1 liegen
|
||||
@msg Second measured segment no longer exists Das zweite gemessene Segment existiert nicht mehr
|
||||
@msg Unknown dimension mode Unbekannter Bemaßungsmodus
|
||||
@msg Unknown dimension option {k} Unbekannte Bemaßungsoption {k}
|
||||
@msg Unknown dimension style Unbekannter Bemaßungsstil
|
||||
@msg Unknown unit Unbekannte Einheit
|
||||
# Revolve cap description
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -4792,6 +4792,7 @@ mark-style Japanese Japonesas
|
||||
@msg Scale ratio must be between 1:1000000 and 1000000:1 La relación de escala debe estar entre 1:1000000 y 1000000:1
|
||||
@msg Second measured segment no longer exists El segundo segmento medido ya no existe
|
||||
@msg Unknown dimension mode Modo de cota desconocido
|
||||
@msg Unknown dimension option {k} Opción de cota desconocida {k}
|
||||
@msg Unknown dimension style Estilo de cota desconocido
|
||||
@msg Unknown unit Unidad desconocida
|
||||
# Revolve cap description
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -4850,6 +4850,7 @@ theme Appearance Apparence
|
||||
@msg Scale ratio must be between 1:1000000 and 1000000:1 Le rapport d’échelle doit être compris entre 1:1000000 et 1000000:1
|
||||
@msg Second measured segment no longer exists Le second segment mesuré n’existe plus
|
||||
@msg Unknown dimension mode Mode de cote inconnu
|
||||
@msg Unknown dimension option {k} Option de cote inconnue {k}
|
||||
@msg Unknown dimension style Style de cote inconnu
|
||||
@msg Unknown unit Unité inconnue
|
||||
# Revolve cap description
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -4817,6 +4817,7 @@ imageTrace Outline Körvonal
|
||||
@msg Scale ratio must be between 1:1000000 and 1000000:1 A lépték aránya 1:1000000 és 1000000:1 között lehet
|
||||
@msg Second measured segment no longer exists A második mért szakasz már nem létezik
|
||||
@msg Unknown dimension mode Ismeretlen méretezési mód
|
||||
@msg Unknown dimension option {k} Ismeretlen méretezési beállítás: {k}
|
||||
@msg Unknown dimension style Ismeretlen méretezési stílus
|
||||
@msg Unknown unit Ismeretlen mértékegység
|
||||
# Revolve cap description
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -4425,6 +4425,7 @@ lighting Light Luce
|
||||
@msg Scale ratio must be between 1:1000000 and 1000000:1 Il rapporto di scala deve essere compreso tra 1:1000000 e 1000000:1
|
||||
@msg Second measured segment no longer exists Il secondo segmento misurato non esiste più
|
||||
@msg Unknown dimension mode Modalità di quota sconosciuta
|
||||
@msg Unknown dimension option {k} Opzione di quota sconosciuta {k}
|
||||
@msg Unknown dimension style Stile di quota sconosciuto
|
||||
@msg Unknown unit Unità sconosciuta
|
||||
# Revolve cap description
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -4420,6 +4420,7 @@ lighting Light ライト
|
||||
@msg Scale ratio must be between 1:1000000 and 1000000:1 縮尺の比率は 1:1000000 から 1000000:1 の間にしてください
|
||||
@msg Second measured segment no longer exists 2 番目の測定セグメントはもう存在しません
|
||||
@msg Unknown dimension mode 寸法のモードが不明です
|
||||
@msg Unknown dimension option {k} 不明な寸法オプション {k}
|
||||
@msg Unknown dimension style 寸法のスタイルが不明です
|
||||
@msg Unknown unit 単位が不明です
|
||||
# Revolve cap description
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -4389,6 +4389,7 @@ lighting Light 광원
|
||||
@msg Scale ratio must be between 1:1000000 and 1000000:1 축척 비율은 1:1000000에서 1000000:1 사이여야 합니다
|
||||
@msg Second measured segment no longer exists 두 번째 측정 세그먼트가 더 이상 없습니다
|
||||
@msg Unknown dimension mode 알 수 없는 치수 모드
|
||||
@msg Unknown dimension option {k} 알 수 없는 치수 옵션 {k}
|
||||
@msg Unknown dimension style 알 수 없는 치수 스타일
|
||||
@msg Unknown unit 알 수 없는 단위
|
||||
# Revolve cap description
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -4692,6 +4692,7 @@ mark-style Japanese Japońskie
|
||||
@msg Scale ratio must be between 1:1000000 and 1000000:1 Współczynnik skali musi mieścić się między 1:1000000 a 1000000:1
|
||||
@msg Second measured segment no longer exists Drugi mierzony odcinek już nie istnieje
|
||||
@msg Unknown dimension mode Nieznany tryb wymiaru
|
||||
@msg Unknown dimension option {k} Nieznana opcja wymiaru {k}
|
||||
@msg Unknown dimension style Nieznany styl wymiaru
|
||||
@msg Unknown unit Nieznana jednostka
|
||||
# Revolve cap description
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -4421,6 +4421,7 @@ lighting Light Свет
|
||||
@msg Scale ratio must be between 1:1000000 and 1000000:1 Соотношение масштаба должно быть от 1:1000000 до 1000000:1
|
||||
@msg Second measured segment no longer exists Второй измеряемый сегмент больше не существует
|
||||
@msg Unknown dimension mode Неизвестный режим размера
|
||||
@msg Unknown dimension option {k} Неизвестный параметр размера {k}
|
||||
@msg Unknown dimension style Неизвестный стиль размера
|
||||
@msg Unknown unit Неизвестная единица
|
||||
# Revolve cap description
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -4405,6 +4405,7 @@ lighting Light Світло
|
||||
@msg Scale ratio must be between 1:1000000 and 1000000:1 Співвідношення масштабу має бути від 1:1000000 до 1000000:1
|
||||
@msg Second measured segment no longer exists Другий виміряний сегмент більше не існує
|
||||
@msg Unknown dimension mode Невідомий режим розміру
|
||||
@msg Unknown dimension option {k} Невідомий параметр розміру {k}
|
||||
@msg Unknown dimension style Невідомий стиль розміру
|
||||
@msg Unknown unit Невідома одиниця
|
||||
# Revolve cap description
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 713 and column 40.
|
@@ -4404,6 +4404,7 @@ theme Appearance Giao diện
|
||||
@msg Scale ratio must be between 1:1000000 and 1000000:1 Tỷ lệ phải nằm trong khoảng 1:1000000 đến 1000000:1
|
||||
@msg Second measured segment no longer exists Đoạn được đo thứ hai không còn tồn tại
|
||||
@msg Unknown dimension mode Chế độ kích thước không xác định
|
||||
@msg Unknown dimension option {k} Tùy chọn kích thước không xác định {k}
|
||||
@msg Unknown dimension style Kiểu kích thước không xác định
|
||||
@msg Unknown unit Đơn vị không xác định
|
||||
# Revolve cap description
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 3682 and column 10.
|
Reference in New Issue
Block a user