on master help sign in
fix: write-all crash (#4384)
5a84834Skyler Hawthorne
helix-term/src/commands.rs+3−2
@@ -2515,19 +2515,20 @@ fn insert_at_line_end(cx: &mut Context) {
2515async fn make_format_callback(
2515async fn make_format_callback(
2516 doc_id: DocumentId,
2516 doc_id: DocumentId,
2517 doc_version: i32,
2517 doc_version: i32,
2518+ view_id: ViewId,
2518 format: impl Future<Output = Result<Transaction, FormatterError>> + Send + 'static,
2519 format: impl Future<Output = Result<Transaction, FormatterError>> + Send + 'static,
2519 write: Option<(Option<PathBuf>, bool)>,
2520 write: Option<(Option<PathBuf>, bool)>,
2520) -> anyhow::Result<job::Callback> {
2521) -> anyhow::Result<job::Callback> {
2521 let format = format.await;
2522 let format = format.await;
2522
2523
2523 let call: job::Callback = Callback::Editor(Box::new(move |editor| {
2524 let call: job::Callback = Callback::Editor(Box::new(move |editor| {
2524− if !editor.documents.contains_key(&doc_id) {
2525+ if !editor.documents.contains_key(&doc_id) || !editor.tree.contains(view_id) {
2525 return;
2526 return;
2526 }
2527 }
2527
2528
2528 let scrolloff = editor.config().scrolloff;
2529 let scrolloff = editor.config().scrolloff;
2529 let doc = doc_mut!(editor, &doc_id);
2530 let doc = doc_mut!(editor, &doc_id);
2530− let view = view_mut!(editor);
2531+ let view = view_mut!(editor, view_id);
2531
2532
2532 if let Ok(format) = format {
2533 if let Ok(format) = format {
2533 if doc.version() == doc_version {
2534 if doc.version() == doc_version {
helix-term/src/commands/typed.rs+29−6
@@ -271,7 +271,7 @@ fn write_impl(
271) -> anyhow::Result<()> {
271) -> anyhow::Result<()> {
272 let editor_auto_fmt = cx.editor.config().auto_format;
272 let editor_auto_fmt = cx.editor.config().auto_format;
273 let jobs = &mut cx.jobs;
273 let jobs = &mut cx.jobs;
274− let doc = doc_mut!(cx.editor);
274+ let (view, doc) = current!(cx.editor);
275 let path = path.map(AsRef::as_ref);
275 let path = path.map(AsRef::as_ref);
276
276
277 let fmt = if editor_auto_fmt {
277 let fmt = if editor_auto_fmt {
@@ -279,6 +279,7 @@ fn write_impl(
279 let callback = make_format_callback(
279 let callback = make_format_callback(
280 doc.id(),
280 doc.id(),
281 doc.version(),
281 doc.version(),
282+ view.id,
282 fmt,
283 fmt,
283 Some((path.map(Into::into), force)),
284 Some((path.map(Into::into), force)),
284 );
285 );
@@ -344,9 +345,9 @@ fn format(
344 return Ok(());
345 return Ok(());
345 }
346 }
346
347
347− let doc = doc!(cx.editor);
348+ let (view, doc) = current!(cx.editor);
348 if let Some(format) = doc.format() {
349 if let Some(format) = doc.format() {
349− let callback = make_format_callback(doc.id(), doc.version(), format, None);
350+ let callback = make_format_callback(doc.id(), doc.version(), view.id, format, None);
350 cx.jobs.callback(callback);
351 cx.jobs.callback(callback);
351 }
352 }
352
353
@@ -568,12 +569,13 @@ pub fn write_all_impl(
568 let mut errors: Vec<&'static str> = Vec::new();
569 let mut errors: Vec<&'static str> = Vec::new();
569 let auto_format = cx.editor.config().auto_format;
570 let auto_format = cx.editor.config().auto_format;
570 let jobs = &mut cx.jobs;
571 let jobs = &mut cx.jobs;
572+ let current_view = view!(cx.editor);
571
573
572 // save all documents
574 // save all documents
573 let saves: Vec<_> = cx
575 let saves: Vec<_> = cx
574 .editor
576 .editor
575 .documents
577 .documents
576− .values()
578+ .values_mut()
577 .filter_map(|doc| {
579 .filter_map(|doc| {
578 if !doc.is_modified() {
580 if !doc.is_modified() {
579 return None;
581 return None;
@@ -585,10 +587,30 @@ pub fn write_all_impl(
585 return None;
587 return None;
586 }
588 }
587
589
590+ // Look for a view to apply the formatting change to. If the document
591+ // is in the current view, just use that. Otherwise, since we don't
592+ // have any other metric available for better selection, just pick
593+ // the first view arbitrarily so that we still commit the document
594+ // state for undos. If somehow we have a document that has not been
595+ // initialized with any view, initialize it with the current view.
596+ let target_view = if doc.selections().contains_key(&current_view.id) {
597+ current_view.id
598+ } else if let Some(view) = doc.selections().keys().next() {
599+ *view
600+ } else {
601+ doc.ensure_view_init(current_view.id);
602+ current_view.id
603+ };
604+
588 let fmt = if auto_format {
605 let fmt = if auto_format {
589 doc.auto_format().map(|fmt| {
606 doc.auto_format().map(|fmt| {
590− let callback =
607+ let callback = make_format_callback(
608+ doc.id(),
609+ doc.version(),
610+ target_view,
611+ fmt,
591− make_format_callback(doc.id(), doc.version(), fmt, Some((None, force)));
612+ Some((None, force)),
613+ );
592 jobs.add(Job::with_callback(callback).wait_before_exiting());
614 jobs.add(Job::with_callback(callback).wait_before_exiting());
593 })
615 })
594 } else {
616 } else {
@@ -598,6 +620,7 @@ pub fn write_all_impl(
598 if fmt.is_none() {
620 if fmt.is_none() {
599 return Some(doc.id());
621 return Some(doc.id());
600 }
622 }
623+
601 None
624 None
602 })
625 })
603 .collect();
626 .collect();