forked from 1b-agent/opencadstudio-upstream
style: apply cargo fmt across workspace
This commit is contained in:
1 parent
85710e5454
commit
9cf9ff2c5c
531 files changed
+57740
-33906
No files matched your search
+160
-105
@@ -217,7 +217,12 @@ impl MTextEditorState {
|
||||
}
|
||||
|
||||
pub fn height_value(&self) -> f64 {
|
||||
self.height.trim().parse::<f64>().ok().filter(|h| *h > 0.0).unwrap_or(0.25)
|
||||
self.height
|
||||
.trim()
|
||||
.parse::<f64>()
|
||||
.ok()
|
||||
.filter(|h| *h > 0.0)
|
||||
.unwrap_or(0.25)
|
||||
}
|
||||
|
||||
/// Pixels per drawing unit used by the editor preview. The dominant glyph
|
||||
@@ -258,8 +263,8 @@ impl MTextEditorState {
|
||||
/// purely by opencadcodec's `to_mtext_string`.
|
||||
fn apply_globals(&self, doc: &mut MTextDocument) {
|
||||
let font = self.font.trim();
|
||||
let color =
|
||||
(self.color_aci != 256 && self.color_aci != 0).then(|| MTextColor::Index(self.color_aci));
|
||||
let color = (self.color_aci != 256 && self.color_aci != 0)
|
||||
.then(|| MTextColor::Index(self.color_aci));
|
||||
let oblique = parse_non_default(&self.oblique, 0.0);
|
||||
let width = parse_non_default(&self.width, 1.0);
|
||||
let tracking = parse_non_default(&self.char_space, 0.0);
|
||||
@@ -346,10 +351,8 @@ impl MTextEditorState {
|
||||
}
|
||||
}
|
||||
if !self.column_auto_height && rectangle_height > 0.0 {
|
||||
mt.column_data.heights = vec![
|
||||
rectangle_height;
|
||||
mt.column_data.column_count as usize
|
||||
];
|
||||
mt.column_data.heights =
|
||||
vec![rectangle_height; mt.column_data.column_count as usize];
|
||||
}
|
||||
}
|
||||
mt
|
||||
@@ -484,7 +487,9 @@ fn cells_to_doc(para0: &ParagraphProperties, cells: &[Cell]) -> MTextDocument {
|
||||
}
|
||||
Cell::Char(ch, props) => match para.spans.last_mut() {
|
||||
Some(s) if s.stacking.is_none() && &s.properties == props => s.text.push(*ch),
|
||||
_ => para.spans.push(MTextSpan::new(ch.to_string(), props.clone())),
|
||||
_ => para
|
||||
.spans
|
||||
.push(MTextSpan::new(ch.to_string(), props.clone())),
|
||||
},
|
||||
Cell::Stack { data, props, head } => {
|
||||
if *head {
|
||||
@@ -514,7 +519,11 @@ fn para_props_at(para0: &ParagraphProperties, cells: &[Cell], caret: usize) -> P
|
||||
|
||||
/// Turn an inserted string (which may carry `\P` breaks) into cells, tagging
|
||||
/// every plain char with `span_props` and every break with `para_props`.
|
||||
fn str_to_cells(s: &str, span_props: &SpanProperties, para_props: &ParagraphProperties) -> Vec<Cell> {
|
||||
fn str_to_cells(
|
||||
s: &str,
|
||||
span_props: &SpanProperties,
|
||||
para_props: &ParagraphProperties,
|
||||
) -> Vec<Cell> {
|
||||
let mut cells = Vec::new();
|
||||
for (i, seg) in s.split("\\P").enumerate() {
|
||||
if i > 0 {
|
||||
@@ -621,7 +630,6 @@ fn cells_delete_range(cells: &mut Vec<Cell>, mut a: usize, mut b: usize) -> usiz
|
||||
a
|
||||
}
|
||||
|
||||
|
||||
// ── App-side editor driver ──────────────────────────────────────────────────
|
||||
|
||||
use crate::scene::convert::tessellate;
|
||||
@@ -640,16 +648,33 @@ fn vertical_caret_target(
|
||||
let anchor = boxes
|
||||
.iter()
|
||||
.find(|item| item.vis == caret)
|
||||
.map(|item| ((if item.is_rtl { item.xmax } else { item.xmin }), item.ymin, item.ymax))
|
||||
.map(|item| {
|
||||
(
|
||||
(if item.is_rtl { item.xmax } else { item.xmin }),
|
||||
item.ymin,
|
||||
item.ymax,
|
||||
)
|
||||
})
|
||||
.or_else(|| {
|
||||
caret.checked_sub(1).and_then(|previous| {
|
||||
boxes
|
||||
.iter()
|
||||
.find(|item| item.vis == previous)
|
||||
.map(|item| ((if item.is_rtl { item.xmin } else { item.xmax }), item.ymin, item.ymax))
|
||||
boxes.iter().find(|item| item.vis == previous).map(|item| {
|
||||
(
|
||||
(if item.is_rtl { item.xmin } else { item.xmax }),
|
||||
item.ymin,
|
||||
item.ymax,
|
||||
)
|
||||
})
|
||||
})
|
||||
})
|
||||
.or_else(|| boxes.first().map(|item| ((if item.is_rtl { item.xmax } else { item.xmin }), item.ymin, item.ymax)));
|
||||
.or_else(|| {
|
||||
boxes.first().map(|item| {
|
||||
(
|
||||
(if item.is_rtl { item.xmax } else { item.xmin }),
|
||||
item.ymin,
|
||||
item.ymax,
|
||||
)
|
||||
})
|
||||
});
|
||||
let Some((anchor_x, anchor_y, anchor_top)) = anchor else {
|
||||
return caret.min(visible_count);
|
||||
};
|
||||
@@ -691,10 +716,9 @@ fn seed_mtext_state(state: &mut MTextEditorState, m: &MText) {
|
||||
state.rect_height = m.rectangle_height.unwrap_or(0.0).max(0.0).to_string();
|
||||
state.annotative = m.is_annotative;
|
||||
state.column_type = m.column_data.column_type;
|
||||
state.column_count = crate::entities::text_support::clamp_mtext_column_count(
|
||||
m.column_data.column_count,
|
||||
)
|
||||
.to_string();
|
||||
state.column_count =
|
||||
crate::entities::text_support::clamp_mtext_column_count(m.column_data.column_count)
|
||||
.to_string();
|
||||
state.column_auto_height = m.column_data.auto_height;
|
||||
state.column_flow_reversed = m.column_data.flow_reversed;
|
||||
state.column_width = m.column_data.width.max(0.0).to_string();
|
||||
@@ -721,7 +745,13 @@ impl super::OpenCADStudio {
|
||||
return;
|
||||
}
|
||||
let mut state = MTextEditorState::new(pos, initial, height, handle);
|
||||
if let Some(p) = self.tabs[self.active_tab].scene.selection.borrow().input.last_move_pos {
|
||||
if let Some(p) = self.tabs[self.active_tab]
|
||||
.scene
|
||||
.selection
|
||||
.borrow()
|
||||
.input
|
||||
.last_move_pos
|
||||
{
|
||||
state.screen_anchor = p;
|
||||
}
|
||||
// Seed attachment / line-spacing / box width from the entity being edited.
|
||||
@@ -764,9 +794,10 @@ impl super::OpenCADStudio {
|
||||
// wrap width is the drawing-unit span that exactly reaches the right
|
||||
// edge of the editor, placing both ruler and slider at their maximum.
|
||||
if handle.is_none() && !has_template {
|
||||
let initial_width = self.mtext_editor.as_ref().map(|ed| {
|
||||
super::view::overlay::MTEXT_EDITOR_WRITING_WIDTH / ed.preview_scale()
|
||||
});
|
||||
let initial_width = self
|
||||
.mtext_editor
|
||||
.as_ref()
|
||||
.map(|ed| super::view::overlay::MTEXT_EDITOR_WRITING_WIDTH / ed.preview_scale());
|
||||
if let (Some(ed), Some(width)) = (self.mtext_editor.as_mut(), initial_width) {
|
||||
ed.rect_width = f64::from(width.max(1e-6));
|
||||
}
|
||||
@@ -786,7 +817,9 @@ impl super::OpenCADStudio {
|
||||
/// never on the drawing canvas).
|
||||
pub(super) fn rebuild_mtext_preview(&mut self) {
|
||||
let i = self.active_tab;
|
||||
let Some(ed) = self.mtext_editor.as_ref() else { return };
|
||||
let Some(ed) = self.mtext_editor.as_ref() else {
|
||||
return;
|
||||
};
|
||||
let mut mt = ed.build_mtext();
|
||||
// A trailing empty paragraph (a fresh line after Enter) is dropped by the
|
||||
// layout's parser, so it emits no caret box there and the caret would be
|
||||
@@ -991,8 +1024,8 @@ impl super::OpenCADStudio {
|
||||
let para0 = doc_para0(&ed.doc);
|
||||
let mut cells = doc_to_cells(&ed.doc);
|
||||
let end = end.min(cells.len());
|
||||
let plain = cells_to_doc(&ParagraphProperties::default(), &cells[start..end])
|
||||
.to_plain_text();
|
||||
let plain =
|
||||
cells_to_doc(&ParagraphProperties::default(), &cells[start..end]).to_plain_text();
|
||||
let Some((split, separator)) = plain
|
||||
.char_indices()
|
||||
.find(|(_, ch)| matches!(ch, '/' | '#' | '^'))
|
||||
@@ -1028,9 +1061,8 @@ impl super::OpenCADStudio {
|
||||
let replacement_len = replacement.len();
|
||||
cells.splice(start..end, replacement);
|
||||
let new_end = start + replacement_len;
|
||||
ed.content = text_editor::Content::with_text(
|
||||
&cells_to_doc(¶0, &cells).to_mtext_string(),
|
||||
);
|
||||
ed.content =
|
||||
text_editor::Content::with_text(&cells_to_doc(¶0, &cells).to_mtext_string());
|
||||
ed.sel = Some((start, new_end));
|
||||
ed.caret = new_end;
|
||||
ed.sel_anchor = start;
|
||||
@@ -1053,9 +1085,8 @@ impl super::OpenCADStudio {
|
||||
*props = SpanProperties::default();
|
||||
}
|
||||
}
|
||||
ed.content = text_editor::Content::with_text(
|
||||
&cells_to_doc(¶0, &cells).to_mtext_string(),
|
||||
);
|
||||
ed.content =
|
||||
text_editor::Content::with_text(&cells_to_doc(¶0, &cells).to_mtext_string());
|
||||
ed.sel = Some((start, end));
|
||||
ed.caret = end;
|
||||
}
|
||||
@@ -1135,10 +1166,9 @@ impl super::OpenCADStudio {
|
||||
let mut matches = Vec::new();
|
||||
let mut index = 0usize;
|
||||
while index + needle.len() <= cells.len() {
|
||||
let found = cells[index..index + needle.len()]
|
||||
.iter()
|
||||
.zip(&needle)
|
||||
.all(|(cell, expected)| matches!(cell, Cell::Char(actual, _) if actual == expected));
|
||||
let found = cells[index..index + needle.len()].iter().zip(&needle).all(
|
||||
|(cell, expected)| matches!(cell, Cell::Char(actual, _) if actual == expected),
|
||||
);
|
||||
if found {
|
||||
matches.push(index);
|
||||
index += needle.len();
|
||||
@@ -1156,9 +1186,8 @@ impl super::OpenCADStudio {
|
||||
let replacement_cells = str_to_cells(&replacement, &props, ¶graph);
|
||||
cells.splice(start..start + needle.len(), replacement_cells);
|
||||
}
|
||||
ed.content = text_editor::Content::with_text(
|
||||
&cells_to_doc(¶0, &cells).to_mtext_string(),
|
||||
);
|
||||
ed.content =
|
||||
text_editor::Content::with_text(&cells_to_doc(¶0, &cells).to_mtext_string());
|
||||
ed.caret = cells.len();
|
||||
ed.sel = Some((ed.caret, ed.caret));
|
||||
ed.sel_anchor = ed.caret;
|
||||
@@ -1200,8 +1229,7 @@ impl super::OpenCADStudio {
|
||||
if !ed.font.trim().is_empty() {
|
||||
ed.font.clone()
|
||||
} else {
|
||||
crate::entities::text_support::resolve_text_style(&ed.style, doc)
|
||||
.font_name
|
||||
crate::entities::text_support::resolve_text_style(&ed.style, doc).font_name
|
||||
}
|
||||
})
|
||||
.unwrap_or_default()
|
||||
@@ -1239,8 +1267,7 @@ impl super::OpenCADStudio {
|
||||
// the one canonical form is the oblique — otherwise an
|
||||
// imported italic run could never be switched off.
|
||||
let on = !all_have(&cells[a..b], |p| {
|
||||
p.oblique_angle == Some(15.0)
|
||||
|| p.font.as_ref().is_some_and(|f| f.italic)
|
||||
p.oblique_angle == Some(15.0) || p.font.as_ref().is_some_and(|f| f.italic)
|
||||
});
|
||||
each(&mut cells[a..b], |p| {
|
||||
p.oblique_angle = on.then_some(15.0);
|
||||
@@ -1252,9 +1279,7 @@ impl super::OpenCADStudio {
|
||||
MTextFmt::Bold => {
|
||||
// Real bold: set the font's bold flag (the SDF renderer bakes
|
||||
// a wider pen), keeping the run's font name + italic.
|
||||
let on = !all_have(&cells[a..b], |p| {
|
||||
p.font.as_ref().is_some_and(|f| f.bold)
|
||||
});
|
||||
let on = !all_have(&cells[a..b], |p| p.font.as_ref().is_some_and(|f| f.bold));
|
||||
each(&mut cells[a..b], |p| {
|
||||
let (name, italic) = p
|
||||
.font
|
||||
@@ -1319,8 +1344,13 @@ impl super::OpenCADStudio {
|
||||
ParaAlign::Justify => MTextParagraphAlignment::Justified,
|
||||
});
|
||||
// Paragraph index of a cell = number of breaks before it.
|
||||
let para_of =
|
||||
|idx: usize| cells.iter().take(idx).filter(|c| matches!(c, Cell::Break(..))).count();
|
||||
let para_of = |idx: usize| {
|
||||
cells
|
||||
.iter()
|
||||
.take(idx)
|
||||
.filter(|c| matches!(c, Cell::Break(..)))
|
||||
.count()
|
||||
};
|
||||
let last_cell = if b > a { b - 1 } else { a };
|
||||
let first = para_of(a);
|
||||
let last = para_of(last_cell);
|
||||
@@ -1415,9 +1445,7 @@ impl super::OpenCADStudio {
|
||||
let count = cells.len();
|
||||
let caret = match ed.sel {
|
||||
Some((a, b)) if a < b && b <= count => cells_delete_range(&mut cells, a, b),
|
||||
_ if ed.caret < count => {
|
||||
cells_delete_range(&mut cells, ed.caret, ed.caret + 1)
|
||||
}
|
||||
_ if ed.caret < count => cells_delete_range(&mut cells, ed.caret, ed.caret + 1),
|
||||
_ => ed.caret.min(count),
|
||||
};
|
||||
ed.content =
|
||||
@@ -1456,19 +1484,10 @@ impl super::OpenCADStudio {
|
||||
|
||||
/// Move the caret to the visually adjacent text line while preserving its
|
||||
/// horizontal position as closely as the laid-out glyph boxes allow.
|
||||
pub(super) fn mtext_caret_move_vertical(
|
||||
&mut self,
|
||||
direction: i8,
|
||||
extend_selection: bool,
|
||||
) {
|
||||
pub(super) fn mtext_caret_move_vertical(&mut self, direction: i8, extend_selection: bool) {
|
||||
if let Some(ed) = self.mtext_editor.as_mut() {
|
||||
let visible_count = doc_to_cells(&ed.doc).len();
|
||||
let caret = vertical_caret_target(
|
||||
&ed.glyph_boxes,
|
||||
ed.caret,
|
||||
visible_count,
|
||||
direction,
|
||||
);
|
||||
let caret = vertical_caret_target(&ed.glyph_boxes, ed.caret, visible_count, direction);
|
||||
ed.caret = caret;
|
||||
if extend_selection {
|
||||
ed.sel = Some((ed.sel_anchor.min(caret), ed.sel_anchor.max(caret)));
|
||||
@@ -1554,7 +1573,11 @@ impl super::OpenCADStudio {
|
||||
}
|
||||
} else if let Some(ed) = self.mtext_editor.as_mut() {
|
||||
// No selection: the global font applies to the whole text.
|
||||
ed.font = if default { String::new() } else { font.to_string() };
|
||||
ed.font = if default {
|
||||
String::new()
|
||||
} else {
|
||||
font.to_string()
|
||||
};
|
||||
}
|
||||
self.rebuild_mtext_preview();
|
||||
}
|
||||
@@ -1635,7 +1658,9 @@ impl super::OpenCADStudio {
|
||||
/// Commit the editor — create a new MText or update the edited one.
|
||||
pub(super) fn mtext_commit(&mut self) -> bool {
|
||||
let i = self.active_tab;
|
||||
let Some(ed) = self.mtext_editor.take() else { return false };
|
||||
let Some(ed) = self.mtext_editor.take() else {
|
||||
return false;
|
||||
};
|
||||
if self.command_mtext_input {
|
||||
self.pending_command_editor_text = Some(ed.build_mtext().value);
|
||||
self.command_mtext_input = false;
|
||||
@@ -1646,10 +1671,10 @@ impl super::OpenCADStudio {
|
||||
let mut mt = ed.build_mtext();
|
||||
let annotative = mt.is_annotative
|
||||
|| ed.editing.is_none()
|
||||
&& crate::scene::annotative::text_style_is_annotative(
|
||||
&self.tabs[i].scene.document,
|
||||
&mt.style,
|
||||
);
|
||||
&& crate::scene::annotative::text_style_is_annotative(
|
||||
&self.tabs[i].scene.document,
|
||||
&mt.style,
|
||||
);
|
||||
if annotative {
|
||||
mt.is_annotative = true;
|
||||
}
|
||||
@@ -1686,7 +1711,10 @@ impl super::OpenCADStudio {
|
||||
_ => {}
|
||||
}
|
||||
// Keep the displayed annotation context in sync.
|
||||
if matches!(self.tabs[i].scene.document.get_entity(h), Some(EntityType::MText(_))) {
|
||||
if matches!(
|
||||
self.tabs[i].scene.document.get_entity(h),
|
||||
Some(EntityType::MText(_))
|
||||
) {
|
||||
crate::scene::annotative::set_entity_annotative(
|
||||
&mut self.tabs[i].scene.document,
|
||||
h,
|
||||
@@ -1706,9 +1734,7 @@ impl super::OpenCADStudio {
|
||||
self.tabs[i].scene.document.get_entity(h),
|
||||
Some(EntityType::MText(_) | EntityType::MultiLeader(_))
|
||||
) {
|
||||
self.tabs[i]
|
||||
.scene
|
||||
.sync_displayed_annotation_context(h);
|
||||
self.tabs[i].scene.sync_displayed_annotation_context(h);
|
||||
}
|
||||
self.tabs[i]
|
||||
.scene
|
||||
@@ -1725,11 +1751,7 @@ impl super::OpenCADStudio {
|
||||
mt.insertion_point.y,
|
||||
mt.insertion_point.z,
|
||||
));
|
||||
mt.insertion_point = codec::types::Vector3::new(
|
||||
position.x,
|
||||
position.y,
|
||||
position.z,
|
||||
);
|
||||
mt.insertion_point = codec::types::Vector3::new(position.x, position.y, position.z);
|
||||
self.push_undo_snapshot(i, "MTEXT");
|
||||
let handle = self.commit_entity_handle(plane.place_entity(EntityType::MText(mt)));
|
||||
if annotative {
|
||||
@@ -1769,10 +1791,10 @@ impl super::OpenCADStudio {
|
||||
};
|
||||
let annotative = mt.is_annotative
|
||||
|| editing.is_none()
|
||||
&& crate::scene::annotative::text_style_is_annotative(
|
||||
&self.tabs[i].scene.document,
|
||||
&mt.style,
|
||||
);
|
||||
&& crate::scene::annotative::text_style_is_annotative(
|
||||
&self.tabs[i].scene.document,
|
||||
&mt.style,
|
||||
);
|
||||
if annotative {
|
||||
mt.is_annotative = true;
|
||||
}
|
||||
@@ -1805,7 +1827,10 @@ impl super::OpenCADStudio {
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
if matches!(self.tabs[i].scene.document.get_entity(h), Some(EntityType::MText(_))) {
|
||||
if matches!(
|
||||
self.tabs[i].scene.document.get_entity(h),
|
||||
Some(EntityType::MText(_))
|
||||
) {
|
||||
crate::scene::annotative::set_entity_annotative(
|
||||
&mut self.tabs[i].scene.document,
|
||||
h,
|
||||
@@ -1825,9 +1850,7 @@ impl super::OpenCADStudio {
|
||||
self.tabs[i].scene.document.get_entity(h),
|
||||
Some(EntityType::MText(_) | EntityType::MultiLeader(_))
|
||||
) {
|
||||
self.tabs[i]
|
||||
.scene
|
||||
.sync_displayed_annotation_context(h);
|
||||
self.tabs[i].scene.sync_displayed_annotation_context(h);
|
||||
}
|
||||
self.tabs[i]
|
||||
.scene
|
||||
@@ -1844,11 +1867,7 @@ impl super::OpenCADStudio {
|
||||
mt.insertion_point.y,
|
||||
mt.insertion_point.z,
|
||||
));
|
||||
mt.insertion_point = codec::types::Vector3::new(
|
||||
position.x,
|
||||
position.y,
|
||||
position.z,
|
||||
);
|
||||
mt.insertion_point = codec::types::Vector3::new(position.x, position.y, position.z);
|
||||
self.push_undo_snapshot(i, "MTEXT");
|
||||
let handle = self.commit_entity_handle(plane.place_entity(EntityType::MText(mt)));
|
||||
self.tabs[i].dirty = true;
|
||||
@@ -1865,9 +1884,7 @@ impl super::OpenCADStudio {
|
||||
// Bind the editor to the fresh entity so the next Apply updates it.
|
||||
if let (Some(h), Some(ed)) = (handle, self.mtext_editor.as_mut()) {
|
||||
ed.editing = Some(h);
|
||||
if let Some(EntityType::MText(mtext)) =
|
||||
self.tabs[i].scene.document.get_entity(h)
|
||||
{
|
||||
if let Some(EntityType::MText(mtext)) = self.tabs[i].scene.document.get_entity(h) {
|
||||
ed.original = Some(mtext.clone());
|
||||
}
|
||||
}
|
||||
@@ -1905,18 +1922,29 @@ mod cell_tests {
|
||||
|
||||
#[test]
|
||||
fn roundtrip_idempotent() {
|
||||
for s in ["hello", "a b c", "one\\Ptwo", "a\\Pb\\Pc", "trailing\\P", "a b", "\\S1/2;"] {
|
||||
for s in [
|
||||
"hello",
|
||||
"a b c",
|
||||
"one\\Ptwo",
|
||||
"a\\Pb\\Pc",
|
||||
"trailing\\P",
|
||||
"a b",
|
||||
"\\S1/2;",
|
||||
] {
|
||||
let once = rt(s);
|
||||
let twice = rt(&once);
|
||||
assert_eq!(once, twice, "not idempotent for {s:?}: {once:?} vs {twice:?}");
|
||||
assert_eq!(
|
||||
once, twice,
|
||||
"not idempotent for {s:?}: {once:?} vs {twice:?}"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cell_count_matches_plain() {
|
||||
assert_eq!(cells_of("ab\\Pcd").len(), 5); // a b Break c d
|
||||
// parse_mtext drops the trailing empty paragraph; the app restores it in
|
||||
// rebuild() (raw.ends_with("\\P")), so this pure-parse count is 2.
|
||||
// parse_mtext drops the trailing empty paragraph; the app restores it in
|
||||
// rebuild() (raw.ends_with("\\P")), so this pure-parse count is 2.
|
||||
assert_eq!(cells_of("ab\\P").len(), 2);
|
||||
}
|
||||
|
||||
@@ -1933,7 +1961,14 @@ mod cell_tests {
|
||||
assert_eq!(back, cells);
|
||||
// Typing after the trailing break lands on the new (empty) paragraph.
|
||||
let mut c2 = cells.clone();
|
||||
c2.splice(3..3, str_to_cells("x", &SpanProperties::default(), &ParagraphProperties::default()));
|
||||
c2.splice(
|
||||
3..3,
|
||||
str_to_cells(
|
||||
"x",
|
||||
&SpanProperties::default(),
|
||||
&ParagraphProperties::default(),
|
||||
),
|
||||
);
|
||||
assert_eq!(
|
||||
paras(&cells_to_doc(&ParagraphProperties::default(), &c2).to_mtext_string()),
|
||||
vec!["ab", "x"]
|
||||
@@ -1943,8 +1978,18 @@ mod cell_tests {
|
||||
#[test]
|
||||
fn insert_break_splits_paragraph() {
|
||||
let mut cells = cells_of("abcd");
|
||||
cells.splice(2..2, str_to_cells("\\P", &SpanProperties::default(), &ParagraphProperties::default()));
|
||||
assert_eq!(paras(&cells_to_doc(&ParagraphProperties::default(), &cells).to_mtext_string()), vec!["ab", "cd"]);
|
||||
cells.splice(
|
||||
2..2,
|
||||
str_to_cells(
|
||||
"\\P",
|
||||
&SpanProperties::default(),
|
||||
&ParagraphProperties::default(),
|
||||
),
|
||||
);
|
||||
assert_eq!(
|
||||
paras(&cells_to_doc(&ParagraphProperties::default(), &cells).to_mtext_string()),
|
||||
vec!["ab", "cd"]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -1952,14 +1997,20 @@ mod cell_tests {
|
||||
let mut cells = cells_of("ab\\Pcd"); // [a,b,Break,c,d]
|
||||
let caret = cells_delete_range(&mut cells, 2, 3); // delete the Break slot
|
||||
assert_eq!(caret, 2);
|
||||
assert_eq!(paras(&cells_to_doc(&ParagraphProperties::default(), &cells).to_mtext_string()), vec!["abcd"]);
|
||||
assert_eq!(
|
||||
paras(&cells_to_doc(&ParagraphProperties::default(), &cells).to_mtext_string()),
|
||||
vec!["abcd"]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn delete_range_across_paragraphs() {
|
||||
let mut cells = cells_of("abc\\Pdef"); // [a,b,c,Break,d,e,f]
|
||||
cells_delete_range(&mut cells, 1, 5); // b c Break d
|
||||
assert_eq!(paras(&cells_to_doc(&ParagraphProperties::default(), &cells).to_mtext_string()), vec!["aef"]);
|
||||
assert_eq!(
|
||||
paras(&cells_to_doc(&ParagraphProperties::default(), &cells).to_mtext_string()),
|
||||
vec!["aef"]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -2027,7 +2078,7 @@ mod cell_tests {
|
||||
assert_eq!(word_range(&cells, 8), (6, 11)); // inside "world"
|
||||
assert_eq!(word_range(&cells, 5), (5, 6)); // the space itself
|
||||
assert_eq!(word_range(&cells, 11), (6, 11)); // past end → last word
|
||||
// Double-click does not cross a paragraph break.
|
||||
// Double-click does not cross a paragraph break.
|
||||
let c2 = cells_of("ab\\Pcd"); // a b Break c d
|
||||
assert_eq!(word_range(&c2, 0), (0, 2)); // "ab"
|
||||
assert_eq!(word_range(&c2, 2), (2, 3)); // the break alone
|
||||
@@ -2093,6 +2144,10 @@ mod cell_tests {
|
||||
if content_has_trailing_break(&raw) {
|
||||
d.paragraphs.push(MTextParagraph::new());
|
||||
}
|
||||
assert_eq!(doc_to_cells(&d).len(), 3, "trailing break must survive rebuild");
|
||||
assert_eq!(
|
||||
doc_to_cells(&d).len(),
|
||||
3,
|
||||
"trailing break must survive rebuild"
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user