1use rust_i18n::t;
13
14use crate::model::event::{BufferId, Event, LeafId};
15use crate::view::prompt::PromptType;
16
17use super::Editor;
18
19impl Editor {
20 pub fn close_buffer(&mut self, id: BufferId) -> anyhow::Result<()> {
22 if let Some(state) = self
24 .windows
25 .get(&self.active_window)
26 .map(|w| &w.buffers)
27 .expect("active window present")
28 .get(&id)
29 {
30 if state.buffer.is_modified() {
31 return Err(anyhow::anyhow!("Buffer has unsaved changes"));
32 }
33 }
34 self.close_buffer_internal(id)
35 }
36
37 pub fn force_close_buffer(&mut self, id: BufferId) -> anyhow::Result<()> {
40 self.close_buffer_internal(id)
41 }
42
43 fn close_buffer_internal(&mut self, id: BufferId) -> anyhow::Result<()> {
45 if let Some((_, preview_id)) = self.active_window().preview {
48 if preview_id == id {
49 self.active_window_mut().preview = None;
50 }
51 }
52
53 if let Some((wait_id, _)) = self.active_window_mut().wait_tracking.remove(&id) {
55 self.active_window_mut().completed_waits.push(wait_id);
56 }
57
58 self.active_window().save_file_state_on_close(id);
60
61 if let Err(e) = self.delete_buffer_recovery(id) {
63 tracing::debug!("Failed to delete buffer recovery on close: {}", e);
64 }
65
66 if let Some(terminal_id) = self.active_window_mut().terminal_buffers.remove(&id) {
68 self.active_window_mut().terminal_manager.close(terminal_id);
70
71 let backing_file = self
73 .active_window_mut()
74 .terminal_backing_files
75 .remove(&terminal_id);
76 if let Some(ref path) = backing_file {
77 #[allow(clippy::let_underscore_must_use)]
79 let _ = self.authority.filesystem.remove_file(path);
80 }
81 if let Some(log_file) = self
83 .active_window_mut()
84 .terminal_log_files
85 .remove(&terminal_id)
86 {
87 if backing_file.as_ref() != Some(&log_file) {
88 #[allow(clippy::let_underscore_must_use)]
90 let _ = self.authority.filesystem.remove_file(&log_file);
91 }
92 }
93
94 self.active_window_mut().terminal_mode_resume.remove(&id);
96
97 if self.active_window().terminal_mode {
99 self.active_window_mut().terminal_mode = false;
100 self.active_window_mut().key_context =
101 crate::input::keybindings::KeyContext::Normal;
102 }
103 }
104
105 let active_split = self
109 .windows
110 .get(&self.active_window)
111 .and_then(|w| w.buffers.splits())
112 .map(|(mgr, _)| mgr)
113 .expect("active window must have a populated split layout")
114 .active_split();
115
116 let replacement_target: Option<crate::view::split::TabTarget> = self
117 .windows
118 .get(&self.active_window)
119 .and_then(|w| w.buffers.splits())
120 .map(|(_, vs)| vs)
121 .expect("active window must have a populated split layout")
122 .get(&active_split)
123 .and_then(|vs| {
124 use crate::view::split::TabTarget;
125 vs.focus_history.iter().rev().find_map(|t| match t {
126 TabTarget::Buffer(bid) if *bid == id => None, TabTarget::Buffer(bid) => {
128 let hidden = self
130 .active_window()
131 .buffer_metadata
132 .get(bid)
133 .map(|m| m.hidden_from_tabs)
134 .unwrap_or(false);
135 if hidden
136 || !self
137 .windows
138 .get(&self.active_window)
139 .map(|w| &w.buffers)
140 .expect("active window present")
141 .contains_key(bid)
142 {
143 None
144 } else {
145 Some(*t)
146 }
147 }
148 TabTarget::Group(leaf) => {
149 if self.active_window().grouped_subtrees.contains_key(leaf) {
151 Some(*t)
152 } else {
153 None
154 }
155 }
156 })
157 });
158
159 let fallback_buffer: Option<BufferId> = self.buffers().find_id(|bid, _| {
162 bid != id
163 && !self
164 .active_window()
165 .buffer_metadata
166 .get(&bid)
167 .map(|m| m.hidden_from_tabs)
168 .unwrap_or(false)
169 });
170
171 let closing_active = self.active_buffer() == id;
174
175 let return_to_group = match replacement_target {
182 Some(crate::view::split::TabTarget::Group(leaf)) => Some(leaf),
183 _ => None,
184 };
185
186 let direct_replacement = match replacement_target {
187 Some(crate::view::split::TabTarget::Buffer(bid)) => Some(bid),
188 _ => None,
189 };
190
191 let already_keyed = return_to_group.and_then(|_| {
199 self.windows
200 .get(&self.active_window)
201 .and_then(|w| w.buffers.splits())
202 .map(|(_, vs)| vs)
203 .expect("active window must have a populated split layout")
204 .get(&active_split)?
205 .keyed_states
206 .keys()
207 .find(|&&bid| bid != id)
208 .copied()
209 });
210
211 let any_remaining = return_to_group.and_then(|_| {
215 self.windows
216 .get(&self.active_window)
217 .map(|w| &w.buffers)
218 .expect("active window present")
219 .find_id(|bid, _| bid != id)
220 });
221
222 let (replacement_buffer, created_empty_buffer) = match direct_replacement
223 .or(already_keyed)
224 .or(fallback_buffer)
225 .or(any_remaining)
226 {
227 Some(bid) => (bid, false),
228 None => {
229 let new_id = self.new_buffer();
235 if !self
236 .config
237 .editor
238 .auto_create_empty_buffer_on_last_buffer_close
239 {
240 if let Some(meta) = self.active_window_mut().buffer_metadata.get_mut(&new_id) {
241 meta.hidden_from_tabs = true;
242 meta.synthetic_placeholder = true;
243 }
244 }
245 (new_id, true)
246 }
247 };
248
249 if closing_active {
253 self.set_active_buffer(replacement_buffer);
254
255 let hidden = self
264 .active_window()
265 .buffer_metadata
266 .get(&replacement_buffer)
267 .is_some_and(|m| m.hidden_from_tabs);
268 if return_to_group.is_some() && hidden {
269 use crate::view::split::TabTarget;
270 if let Some(vs) = self
271 .windows
272 .get_mut(&self.active_window)
273 .and_then(|w| w.split_view_states_mut())
274 .expect("active window must have a populated split layout")
275 .get_mut(&active_split)
276 {
277 vs.open_buffers
278 .retain(|t| *t != TabTarget::Buffer(replacement_buffer));
279 vs.focus_history
280 .retain(|t| *t != TabTarget::Buffer(replacement_buffer));
281 }
282 }
283 }
284
285 let splits_to_update = self
291 .windows
292 .get(&self.active_window)
293 .and_then(|w| w.buffers.splits())
294 .map(|(mgr, _)| mgr)
295 .expect("active window must have a populated split layout")
296 .splits_for_buffer(id);
297 for split_id in splits_to_update {
298 self.active_window_mut()
299 .set_pane_buffer(split_id, replacement_buffer);
300 }
301
302 self.windows
303 .get_mut(&self.active_window)
304 .map(|w| &mut w.buffers)
305 .expect("active window present")
306 .remove(&id);
307 self.detach_buffer_from_all_windows(id);
308 self.active_window_mut().event_logs.remove(&id);
309 self.active_window_mut().seen_byte_ranges.remove(&id);
310 self.active_window_mut().buffer_metadata.remove(&id);
311 if let Some((request_id, _, _)) = self
312 .active_window_mut()
313 .semantic_tokens_in_flight
314 .remove(&id)
315 {
316 self.active_window_mut()
317 .pending_semantic_token_requests
318 .remove(&request_id);
319 }
320 if let Some((request_id, _, _, _)) = self
321 .active_window_mut()
322 .semantic_tokens_range_in_flight
323 .remove(&id)
324 {
325 self.active_window_mut()
326 .pending_semantic_token_range_requests
327 .remove(&request_id);
328 }
329 self.active_window_mut()
330 .semantic_tokens_range_last_request
331 .remove(&id);
332 self.active_window_mut()
333 .semantic_tokens_range_applied
334 .remove(&id);
335 self.active_window_mut()
336 .semantic_tokens_full_debounce
337 .remove(&id);
338
339 self.panel_ids_mut().retain(|_, &mut buf_id| buf_id != id);
343
344 for view_state in self
346 .windows
347 .get_mut(&self.active_window)
348 .and_then(|w| w.split_view_states_mut())
349 .expect("active window must have a populated split layout")
350 .values_mut()
351 {
352 view_state.remove_buffer(id);
353 view_state.remove_from_history(id);
354 }
355
356 if closing_active {
357 if created_empty_buffer && self.config.file_explorer.auto_open_on_last_buffer_close {
358 self.focus_file_explorer();
359 }
360 if let Some(group_leaf) = return_to_group {
361 self.activate_group_tab(active_split, group_leaf);
362 }
363 }
364
365 self.plugin_manager.read().unwrap().run_hook(
370 "buffer_closed",
371 fresh_core::hooks::HookArgs::BufferClosed { buffer_id: id },
372 );
373
374 Ok(())
375 }
376
377 pub fn switch_buffer(&mut self, id: BufferId) {
379 if self
380 .windows
381 .get(&self.active_window)
382 .map(|w| &w.buffers)
383 .expect("active window present")
384 .contains_key(&id)
385 && id != self.active_buffer()
386 {
387 self.active_window_mut()
389 .position_history
390 .commit_pending_movement();
391
392 let cursors = self.active_cursors();
394 let position = cursors.primary().position;
395 let anchor = cursors.primary().anchor;
396 let buffer_id = self.active_buffer();
397 let ph = &mut self.active_window_mut().position_history;
398 ph.record_movement(buffer_id, position, anchor);
399 ph.commit_pending_movement();
400
401 self.set_active_buffer(id);
402 }
403 }
404
405 pub fn close_tab(&mut self) {
414 let active_split = self
419 .windows
420 .get(&self.active_window)
421 .and_then(|w| w.buffers.splits())
422 .map(|(mgr, _)| mgr)
423 .expect("active window must have a populated split layout")
424 .active_split();
425 if let Some(group_leaf_id) = self
426 .windows
427 .get(&self.active_window)
428 .and_then(|w| w.buffers.splits())
429 .map(|(_, vs)| vs)
430 .expect("active window must have a populated split layout")
431 .get(&active_split)
432 .and_then(|vs| vs.active_group_tab)
433 {
434 self.close_buffer_group_by_leaf(group_leaf_id);
435 self.set_status_message(t!("buffer.tab_closed").to_string());
436 return;
437 }
438
439 let buffer_id = self.active_buffer();
443 self.close_tab_in_split(buffer_id, active_split);
444 }
445
446 pub fn close_tab_in_split(&mut self, buffer_id: BufferId, split_id: LeafId) -> bool {
456 if self.active_window().terminal_mode && self.active_window().is_terminal_buffer(buffer_id)
458 {
459 self.active_window_mut().terminal_mode = false;
460 self.active_window_mut().key_context = crate::input::keybindings::KeyContext::Normal;
461 }
462
463 let buffer_in_other_splits = self
465 .windows
466 .get(&self.active_window)
467 .and_then(|w| w.buffers.splits())
468 .map(|(_, vs)| vs)
469 .expect("active window must have a populated split layout")
470 .iter()
471 .filter(|(&sid, view_state)| sid != split_id && view_state.has_buffer(buffer_id))
472 .count();
473
474 let split_tabs = self
476 .windows
477 .get(&self.active_window)
478 .and_then(|w| w.buffers.splits())
479 .map(|(_, vs)| vs)
480 .expect("active window must have a populated split layout")
481 .get(&split_id)
482 .map(|vs| vs.buffer_tab_ids_vec())
483 .unwrap_or_default();
484
485 let is_last_viewport = buffer_in_other_splits == 0;
486
487 if is_last_viewport {
488 if let Some(state) = self
490 .windows
491 .get(&self.active_window)
492 .map(|w| &w.buffers)
493 .expect("active window present")
494 .get(&buffer_id)
495 {
496 if state.buffer.is_modified() {
497 let name = self.get_buffer_display_name(buffer_id);
499 let save_key = t!("prompt.key.save").to_string();
500 let discard_key = t!("prompt.key.discard").to_string();
501 let cancel_key = t!("prompt.key.cancel").to_string();
502 self.start_prompt(
503 t!(
504 "prompt.buffer_modified",
505 name = name,
506 save_key = save_key,
507 discard_key = discard_key,
508 cancel_key = cancel_key
509 )
510 .to_string(),
511 PromptType::ConfirmCloseBuffer { buffer_id },
512 );
513 return false;
514 }
515 }
516 let has_other_splits = self
523 .windows
524 .get(&self.active_window)
525 .and_then(|w| w.buffers.splits())
526 .map(|(mgr, _)| mgr)
527 .expect("active window must have a populated split layout")
528 .root()
529 .count_leaves()
530 > 1;
531 if split_tabs.len() <= 1 && has_other_splits {
532 self.handle_close_split(split_id.into());
533 if let Err(e) = self.close_buffer(buffer_id) {
536 tracing::debug!(
537 "close_tab_in_split: buffer cleanup after split close failed: {}",
538 e
539 );
540 }
541 self.set_status_message(t!("buffer.tab_closed").to_string());
542 return true;
543 }
544 if let Err(e) = self.close_buffer(buffer_id) {
545 self.set_status_message(t!("file.cannot_close", error = e.to_string()).to_string());
546 } else {
547 self.set_status_message(t!("buffer.tab_closed").to_string());
548 }
549 } else {
550 if split_tabs.len() <= 1 {
552 self.handle_close_split(split_id.into());
554 return true;
555 }
556
557 let current_idx = split_tabs
559 .iter()
560 .position(|&id| id == buffer_id)
561 .unwrap_or(0);
562 let replacement_idx = if current_idx > 0 { current_idx - 1 } else { 1 };
563 let replacement_buffer = split_tabs[replacement_idx];
564
565 if let Some(view_state) = self
567 .windows
568 .get_mut(&self.active_window)
569 .and_then(|w| w.split_view_states_mut())
570 .expect("active window must have a populated split layout")
571 .get_mut(&split_id)
572 {
573 view_state.remove_buffer(buffer_id);
574 }
575
576 self.windows
578 .get_mut(&self.active_window)
579 .and_then(|w| w.split_manager_mut())
580 .expect("active window must have a populated split layout")
581 .set_split_buffer(split_id, replacement_buffer);
582
583 self.set_status_message(t!("buffer.tab_closed").to_string());
584 }
585 true
586 }
587
588 pub fn close_other_tabs_in_split(&mut self, keep_buffer_id: BufferId, split_id: LeafId) {
590 let split_tabs = self
592 .windows
593 .get(&self.active_window)
594 .and_then(|w| w.buffers.splits())
595 .map(|(_, vs)| vs)
596 .expect("active window must have a populated split layout")
597 .get(&split_id)
598 .map(|vs| vs.buffer_tab_ids_vec())
599 .unwrap_or_default();
600
601 let tabs_to_close: Vec<_> = split_tabs
603 .iter()
604 .filter(|&&id| id != keep_buffer_id)
605 .copied()
606 .collect();
607
608 let mut closed = 0;
609 let mut skipped_modified = 0;
610 for buffer_id in tabs_to_close {
611 if self.close_tab_in_split_silent(buffer_id, split_id) {
612 closed += 1;
613 } else {
614 skipped_modified += 1;
615 }
616 }
617
618 self.windows
620 .get_mut(&self.active_window)
621 .and_then(|w| w.split_manager_mut())
622 .expect("active window must have a populated split layout")
623 .set_split_buffer(split_id, keep_buffer_id);
624
625 self.set_batch_close_status_message(closed, skipped_modified);
626 }
627
628 pub fn close_tabs_to_right_in_split(&mut self, buffer_id: BufferId, split_id: LeafId) {
630 let split_tabs = self
632 .windows
633 .get(&self.active_window)
634 .and_then(|w| w.buffers.splits())
635 .map(|(_, vs)| vs)
636 .expect("active window must have a populated split layout")
637 .get(&split_id)
638 .map(|vs| vs.buffer_tab_ids_vec())
639 .unwrap_or_default();
640
641 let Some(target_idx) = split_tabs.iter().position(|&id| id == buffer_id) else {
643 return;
644 };
645
646 let tabs_to_close: Vec<_> = split_tabs.iter().skip(target_idx + 1).copied().collect();
648
649 let mut closed = 0;
650 let mut skipped_modified = 0;
651 for buf_id in tabs_to_close {
652 if self.close_tab_in_split_silent(buf_id, split_id) {
653 closed += 1;
654 } else {
655 skipped_modified += 1;
656 }
657 }
658
659 self.set_batch_close_status_message(closed, skipped_modified);
660 }
661
662 pub fn close_tabs_to_left_in_split(&mut self, buffer_id: BufferId, split_id: LeafId) {
664 let split_tabs = self
666 .windows
667 .get(&self.active_window)
668 .and_then(|w| w.buffers.splits())
669 .map(|(_, vs)| vs)
670 .expect("active window must have a populated split layout")
671 .get(&split_id)
672 .map(|vs| vs.buffer_tab_ids_vec())
673 .unwrap_or_default();
674
675 let Some(target_idx) = split_tabs.iter().position(|&id| id == buffer_id) else {
677 return;
678 };
679
680 let tabs_to_close: Vec<_> = split_tabs.iter().take(target_idx).copied().collect();
682
683 let mut closed = 0;
684 let mut skipped_modified = 0;
685 for buf_id in tabs_to_close {
686 if self.close_tab_in_split_silent(buf_id, split_id) {
687 closed += 1;
688 } else {
689 skipped_modified += 1;
690 }
691 }
692
693 self.set_batch_close_status_message(closed, skipped_modified);
694 }
695
696 pub fn close_all_tabs_in_split(&mut self, split_id: LeafId) {
698 let split_tabs = self
700 .windows
701 .get(&self.active_window)
702 .and_then(|w| w.buffers.splits())
703 .map(|(_, vs)| vs)
704 .expect("active window must have a populated split layout")
705 .get(&split_id)
706 .map(|vs| vs.buffer_tab_ids_vec())
707 .unwrap_or_default();
708
709 let mut closed = 0;
710 let mut skipped_modified = 0;
711
712 for buffer_id in split_tabs {
714 if self.close_tab_in_split_silent(buffer_id, split_id) {
715 closed += 1;
716 } else {
717 skipped_modified += 1;
718 }
719 }
720
721 self.set_batch_close_status_message(closed, skipped_modified);
722 }
723
724 fn set_batch_close_status_message(&mut self, closed: usize, skipped_modified: usize) {
726 let message = match (closed, skipped_modified) {
727 (0, 0) => t!("buffer.no_tabs_to_close").to_string(),
728 (0, n) => t!("buffer.skipped_modified", count = n).to_string(),
729 (n, 0) => t!("buffer.closed_tabs", count = n).to_string(),
730 (c, s) => t!("buffer.closed_tabs_skipped", closed = c, skipped = s).to_string(),
731 };
732 self.set_status_message(message);
733 }
734
735 fn close_tab_in_split_silent(&mut self, buffer_id: BufferId, split_id: LeafId) -> bool {
739 if self.active_window().terminal_mode && self.active_window().is_terminal_buffer(buffer_id)
741 {
742 self.active_window_mut().terminal_mode = false;
743 self.active_window_mut().key_context = crate::input::keybindings::KeyContext::Normal;
744 }
745
746 let buffer_in_other_splits = self
748 .windows
749 .get(&self.active_window)
750 .and_then(|w| w.buffers.splits())
751 .map(|(_, vs)| vs)
752 .expect("active window must have a populated split layout")
753 .iter()
754 .filter(|(&sid, view_state)| sid != split_id && view_state.has_buffer(buffer_id))
755 .count();
756
757 let split_tabs = self
759 .windows
760 .get(&self.active_window)
761 .and_then(|w| w.buffers.splits())
762 .map(|(_, vs)| vs)
763 .expect("active window must have a populated split layout")
764 .get(&split_id)
765 .map(|vs| vs.buffer_tab_ids_vec())
766 .unwrap_or_default();
767
768 let is_last_viewport = buffer_in_other_splits == 0;
769
770 if is_last_viewport {
771 if let Some(state) = self
774 .windows
775 .get(&self.active_window)
776 .map(|w| &w.buffers)
777 .expect("active window present")
778 .get(&buffer_id)
779 {
780 if state.buffer.is_modified() {
781 return false;
783 }
784 }
785 if let Err(e) = self.close_buffer(buffer_id) {
786 tracing::warn!("Failed to close buffer: {}", e);
787 }
788 true
789 } else {
790 if split_tabs.len() <= 1 {
792 self.handle_close_split(split_id.into());
794 return true;
795 }
796
797 let current_idx = split_tabs
799 .iter()
800 .position(|&id| id == buffer_id)
801 .unwrap_or(0);
802 let replacement_idx = if current_idx > 0 { current_idx - 1 } else { 1 };
803 let replacement_buffer = split_tabs.get(replacement_idx).copied();
804
805 if let Some(view_state) = self
807 .windows
808 .get_mut(&self.active_window)
809 .and_then(|w| w.split_view_states_mut())
810 .expect("active window must have a populated split layout")
811 .get_mut(&split_id)
812 {
813 view_state.remove_buffer(buffer_id);
814 }
815
816 if let Some(replacement) = replacement_buffer {
819 self.active_window_mut()
820 .set_pane_buffer(split_id, replacement);
821 }
822 true
823 }
824 }
825
826 pub fn next_buffer(&mut self) {
828 self.cycle_tab(1);
829 }
830
831 pub fn prev_buffer(&mut self) {
833 self.cycle_tab(-1);
834 }
835
836 fn cycle_tab(&mut self, direction: i32) {
839 use crate::view::split::TabTarget;
840
841 let active_split = self
842 .windows
843 .get(&self.active_window)
844 .and_then(|w| w.buffers.splits())
845 .map(|(mgr, _)| mgr)
846 .expect("active window must have a populated split layout")
847 .active_split();
848 let Some(view_state) = self
849 .windows
850 .get(&self.active_window)
851 .and_then(|w| w.buffers.splits())
852 .map(|(_, vs)| vs)
853 .expect("active window must have a populated split layout")
854 .get(&active_split)
855 else {
856 return;
857 };
858
859 let targets: Vec<TabTarget> = view_state
861 .open_buffers
862 .iter()
863 .copied()
864 .filter(|t| match t {
865 TabTarget::Buffer(id) => !self
866 .active_window()
867 .buffer_metadata
868 .get(id)
869 .map(|m| m.hidden_from_tabs)
870 .unwrap_or(false),
871 TabTarget::Group(_) => true,
872 })
873 .collect();
874
875 if targets.len() < 2 {
876 return;
877 }
878
879 let current_target = view_state.active_target();
880 let Some(idx) = targets.iter().position(|t| *t == current_target) else {
881 return;
882 };
883
884 let next_idx = if direction > 0 {
885 (idx + 1) % targets.len()
886 } else if idx == 0 {
887 targets.len() - 1
888 } else {
889 idx - 1
890 };
891
892 if targets[next_idx] == current_target {
893 return;
894 }
895
896 self.active_window_mut()
898 .position_history
899 .commit_pending_movement();
900 let cursors = self.active_cursors();
901 let position = cursors.primary().position;
902 let anchor = cursors.primary().anchor;
903 let buffer_id = self.active_buffer();
904 let ph = &mut self.active_window_mut().position_history;
905 ph.record_movement(buffer_id, position, anchor);
906 ph.commit_pending_movement();
907
908 self.active_window_mut()
916 .animate_tab_switch(active_split, direction.signum());
917
918 match targets[next_idx] {
919 TabTarget::Buffer(buffer_id) => {
920 self.set_active_buffer(buffer_id);
921 }
922 TabTarget::Group(group_leaf_id) => {
923 self.activate_group_tab(active_split, group_leaf_id);
924 }
925 }
926 }
927
928 pub fn navigate_back(&mut self) {
930 self.active_window_mut().in_navigation = true;
932
933 self.active_window_mut()
935 .position_history
936 .commit_pending_movement();
937
938 if self.active_window_mut().position_history.can_go_back()
941 && !self.active_window_mut().position_history.can_go_forward()
942 {
943 let cursors = self.active_cursors();
944 let position = cursors.primary().position;
945 let anchor = cursors.primary().anchor;
946 let buffer_id = self.active_buffer();
947 let ph = &mut self.active_window_mut().position_history;
948 ph.record_movement(buffer_id, position, anchor);
949 ph.commit_pending_movement();
950 }
951
952 if let Some(entry) = self.active_window_mut().position_history.back() {
954 let target_buffer = entry.buffer_id;
955 let target_position = entry.position;
956 let target_anchor = entry.anchor;
957
958 if self
960 .windows
961 .get(&self.active_window)
962 .map(|w| &w.buffers)
963 .expect("active window present")
964 .contains_key(&target_buffer)
965 {
966 self.set_active_buffer(target_buffer);
967
968 let cursors = self.active_cursors();
970 let cursor_id = cursors.primary_id();
971 let old_position = cursors.primary().position;
972 let old_anchor = cursors.primary().anchor;
973 let old_sticky_column = cursors.primary().sticky_column;
974 let event = Event::MoveCursor {
975 cursor_id,
976 old_position,
977 new_position: target_position,
978 old_anchor,
979 new_anchor: target_anchor,
980 old_sticky_column,
981 new_sticky_column: 0, };
983 let split_id = self
984 .windows
985 .get(&self.active_window)
986 .and_then(|w| w.buffers.splits())
987 .map(|(mgr, _)| mgr)
988 .expect("active window must have a populated split layout")
989 .active_split();
990 self.active_window_mut()
991 .apply_event_to_buffer(target_buffer, split_id, &event);
992 self.active_window_mut()
996 .ensure_active_cursor_visible_for_navigation(true);
997 }
998 }
999
1000 self.active_window_mut().in_navigation = false;
1002 }
1003
1004 pub fn navigate_forward(&mut self) {
1006 self.active_window_mut().in_navigation = true;
1008
1009 if let Some(entry) = self.active_window_mut().position_history.forward() {
1010 let target_buffer = entry.buffer_id;
1011 let target_position = entry.position;
1012 let target_anchor = entry.anchor;
1013
1014 if self
1016 .windows
1017 .get(&self.active_window)
1018 .map(|w| &w.buffers)
1019 .expect("active window present")
1020 .contains_key(&target_buffer)
1021 {
1022 self.set_active_buffer(target_buffer);
1023
1024 let cursors = self.active_cursors();
1026 let cursor_id = cursors.primary_id();
1027 let old_position = cursors.primary().position;
1028 let old_anchor = cursors.primary().anchor;
1029 let old_sticky_column = cursors.primary().sticky_column;
1030 let event = Event::MoveCursor {
1031 cursor_id,
1032 old_position,
1033 new_position: target_position,
1034 old_anchor,
1035 new_anchor: target_anchor,
1036 old_sticky_column,
1037 new_sticky_column: 0, };
1039 let split_id = self
1040 .windows
1041 .get(&self.active_window)
1042 .and_then(|w| w.buffers.splits())
1043 .map(|(mgr, _)| mgr)
1044 .expect("active window must have a populated split layout")
1045 .active_split();
1046 self.active_window_mut()
1047 .apply_event_to_buffer(target_buffer, split_id, &event);
1048 self.active_window_mut()
1052 .ensure_active_cursor_visible_for_navigation(true);
1053 }
1054 }
1055
1056 self.active_window_mut().in_navigation = false;
1058 }
1059}