Fix crash when cursor moves inside folded subtree

This commit is contained in:
Joscha 2023-05-03 00:02:09 +02:00
parent 2afda17d4b
commit e6585286e3
4 changed files with 46 additions and 12 deletions

View file

@ -178,7 +178,7 @@ where
}
/// Expand blocks such that the screen is full for any offset where the
/// specified block is visible.
/// specified block is visible. The block must exist.
pub async fn expand_to_fill_screen_around_block<Id, R>(r: &mut R, id: &Id) -> Result<(), R::Error>
where
Id: Eq,
@ -196,6 +196,8 @@ where
Ok(())
}
/// Scroll so that the top of the block is at the specified value. Returns
/// `true` if successful, or `false` if the block could not be found.
pub fn scroll_to_set_block_top<Id, R>(r: &mut R, id: &Id, top: i32) -> bool
where
Id: Eq,

View file

@ -439,7 +439,7 @@ where
let mut renderer = TreeRenderer::new(
context,
&self.state.store,
&self.state.folded,
&mut self.state.folded,
self.cursor,
self.editor,
frame.widthdb(),

View file

@ -80,7 +80,7 @@ pub struct TreeRenderer<'a, M: Msg, S: MsgStore<M>> {
context: TreeContext<M::Id>,
store: &'a S,
folded: &'a HashSet<M::Id>,
folded: &'a mut HashSet<M::Id>,
cursor: &'a mut Cursor<M::Id>,
editor: &'a mut EditorState,
widthdb: &'a mut WidthDb,
@ -107,7 +107,7 @@ where
pub fn new(
context: TreeContext<M::Id>,
store: &'a S,
folded: &'a HashSet<M::Id>,
folded: &'a mut HashSet<M::Id>,
cursor: &'a mut Cursor<M::Id>,
editor: &'a mut EditorState,
widthdb: &'a mut WidthDb,
@ -279,12 +279,30 @@ where
Ok(Some(path.into_first()))
}
async fn prepare_initial_tree(&mut self, root_id: &Option<M::Id>) -> Result<(), S::Error> {
/// Render the tree containing the cursor to the blocks and set the top and
/// bottom root id accordingly. This function will always render a block
/// that has the cusor id.
async fn prepare_initial_tree(
&mut self,
cursor_id: &TreeBlockId<M::Id>,
root_id: &Option<M::Id>,
) -> Result<(), S::Error> {
self.top_root_id = root_id.clone();
self.bottom_root_id = root_id.clone();
let blocks = if let Some(root_id) = root_id {
let tree = self.store.tree(root_id).await?;
// To ensure the cursor block will be rendered, all its parents must
// be unfolded.
if let TreeBlockId::Msg(id) | TreeBlockId::After(id) = cursor_id {
let mut id = id.clone();
while let Some(parent_id) = tree.parent(&id) {
self.folded.remove(&parent_id);
id = parent_id;
}
}
self.layout_tree(tree)
} else {
self.layout_bottom()
@ -318,9 +336,11 @@ where
let cursor_id = TreeBlockId::from_cursor(self.cursor);
let cursor_root_id = self.root_id(&cursor_id).await?;
// Render cursor and blocks around it until screen is filled as long as
// the cursor is visible, regardless of how the screen is scrolled.
self.prepare_initial_tree(&cursor_root_id).await?;
// Render cursor and blocks around it so that the screen will always be
// filled as long as the cursor is visible, regardless of how the screen
// is scrolled.
self.prepare_initial_tree(&cursor_id, &cursor_root_id)
.await?;
renderer::expand_to_fill_screen_around_block(self, &cursor_id).await?;
// Scroll based on last cursor position

View file

@ -33,8 +33,14 @@ where
delta: i32,
) -> Result<(), S::Error> {
let context = self.last_context();
let mut renderer =
TreeRenderer::new(context, &self.store, &self.folded, cursor, editor, widthdb);
let mut renderer = TreeRenderer::new(
context,
&self.store,
&mut self.folded,
cursor,
editor,
widthdb,
);
renderer.prepare_blocks_for_drawing().await?;
renderer.scroll_by(delta).await?;
@ -54,8 +60,14 @@ where
widthdb: &mut WidthDb,
) -> Result<(), S::Error> {
let context = self.last_context();
let mut renderer =
TreeRenderer::new(context, &self.store, &self.folded, cursor, editor, widthdb);
let mut renderer = TreeRenderer::new(
context,
&self.store,
&mut self.folded,
cursor,
editor,
widthdb,
);
renderer.prepare_blocks_for_drawing().await?;
renderer.center_cursor();