diff --git a/helix-term/src/commands/lsp.rs b/helix-term/src/commands/lsp.rs index 34ffa529c..0096e6aa9 100644 --- a/helix-term/src/commands/lsp.rs +++ b/helix-term/src/commands/lsp.rs @@ -896,7 +896,6 @@ pub fn apply_workspace_edit( } }; - let current_view_id = view!(editor).id; let doc_id = match editor.open(&path, Action::Load) { Ok(doc_id) => doc_id, Err(err) => { @@ -907,7 +906,7 @@ pub fn apply_workspace_edit( } }; - let doc = doc_mut!(editor, &doc_id); + let doc = doc!(editor, &doc_id); if let Some(version) = version { if version != doc.version() { let err = format!("outdated workspace edit for {path:?}"); @@ -918,18 +917,8 @@ pub fn apply_workspace_edit( } // Need to determine a view for apply/append_changes_to_history - let selections = doc.selections(); - let view_id = if selections.contains_key(¤t_view_id) { - // use current if possible - current_view_id - } else { - // Hack: we take the first available view_id - selections - .keys() - .next() - .copied() - .expect("No view_id available") - }; + let view_id = editor.get_synced_view_id(doc_id); + let doc = doc_mut!(editor, &doc_id); let transaction = helix_lsp::util::generate_transaction_from_edits( doc.text(), diff --git a/helix-term/src/commands/typed.rs b/helix-term/src/commands/typed.rs index 208854e8a..f1c3cb71c 100644 --- a/helix-term/src/commands/typed.rs +++ b/helix-term/src/commands/typed.rs @@ -674,13 +674,15 @@ pub fn write_all_impl( let mut errors: Vec<&'static str> = Vec::new(); let config = cx.editor.config(); let jobs = &mut cx.jobs; - let current_view = view!(cx.editor); - let saves: Vec<_> = cx .editor .documents - .values_mut() - .filter_map(|doc| { + .keys() + .cloned() + .collect::>() + .into_iter() + .filter_map(|id| { + let doc = doc!(cx.editor, &id); if !doc.is_modified() { return None; } @@ -691,22 +693,9 @@ pub fn write_all_impl( return None; } - // Look for a view to apply the formatting change to. If the document - // is in the current view, just use that. Otherwise, since we don't - // have any other metric available for better selection, just pick - // the first view arbitrarily so that we still commit the document - // state for undos. If somehow we have a document that has not been - // initialized with any view, initialize it with the current view. - let target_view = if doc.selections().contains_key(¤t_view.id) { - current_view.id - } else if let Some(view) = doc.selections().keys().next() { - *view - } else { - doc.ensure_view_init(current_view.id); - current_view.id - }; - - Some((doc.id(), target_view)) + // Look for a view to apply the formatting change to. + let target_view = cx.editor.get_synced_view_id(doc.id()); + Some((id, target_view)) }) .collect(); diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs index c018668cb..f13df2135 100644 --- a/helix-view/src/editor.rs +++ b/helix-view/src/editor.rs @@ -1910,6 +1910,30 @@ pub fn current_stack_frame(&self) -> Option<&StackFrame> { .as_ref() .and_then(|debugger| debugger.current_stack_frame()) } + + /// Returns the id of a view that this doc contains a selection for, + /// making sure it is synced with the current changes + /// if possible or there are no selections returns current_view + /// otherwise uses an arbitrary view + pub fn get_synced_view_id(&mut self, id: DocumentId) -> ViewId { + let current_view = view_mut!(self); + let doc = self.documents.get_mut(&id).unwrap(); + if doc.selections().contains_key(¤t_view.id) { + // only need to sync current view if this is not the current doc + if current_view.doc != id { + current_view.sync_changes(doc); + } + current_view.id + } else if let Some(view_id) = doc.selections().keys().next() { + let view_id = *view_id; + let view = self.tree.get_mut(view_id); + view.sync_changes(doc); + view_id + } else { + doc.ensure_view_init(current_view.id); + current_view.id + } + } } fn try_restore_indent(doc: &mut Document, view: &mut View) {