1use super::*;
4
5impl Editor {
6 pub fn source(&self) -> String {
11 source(&self.doc, self.mode, &self.synced)
12 }
13
14 pub fn mode(&self) -> Mode {
16 self.mode
17 }
18
19 pub fn formatting(&self) -> Formatting {
21 let at = self.cursor();
22 let marks = if self.blocks() {
23 let mut marks = self.doc.marks(self.selection);
24 for mark in &self.stored {
27 if !marks.contains(mark) {
28 marks.push(mark.clone());
29 }
30 }
31 marks
32 } else {
33 Vec::new()
34 };
35 Formatting {
36 mode: self.mode,
37 marks,
38 block: self
39 .doc
40 .blocks
41 .get(at.block)
42 .and_then(|block| crate::slash::label(&block.kind)),
43 quote: self.doc.blocks.get(at.block).and_then(|block| block.quote),
44 fenceable: self.blocks() && fenceable(&self.doc, self.selection),
45 }
46 }
47
48 pub fn set_mode(&mut self, mode: Mode, cx: &mut Context<Self>) {
58 if mode == self.mode {
59 return;
60 }
61 let (was, selection) = (self.mode, self.selection);
62 self.document.update(cx, |document, _| {
63 document
64 .history
65 .record(false, was, &self.doc, selection, &self.anchors)
66 });
67 self.dismiss_menus();
68 self.switch(mode);
69 self.run.landed(EditKind::Structure, self.selection);
70 self.reveal = Some(Reveal::Nearest);
71 self.caret_moved();
72 self.publish(Change::Replaced, cx);
73 cx.emit(EditorEvent::ModeChanged(mode));
74 cx.emit(EditorEvent::Changed);
75 cx.notify();
76 }
77
78 pub(super) fn switch(&mut self, mode: Mode) {
81 let caret = self.cursor();
82 let caret = switch(
83 &mut self.doc,
84 &mut self.synced.borrow_mut(),
85 &mut self.anchors,
86 mode,
87 caret,
88 );
89 self.selection = Selection::at(caret);
90 self.mode = mode;
91 }
92
93 pub fn toggle_source(&mut self, cx: &mut Context<Self>) {
96 self.set_mode(
97 match self.mode {
98 Mode::Blocks => Mode::Source,
99 Mode::Source => Mode::Blocks,
100 },
101 cx,
102 );
103 }
104
105 pub(super) fn blocks(&self) -> bool {
112 self.mode == Mode::Blocks
113 }
114
115 pub(super) fn refresh_source_view(&mut self, cx: &mut Context<Self>) {
120 let revision = self.doc.revision();
121 let job = match &mut self.source_view {
122 Some((built, view)) => {
123 let edited = match *built == revision {
124 true => None,
125 false => {
126 *built = revision;
127 view.edit(source_of(&self.doc), cx)
128 }
129 };
130 edited.or_else(|| view.rehighlight(cx))
131 }
132 None => {
133 let view = markdown::SourceText::new(source_of(&self.doc), cx);
134 self.source_view = Some((revision, view));
135 None
136 }
137 };
138 let Some(job) = job else { return };
139 self.source_spans = Some(cx.spawn(async move |editor, cx| {
140 let spans = cx
141 .background_executor()
142 .spawn(async move { job.run() })
143 .await;
144 editor
145 .update(cx, |editor, cx| {
146 if let Some((_, view)) = &mut editor.source_view
147 && view.set_spans(spans)
148 {
149 cx.notify();
150 }
151 })
152 .ok();
153 }));
154 }
155
156 pub(super) fn drop_source_view(&mut self) {
158 self.source_view = None;
159 self.source_spans = None;
160 }
161
162 pub(super) fn source_view(&self) -> &markdown::SourceText {
164 &self
165 .source_view
166 .as_ref()
167 .expect("render refreshes the source view before reading it")
168 .1
169 }
170
171 pub fn source_lines(&self) -> usize {
174 match &self.source_view {
175 Some((built, view)) if *built == self.doc.revision() => view.lines(),
176 _ => {
177 self.source_text()
178 .bytes()
179 .filter(|byte| *byte == b'\n')
180 .count()
181 + 1
182 }
183 }
184 }
185
186 pub(super) fn source_text(&self) -> &str {
190 source_of(&self.doc)
191 }
192
193 pub(super) fn ensure_source(&mut self) -> bool {
202 if self.doc.blocks.len() == 1 && matches!(self.doc.blocks[0].kind, BlockKind::Code { .. }) {
203 return false;
204 }
205 let source = self
206 .doc
207 .blocks
208 .iter()
209 .filter_map(|block| block.text_at(*block.parts().first()?))
210 .map(|text| text.text.clone())
211 .collect::<Vec<_>>()
212 .join("\n");
213 let offset = self.selection.head.offset.min(source.len());
214 self.doc.set(source_doc(&source));
215 self.selection = Selection::at(Cursor::new(0, Part::Code, offset));
216 for anchor in &mut self.anchors {
217 anchor.range = anchor.range.clamp(&self.doc);
218 }
219 true
220 }
221
222 pub(super) fn dismiss_menus(&mut self) {
225 self.slash = None;
226 self.pasted = None;
227 self.url_prompt = None;
228 self.hovered = None;
229 self.lifted = None;
230 self.table_drag = None;
231 self.dropping = None;
232 }
233}
234
235pub(crate) fn source_of(doc: &Doc) -> &str {
237 doc.blocks
238 .first()
239 .and_then(|block| block.text_at(Part::Code))
240 .map_or("", |text| text.text.as_str())
241}
242
243pub(crate) fn source(doc: &Tracked, mode: Mode, synced: &RefCell<Synced>) -> String {
245 match mode {
246 Mode::Blocks => {
247 let mut synced = synced.borrow_mut();
248 synced.set_doc(doc.shared());
249 synced.text().to_owned()
250 }
251 Mode::Source => source_of(doc).to_string(),
252 }
253}
254
255pub(crate) fn switch(
262 doc: &mut Tracked,
263 synced: &mut Synced,
264 anchors: &mut [Anchor],
265 mode: Mode,
266 caret: Cursor,
267) -> Cursor {
268 let ends: Vec<(Cursor, Cursor)> = anchors
269 .iter()
270 .map(|anchor| anchor.range.ordered())
271 .collect();
272 match mode {
273 Mode::Source => {
274 synced.set_doc(doc.shared());
275 let mut at = vec![caret];
276 at.extend(ends.iter().flat_map(|(start, end)| [*start, *end]));
277 let offsets = synced.offsets(&at);
278 let source = synced.text();
279 doc.set(source_doc(source));
280 let place = |ix: usize| offsets[ix].map(|offset| Cursor::new(0, Part::Code, offset));
281 place_anchors(anchors, |ix| place(ix + 1));
282 place(0).unwrap_or(Cursor::new(0, Part::Code, source.len()))
283 }
284 Mode::Blocks => {
285 let mut offsets = vec![caret.offset];
286 offsets.extend(
287 ends.iter()
288 .flat_map(|(start, end)| [start.offset, end.offset]),
289 );
290 synced.set_text(source_of(doc));
291 let at = synced.cursors(&offsets);
292 doc.share(synced.doc().clone());
293 doc.ensure_block();
294 let place = |ix: usize| at[ix].map(|at: Cursor| at.clamp(doc));
295 let caret = place(0).unwrap_or_else(|| Cursor::default().clamp(doc));
296 let ends: Vec<_> = (1..at.len()).map(place).collect();
297 place_anchors(anchors, |ix| ends[ix]);
298 caret
299 }
300 }
301}
302
303fn place_anchors(anchors: &mut [Anchor], place: impl Fn(usize) -> Option<Cursor>) {
307 for (ix, anchor) in anchors.iter_mut().enumerate() {
308 anchor.range = match (place(2 * ix), place(2 * ix + 1)) {
309 (Some(start), Some(end)) => Selection::new(start, end),
310 (surviving, other) => Selection::at(surviving.or(other).unwrap_or_default()),
311 };
312 }
313}