strop_engine/editor/collections/
navigation.rs1use super::{CollectionRow, Editor};
3use strop_core::id::DocumentId;
4
5impl Editor {
6 pub fn collection_open_source_pub(&mut self) {
13 self.collection_open_source();
14 }
15
16 pub(crate) fn navigation_source(&self) -> Option<(DocumentId, usize)> {
19 if let Some(source) = self.source_position(self.current(), self.head()) {
20 return Some(source);
21 }
22 let line = self.buf().line_of(self.head());
23 self.collections
24 .get(&self.current())?
25 .excerpts
26 .iter()
27 .find(|excerpt| excerpt.view_line == line)
28 .map(|excerpt| (excerpt.source, excerpt.start))
29 }
30 pub(crate) fn collection_open_source(&mut self) {
31 if !self.collections.contains_key(&self.current()) {
32 return;
33 }
34 let target = self.navigation_source();
35 let Some((document, head)) = target else {
36 self.message = "not on an excerpt".into();
37 return;
38 };
39 if self.docs.get(document).is_none() {
40 self.message = "collection: that source was closed".into();
41 return;
42 }
43 self.push_jump();
44 self.jump_land(document, head);
45 self.lsp_maybe_attach();
46 }
47}
48
49impl Editor {
50 pub fn collection_file_step_pub(&mut self, forward: bool) {
53 self.collection_file_step(forward);
54 }
55
56 pub(crate) fn collection_file_step(&mut self, forward: bool) {
57 let id = self.current();
58 let Some(collection) = self.collections.get(&id) else {
59 self.message = "file cards live in collections".into();
60 return;
61 };
62 let caret = self.buf().line_of(self.head());
63 let mut tops: Vec<usize> = Vec::new();
64 for (row, kind) in collection.rows.iter().enumerate() {
65 if matches!(kind, CollectionRow::CardTop(_)) {
66 tops.push(row);
67 }
68 }
69 let target = if forward {
70 tops.iter().copied().find(|row| *row > caret)
71 } else {
72 tops.iter().copied().rev().find(|row| *row < caret)
73 };
74 let Some(row) = target else {
75 self.message = if forward { "last card" } else { "first card" }.into();
76 return;
77 };
78 self.push_jump();
79 self.set_head(self.buf().line_start(row));
80 self.clamp_cursor();
81 self.scroll_to_cursor(self.view_rows());
82 }
83}
84
85impl Editor {
86 pub fn collection_excerpt_step(&mut self, forward: bool) {
87 let Some(collection) = self.collections.get(&self.current()) else {
88 self.message = "excerpt navigation belongs to a collection".into();
89 return;
90 };
91 let after = collection
92 .excerpts
93 .partition_point(|excerpt| excerpt.view_start <= self.head());
94 let index = if forward {
95 Some(after)
96 } else {
97 after.checked_sub(2)
98 };
99 let target = index
100 .and_then(|index| collection.excerpts.get(index))
101 .map(|excerpt| excerpt.view_start);
102 let Some(target) = target else {
103 self.message = if forward {
104 "last excerpt"
105 } else {
106 "first excerpt"
107 }
108 .into();
109 return;
110 };
111 self.push_jump();
112 self.set_head(target);
113 self.place_jump_target();
114 }
115}