fix(resurrection): log failure instead of crashing in some edge cases (#2851)

* fix(resurrection): log failure instead of crashing in some edge cases

* style(fmt): rustfmt
This commit is contained in:
Aram Drevekenin 2023-10-13 11:54:05 +02:00 committed by GitHub
parent a6ab09cbb0
commit 404608e7e3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 147 additions and 84 deletions

View file

@ -535,23 +535,43 @@ pub(crate) fn pty_thread_main(mut pty: Pty, layout: Box<Layout>) -> Result<()> {
PtyInstruction::DumpLayout(mut session_layout_metadata, client_id) => { PtyInstruction::DumpLayout(mut session_layout_metadata, client_id) => {
let err_context = || format!("Failed to dump layout"); let err_context = || format!("Failed to dump layout");
pty.populate_session_layout_metadata(&mut session_layout_metadata); pty.populate_session_layout_metadata(&mut session_layout_metadata);
let (kdl_layout, _pane_contents) = match session_serialization::serialize_session_layout(
session_serialization::serialize_session_layout(session_layout_metadata.into()); session_layout_metadata.into(),
pty.bus ) {
.senders Ok((kdl_layout, _pane_contents)) => {
.send_to_server(ServerInstruction::Log(vec![kdl_layout], client_id)) pty.bus
.with_context(err_context) .senders
.non_fatal(); .send_to_server(ServerInstruction::Log(vec![kdl_layout], client_id))
.with_context(err_context)
.non_fatal();
},
Err(e) => {
pty.bus
.senders
.send_to_server(ServerInstruction::Log(vec![e.to_owned()], client_id))
.with_context(err_context)
.non_fatal();
},
}
}, },
PtyInstruction::LogLayoutToHd(mut session_layout_metadata) => { PtyInstruction::LogLayoutToHd(mut session_layout_metadata) => {
let err_context = || format!("Failed to dump layout"); let err_context = || format!("Failed to dump layout");
pty.populate_session_layout_metadata(&mut session_layout_metadata); pty.populate_session_layout_metadata(&mut session_layout_metadata);
let kdl_layout = match session_serialization::serialize_session_layout(
session_serialization::serialize_session_layout(session_layout_metadata.into()); session_layout_metadata.into(),
pty.bus ) {
.senders Ok(kdl_layout_and_pane_contents) => {
.send_to_background_jobs(BackgroundJob::ReportLayoutInfo(kdl_layout)) pty.bus
.with_context(err_context)?; .senders
.send_to_background_jobs(BackgroundJob::ReportLayoutInfo(
kdl_layout_and_pane_contents,
))
.with_context(err_context)?;
},
Err(e) => {
log::error!("Failed to log layout to HD: {}", e);
},
}
}, },
PtyInstruction::Exit => break, PtyInstruction::Exit => break,
} }

View file

@ -64,16 +64,18 @@ pub struct PaneLayoutManifest {
pub fn serialize_session_layout( pub fn serialize_session_layout(
global_layout_manifest: GlobalLayoutManifest, global_layout_manifest: GlobalLayoutManifest,
) -> (String, BTreeMap<String, String>) { ) -> Result<(String, BTreeMap<String, String>), &'static str> {
// BTreeMap is the pane contents and their file names // BTreeMap is the pane contents and their file names
let mut kdl_string = String::from("layout {\n"); let mut kdl_string = String::from("layout {\n");
let mut pane_contents = BTreeMap::new(); let mut pane_contents = BTreeMap::new();
stringify_global_cwd(&global_layout_manifest.global_cwd, &mut kdl_string); stringify_global_cwd(&global_layout_manifest.global_cwd, &mut kdl_string);
stringify_multiple_tabs( if let Err(e) = stringify_multiple_tabs(
global_layout_manifest.tabs, global_layout_manifest.tabs,
&mut pane_contents, &mut pane_contents,
&mut kdl_string, &mut kdl_string,
); ) {
return Err(e);
}
stringify_new_tab_template( stringify_new_tab_template(
global_layout_manifest.default_layout.template, global_layout_manifest.default_layout.template,
&mut pane_contents, &mut pane_contents,
@ -90,7 +92,7 @@ pub fn serialize_session_layout(
&mut kdl_string, &mut kdl_string,
); );
kdl_string.push_str("}"); kdl_string.push_str("}");
(kdl_string, pane_contents) Ok((kdl_string, pane_contents))
} }
fn stringify_tab( fn stringify_tab(
@ -100,31 +102,38 @@ fn stringify_tab(
tiled_panes: &Vec<PaneLayoutManifest>, tiled_panes: &Vec<PaneLayoutManifest>,
floating_panes: &Vec<PaneLayoutManifest>, floating_panes: &Vec<PaneLayoutManifest>,
pane_contents: &mut BTreeMap<String, String>, pane_contents: &mut BTreeMap<String, String>,
) -> String { ) -> Option<String> {
let mut kdl_string = String::new(); let mut kdl_string = String::new();
let tiled_panes_layout = get_tiled_panes_layout_from_panegeoms(tiled_panes, None); // let tiled_panes_layout = get_tiled_panes_layout_from_panegeoms(tiled_panes, None);
let floating_panes_layout = get_floating_panes_layout_from_panegeoms(floating_panes); match get_tiled_panes_layout_from_panegeoms(tiled_panes, None) {
let tiled_panes = if &tiled_panes_layout.children_split_direction != &SplitDirection::default() Some(tiled_panes_layout) => {
{ let floating_panes_layout = get_floating_panes_layout_from_panegeoms(floating_panes);
vec![tiled_panes_layout] let tiled_panes =
} else { if &tiled_panes_layout.children_split_direction != &SplitDirection::default() {
tiled_panes_layout.children vec![tiled_panes_layout]
}; } else {
let mut tab_attributes = vec![format!("name=\"{}\"", tab_name,)]; tiled_panes_layout.children
if is_focused { };
tab_attributes.push(format!("focus=true")); let mut tab_attributes = vec![format!("name=\"{}\"", tab_name,)];
if is_focused {
tab_attributes.push(format!("focus=true"));
}
if hide_floating_panes {
tab_attributes.push(format!("hide_floating_panes=true"));
}
kdl_string.push_str(&kdl_string_from_tab(
&tiled_panes,
&floating_panes_layout,
tab_attributes,
None,
pane_contents,
));
Some(kdl_string)
},
None => {
return None;
},
} }
if hide_floating_panes {
tab_attributes.push(format!("hide_floating_panes=true"));
}
kdl_string.push_str(&kdl_string_from_tab(
&tiled_panes,
&floating_panes_layout,
tab_attributes,
None,
pane_contents,
));
kdl_string
} }
/// Redundant with `geoms_to_kdl_tab` /// Redundant with `geoms_to_kdl_tab`
@ -507,23 +516,29 @@ fn stringify_multiple_tabs(
tabs: Vec<(String, TabLayoutManifest)>, tabs: Vec<(String, TabLayoutManifest)>,
pane_contents: &mut BTreeMap<String, String>, pane_contents: &mut BTreeMap<String, String>,
kdl_string: &mut String, kdl_string: &mut String,
) { ) -> Result<(), &'static str> {
for (tab_name, tab_layout_manifest) in tabs { for (tab_name, tab_layout_manifest) in tabs {
let tiled_panes = tab_layout_manifest.tiled_panes; let tiled_panes = tab_layout_manifest.tiled_panes;
let floating_panes = tab_layout_manifest.floating_panes; let floating_panes = tab_layout_manifest.floating_panes;
let hide_floating_panes = tab_layout_manifest.hide_floating_panes; let hide_floating_panes = tab_layout_manifest.hide_floating_panes;
kdl_string.push_str(&indent( let stringified = stringify_tab(
&stringify_tab( tab_name.clone(),
tab_name.clone(), tab_layout_manifest.is_focused,
tab_layout_manifest.is_focused, hide_floating_panes,
hide_floating_panes, &tiled_panes,
&tiled_panes, &floating_panes,
&floating_panes, pane_contents,
pane_contents, );
), match stringified {
INDENT, Some(stringified) => {
)); kdl_string.push_str(&indent(&stringified, INDENT));
},
None => {
return Err("Failed to stringify tab");
},
}
} }
Ok(())
} }
fn kdl_string_from_floating_pane( fn kdl_string_from_floating_pane(
@ -592,10 +607,15 @@ fn tiled_pane_layout_from_manifest(
fn get_tiled_panes_layout_from_panegeoms( fn get_tiled_panes_layout_from_panegeoms(
geoms: &Vec<PaneLayoutManifest>, geoms: &Vec<PaneLayoutManifest>,
split_size: Option<SplitSize>, split_size: Option<SplitSize>,
) -> TiledPaneLayout { ) -> Option<TiledPaneLayout> {
let (children_split_direction, splits) = match get_splits(&geoms) { let (children_split_direction, splits) = match get_splits(&geoms) {
Some(x) => x, Some(x) => x,
None => return tiled_pane_layout_from_manifest(geoms.iter().next(), split_size), None => {
return Some(tiled_pane_layout_from_manifest(
geoms.iter().next(),
split_size,
))
},
}; };
let mut children = Vec::new(); let mut children = Vec::new();
let mut remaining_geoms = geoms.clone(); let mut remaining_geoms = geoms.clone();
@ -614,29 +634,38 @@ fn get_tiled_panes_layout_from_panegeoms(
.into_iter() .into_iter()
.partition(|g| g.geom.x + g.geom.cols.as_usize() <= v_max), .partition(|g| g.geom.x + g.geom.cols.as_usize() <= v_max),
}; };
let constraint = match get_domain_constraint(&subgeoms, &children_split_direction, (v_min, v_max)) {
get_domain_constraint(&subgeoms, &children_split_direction, (v_min, v_max)); Some(constraint) => {
new_geoms.push(subgeoms); new_geoms.push(subgeoms);
new_constraints.push(constraint); new_constraints.push(constraint);
},
None => {
return None;
},
}
} }
let new_split_sizes = get_split_sizes(&new_constraints); let new_split_sizes = get_split_sizes(&new_constraints);
for (subgeoms, subsplit_size) in new_geoms.iter().zip(new_split_sizes) { for (subgeoms, subsplit_size) in new_geoms.iter().zip(new_split_sizes) {
children.push(get_tiled_panes_layout_from_panegeoms( match get_tiled_panes_layout_from_panegeoms(&subgeoms, subsplit_size) {
&subgeoms, Some(child) => {
subsplit_size, children.push(child);
)); },
None => {
return None;
},
}
} }
let children_are_stacked = children_split_direction == SplitDirection::Horizontal let children_are_stacked = children_split_direction == SplitDirection::Horizontal
&& new_geoms && new_geoms
.iter() .iter()
.all(|c| c.iter().all(|c| c.geom.is_stacked)); .all(|c| c.iter().all(|c| c.geom.is_stacked));
TiledPaneLayout { Some(TiledPaneLayout {
children_split_direction, children_split_direction,
split_size, split_size,
children, children,
children_are_stacked, children_are_stacked,
..Default::default() ..Default::default()
} })
} }
fn get_floating_panes_layout_from_panegeoms( fn get_floating_panes_layout_from_panegeoms(
@ -789,7 +818,7 @@ fn get_domain_constraint(
geoms: &Vec<PaneLayoutManifest>, geoms: &Vec<PaneLayoutManifest>,
split_direction: &SplitDirection, split_direction: &SplitDirection,
(v_min, v_max): (usize, usize), (v_min, v_max): (usize, usize),
) -> Constraint { ) -> Option<Constraint> {
match split_direction { match split_direction {
SplitDirection::Horizontal => get_domain_row_constraint(&geoms, (v_min, v_max)), SplitDirection::Horizontal => get_domain_row_constraint(&geoms, (v_min, v_max)),
SplitDirection::Vertical => get_domain_col_constraint(&geoms, (v_min, v_max)), SplitDirection::Vertical => get_domain_col_constraint(&geoms, (v_min, v_max)),
@ -800,21 +829,28 @@ fn get_domain_constraint(
fn get_domain_col_constraint( fn get_domain_col_constraint(
geoms: &Vec<PaneLayoutManifest>, geoms: &Vec<PaneLayoutManifest>,
(x_min, x_max): (usize, usize), (x_min, x_max): (usize, usize),
) -> Constraint { ) -> Option<Constraint> {
let mut percent = 0.0; let mut percent = 0.0;
let mut x = x_min; let mut x = x_min;
while x != x_max { while x != x_max {
// we only look at one (ie the last) geom that has value `x` for `g.x` // we only look at one (ie the last) geom that has value `x` for `g.x`
let geom = geoms.iter().filter(|g| g.geom.x == x).last().unwrap(); let geom = geoms.iter().filter(|g| g.geom.x == x).last();
if let Some(size) = geom.geom.cols.as_percent() { match geom {
percent += size; Some(geom) => {
if let Some(size) = geom.geom.cols.as_percent() {
percent += size;
}
x += geom.geom.cols.as_usize();
},
None => {
return None;
},
} }
x += geom.geom.cols.as_usize();
} }
if percent == 0.0 { if percent == 0.0 {
Constraint::Fixed(x_max - x_min) Some(Constraint::Fixed(x_max - x_min))
} else { } else {
Constraint::Percent(percent) Some(Constraint::Percent(percent))
} }
} }
@ -822,21 +858,28 @@ fn get_domain_col_constraint(
fn get_domain_row_constraint( fn get_domain_row_constraint(
geoms: &Vec<PaneLayoutManifest>, geoms: &Vec<PaneLayoutManifest>,
(y_min, y_max): (usize, usize), (y_min, y_max): (usize, usize),
) -> Constraint { ) -> Option<Constraint> {
let mut percent = 0.0; let mut percent = 0.0;
let mut y = y_min; let mut y = y_min;
while y != y_max { while y != y_max {
// we only look at one (ie the last) geom that has value `y` for `g.y` // we only look at one (ie the last) geom that has value `y` for `g.y`
let geom = geoms.iter().filter(|g| g.geom.y == y).last().unwrap(); let geom = geoms.iter().filter(|g| g.geom.y == y).last();
if let Some(size) = geom.geom.rows.as_percent() { match geom {
percent += size; Some(geom) => {
if let Some(size) = geom.geom.rows.as_percent() {
percent += size;
}
y += geom.geom.rows.as_usize();
},
None => {
return None;
},
} }
y += geom.geom.rows.as_usize();
} }
if percent == 0.0 { if percent == 0.0 {
Constraint::Fixed(y_max - y_min) Some(Constraint::Fixed(y_max - y_min))
} else { } else {
Constraint::Percent(percent) Some(Constraint::Percent(percent))
} }
} }
@ -932,7 +975,7 @@ mod tests {
..Default::default() ..Default::default()
}; };
// let kdl = kdl_string_from_panegeoms(&geoms); // let kdl = kdl_string_from_panegeoms(&geoms);
let kdl = serialize_session_layout(global_layout_manifest); let kdl = serialize_session_layout(global_layout_manifest).unwrap();
expect![[r#"layout { expect![[r#"layout {
tab name="Tab #1" { tab name="Tab #1" {
pane size=1 pane size=1
@ -958,7 +1001,7 @@ mod tests {
tabs: vec![("Tab #1".to_owned(), tab_layout_manifest)], tabs: vec![("Tab #1".to_owned(), tab_layout_manifest)],
..Default::default() ..Default::default()
}; };
let kdl = serialize_session_layout(global_layout_manifest); let kdl = serialize_session_layout(global_layout_manifest).unwrap();
expect![[r#"layout { expect![[r#"layout {
tab name="Tab #1" { tab name="Tab #1" {
pane pane
@ -986,7 +1029,7 @@ mod tests {
tabs: vec![("Tab #1".to_owned(), tab_layout_manifest)], tabs: vec![("Tab #1".to_owned(), tab_layout_manifest)],
..Default::default() ..Default::default()
}; };
let kdl = serialize_session_layout(global_layout_manifest); let kdl = serialize_session_layout(global_layout_manifest).unwrap();
expect![[r#"layout { expect![[r#"layout {
tab name="Tab #1" { tab name="Tab #1" {
pane size=10 split_direction="vertical" { pane size=10 split_direction="vertical" {
@ -1022,7 +1065,7 @@ mod tests {
tabs: vec![("Tab #1".to_owned(), tab_layout_manifest)], tabs: vec![("Tab #1".to_owned(), tab_layout_manifest)],
..Default::default() ..Default::default()
}; };
let kdl = serialize_session_layout(global_layout_manifest); let kdl = serialize_session_layout(global_layout_manifest).unwrap();
expect![[r#"layout { expect![[r#"layout {
tab name="Tab #1" { tab name="Tab #1" {
pane split_direction="vertical" { pane split_direction="vertical" {
@ -1059,7 +1102,7 @@ mod tests {
tabs: vec![("Tab #1".to_owned(), tab_layout_manifest)], tabs: vec![("Tab #1".to_owned(), tab_layout_manifest)],
..Default::default() ..Default::default()
}; };
let kdl = serialize_session_layout(global_layout_manifest); let kdl = serialize_session_layout(global_layout_manifest).unwrap();
expect![[r#"layout { expect![[r#"layout {
tab name="Tab #1" { tab name="Tab #1" {
pane size=5 pane size=5