1use super::*;
4
5impl Editor {
6 pub(super) fn turn_into(&mut self, ix: usize, kind: BlockKind, cx: &mut Context<Self>) {
12 self.edit(EditKind::Structure, cx, |this| {
13 let held = this.doc.blocks[ix]
17 .text_at(Part::Body)
18 .map_or(0, |text| text.text.len());
19 this.doc
20 .edit()
21 .edit_at(Cursor::new(ix, Part::Body, 0), |text| {
22 *text = Text::default()
23 });
24 this.doc.edit().set_kind(ix, kind);
25 let part = this.doc.blocks[ix].parts().first().copied();
28 let at = match part {
29 Some(part) => Cursor::new(ix, part, 0),
30 None => {
31 if this.doc.blocks.len() <= ix + 1 {
32 this.doc
33 .edit()
34 .blocks
35 .push(markdown::Block::new(BlockKind::Paragraph(Text::default())));
36 }
37 Cursor::new(ix + 1, Part::Body, 0)
38 }
39 };
40 this.selection = Selection::at(at.clamp(&this.doc));
41 vec![Delta::Spliced(Splice {
42 removed: Selection::new(
43 Cursor::new(ix, Part::Body, 0),
44 Cursor::new(ix, Part::Body, held),
45 ),
46 caret: Cursor::new(ix, Part::Body, 0),
47 blocks: 0,
48 })]
49 });
50 }
51
52 pub(super) fn undo(&mut self, _: &Undo, _: &mut Window, cx: &mut Context<Self>) {
53 let (mode, selection) = (self.mode, self.selection);
54 let step = self.document.update(cx, |document, _| {
55 document
56 .history
57 .undo(mode, &self.doc, selection, &self.anchors)
58 });
59 if let Some(step) = step {
60 self.restore(step, cx);
61 }
62 }
63
64 pub(super) fn redo(&mut self, _: &Redo, _: &mut Window, cx: &mut Context<Self>) {
65 let (mode, selection) = (self.mode, self.selection);
66 let step = self.document.update(cx, |document, _| {
67 document
68 .history
69 .redo(mode, &self.doc, selection, &self.anchors)
70 });
71 if let Some(step) = step {
72 self.restore(step, cx);
73 }
74 }
75
76 pub(super) fn restore(&mut self, step: crate::history::Step, cx: &mut Context<Self>) {
82 self.doc.set(step.doc);
83 self.selection = step.selection.clamp(&self.doc);
84 self.run.interrupt();
85 self.caret_moved();
86 self.anchors = step.anchors;
87 let switched = step.mode != self.mode;
88 self.mode = step.mode;
89 self.publish(Change::Replaced, cx);
90 if switched {
91 self.dismiss_menus();
92 cx.emit(EditorEvent::ModeChanged(step.mode));
93 }
94 cx.emit(EditorEvent::Changed);
95 cx.notify();
96 }
97
98 pub fn move_block(&mut self, ix: usize, delta: isize, cx: &mut Context<Self>) {
103 if !self.blocks() {
104 return;
105 }
106 self.edit(EditKind::Structure, cx, |this| {
107 let caret = this.cursor();
108 let at = this.doc.subtree(ix);
109 let Some(to) = this.doc.edit().move_block(ix, delta) else {
110 return vec![];
111 };
112 let block = to + caret.block.saturating_sub(ix);
115 this.selection = Selection::at(Cursor { block, ..caret }.clamp(&this.doc));
116 vec![Delta::Moved { at, to: Some(to) }]
117 });
118 }
119
120 pub fn duplicate_block(&mut self, ix: usize, cx: &mut Context<Self>) {
121 if !self.blocks() {
122 return;
123 }
124 self.edit(EditKind::Structure, cx, |this| {
125 let span = this.doc.subtree(ix);
126 let Some(copy) = this.doc.edit().duplicate(ix) else {
127 return vec![];
128 };
129 this.selection = Selection::at(Cursor::new(copy, Part::Body, 0).clamp(&this.doc));
130 vec![Delta::Opened {
131 at: copy,
132 count: span.len(),
133 }]
134 });
135 }
136
137 pub fn remove_block(&mut self, ix: usize, cx: &mut Context<Self>) {
138 if !self.blocks() {
139 return;
140 }
141 self.edit(EditKind::Structure, cx, |this| {
142 let at = this.doc.subtree(ix);
143 this.doc.edit().remove_block(ix);
144 this.selection =
145 Selection::at(Cursor::new(ix.saturating_sub(1), Part::Body, 0).clamp(&this.doc));
146 vec![Delta::Moved { at, to: None }]
147 });
148 }
149
150 pub fn set_language(&mut self, ix: usize, language: Option<String>, cx: &mut Context<Self>) {
152 if !self.blocks() {
153 return;
154 }
155 self.edit(EditKind::Structure, cx, |this| {
156 this.doc.edit().set_language(ix, language);
157 vec![]
158 });
159 }
160
161 pub fn set_block(&mut self, ix: usize, kind: BlockKind, cx: &mut Context<Self>) {
164 if !self.blocks() {
165 return;
166 }
167 self.edit(EditKind::Structure, cx, |this| {
168 this.doc.edit().set_kind(ix, kind);
169 this.selection = this.selection.clamp(&this.doc);
170 vec![]
171 });
172 }
173
174 pub fn toggle_quote(
177 &mut self,
178 ix: usize,
179 alert: Option<markdown::QuoteKind>,
180 cx: &mut Context<Self>,
181 ) {
182 if !self.blocks() {
183 return;
184 }
185 self.edit(EditKind::Structure, cx, |this| {
186 this.doc.edit().toggle_quote(ix, alert);
187 this.selection = this.selection.clamp(&this.doc);
188 vec![]
189 });
190 }
191
192 pub fn set_code(&mut self, ix: usize, code: String, cx: &mut Context<Self>) {
195 if !self.blocks() {
196 return;
197 }
198 self.edit(EditKind::Structure, cx, |this| {
199 this.doc.edit().set_code(ix, code);
200 this.selection = this.selection.clamp(&this.doc);
201 vec![]
202 });
203 }
204
205 pub fn place_block(&mut self, ix: usize, kind: BlockKind, cx: &mut Context<Self>) {
211 if !self.blocks() || ix >= self.doc.blocks.len() {
212 return;
213 }
214 self.edit(EditKind::Structure, cx, |this| {
215 this.doc.edit().blocks[ix].kind = kind;
216 this.selection = this.selection.clamp(&this.doc);
217 vec![]
218 });
219 self.step_past(ix, cx);
220 }
221
222 pub(super) fn step_past(&mut self, ix: usize, cx: &mut Context<Self>) {
225 if self.doc.blocks.len() <= ix + 1 {
226 self.edit(EditKind::Structure, cx, |this| {
227 this.doc
228 .edit()
229 .blocks
230 .push(markdown::Block::new(BlockKind::Paragraph(Text::default())));
231 vec![]
232 });
233 }
234 let at = Cursor::new(ix + 1, Part::Body, 0).clamp(&self.doc);
235 self.select(Selection::at(at), cx);
236 }
237
238 pub(super) fn leave_block(&mut self, ix: usize, window: &mut Window, cx: &mut Context<Self>) {
240 self.focus_handle.focus(window, cx);
241 self.step_past(ix, cx);
242 }
243
244 pub fn relink(&mut self, from: &str, to: &str, cx: &mut Context<Self>) {
249 if self.blocks() {
250 let found: Vec<(usize, BlockKind)> = self
251 .doc
252 .blocks
253 .iter()
254 .enumerate()
255 .filter_map(|(ix, block)| match &block.kind {
256 BlockKind::Image { url, alt, width } if url == from => Some((
257 ix,
258 BlockKind::Image {
259 url: to.to_owned(),
260 alt: alt.clone(),
261 width: *width,
262 },
263 )),
264 _ => None,
265 })
266 .collect();
267 if found.is_empty() {
268 return;
269 }
270 self.edit(EditKind::Structure, cx, |this| {
271 for (ix, kind) in found {
272 this.doc.edit().set_kind(ix, kind);
273 }
274 this.selection = this.selection.clamp(&this.doc);
275 vec![]
276 });
277 return;
278 }
279 let source = self.source_text();
280 let mut hits: Vec<(Range<usize>, String)> = [
281 (format!("]({from})"), format!("]({to})")),
282 (format!("](<{from}>)"), format!("](<{to}>)")),
283 ]
284 .into_iter()
285 .flat_map(|(old, new)| {
286 source
287 .match_indices(&old)
288 .map(|(at, _)| (at..at + old.len(), new.clone()))
289 .collect::<Vec<_>>()
290 })
291 .collect();
292 if hits.is_empty() {
293 return;
294 }
295 hits.sort_by_key(|(range, _)| std::cmp::Reverse(range.start));
297 let moved = |cursor: Cursor| {
298 let offset = hits
299 .iter()
300 .fold(cursor.offset as isize, |at, (range, new)| {
301 if cursor.offset >= range.end {
302 at + new.len() as isize - range.len() as isize
303 } else if cursor.offset > range.start {
304 at - (cursor.offset - range.start) as isize
305 } else {
306 at
307 }
308 });
309 Cursor {
310 offset: offset.max(0) as usize,
311 ..cursor
312 }
313 };
314 let selection = Selection::new(moved(self.selection.anchor), moved(self.selection.head));
315 self.edit(EditKind::Structure, cx, |this| {
316 let at = |offset| Cursor::new(0, Part::Code, offset);
317 let splices = hits
318 .iter()
319 .map(|(range, new)| {
320 Delta::Spliced(this.doc.edit().replace(
321 Selection::new(at(range.start), at(range.end)),
322 Text::plain(new.as_str()),
323 ))
324 })
325 .collect();
326 this.selection = selection.clamp(&this.doc);
327 splices
328 });
329 }
330
331 pub fn toggle_task(&mut self, ix: usize, cx: &mut Context<Self>) {
338 if !self.blocks() {
339 return;
340 }
341 let checked = match self.doc.blocks.get(ix).map(|block| &block.kind) {
342 Some(BlockKind::Task { checked, .. }) => !checked,
343 _ => return,
344 };
345 self.edit(EditKind::Structure, cx, |this| {
346 if let Some(BlockKind::Task { checked: at, .. }) = this
347 .doc
348 .edit()
349 .blocks
350 .get_mut(ix)
351 .map(|block| &mut block.kind)
352 {
353 *at = checked;
354 }
355 vec![]
356 });
357 self.reveal = None;
362 }
363
364 pub fn add_row(&mut self, ix: usize, row: usize, cx: &mut Context<Self>) {
367 if !self.blocks() || !matches!(self.kind_at(ix), Some(BlockKind::Table { .. })) {
368 return;
369 }
370 self.edit(EditKind::Structure, cx, |this| {
371 this.doc.edit().insert_row(ix, row);
372 let row = row.max(1);
373 this.selection = Selection::at(Cursor::new(ix, Part::Cell { row, column: 0 }, 0));
374 vec![Delta::Cells {
375 block: ix,
376 row: Some(row),
377 column: None,
378 }]
379 });
380 }
381
382 pub fn add_column(&mut self, ix: usize, column: usize, cx: &mut Context<Self>) {
385 if !self.blocks() || !matches!(self.kind_at(ix), Some(BlockKind::Table { .. })) {
386 return;
387 }
388 let row = match self.cursor() {
389 Cursor {
390 block,
391 part: Part::Cell { row, .. },
392 ..
393 } if block == ix => row,
394 _ => self.doc.blocks[ix]
395 .parts()
396 .first()
397 .map_or(0, |part| match part {
398 Part::Cell { row, .. } => *row,
399 _ => 0,
400 }),
401 };
402 self.edit(EditKind::Structure, cx, |this| {
403 this.doc.edit().insert_column(ix, column);
404 this.selection = Selection::at(Cursor::new(ix, Part::Cell { row, column }, 0));
405 vec![Delta::Cells {
406 block: ix,
407 row: None,
408 column: Some(column),
409 }]
410 });
411 }
412
413 pub(super) fn step_cell(&mut self, forward: bool, cx: &mut Context<Self>) -> bool {
416 let at = self.cursor();
417 let Part::Cell { row, .. } = at.part else {
418 return false;
419 };
420 let parts = self.doc.blocks[at.block].parts();
421 let Some(here) = parts.iter().position(|part| *part == at.part) else {
422 return false;
423 };
424 let next = match forward {
425 true => parts.get(here + 1),
426 false => here.checked_sub(1).and_then(|ix| parts.get(ix)),
427 };
428 match next {
429 Some(part) => {
430 let end = Cursor::new(at.block, *part, usize::MAX).clamp(&self.doc);
431 self.head_to(end, false);
432 cx.notify();
433 }
434 None if forward => self.add_row(at.block, row + 1, cx),
435 None => {}
436 }
437 true
438 }
439
440 pub(super) fn cell_down(&mut self, cx: &mut Context<Self>) -> bool {
443 let at = self.cursor();
444 let Part::Cell { row, column } = at.part else {
445 return false;
446 };
447 let below = Part::Cell {
448 row: row + 1,
449 column,
450 };
451 if self.doc.blocks[at.block].text_at(below).is_none() {
452 self.add_row(at.block, row + 1, cx);
453 if column > 0 {
454 self.head_to(Cursor::new(at.block, below, 0).clamp(&self.doc), false);
455 }
456 return true;
457 }
458 let end = Cursor::new(at.block, below, usize::MAX).clamp(&self.doc);
459 self.head_to(end, false);
460 cx.notify();
461 true
462 }
463
464 pub fn remove_row(&mut self, ix: usize, row: usize, cx: &mut Context<Self>) {
466 self.remove_line(ix, Line::Row(row), cx);
467 }
468
469 pub fn remove_column(&mut self, ix: usize, column: usize, cx: &mut Context<Self>) {
471 self.remove_line(ix, Line::Column(column), cx);
472 }
473
474 fn remove_line(&mut self, ix: usize, line: Line, cx: &mut Context<Self>) {
475 if !self.blocks() {
476 return;
477 }
478 let Some(BlockKind::Table { header, rows, .. }) = self.kind_at(ix) else {
479 return;
480 };
481 let width = rows
482 .iter()
483 .map(Vec::len)
484 .chain([header.len()])
485 .max()
486 .unwrap_or(0);
487 let removable = match line {
488 Line::Row(row) => (1..=rows.len()).contains(&row),
489 Line::Column(column) => width > 1 && column < width,
490 };
491 if !removable {
492 return;
493 }
494 self.edit(EditKind::Structure, cx, |this| {
495 match line {
496 Line::Row(row) => this.doc.edit().remove_row(ix, row),
497 Line::Column(column) => this.doc.edit().remove_column(ix, column),
498 };
499 this.selection = this.selection.clamp(&this.doc);
500 let (row, column) = match line {
501 Line::Row(row) => (Some(row), None),
502 Line::Column(column) => (None, Some(column)),
503 };
504 vec![Delta::CellsRemoved {
505 block: ix,
506 row,
507 column,
508 }]
509 });
510 }
511
512 fn kind_at(&self, ix: usize) -> Option<&BlockKind> {
513 self.doc.blocks.get(ix).map(|block| &block.kind)
514 }
515}