T21a round 2 fixes
- a field notes its selection when a key goes down, so undo of typing selects what the typing replaced - reading order skips table cells merged away, so Up and Down across blocks land on cells that show
This commit is contained in:
6 files changed
+68
-3
No files matched your search
@@ -248,4 +248,5 @@ Per-component lines live in `tasks/`. Tags there:
|
|||||||
| T20 | 1 | FAIL | the demo picked past memory's end; an empty gutter had no height to press; a breakpoint's box also opened it; zoomed ticks lost their places; docs promised bound keys and batch actions |
|
| T20 | 1 | FAIL | the demo picked past memory's end; an empty gutter had no height to press; a breakpoint's box also opened it; zoomed ticks lost their places; docs promised bound keys and batch actions |
|
||||||
| T20 | 2 | PASS | |
|
| T20 | 2 | PASS | |
|
||||||
| T21a | 1 | FAIL | Enter kept a selection; undo of a split left focus on a gone field; italic inside bold ate the bold; keys went into merged cells; undo kept a changed kind's highlighter |
|
| T21a | 1 | FAIL | Enter kept a selection; undo of a split left focus on a gone field; italic inside bold ate the bold; keys went into merged cells; undo kept a changed kind's highlighter |
|
||||||
| T21a | 2 | — | pending review |
|
| T21a | 2 | FAIL | undo of typing lost the selection it replaced; Up from below a table landed in a hidden merged cell |
|
||||||
|
| T21a | 3 | — | pending review |
|
||||||
@@ -162,14 +162,26 @@ impl BlockEditor {
|
|||||||
/// Records what changed as one undo step, a burst of typing as one, and tells the owner.
|
/// Records what changed as one undo step, a burst of typing as one, and tells the owner.
|
||||||
pub(super) fn settle(&mut self, typing: bool, cx: &mut Context<Self>) {
|
pub(super) fn settle(&mut self, typing: bool, cx: &mut Context<Self>) {
|
||||||
let now = self.snapshot(cx);
|
let now = self.snapshot(cx);
|
||||||
|
let typed_from = self.typed_from.take();
|
||||||
if now.blocks != self.current.blocks {
|
if now.blocks != self.current.blocks {
|
||||||
let before = std::mem::replace(&mut self.current, now);
|
let mut before = std::mem::replace(&mut self.current, now);
|
||||||
|
if typed_from.is_some() {
|
||||||
|
before.caret = typed_from;
|
||||||
|
}
|
||||||
self.history.record(before, typing);
|
self.history.record(before, typing);
|
||||||
cx.emit(BlockEvent::Changed);
|
cx.emit(BlockEvent::Changed);
|
||||||
cx.notify();
|
cx.notify();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Where a key went down, before the field acts on it: the start a typing burst's undo goes back to.
|
||||||
|
pub(crate) fn note_key(&mut self, key: u64, field: usize, cx: &Context<Self>) {
|
||||||
|
let selection = self.blocks[self.index(key)].fields[field]
|
||||||
|
.read(cx)
|
||||||
|
.selection();
|
||||||
|
self.typed_from = Some((key, field, selection));
|
||||||
|
}
|
||||||
|
|
||||||
/// Records the document before a change to its blocks.
|
/// Records the document before a change to its blocks.
|
||||||
pub(crate) fn before_change(&mut self, cx: &mut Context<Self>) {
|
pub(crate) fn before_change(&mut self, cx: &mut Context<Self>) {
|
||||||
self.settle(true, cx);
|
self.settle(true, cx);
|
||||||
|
|||||||
@@ -18,7 +18,16 @@ impl BlockEditor {
|
|||||||
BlockKind::Toggle(false) => 1,
|
BlockKind::Toggle(false) => 1,
|
||||||
_ => block.fields.len(),
|
_ => block.fields.len(),
|
||||||
};
|
};
|
||||||
(0..shown).map(move |field| (block.key, field))
|
let hidden: Vec<usize> = match &block.kind {
|
||||||
|
BlockKind::Table { columns, merged } => merged
|
||||||
|
.iter()
|
||||||
|
.map(|(row, column)| row * columns + column)
|
||||||
|
.collect(),
|
||||||
|
_ => Vec::new(),
|
||||||
|
};
|
||||||
|
(0..shown)
|
||||||
|
.filter(move |field| !hidden.contains(field))
|
||||||
|
.map(move |field| (block.key, field))
|
||||||
})
|
})
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -76,6 +76,8 @@ pub struct BlockEditor {
|
|||||||
current: Snapshot,
|
current: Snapshot,
|
||||||
/// The field that last held focus, as block and field.
|
/// The field that last held focus, as block and field.
|
||||||
caret: Option<(u64, usize)>,
|
caret: Option<(u64, usize)>,
|
||||||
|
/// The selection a key went down on, before its field changed.
|
||||||
|
typed_from: Option<(u64, usize, std::ops::Range<usize>)>,
|
||||||
pub(crate) people: Vec<SharedString>,
|
pub(crate) people: Vec<SharedString>,
|
||||||
pub(crate) diagram: Option<RenderDiagram>,
|
pub(crate) diagram: Option<RenderDiagram>,
|
||||||
_synced: Subscription,
|
_synced: Subscription,
|
||||||
@@ -95,6 +97,7 @@ impl BlockEditor {
|
|||||||
caret: None,
|
caret: None,
|
||||||
},
|
},
|
||||||
caret: None,
|
caret: None,
|
||||||
|
typed_from: None,
|
||||||
people: Vec::new(),
|
people: Vec::new(),
|
||||||
diagram: None,
|
diagram: None,
|
||||||
_synced: synced,
|
_synced: synced,
|
||||||
|
|||||||
@@ -114,6 +114,7 @@ impl BlockEditor {
|
|||||||
cx.stop_propagation();
|
cx.stop_propagation();
|
||||||
editor.on_submit(key, window, cx);
|
editor.on_submit(key, window, cx);
|
||||||
}))
|
}))
|
||||||
|
.capture_key_down(cx.listener(move |editor, _, _, cx| editor.note_key(key, ix, cx)))
|
||||||
.on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
|
.on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
|
||||||
.child(field.clone());
|
.child(field.clone());
|
||||||
let slash = move |query: &str, at: usize, caret: usize| -> (Vec<Choice>, Pick) {
|
let slash = move |query: &str, at: usize, caret: usize| -> (Vec<Choice>, Pick) {
|
||||||
|
|||||||
@@ -305,3 +305,42 @@ fn undoing_a_kind_change_brings_back_its_styling(cx: &mut TestAppContext) {
|
|||||||
);
|
);
|
||||||
assert!(bold, "the paragraph styles its markdown again");
|
assert!(bold, "the paragraph styles its markdown again");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[gpui::test]
|
||||||
|
fn undo_of_typing_restores_the_selection_it_replaced(cx: &mut TestAppContext) {
|
||||||
|
let (editor, cx) = open(vec![BlockData::new(BlockKind::Paragraph, ["abcdef"])], cx);
|
||||||
|
select(&editor, 0, 0, 2..4, cx);
|
||||||
|
cx.simulate_keystrokes("x");
|
||||||
|
settle(cx);
|
||||||
|
assert_eq!(blocks(&editor, cx), [text(BlockKind::Paragraph, "abxef")]);
|
||||||
|
cx.simulate_keystrokes("cmd-z");
|
||||||
|
settle(cx);
|
||||||
|
let selection = cx.update(|_, cx| editor.read(cx).blocks[0].fields[0].read(cx).selection());
|
||||||
|
assert_eq!(blocks(&editor, cx), [text(BlockKind::Paragraph, "abcdef")]);
|
||||||
|
assert_eq!(selection, 2..4, "undo selects what the typing replaced");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[gpui::test]
|
||||||
|
fn up_into_a_table_skips_its_hidden_cells(cx: &mut TestAppContext) {
|
||||||
|
let table = BlockKind::Table {
|
||||||
|
columns: 2,
|
||||||
|
merged: vec![(1, 1)],
|
||||||
|
};
|
||||||
|
let (editor, cx) = open(
|
||||||
|
vec![
|
||||||
|
BlockData::new(table, ["A", "B", "c", ""]),
|
||||||
|
BlockData::new(BlockKind::Paragraph, ["after"]),
|
||||||
|
],
|
||||||
|
cx,
|
||||||
|
);
|
||||||
|
caret(&editor, 1, 0, cx);
|
||||||
|
cx.simulate_keystrokes("up");
|
||||||
|
settle(cx);
|
||||||
|
let key = cx.update(|_, cx| editor.read(cx).blocks[0].key);
|
||||||
|
let focused = cx.update(|window, cx| editor.read(cx).focused(window, cx));
|
||||||
|
assert_eq!(
|
||||||
|
focused,
|
||||||
|
Some((key, 2)),
|
||||||
|
"up lands on the cell that shows in the last row"
|
||||||
|
);
|
||||||
|
}
|
||||||
Reference in new issue
Block a user