1use crate::parser::{parse_bytes, source_cap, Engine};
20use crate::{parse, Document, Kind, Markdown, Mode, Node, Span, EMPHASIS_DEPTH, MARKDOWN_DEPTH};
21use std::collections::VecDeque;
22use std::sync::Arc;
23
24pub const STREAM_CONTEXT_BYTES: usize = 32 * 1024;
29pub const TAG_OPENING_BYTES: usize = 4 * 1024;
32pub const PENDING_REFERENCE_CHARS: usize = 24;
36
37const RUN_BYTES: usize = 1024;
40const LABEL_DEPTH: usize = 4;
44const CONTAINERS: usize = 2 * MARKDOWN_DEPTH;
47
48#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
52#[non_exhaustive]
53pub struct Work {
54 pub scanned: usize,
57 pub reexamined: usize,
61}
62
63#[derive(Clone, Debug, Default, PartialEq, Eq)]
78#[non_exhaustive]
79pub struct Revision {
80 pub nodes: Vec<Arc<DisplayNode>>,
81}
82
83#[derive(Clone, Debug, PartialEq, Eq)]
87#[non_exhaustive]
88pub struct DisplayNode {
89 pub span: Span,
90 pub kind: Display,
91 pub children: Vec<Arc<DisplayNode>>,
92}
93
94#[derive(Clone, Debug, PartialEq, Eq)]
96#[non_exhaustive]
97pub enum Display {
98 Paragraph,
99 Heading(u8),
100 ThematicBreak,
101 CodeBlock {
103 language: String,
104 },
105 Quote,
106 List {
107 start: Option<u64>,
110 },
111 Item,
112 Task(bool),
116 Table,
117 TableHead,
118 TableRow,
119 TableCell,
120 Emphasis,
121 Strong,
122 Strikethrough,
123 Code(String),
124 Link {
126 image: bool,
127 },
128 Text(String),
129 Literal(String),
132 SoftBreak,
133 HardBreak,
134 Tag {
136 name: String,
137 block: bool,
138 },
139 PendingReference,
141}
142
143pub struct StreamParser {
157 mode: Mode,
158 bytes: Vec<u8>,
159 machine: Option<Box<Machine>>,
160 last: Revision,
161 work: Work,
162}
163
164impl StreamParser {
165 pub fn new(mode: Mode) -> Self {
166 Self {
167 mode,
168 bytes: vec![],
169 machine: (mode == Mode::Reply).then(|| Box::new(Machine::new())),
170 last: Revision::default(),
171 work: Work::default(),
172 }
173 }
174
175 pub fn feed(&mut self, chunk: &[u8]) -> Option<Revision> {
178 let keep = chunk
179 .len()
180 .min((source_cap(self.mode) + 3).saturating_sub(self.bytes.len()));
181 self.bytes.extend_from_slice(&chunk[..keep]);
182 self.work = Work::default();
183 let machine = self.machine.as_mut()?;
184 for &byte in chunk {
185 if machine.stopped {
186 break;
187 }
188 machine.byte(byte);
189 }
190 self.work = std::mem::take(&mut machine.work);
191 if !std::mem::take(&mut machine.out.dirty) {
192 return None;
193 }
194 let revision = machine.out.snapshot();
195 if revision == self.last {
196 return None;
197 }
198 self.last = revision.clone();
199 Some(revision)
200 }
201
202 pub fn revision(&self) -> &Revision {
205 &self.last
206 }
207
208 pub fn work(&self) -> Work {
210 self.work
211 }
212
213 pub fn finish(self) -> Document {
215 parse_bytes(&self.bytes, self.mode)
216 }
217}
218
219fn sanitize(c: char) -> char {
223 match c {
224 '\r' => '\n',
225 '\n' | '\t' => c,
226 c if c.is_control() => '\u{fffd}',
227 c => c,
228 }
229}
230
231fn sanitize_str(text: &str) -> String {
232 let mut out = String::with_capacity(text.len());
233 let mut cr = false;
234 for c in text.chars() {
235 if !(cr && c == '\n') {
236 out.push(sanitize(c));
237 }
238 cr = c == '\r';
239 }
240 out
241}
242
243struct Run {
245 literal: bool,
246 span: Span,
247 text: String,
248 cr: bool,
249}
250
251impl Run {
252 fn node(&self) -> DisplayNode {
253 DisplayNode {
254 span: self.span,
255 kind: if self.literal {
256 Display::Literal(self.text.clone())
257 } else {
258 Display::Text(self.text.clone())
259 },
260 children: vec![],
261 }
262 }
263}
264
265struct Frame {
267 kind: Display,
268 span: Span,
269 children: Vec<Arc<DisplayNode>>,
270 run: Option<Run>,
271}
272
273struct Builder {
278 frames: Vec<Frame>,
279 dirty: bool,
280}
281
282impl Builder {
283 fn new() -> Self {
284 Self {
285 frames: vec![Frame {
286 kind: Display::Paragraph,
287 span: Span::default(),
288 children: vec![],
289 run: None,
290 }],
291 dirty: false,
292 }
293 }
294 fn top(&mut self) -> &mut Frame {
295 self.frames.last_mut().expect("the root frame stays open")
296 }
297 fn top_kind(&self) -> &Display {
298 &self.frames.last().expect("the root frame stays open").kind
299 }
300 fn flush_run(&mut self) {
301 let top = self.top();
302 if let Some(run) = top.run.take() {
303 top.children.push(Arc::new(run.node()));
304 }
305 }
306 fn extend(&mut self, end: usize) {
307 let top = self.top();
308 top.span.end = top.span.end.max(end);
309 }
310 fn open(&mut self, kind: Display, at: usize) {
311 self.flush_run();
312 self.frames.push(Frame {
313 kind,
314 span: Span::new(at, at),
315 children: vec![],
316 run: None,
317 });
318 self.dirty = true;
319 }
320 fn close(&mut self) {
321 if self.frames.len() < 2 {
322 return;
323 }
324 self.flush_run();
325 let frame = self.frames.pop().expect("checked above");
326 let node = DisplayNode {
327 span: frame.span,
328 kind: frame.kind,
329 children: frame.children,
330 };
331 self.extend(node.span.end);
332 self.top().children.push(Arc::new(node));
333 self.dirty = true;
334 }
335 fn discard(&mut self) {
337 if self.frames.len() > 1 {
338 self.frames.pop();
339 self.dirty = true;
340 }
341 }
342 fn push(&mut self, node: DisplayNode) {
343 self.flush_run();
344 self.extend(node.span.end);
345 self.top().children.push(Arc::new(node));
346 self.dirty = true;
347 }
348 fn char(&mut self, c: char, start: usize, end: usize, literal: bool) {
349 let top = self.top();
350 let same = top
351 .run
352 .as_ref()
353 .is_some_and(|run| run.literal == literal && run.text.len() < RUN_BYTES);
354 if !same {
355 if let Some(run) = top.run.take() {
356 top.children.push(Arc::new(run.node()));
357 }
358 top.run = Some(Run {
359 literal,
360 span: Span::new(start, start),
361 text: String::new(),
362 cr: false,
363 });
364 }
365 let run = top.run.as_mut().expect("opened above");
366 if !(run.cr && c == '\n') {
367 run.text.push(sanitize(c));
368 }
369 run.cr = c == '\r';
370 run.span.end = end;
371 top.span.end = top.span.end.max(end);
372 self.dirty = true;
373 }
374 fn trim_run(&mut self) {
376 let top = self.top();
377 let Some(run) = &mut top.run else { return };
378 let kept = run.text.trim_end_matches([' ', '\t']).len();
379 if run.literal || kept == run.text.len() {
380 return;
381 }
382 run.span.end -= run.text.len() - kept;
383 run.text.truncate(kept);
384 if run.text.is_empty() {
385 top.run = None;
386 }
387 self.dirty = true;
388 }
389 fn snapshot(&self) -> Revision {
390 let mut nested: Option<DisplayNode> = None;
391 for (i, frame) in self.frames.iter().enumerate().rev() {
392 let mut children = frame.children.clone();
393 let mut end = frame.span.end;
394 if let Some(run) = &frame.run {
395 children.push(Arc::new(run.node()));
396 }
397 if let Some(node) = nested.take() {
398 end = end.max(node.span.end);
399 children.push(Arc::new(node));
400 }
401 if i == 0 {
402 return Revision { nodes: children };
403 }
404 nested = Some(DisplayNode {
405 span: Span::new(frame.span.start, end),
406 kind: frame.kind.clone(),
407 children,
408 });
409 }
410 Revision::default()
411 }
412}
413
414fn convert(node: &Node, source: &str, map: &dyn Fn(usize) -> usize) -> DisplayNode {
417 let span = Span::new(map(node.span.start), map(node.span.end));
418 let mut children: Vec<Arc<DisplayNode>> = node
419 .children
420 .iter()
421 .map(|child| Arc::new(convert(child, source, map)))
422 .collect();
423 let kind = match &node.kind {
424 Kind::Markdown(markdown) => match markdown {
425 Markdown::Paragraph => Display::Paragraph,
426 Markdown::Heading(level) => Display::Heading(*level),
427 Markdown::ThematicBreak => Display::ThematicBreak,
428 Markdown::CodeBlock { language, text } => {
429 children = vec![Arc::new(DisplayNode {
430 span,
431 kind: Display::Text(sanitize_str(text)),
432 children: vec![],
433 })];
434 Display::CodeBlock {
435 language: sanitize_str(language),
436 }
437 }
438 Markdown::Code(text) => Display::Code(sanitize_str(text)),
439 Markdown::Quote => Display::Quote,
440 Markdown::List { start } => Display::List { start: *start },
441 Markdown::Item => Display::Item,
442 Markdown::Task(checked) => Display::Task(*checked),
443 Markdown::Table => Display::Table,
444 Markdown::TableHead => Display::TableHead,
445 Markdown::TableRow => Display::TableRow,
446 Markdown::TableCell => Display::TableCell,
447 Markdown::Emphasis => Display::Emphasis,
448 Markdown::Strong => Display::Strong,
449 Markdown::Strikethrough => Display::Strikethrough,
450 Markdown::Link { image, .. } => Display::Link { image: *image },
451 Markdown::SoftBreak => Display::SoftBreak,
452 Markdown::HardBreak => Display::HardBreak,
453 },
454 Kind::Text(text) => Display::Text(sanitize_str(text)),
455 Kind::Literal(text) => Display::Literal(sanitize_str(text)),
456 Kind::Reference { .. } => Display::PendingReference,
457 Kind::Tag { name, block, .. } => Display::Tag {
458 name: name.clone(),
459 block: *block,
460 },
461 Kind::Handle { .. }
463 | Kind::Interpolation { .. }
464 | Kind::Declaration { .. }
465 | Kind::Expression(_) => {
466 children.clear();
467 Display::Literal(sanitize_str(
468 source
469 .get(node.span.start..node.span.end)
470 .unwrap_or_default(),
471 ))
472 }
473 };
474 DisplayNode {
475 span,
476 kind,
477 children,
478 }
479}
480
481#[derive(Default)]
484struct Decoder {
485 buf: [u8; 4],
486 len: usize,
487 need: usize,
488}
489
490impl Decoder {
491 fn push(&mut self, byte: u8, out: &mut Vec<(char, usize)>) {
494 if self.len > 0 {
495 let valid = match (self.buf[0], self.len) {
496 (0xE0, 1) => (0xA0..=0xBF).contains(&byte),
497 (0xED, 1) => (0x80..=0x9F).contains(&byte),
498 (0xF0, 1) => (0x90..=0xBF).contains(&byte),
499 (0xF4, 1) => (0x80..=0x8F).contains(&byte),
500 _ => (0x80..=0xBF).contains(&byte),
501 };
502 if valid {
503 self.buf[self.len] = byte;
504 self.len += 1;
505 if self.len == self.need {
506 let c = std::str::from_utf8(&self.buf[..self.len])
507 .ok()
508 .and_then(|s| s.chars().next())
509 .unwrap_or('\u{fffd}');
510 self.len = 0;
511 out.push((c, 0));
512 }
513 return;
514 }
515 self.len = 0;
516 out.push(('\u{fffd}', 1));
517 }
518 let need = match byte {
519 0x00..=0x7F => {
520 out.push((byte as char, 0));
521 return;
522 }
523 0xC2..=0xDF => 2,
524 0xE0..=0xEF => 3,
525 0xF0..=0xF4 => 4,
526 _ => {
527 out.push(('\u{fffd}', 0));
528 return;
529 }
530 };
531 self.buf[0] = byte;
532 self.len = 1;
533 self.need = need;
534 }
535}
536
537#[derive(Clone, Copy, Debug)]
541struct Item {
542 at: usize,
543 c: char,
544 fresh: bool,
545}
546
547impl Item {
548 fn end(self) -> usize {
549 self.at + self.c.len_utf8()
550 }
551 fn inline(self) -> Self {
552 Self {
553 fresh: false,
554 ..self
555 }
556 }
557}
558
559fn eol(c: char) -> bool {
560 c == '\n' || c == '\r'
561}
562
563fn bytes(items: &[Item]) -> usize {
564 items.iter().map(|item| item.c.len_utf8()).sum()
565}
566
567enum Container {
568 Quote,
569 List { ordered: bool },
570 Item { width: usize },
571}
572
573#[derive(Default)]
575enum Leaf {
576 #[default]
577 None,
578 Paragraph {
579 header: Option<Header>,
582 lines: usize,
583 },
584 Heading,
585 Fence {
586 ch: char,
587 len: usize,
588 indent: usize,
589 },
590 Table,
591}
592
593#[derive(Default)]
594struct Header {
595 items: Vec<Item>,
596 bytes: usize,
597 pipe: bool,
598}
599
600enum Line {
601 Start(Box<LineStart>),
603 Content { skip_ws: bool },
605 Code,
607}
608
609impl Line {
610 fn start() -> Self {
611 Self::Start(Box::default())
612 }
613}
614
615#[derive(Default)]
616struct LineStart {
617 matched: usize,
619 indent: usize,
621 swallow: bool,
623 opened: Vec<Opening>,
625 phase: Phase,
626 consumed: usize,
628 no_delim: bool,
630 declaration: bool,
632}
633
634enum Opening {
635 Quote {
636 at: usize,
637 },
638 Item {
639 at: usize,
640 ordered: bool,
641 start: Option<u64>,
642 width: usize,
643 },
644}
645
646#[derive(Default)]
647enum Phase {
648 #[default]
649 Match,
650 Open,
651 Bullet {
652 ch: char,
653 buf: Vec<Item>,
654 indent: usize,
655 },
656 Thematic {
659 ch: char,
660 count: usize,
661 buf: Vec<Item>,
662 item: Option<usize>,
663 },
664 Ordered {
665 buf: Vec<Item>,
666 value: u64,
667 digits: usize,
668 indent: usize,
669 },
670 OrderedDelim {
671 buf: Vec<Item>,
672 value: u64,
673 width: usize,
674 },
675 ItemSpaces {
676 at: usize,
677 ordered: bool,
678 start: Option<u64>,
679 width: usize,
680 spaces: usize,
681 },
682 Heading {
683 buf: Vec<Item>,
684 level: u8,
685 },
686 FenceRun {
687 buf: Vec<Item>,
688 ch: char,
689 count: usize,
690 },
691 FenceInfo {
692 buf: Vec<Item>,
693 ch: char,
694 count: usize,
695 info: String,
696 },
697 Declaration {
698 buf: Vec<Item>,
699 },
700 DelimRow {
701 buf: Vec<Item>,
702 },
703 FenceIndent {
704 stripped: usize,
705 },
706 FenceClose {
707 buf: Vec<Item>,
708 count: usize,
709 lead: usize,
710 trailing: bool,
711 },
712}
713
714#[derive(Clone, Copy, PartialEq, Eq)]
715enum Target {
716 Paragraph,
717 Heading,
718 Cell,
719}
720
721#[derive(Default)]
723struct Inline {
724 target: Option<Target>,
725 opened: bool,
727 pending: Pending,
728 delims: Vec<Delim>,
729 prev: char,
731 spaces: usize,
733 url: bool,
735 recent: String,
736 block_start: bool,
738 declaration: bool,
740 leading: bool,
742}
743
744#[derive(Default)]
746enum Pending {
747 #[default]
748 None,
749 Escape(usize),
750 Bang(usize),
751 Angle {
752 at: usize,
753 block: bool,
754 },
755 Delim {
756 ch: char,
757 at: usize,
758 len: usize,
759 },
760 Reference(Vec<Item>),
761 Ticks {
762 at: usize,
763 len: usize,
764 },
765 Code(Code),
766 Link(Link),
767}
768
769struct Code {
770 at: usize,
771 run: usize,
772 buf: Vec<Item>,
773 closing: usize,
774 bytes: usize,
775}
776
777struct Link {
778 image: bool,
779 buf: Vec<Item>,
780 bytes: usize,
781 stage: Stage,
782 escaped: bool,
783}
784
785enum Stage {
786 Label { depth: usize },
787 Paren,
788 Destination { nesting: usize, quote: Option<char> },
789}
790
791struct Delim {
794 ch: char,
795 count: usize,
796 orig: usize,
797 close: bool,
798 index: usize,
799 start: usize,
800 end: usize,
801}
802
803enum Raw {
805 Braces(Braces),
807 Declaration(Declaration),
809 Capture(Box<Capture>),
811}
812
813struct Braces {
814 depth: usize,
815 escaped: bool,
816 cr: bool,
817 held: Option<Vec<Item>>,
820}
821
822struct Declaration {
823 scan: DeclarationScan,
824 cr: bool,
825 held: Option<(Vec<Item>, String)>,
828}
829
830struct Machine {
831 decoder: Decoder,
832 decoded: Vec<(char, usize)>,
833 raw: usize,
834 offset: usize,
835 stopped: bool,
836 queue: VecDeque<Item>,
837 out: Builder,
838 containers: Vec<Container>,
839 leaf: Leaf,
840 line: Line,
841 eol: Option<usize>,
844 cr: bool,
845 inline: Inline,
846 raw_mode: Option<Raw>,
847 work: Work,
848}
849
850impl Machine {
851 fn new() -> Self {
852 Self {
853 decoder: Decoder::default(),
854 decoded: vec![],
855 raw: 0,
856 offset: 0,
857 stopped: false,
858 queue: VecDeque::new(),
859 out: Builder::new(),
860 containers: vec![],
861 leaf: Leaf::None,
862 line: Line::start(),
863 eol: None,
864 cr: false,
865 inline: Inline::default(),
866 raw_mode: None,
867 work: Work::default(),
868 }
869 }
870
871 fn byte(&mut self, byte: u8) {
872 self.work.scanned += 1;
873 self.raw += 1;
874 let mut decoded = std::mem::take(&mut self.decoded);
875 self.decoder.push(byte, &mut decoded);
876 for (c, uncovered) in decoded.drain(..) {
877 if self.raw - uncovered > crate::REPLY_BYTES {
879 self.stopped = true;
880 break;
881 }
882 self.char(c);
883 }
884 self.decoded = decoded;
885 if self.raw >= crate::REPLY_BYTES + 3 {
886 self.stopped = true;
887 }
888 }
889
890 fn char(&mut self, c: char) {
891 let at = self.offset;
892 self.offset += c.len_utf8();
893 if at == 0 && c == '\u{feff}' {
894 return;
895 }
896 let mut queue = std::mem::take(&mut self.queue);
897 queue.push_back(Item { at, c, fresh: true });
898 while let Some(item) = queue.pop_front() {
899 self.step(item, &mut queue);
900 }
901 self.queue = queue;
902 }
903
904 fn step(&mut self, item: Item, q: &mut VecDeque<Item>) {
905 if self.raw_mode.is_some() {
906 self.raw_step(item, q);
907 } else if item.fresh {
908 self.block_step(item, q);
909 } else {
910 self.inline_step(item, q);
911 }
912 }
913
914 fn rerun(&mut self, q: &mut VecDeque<Item>, items: &[Item]) {
916 for item in items.iter().rev() {
917 self.work.reexamined += item.c.len_utf8();
918 q.push_front(*item);
919 }
920 }
921
922 fn run_now(&mut self, items: &[Item]) {
925 let mut q = VecDeque::new();
926 self.rerun(&mut q, items);
927 while let Some(item) = q.pop_front() {
928 if self.raw_mode.is_some() {
929 self.raw_step(item, &mut q);
930 } else {
931 self.inline_step(item.inline(), &mut q);
932 }
933 }
934 }
935}
936
937enum Block {
939 Heading {
940 at: usize,
941 level: u8,
942 },
943 Thematic {
944 span: Span,
945 },
946 Fence {
947 at: usize,
948 ch: char,
949 len: usize,
950 indent: usize,
951 language: String,
952 },
953}
954
955impl Machine {
956 fn block_step(&mut self, item: Item, q: &mut VecDeque<Item>) {
957 let c = item.c;
958 let crlf = c == '\n' && self.cr;
959 self.cr = c == '\r';
960 if crlf {
961 return;
962 }
963 match &mut self.line {
964 Line::Content { skip_ws } => {
965 if eol(c) {
966 self.content_eol(item.at);
967 return;
968 }
969 if *skip_ws && (c == ' ' || c == '\t') {
970 return;
971 }
972 *skip_ws = false;
973 if let Leaf::Paragraph {
974 header: Some(header),
975 lines: 1,
976 } = &mut self.leaf
977 {
978 header.items.push(item);
979 header.bytes += c.len_utf8();
980 header.pipe |= c == '|';
981 if header.bytes > STREAM_CONTEXT_BYTES {
982 self.drop_header();
983 }
984 }
985 self.inline_step(item.inline(), q);
986 }
987 Line::Code => {
988 self.out.char(c, item.at, item.end(), false);
989 if eol(c) {
990 self.out.flush_run();
991 self.line = Line::start();
992 }
993 }
994 Line::Start(_) => self.line_char(item, q),
995 }
996 }
997
998 fn drop_header(&mut self) {
999 if let Leaf::Paragraph { header, .. } = &mut self.leaf {
1000 *header = None;
1001 }
1002 }
1003
1004 fn content_eol(&mut self, at: usize) {
1006 match &mut self.leaf {
1007 Leaf::Paragraph { header, .. } => {
1008 if header.as_ref().is_some_and(|header| !header.pipe) {
1009 *header = None;
1010 }
1011 self.eol = Some(at);
1012 }
1013 Leaf::Heading => {
1014 self.end_run();
1015 self.leaf = Leaf::None;
1016 }
1017 Leaf::Table => {
1018 self.end_run();
1019 self.out.close();
1020 }
1021 Leaf::None | Leaf::Fence { .. } => {}
1022 }
1023 self.line = Line::start();
1024 }
1025
1026 fn line_char(&mut self, item: Item, q: &mut VecDeque<Item>) {
1028 let Line::Start(mut ls) = std::mem::replace(&mut self.line, Line::Code) else {
1029 return;
1030 };
1031 let decided = self.classify(&mut ls, item, q);
1032 if !decided {
1033 ls.consumed += 1;
1034 self.line = Line::Start(ls);
1035 }
1036 }
1037
1038 fn classify(&mut self, ls: &mut LineStart, item: Item, q: &mut VecDeque<Item>) -> bool {
1040 let c = item.c;
1041 loop {
1042 if ls.swallow {
1043 ls.swallow = false;
1044 if c == ' ' {
1045 return false;
1046 }
1047 }
1048 match &mut ls.phase {
1049 Phase::Match => {
1050 while matches!(
1051 self.containers.get(ls.matched),
1052 Some(Container::List { .. })
1053 ) {
1054 ls.matched += 1;
1055 }
1056 if ls.matched == self.containers.len() {
1057 ls.phase = if matches!(self.leaf, Leaf::Fence { .. }) {
1058 Phase::FenceIndent { stripped: 0 }
1059 } else {
1060 Phase::Open
1061 };
1062 continue;
1063 }
1064 if eol(c) {
1065 return self.blank_line(ls, item);
1066 }
1067 let fits = match self.containers[ls.matched] {
1068 Container::Quote => {
1069 if c == '>' && ls.indent <= 3 {
1070 ls.matched += 1;
1071 ls.indent = 0;
1072 ls.swallow = true;
1073 return false;
1074 }
1075 (c == ' ' || c == '\t') && ls.indent < 3
1076 }
1077 Container::Item { width } => {
1078 if c == ' ' || c == '\t' {
1079 ls.indent += if c == '\t' { 4 - ls.indent % 4 } else { 1 };
1080 if ls.indent >= width {
1081 ls.indent -= width;
1082 ls.matched += 1;
1083 }
1084 return false;
1085 }
1086 false
1087 }
1088 Container::List { .. } => unreachable!("lists match through their items"),
1089 };
1090 if fits {
1091 ls.indent += if c == '\t' { 4 - ls.indent % 4 } else { 1 };
1092 return false;
1093 }
1094 if matches!(self.leaf, Leaf::Fence { .. }) {
1097 self.close_containers(ls.matched);
1098 }
1099 ls.phase = Phase::Open;
1100 }
1101 Phase::Open => {
1102 if c == ' ' || c == '\t' {
1103 ls.indent += if c == '\t' { 4 - ls.indent % 4 } else { 1 };
1104 return false;
1105 }
1106 if eol(c) {
1107 return self.blank_line(ls, item);
1108 }
1109 let header = matches!(
1110 &self.leaf,
1111 Leaf::Paragraph { header: Some(h), lines: 1 } if h.pipe
1112 );
1113 if header
1114 && !ls.no_delim
1115 && ls.opened.is_empty()
1116 && ls.matched == self.containers.len()
1117 && matches!(c, '|' | '-' | ':')
1118 {
1119 ls.phase = Phase::DelimRow { buf: vec![item] };
1120 return false;
1121 }
1122 if ls.indent >= 4 {
1123 return self.content(ls, &[item], q);
1124 }
1125 let buf = vec![item];
1126 let indent = ls.indent;
1127 ls.phase = match c {
1128 '>' => {
1129 ls.opened.push(Opening::Quote { at: item.at });
1130 ls.indent = 0;
1131 ls.swallow = true;
1132 return false;
1133 }
1134 '-' | '+' | '*' => Phase::Bullet { ch: c, buf, indent },
1135 '_' => Phase::Thematic {
1136 ch: c,
1137 count: 1,
1138 buf,
1139 item: None,
1140 },
1141 '0'..='9' => Phase::Ordered {
1142 buf,
1143 value: u64::from(c as u8 - b'0'),
1144 digits: 1,
1145 indent,
1146 },
1147 '#' => Phase::Heading { buf, level: 1 },
1148 '`' | '~' => Phase::FenceRun {
1149 buf,
1150 ch: c,
1151 count: 1,
1152 },
1153 'e' if ls.consumed == 0 => Phase::Declaration { buf },
1154 _ => return self.content(ls, &buf, q),
1155 };
1156 return false;
1157 }
1158 Phase::Bullet { ch, buf, indent } => {
1159 let (ch, indent) = (*ch, *indent);
1160 if c == ' ' || c == '\t' || eol(c) {
1161 if ch == '+' {
1162 ls.phase = Phase::ItemSpaces {
1163 at: buf[0].at,
1164 ordered: false,
1165 start: None,
1166 width: indent + 1,
1167 spaces: 0,
1168 };
1169 } else {
1170 ls.phase = Phase::Thematic {
1171 ch,
1172 count: 1,
1173 buf: std::mem::take(buf),
1174 item: Some(indent + 1),
1175 };
1176 }
1177 continue;
1178 }
1179 if c == ch && ch != '+' {
1180 buf.push(item);
1181 ls.phase = Phase::Thematic {
1182 ch,
1183 count: 2,
1184 buf: std::mem::take(buf),
1185 item: None,
1186 };
1187 return false;
1188 }
1189 let mut buf = std::mem::take(buf);
1190 buf.push(item);
1191 return self.content(ls, &buf, q);
1192 }
1193 Phase::Thematic {
1194 ch,
1195 count,
1196 buf,
1197 item: marker,
1198 } => {
1199 if c == *ch || c == ' ' || c == '\t' {
1200 if buf.len() >= STREAM_CONTEXT_BYTES {
1202 let mut buf = std::mem::take(buf);
1203 buf.push(item);
1204 return self.content_with(ls, &buf, q, true);
1205 }
1206 *count += usize::from(c == *ch);
1207 buf.push(item);
1208 return false;
1209 }
1210 if eol(c) && *count >= 3 {
1211 let span = Span::new(buf[0].at, item.at);
1212 return self.block(ls, Block::Thematic { span }, Some(item), q);
1213 }
1214 let mut buf = std::mem::take(buf);
1215 buf.push(item);
1216 if let Some(width) = *marker {
1217 ls.phase = Phase::ItemSpaces {
1220 at: buf[0].at,
1221 ordered: false,
1222 start: None,
1223 width,
1224 spaces: 0,
1225 };
1226 self.rerun(q, &buf[1..]);
1227 return false;
1228 }
1229 return self.content(ls, &buf, q);
1230 }
1231 Phase::Ordered {
1232 buf,
1233 value,
1234 digits,
1235 indent,
1236 } => {
1237 if c.is_ascii_digit() && *digits < 9 {
1238 *value = *value * 10 + u64::from(c as u8 - b'0');
1239 *digits += 1;
1240 buf.push(item);
1241 return false;
1242 }
1243 let mut buf = std::mem::take(buf);
1244 buf.push(item);
1245 if c == '.' || c == ')' {
1246 ls.phase = Phase::OrderedDelim {
1247 width: *indent + *digits + 1,
1248 value: *value,
1249 buf,
1250 };
1251 return false;
1252 }
1253 return self.content(ls, &buf, q);
1254 }
1255 Phase::OrderedDelim { buf, value, width } => {
1256 if c == ' ' || c == '\t' || eol(c) {
1257 ls.phase = Phase::ItemSpaces {
1258 at: buf[0].at,
1259 ordered: true,
1260 start: Some(*value),
1261 width: *width,
1262 spaces: 0,
1263 };
1264 continue;
1265 }
1266 let mut buf = std::mem::take(buf);
1267 buf.push(item);
1268 return self.content(ls, &buf, q);
1269 }
1270 Phase::ItemSpaces {
1271 at,
1272 ordered,
1273 start,
1274 width,
1275 spaces,
1276 } => {
1277 if c == ' ' || c == '\t' {
1278 *spaces += if c == '\t' {
1279 4 - (*width + *spaces) % 4
1280 } else {
1281 1
1282 };
1283 return false;
1284 }
1285 let content_spaces = if *spaces == 0 || *spaces > 4 {
1286 1
1287 } else {
1288 *spaces
1289 };
1290 ls.indent = spaces.saturating_sub(content_spaces);
1291 ls.opened.push(Opening::Item {
1292 at: *at,
1293 ordered: *ordered,
1294 start: *start,
1295 width: *width + content_spaces,
1296 });
1297 ls.phase = Phase::Open;
1298 }
1299 Phase::Heading { buf, level } => {
1300 if c == '#' && *level < 6 {
1301 *level += 1;
1302 buf.push(item);
1303 return false;
1304 }
1305 if c == ' ' || c == '\t' || eol(c) {
1306 let block = Block::Heading {
1307 at: buf[0].at,
1308 level: *level,
1309 };
1310 return self.block(ls, block, eol(c).then_some(item), q);
1311 }
1312 let mut buf = std::mem::take(buf);
1313 buf.push(item);
1314 return self.content(ls, &buf, q);
1315 }
1316 Phase::FenceRun { buf, ch, count } => {
1317 if c == *ch {
1318 *count += 1;
1319 buf.push(item);
1320 return false;
1321 }
1322 if *count < 3 {
1323 let mut buf = std::mem::take(buf);
1324 buf.push(item);
1325 return self.content(ls, &buf, q);
1326 }
1327 ls.phase = Phase::FenceInfo {
1328 buf: std::mem::take(buf),
1329 ch: *ch,
1330 count: *count,
1331 info: String::new(),
1332 };
1333 }
1334 Phase::FenceInfo {
1335 buf,
1336 ch,
1337 count,
1338 info,
1339 } => {
1340 if eol(c) {
1341 let block = Block::Fence {
1342 at: buf[0].at,
1343 ch: *ch,
1344 len: *count,
1345 indent: ls.indent,
1346 language: info.split_whitespace().next().unwrap_or("").to_owned(),
1347 };
1348 return self.block(ls, block, None, q);
1349 }
1350 buf.push(item);
1351 if *ch == '`' && c == '`' {
1354 let buf = std::mem::take(buf);
1355 return self.content(ls, &buf, q);
1356 }
1357 if info.len() >= STREAM_CONTEXT_BYTES {
1358 let buf = std::mem::take(buf);
1359 return self.content_with(ls, &buf, q, true);
1360 }
1361 info.push(c);
1362 return false;
1363 }
1364 Phase::Declaration { buf } => {
1365 let mut text: String = buf.iter().map(|item| item.c).collect();
1366 text.push(c);
1367 let mut buf = std::mem::take(buf);
1368 buf.push(item);
1369 match declaration_prefix(&text) {
1370 Some(true) => {
1371 ls.declaration = true;
1372 return self.content(ls, &buf, q);
1373 }
1374 Some(false) => {
1375 ls.phase = Phase::Declaration { buf };
1376 return false;
1377 }
1378 None => return self.content(ls, &buf, q),
1379 }
1380 }
1381 Phase::DelimRow { buf } => {
1382 if matches!(c, '|' | '-' | ':' | ' ' | '\t') && buf.len() < STREAM_CONTEXT_BYTES
1383 {
1384 buf.push(item);
1385 return false;
1386 }
1387 let mut buf = std::mem::take(buf);
1388 if eol(c) && self.delimiter_row(&buf) {
1389 self.make_table(&buf);
1390 self.line = Line::start();
1391 return true;
1392 }
1393 ls.no_delim = true;
1395 ls.phase = Phase::Open;
1396 buf.push(item);
1397 self.rerun(q, &buf);
1398 return false;
1399 }
1400 Phase::FenceIndent { stripped } => {
1401 let indent = match self.leaf {
1402 Leaf::Fence { indent, .. } => indent,
1403 _ => 0,
1404 };
1405 if c == ' ' && *stripped < indent {
1406 *stripped += 1;
1407 return false;
1408 }
1409 ls.phase = Phase::FenceClose {
1410 buf: vec![],
1411 count: 0,
1412 lead: 0,
1413 trailing: false,
1414 };
1415 }
1416 Phase::FenceClose {
1417 buf,
1418 count,
1419 lead,
1420 trailing,
1421 } => {
1422 let (ch, len) = match self.leaf {
1423 Leaf::Fence { ch, len, .. } => (ch, len),
1424 _ => ('`', usize::MAX),
1425 };
1426 if eol(c) && *count >= len {
1427 self.close_leaf();
1428 self.line = Line::start();
1429 return true;
1430 }
1431 let held = if c == ' ' && *count == 0 && *lead < 3 {
1432 *lead += 1;
1433 true
1434 } else if c == ch && !*trailing {
1435 *count += 1;
1436 true
1437 } else if (c == ' ' || c == '\t') && *count > 0 {
1438 *trailing = true;
1439 true
1440 } else {
1441 false
1442 };
1443 if held && !eol(c) {
1444 buf.push(item);
1445 return false;
1446 }
1447 let mut buf = std::mem::take(buf);
1448 buf.push(item);
1449 self.line = Line::Code;
1450 self.rerun(q, &buf);
1451 return true;
1452 }
1453 }
1454 }
1455 }
1456
1457 fn blank_line(&mut self, ls: &mut LineStart, item: Item) -> bool {
1459 let mut keep = ls.matched;
1461 while keep < self.containers.len() && !matches!(self.containers[keep], Container::Quote) {
1462 keep += 1;
1463 }
1464 if ls.opened.is_empty()
1465 && keep == self.containers.len()
1466 && matches!(self.leaf, Leaf::Fence { .. })
1467 {
1468 self.out.char('\n', item.at, item.end(), false);
1469 self.out.flush_run();
1470 } else if ls.opened.is_empty() {
1471 self.close_containers(keep);
1472 } else {
1473 self.settle(ls, false);
1474 }
1475 self.line = Line::start();
1476 true
1477 }
1478
1479 fn settle(&mut self, ls: &mut LineStart, content: bool) -> bool {
1482 if content && ls.opened.is_empty() && matches!(self.leaf, Leaf::Paragraph { .. }) {
1483 return true;
1484 }
1485 let mut keep = ls.matched;
1486 if keep > 0 {
1487 if let Container::List { ordered } = self.containers[keep - 1] {
1488 let same = matches!(ls.opened.first(), Some(Opening::Item { ordered: o, .. }) if *o == ordered);
1489 if !same {
1490 keep -= 1;
1491 }
1492 }
1493 }
1494 self.close_containers(keep);
1495 for opening in std::mem::take(&mut ls.opened) {
1496 if self.containers.len() + 2 > CONTAINERS {
1497 break;
1498 }
1499 match opening {
1500 Opening::Quote { at } => {
1501 self.containers.push(Container::Quote);
1502 self.out.open(Display::Quote, at);
1503 }
1504 Opening::Item {
1505 at,
1506 ordered,
1507 start,
1508 width,
1509 } => {
1510 let reuse = matches!(self.containers.last(), Some(Container::List { ordered: o }) if *o == ordered);
1511 if !reuse {
1512 if matches!(self.containers.last(), Some(Container::List { .. })) {
1513 self.containers.pop();
1514 self.out.close();
1515 }
1516 self.containers.push(Container::List { ordered });
1517 self.out.open(Display::List { start }, at);
1518 }
1519 self.containers.push(Container::Item { width });
1520 self.out.open(Display::Item, at);
1521 }
1522 }
1523 }
1524 false
1525 }
1526
1527 fn close_leaf(&mut self) {
1528 match std::mem::take(&mut self.leaf) {
1529 Leaf::Paragraph { .. } | Leaf::Heading => self.end_run(),
1530 Leaf::Fence { .. } => self.out.close(),
1531 Leaf::Table => {
1532 self.end_run();
1533 while matches!(
1534 self.out.top_kind(),
1535 Display::TableRow | Display::TableHead | Display::TableCell
1536 ) {
1537 self.out.close();
1538 }
1539 self.out.close();
1540 }
1541 Leaf::None => {}
1542 }
1543 self.eol = None;
1544 }
1545
1546 fn close_containers(&mut self, keep: usize) {
1547 self.close_leaf();
1548 while self.containers.len() > keep {
1549 self.containers.pop();
1550 self.out.close();
1551 }
1552 }
1553
1554 fn content(&mut self, ls: &mut LineStart, items: &[Item], q: &mut VecDeque<Item>) -> bool {
1556 self.content_with(ls, items, q, false)
1557 }
1558
1559 fn content_with(
1562 &mut self,
1563 ls: &mut LineStart,
1564 items: &[Item],
1565 q: &mut VecDeque<Item>,
1566 capped: bool,
1567 ) -> bool {
1568 let block_start = ls.indent <= 3 && !capped;
1569 let row = ls.opened.is_empty()
1570 && ls.matched == self.containers.len()
1571 && matches!(self.leaf, Leaf::Table);
1572 self.line = Line::Content { skip_ws: false };
1573 let mut newline = None;
1574 if row {
1575 self.out.open(Display::TableRow, items[0].at);
1576 self.start_run(Target::Cell);
1577 } else if self.settle(ls, true) {
1578 if let Leaf::Paragraph { header, lines } = &mut self.leaf {
1579 *lines += 1;
1580 *header = None;
1581 }
1582 newline = self.eol.take().map(|at| Item {
1583 at,
1584 c: '\n',
1585 fresh: false,
1586 });
1587 } else {
1588 self.leaf = Leaf::Paragraph {
1589 header: Some(Header::default()),
1590 lines: 1,
1591 };
1592 self.start_run(Target::Paragraph);
1593 }
1594 self.inline.block_start = block_start && !row;
1595 self.inline.declaration = ls.declaration;
1596 if capped {
1597 if let Some(newline) = newline {
1598 self.run_now(&[newline]);
1599 }
1600 self.drop_header();
1601 self.cap_flush(items, "", items[0].at);
1602 } else {
1603 self.rerun(q, items);
1607 if let Some(newline) = newline {
1608 q.push_front(newline);
1609 }
1610 }
1611 true
1612 }
1613
1614 fn block(
1616 &mut self,
1617 ls: &mut LineStart,
1618 block: Block,
1619 eol_item: Option<Item>,
1620 q: &mut VecDeque<Item>,
1621 ) -> bool {
1622 self.settle(ls, false);
1623 match block {
1624 Block::Thematic { span } => {
1625 self.out.push(DisplayNode {
1626 span,
1627 kind: Display::ThematicBreak,
1628 children: vec![],
1629 });
1630 self.line = Line::start();
1631 }
1632 Block::Heading { at, level } => {
1633 self.out.open(Display::Heading(level), at);
1634 self.leaf = Leaf::Heading;
1635 self.start_run(Target::Heading);
1636 self.inline.opened = true;
1637 self.line = Line::Content { skip_ws: true };
1638 if let Some(item) = eol_item {
1639 self.rerun(q, &[item]);
1640 }
1641 }
1642 Block::Fence {
1643 at,
1644 ch,
1645 len,
1646 indent,
1647 language,
1648 } => {
1649 self.out.open(
1650 Display::CodeBlock {
1651 language: sanitize_str(&language),
1652 },
1653 at,
1654 );
1655 self.leaf = Leaf::Fence { ch, len, indent };
1656 self.line = Line::start();
1657 }
1658 }
1659 true
1660 }
1661
1662 fn delimiter_row(&self, buf: &[Item]) -> bool {
1664 let Leaf::Paragraph {
1665 header: Some(header),
1666 ..
1667 } = &self.leaf
1668 else {
1669 return false;
1670 };
1671 let row: String = buf.iter().map(|item| item.c).collect();
1672 let head: String = header.items.iter().map(|item| item.c).collect();
1673 let cells = row_cells(&row);
1674 !cells.is_empty()
1675 && cells.len() == row_cells(&head).len()
1676 && cells.iter().all(|cell| {
1677 let cell = cell.trim();
1678 let dashes = cell.trim_start_matches(':').trim_end_matches(':');
1679 !dashes.is_empty()
1680 && dashes.bytes().all(|b| b == b'-')
1681 && cell.len() - dashes.len() <= 2
1682 })
1683 }
1684
1685 fn make_table(&mut self, delimiter: &[Item]) {
1687 let header = match &mut self.leaf {
1688 Leaf::Paragraph { header, .. } => header.take().unwrap_or_default(),
1689 _ => Header::default(),
1690 };
1691 self.discard_run();
1692 self.leaf = Leaf::Table;
1693 let at = header.items.first().map_or(delimiter[0].at, |item| item.at);
1694 self.out.open(Display::Table, at);
1695 self.out.open(Display::TableHead, at);
1696 self.start_run(Target::Cell);
1697 self.run_now(&header.items);
1698 self.finish_raw();
1699 self.end_run();
1700 self.out.close();
1701 }
1702}
1703
1704fn row_cells(row: &str) -> Vec<String> {
1707 let row = row.trim();
1708 let row = row.strip_prefix('|').unwrap_or(row);
1709 let row = match row.strip_suffix('|') {
1710 Some(rest) if !rest.ends_with('\\') => rest,
1711 _ => row,
1712 };
1713 let mut cells = vec![String::new()];
1714 let mut escaped = false;
1715 for c in row.chars() {
1716 if c == '|' && !escaped {
1717 cells.push(String::new());
1718 } else {
1719 cells.last_mut().expect("starts non-empty").push(c);
1720 }
1721 escaped = c == '\\' && !escaped;
1722 }
1723 cells
1724}
1725
1726fn declaration_prefix(text: &str) -> Option<bool> {
1730 if text.len() > 64 {
1731 return None;
1732 }
1733 let Some(rest) = text.strip_prefix("export") else {
1734 return "export".starts_with(text).then_some(false);
1735 };
1736 if rest.is_empty() {
1737 return Some(false);
1738 }
1739 if !rest.starts_with([' ', '\t']) {
1740 return None;
1741 }
1742 let rest = rest.trim_start_matches([' ', '\t']);
1743 for keyword in ["let", "const"] {
1744 if let Some(tail) = rest.strip_prefix(keyword) {
1745 return match tail.chars().next() {
1746 None => Some(false),
1747 Some(' ' | '\t') => Some(true),
1748 Some(_) => None,
1749 };
1750 }
1751 if keyword.starts_with(rest) {
1752 return Some(false);
1753 }
1754 }
1755 None
1756}
1757
1758fn is_punctuation(c: char) -> bool {
1759 c.is_ascii_punctuation() || (!c.is_ascii() && !c.is_alphanumeric() && !c.is_whitespace())
1760}
1761
1762fn literal_node(items: &[Item], prefix: &str, at: usize) -> DisplayNode {
1764 let mut text = String::from(prefix);
1765 text.extend(items.iter().map(|item| item.c));
1766 DisplayNode {
1767 span: Span::new(
1768 at,
1769 items.last().map_or(at + prefix.len(), |item| item.end()),
1770 ),
1771 kind: Display::Literal(sanitize_str(&text)),
1772 children: vec![],
1773 }
1774}
1775
1776impl Machine {
1777 fn start_run(&mut self, target: Target) {
1778 self.inline = Inline {
1779 target: Some(target),
1780 prev: ' ',
1781 leading: target == Target::Cell,
1782 ..Inline::default()
1783 };
1784 }
1785
1786 fn ensure_frame(&mut self, at: usize) {
1788 if self.inline.opened {
1789 return;
1790 }
1791 let kind = match self.inline.target {
1792 Some(Target::Cell) => Display::TableCell,
1793 Some(Target::Heading) => Display::Heading(1),
1794 Some(Target::Paragraph) => Display::Paragraph,
1795 None => {
1796 self.leaf = Leaf::Paragraph {
1801 header: None,
1802 lines: 1,
1803 };
1804 self.inline.target = Some(Target::Paragraph);
1805 Display::Paragraph
1806 }
1807 };
1808 self.out.open(kind, at);
1809 self.inline.opened = true;
1810 }
1811
1812 fn emit_char(&mut self, c: char, start: usize, end: usize) {
1813 self.ensure_frame(start);
1814 self.out.char(c, start, end, false);
1815 let inline = &mut self.inline;
1816 inline.prev = c;
1817 inline.spaces = if c == ' ' { inline.spaces + 1 } else { 0 };
1818 inline.recent.push(c);
1819 if inline.recent.len() > 8 {
1820 inline.recent.remove(0);
1821 }
1822 if inline.recent.ends_with("http://") || inline.recent.ends_with("https://") {
1823 inline.url = true;
1824 }
1825 }
1826
1827 fn emit_items(&mut self, items: &[Item]) {
1828 for item in items {
1829 self.emit_char(item.c, item.at, item.end());
1830 }
1831 }
1832
1833 fn literal_char(&mut self, item: Item) {
1834 self.ensure_frame(item.at);
1835 self.out.char(item.c, item.at, item.end(), true);
1836 self.inline.prev = item.c;
1837 self.inline.spaces = 0;
1838 self.inline.recent.clear();
1839 }
1840
1841 fn emit_node(&mut self, node: DisplayNode, prev: char) {
1842 self.ensure_frame(node.span.start);
1843 self.out.push(node);
1844 self.inline.prev = prev;
1845 self.inline.spaces = 0;
1846 self.inline.recent.clear();
1847 }
1848
1849 fn cap_flush(&mut self, items: &[Item], prefix: &str, at: usize) {
1852 self.work.reexamined += bytes(items) + prefix.len();
1853 let prev = items.last().map_or(' ', |item| item.c);
1854 self.emit_node(literal_node(items, prefix, at), prev);
1855 }
1856
1857 fn end_run(&mut self) {
1859 let Some(target) = self.inline.target else {
1860 return;
1861 };
1862 let pending = std::mem::take(&mut self.inline.pending);
1863 let again = self.resolve_end(pending);
1864 if !again.is_empty() {
1865 self.run_now(&again);
1866 }
1867 let pending = std::mem::take(&mut self.inline.pending);
1869 self.flush_pending(pending);
1870 self.finish_raw();
1871 if self.inline.opened {
1872 self.out.trim_run();
1873 if target == Target::Heading {
1874 self.trim_closing_hashes();
1875 }
1876 self.out.close();
1877 }
1878 self.inline = Inline::default();
1879 }
1880
1881 fn discard_run(&mut self) {
1883 if self.inline.opened {
1884 self.out.discard();
1885 }
1886 self.inline = Inline::default();
1887 self.eol = None;
1888 }
1889
1890 fn trim_closing_hashes(&mut self) {
1892 let top = self.out.top();
1893 let Some(run) = &mut top.run else { return };
1894 let kept = run.text.trim_end_matches('#');
1895 if kept.len() < run.text.len() && (kept.is_empty() || kept.ends_with([' ', '\t'])) {
1896 let kept = kept.trim_end_matches([' ', '\t']).len();
1897 run.span.end -= run.text.len() - kept;
1898 run.text.truncate(kept);
1899 if run.text.is_empty() {
1900 top.run = None;
1901 }
1902 self.out.dirty = true;
1903 }
1904 }
1905
1906 fn resolve_end(&mut self, pending: Pending) -> Vec<Item> {
1909 match pending {
1910 Pending::Code(code) if code.closing == code.run => {
1911 self.resolve_code(code);
1912 vec![]
1913 }
1914 Pending::Code(code) => {
1915 for i in 0..code.run {
1916 self.emit_char('`', code.at + i, code.at + i + 1);
1917 }
1918 code.buf
1919 }
1920 Pending::Link(link) => {
1921 let opener = if link.image { 2 } else { 1 };
1922 self.emit_items(&link.buf[..opener]);
1923 link.buf[opener..].to_vec()
1924 }
1925 other => {
1926 self.flush_pending(other);
1927 vec![]
1928 }
1929 }
1930 }
1931
1932 fn flush_pending(&mut self, pending: Pending) {
1934 match pending {
1935 Pending::None => {}
1936 Pending::Escape(at) => self.emit_char('\\', at, at + 1),
1937 Pending::Bang(at) => self.emit_char('!', at, at + 1),
1938 Pending::Angle { at, .. } => self.emit_char('<', at, at + 1),
1939 Pending::Delim { ch, at, len } => self.resolve_delim(ch, at, len, ' '),
1940 Pending::Ticks { at, len } => {
1941 for i in 0..len {
1942 self.emit_char('`', at + i, at + i + 1);
1943 }
1944 }
1945 Pending::Reference(buf) => {
1946 self.work.reexamined += bytes(&buf);
1947 self.emit_items(&buf);
1948 }
1949 Pending::Code(code) => {
1950 self.work.reexamined += code.bytes;
1951 for i in 0..code.run {
1952 self.emit_char('`', code.at + i, code.at + i + 1);
1953 }
1954 self.emit_items(&code.buf);
1955 }
1956 Pending::Link(link) => {
1957 self.work.reexamined += link.bytes;
1958 self.emit_items(&link.buf);
1959 }
1960 }
1961 }
1962
1963 fn inline_step(&mut self, item: Item, q: &mut VecDeque<Item>) {
1964 let c = item.c;
1965 if self.inline.target == Some(Target::Cell)
1967 && c == '|'
1968 && !matches!(self.inline.pending, Pending::Escape(_))
1969 {
1970 self.cell_boundary(item);
1971 return;
1972 }
1973 match std::mem::take(&mut self.inline.pending) {
1974 Pending::None => self.plain(item, q),
1975 Pending::Escape(at) => {
1976 if c == '\n' {
1977 let node = DisplayNode {
1978 span: Span::new(at, item.end()),
1979 kind: Display::HardBreak,
1980 children: vec![],
1981 };
1982 self.emit_node(node, '\n');
1983 } else if c.is_ascii_punctuation() {
1984 self.emit_char(c, at, item.end());
1985 } else {
1986 self.emit_char('\\', at, at + 1);
1987 q.push_front(item);
1988 }
1989 }
1990 Pending::Bang(at) => {
1991 if c == '[' {
1992 self.inline.pending = Pending::Link(Link {
1993 image: true,
1994 buf: vec![
1995 Item {
1996 at,
1997 c: '!',
1998 fresh: false,
1999 },
2000 item,
2001 ],
2002 bytes: 2,
2003 stage: Stage::Label { depth: 1 },
2004 escaped: false,
2005 });
2006 } else {
2007 self.emit_char('!', at, at + 1);
2008 q.push_front(item);
2009 }
2010 }
2011 Pending::Angle { at, block } => {
2012 if c.is_ascii_uppercase() {
2013 self.drop_header();
2014 self.raw_mode = Some(Raw::Capture(Box::new(Capture::new(at, block))));
2015 self.raw_step(item, q);
2016 } else {
2017 self.emit_char('<', at, at + 1);
2018 q.push_front(item);
2019 }
2020 }
2021 Pending::Delim { ch, at, len } => {
2022 if c == ch {
2023 self.inline.pending = Pending::Delim {
2024 ch,
2025 at,
2026 len: len + 1,
2027 };
2028 } else {
2029 self.resolve_delim(ch, at, len, c);
2030 q.push_front(item);
2031 }
2032 }
2033 Pending::Reference(buf) => self.reference(buf, item, q),
2034 Pending::Ticks { at, len } => {
2035 if c == '`' {
2036 self.inline.pending = Pending::Ticks { at, len: len + 1 };
2037 } else {
2038 self.inline.pending = Pending::Code(Code {
2039 at,
2040 run: len,
2041 buf: vec![],
2042 closing: 0,
2043 bytes: len,
2044 });
2045 q.push_front(item);
2046 }
2047 }
2048 Pending::Code(code) => self.code_char(code, item, q),
2049 Pending::Link(link) => self.link_char(link, item, q),
2050 }
2051 }
2052
2053 fn plain(&mut self, item: Item, q: &mut VecDeque<Item>) {
2054 let (c, at) = (item.c, item.at);
2055 if c == '\n' {
2056 self.newline(at);
2057 return;
2058 }
2059 if std::mem::take(&mut self.inline.declaration) {
2060 self.drop_header();
2061 self.raw_mode = Some(Raw::Declaration(Declaration {
2062 scan: DeclarationScan::default(),
2063 cr: false,
2064 held: None,
2065 }));
2066 self.raw_step(item, q);
2067 return;
2068 }
2069 if self.inline.url {
2070 if c.is_whitespace() || c == '<' || c == '>' {
2071 self.inline.url = false;
2072 } else {
2073 self.emit_char(c, at, item.end());
2074 return;
2075 }
2076 }
2077 let block = std::mem::take(&mut self.inline.block_start);
2078 if self.inline.target == Some(Target::Cell)
2079 && !self.inline.opened
2080 && (c == ' ' || c == '\t')
2081 {
2082 return;
2083 }
2084 self.inline.leading = false;
2085 self.inline.pending = match c {
2086 '\\' => Pending::Escape(at),
2087 '`' => Pending::Ticks { at, len: 1 },
2088 '[' => Pending::Link(Link {
2089 image: false,
2090 buf: vec![item],
2091 bytes: 1,
2092 stage: Stage::Label { depth: 1 },
2093 escaped: false,
2094 }),
2095 '!' => Pending::Bang(at),
2096 '*' | '_' | '~' => Pending::Delim { ch: c, at, len: 1 },
2097 '$' => Pending::Reference(vec![item]),
2098 '<' => Pending::Angle { at, block },
2099 '{' => {
2100 self.drop_header();
2102 self.literal_char(item);
2103 self.raw_mode = Some(Raw::Braces(Braces {
2104 depth: 1,
2105 escaped: false,
2106 cr: false,
2107 held: None,
2108 }));
2109 Pending::None
2110 }
2111 _ => {
2112 self.emit_char(c, at, item.end());
2113 Pending::None
2114 }
2115 };
2116 }
2117
2118 fn newline(&mut self, at: usize) {
2120 let hard = self.inline.spaces >= 2;
2121 if self.inline.opened {
2122 self.out.trim_run();
2123 let node = DisplayNode {
2124 span: Span::new(at, at + 1),
2125 kind: if hard {
2126 Display::HardBreak
2127 } else {
2128 Display::SoftBreak
2129 },
2130 children: vec![],
2131 };
2132 self.out.push(node);
2133 }
2134 self.inline.prev = '\n';
2135 self.inline.spaces = 0;
2136 self.inline.url = false;
2137 self.inline.recent.clear();
2138 }
2139
2140 fn cell_boundary(&mut self, item: Item) {
2141 if std::mem::take(&mut self.inline.leading) {
2142 return;
2143 }
2144 let opened = self.inline.opened;
2145 self.end_run();
2146 if !opened {
2147 self.out.open(Display::TableCell, item.at);
2148 self.out.close();
2149 }
2150 self.start_run(Target::Cell);
2151 self.inline.leading = false;
2152 }
2153
2154 fn resolve_delim(&mut self, ch: char, at: usize, len: usize, next: char) {
2157 let prev = self.inline.prev;
2158 let left = !next.is_whitespace()
2159 && (!is_punctuation(next) || prev.is_whitespace() || is_punctuation(prev));
2160 let right = !prev.is_whitespace()
2161 && (!is_punctuation(prev) || next.is_whitespace() || is_punctuation(next));
2162 let (open, close) = if ch == '_' {
2163 (
2164 left && (!right || is_punctuation(prev)),
2165 right && (!left || is_punctuation(next)),
2166 )
2167 } else {
2168 (left, right)
2169 };
2170 if ch == '~' && len != 2 {
2171 for i in 0..len {
2172 self.emit_char('~', at + i, at + i + 1);
2173 }
2174 return;
2175 }
2176 let mut count = len;
2177 let mut pos = at;
2178 while close && count > 0 {
2179 let found = self.inline.delims.iter().rposition(|d| {
2180 d.ch == ch
2181 && (ch != '~' || d.count == count)
2182 && !((d.close || open)
2183 && (d.orig + len).is_multiple_of(3)
2184 && !(d.orig.is_multiple_of(3) && len.is_multiple_of(3)))
2185 });
2186 let Some(j) = found else { break };
2187 let used = if ch == '~' || (self.inline.delims[j].count >= 2 && count >= 2) {
2188 2
2189 } else {
2190 1
2191 };
2192 let kind = match (ch, used) {
2193 ('~', _) => Display::Strikethrough,
2194 (_, 2) => Display::Strong,
2195 _ => Display::Emphasis,
2196 };
2197 self.wrap(j, used, pos, kind);
2198 count -= used;
2199 pos += used;
2200 }
2201 if count > 0 {
2202 self.ensure_frame(pos);
2203 self.out.push(DisplayNode {
2204 span: Span::new(pos, at + len),
2205 kind: Display::Text(std::iter::repeat_n(ch, count).collect()),
2206 children: vec![],
2207 });
2208 if open && self.inline.delims.len() < EMPHASIS_DEPTH {
2209 let index = self.out.top().children.len() - 1;
2210 self.inline.delims.push(Delim {
2211 ch,
2212 count,
2213 orig: len,
2214 close,
2215 index,
2216 start: pos,
2217 end: at + len,
2218 });
2219 }
2220 }
2221 self.inline.prev = ch;
2222 self.inline.spaces = 0;
2223 self.inline.recent.clear();
2224 }
2225
2226 fn wrap(&mut self, j: usize, used: usize, pos: usize, kind: Display) {
2229 self.out.flush_run();
2230 let opener = &mut self.inline.delims[j];
2231 opener.count -= used;
2232 opener.end -= used;
2233 let (index, count, start, end, ch) = (
2234 opener.index,
2235 opener.count,
2236 opener.start,
2237 opener.end,
2238 opener.ch,
2239 );
2240 let span = Span::new(end, pos + used);
2241 let top = self.out.top();
2242 let inner = top.children.split_off(index + 1);
2243 if count == 0 {
2244 top.children.pop();
2245 } else {
2246 top.children[index] = Arc::new(DisplayNode {
2247 span: Span::new(start, end),
2248 kind: Display::Text(std::iter::repeat_n(ch, count).collect()),
2249 children: vec![],
2250 });
2251 }
2252 top.children.push(Arc::new(DisplayNode {
2253 span,
2254 kind,
2255 children: inner,
2256 }));
2257 top.span.end = top.span.end.max(span.end);
2258 self.inline.delims.truncate(j + 1);
2259 if count == 0 {
2260 self.inline.delims.pop();
2261 }
2262 self.out.dirty = true;
2263 }
2264
2265 fn reference(&mut self, mut buf: Vec<Item>, item: Item, q: &mut VecDeque<Item>) {
2268 let c = item.c;
2269 let i = buf.len();
2270 let fits = match i {
2271 1 => c == '$',
2272 2 => c == 't',
2273 3 => c == 'c',
2274 4 => c == '(',
2275 _ => (c.is_ascii_digit() && !(i > 5 && buf[5].c == '0')) || (c == ')' && i > 5),
2276 };
2277 if !fits {
2278 self.emit_char('$', buf[0].at, buf[0].end());
2280 q.push_front(item);
2281 self.rerun(q, &buf[1..]);
2282 return;
2283 }
2284 if c == ')' {
2285 let node = DisplayNode {
2286 span: Span::new(buf[0].at, item.end()),
2287 kind: Display::PendingReference,
2288 children: vec![],
2289 };
2290 self.emit_node(node, ')');
2291 return;
2292 }
2293 if buf.len() == PENDING_REFERENCE_CHARS {
2294 self.cap_flush(&buf, "", buf[0].at);
2295 q.push_front(item);
2296 return;
2297 }
2298 buf.push(item);
2299 self.inline.pending = Pending::Reference(buf);
2300 }
2301
2302 fn code_char(&mut self, mut code: Code, item: Item, q: &mut VecDeque<Item>) {
2303 if item.c == '`' {
2304 code.closing += 1;
2305 } else if code.closing == code.run {
2306 self.resolve_code(code);
2307 q.push_front(item);
2308 return;
2309 } else {
2310 code.closing = 0;
2311 }
2312 code.buf.push(item);
2313 code.bytes += item.c.len_utf8();
2314 if code.bytes > STREAM_CONTEXT_BYTES {
2315 let ticks = "`".repeat(code.run);
2316 self.cap_flush(&code.buf, &ticks, code.at);
2317 return;
2318 }
2319 self.inline.pending = Pending::Code(code);
2320 }
2321
2322 fn resolve_code(&mut self, code: Code) {
2324 self.work.reexamined += code.bytes;
2325 let content = &code.buf[..code.buf.len() - code.run];
2326 let mut text: String = content
2327 .iter()
2328 .map(|item| if eol(item.c) { ' ' } else { item.c })
2329 .collect();
2330 if text.len() >= 2
2331 && text.starts_with(' ')
2332 && text.ends_with(' ')
2333 && text.chars().any(|c| c != ' ')
2334 {
2335 text = text[1..text.len() - 1].to_owned();
2336 }
2337 let end = code
2338 .buf
2339 .last()
2340 .map_or(code.at + code.run, |item| item.end());
2341 let node = DisplayNode {
2342 span: Span::new(code.at, end),
2343 kind: Display::Code(sanitize_str(&text)),
2344 children: vec![],
2345 };
2346 self.emit_node(node, '`');
2347 }
2348
2349 fn link_char(&mut self, mut link: Link, item: Item, q: &mut VecDeque<Item>) {
2350 let c = item.c;
2351 link.buf.push(item);
2352 link.bytes += c.len_utf8();
2353 if link.bytes > STREAM_CONTEXT_BYTES {
2354 self.cap_flush(&link.buf, "", link.buf[0].at);
2355 return;
2356 }
2357 if std::mem::take(&mut link.escaped) {
2358 self.inline.pending = Pending::Link(link);
2359 return;
2360 }
2361 match &mut link.stage {
2362 Stage::Label { depth } => match c {
2363 '\\' => link.escaped = true,
2364 '[' => {
2365 *depth += 1;
2366 if *depth > LABEL_DEPTH {
2367 self.cap_flush(&link.buf, "", link.buf[0].at);
2368 return;
2369 }
2370 }
2371 ']' => {
2372 *depth -= 1;
2373 if *depth == 0 {
2374 link.stage = Stage::Paren;
2375 }
2376 }
2377 _ => {}
2378 },
2379 Stage::Paren => {
2380 if c != '(' {
2381 self.link_failed(link, q);
2382 return;
2383 }
2384 link.stage = Stage::Destination {
2385 nesting: 1,
2386 quote: None,
2387 };
2388 }
2389 Stage::Destination { nesting, quote } => match (*quote, c) {
2390 (_, '\\') => link.escaped = true,
2391 (Some(open), c) if c == open => *quote = None,
2392 (Some(_), _) => {}
2393 (None, '"' | '\'') => *quote = Some(c),
2394 (None, '(') => *nesting += 1,
2395 (None, ')') => {
2396 *nesting -= 1;
2397 if *nesting == 0 {
2398 self.link_complete(link, q);
2399 return;
2400 }
2401 }
2402 _ => {}
2403 },
2404 }
2405 self.inline.pending = Pending::Link(link);
2406 }
2407
2408 fn link_failed(&mut self, link: Link, q: &mut VecDeque<Item>) {
2411 let opener = if link.image { 2 } else { 1 };
2412 self.emit_items(&link.buf[..opener]);
2413 self.rerun(q, &link.buf[opener..]);
2414 }
2415
2416 fn link_complete(&mut self, link: Link, q: &mut VecDeque<Item>) {
2418 let text: String = link.buf.iter().map(|item| item.c).collect();
2419 self.work.reexamined += text.len();
2420 let doc = parse(&text, Mode::Reply);
2421 let found = match doc.nodes.as_slice() {
2422 [Node {
2423 kind: Kind::Markdown(Markdown::Paragraph),
2424 children,
2425 ..
2426 }] => match children.as_slice() {
2427 [node @ Node {
2428 kind: Kind::Markdown(Markdown::Link { .. }),
2429 ..
2430 }] if node.span == Span::new(0, text.len()) => Some(node.clone()),
2431 _ => None,
2432 },
2433 _ => None,
2434 };
2435 let Some(node) = found else {
2436 self.link_failed(link, q);
2437 return;
2438 };
2439 let mut offsets = Vec::with_capacity(text.len() + 1);
2441 for item in &link.buf {
2442 offsets.extend((0..item.c.len_utf8()).map(|i| item.at + i));
2443 }
2444 offsets.push(link.buf.last().map_or(0, |item| item.end()));
2445 let display = convert(&node, &text, &|o| offsets[o.min(offsets.len() - 1)]);
2446 self.emit_node(display, ')');
2447 }
2448}
2449
2450struct DeclarationScan {
2454 depth: i32,
2455 tags: i32,
2456 header: bool,
2457 closing: bool,
2458 header_braces: i32,
2459 quote: Option<char>,
2460 escaped: bool,
2461 operand: bool,
2462 previous: char,
2463 angle: bool,
2465}
2466
2467impl Default for DeclarationScan {
2468 fn default() -> Self {
2469 Self {
2470 depth: 0,
2471 tags: 0,
2472 header: false,
2473 closing: false,
2474 header_braces: 0,
2475 quote: None,
2476 escaped: false,
2477 operand: true,
2478 previous: '\0',
2479 angle: false,
2480 }
2481 }
2482}
2483
2484impl DeclarationScan {
2485 fn feed(&mut self, c: char) {
2486 if std::mem::take(&mut self.angle) {
2487 if c.is_ascii_uppercase() || c == '/' {
2488 self.closing = c == '/';
2489 self.tags += if self.closing { -1 } else { 1 };
2490 self.header = true;
2491 self.header_braces = 0;
2492 } else if self.tags == 0 {
2493 self.operand = true;
2494 }
2495 self.previous = '<';
2496 }
2497 if self.escaped {
2498 self.escaped = false;
2499 return;
2500 }
2501 if c == '\\' {
2502 self.escaped = true;
2503 return;
2504 }
2505 if let Some(quote) = self.quote {
2506 if c == quote {
2507 self.quote = None;
2508 self.operand = false;
2509 }
2510 return;
2511 }
2512 if (self.header || self.tags == 0) && (c == '\'' || c == '"') {
2513 self.quote = Some(c);
2514 return;
2515 }
2516 if c == '<' && !self.header && (self.tags > 0 || self.operand) {
2517 self.angle = true;
2518 return;
2519 }
2520 if self.header {
2521 match c {
2522 '{' => self.header_braces += 1,
2523 '}' => self.header_braces -= 1,
2524 '>' if self.header_braces == 0 => {
2525 if !self.closing && self.previous == '/' {
2526 self.tags -= 1;
2527 }
2528 self.header = false;
2529 self.operand = false;
2530 }
2531 _ => {}
2532 }
2533 } else if self.tags == 0 {
2534 match c {
2535 '(' | '[' | '{' => {
2536 self.depth += 1;
2537 self.operand = true;
2538 }
2539 ')' | ']' | '}' => {
2540 self.depth -= 1;
2541 self.operand = false;
2542 }
2543 '+' | '-' | '*' | '/' | '%' | '?' | ':' | ',' | '=' | '!' | '<' | '>' | '&'
2544 | '|' => self.operand = true,
2545 c if !c.is_whitespace() => self.operand = false,
2546 _ => {}
2547 }
2548 }
2549 if !c.is_whitespace() {
2550 self.previous = c;
2551 }
2552 }
2553 fn continues(&self) -> bool {
2554 self.depth > 0 || self.tags > 0 || self.header || self.operand || self.angle
2555 }
2556}
2557
2558#[derive(Default)]
2561struct TagScan {
2562 quote: Option<char>,
2563 braces: usize,
2564 escaped: bool,
2565 prev: char,
2566}
2567
2568impl TagScan {
2569 fn feed(&mut self, c: char) -> Option<bool> {
2571 let prev = std::mem::replace(&mut self.prev, c);
2572 if self.escaped {
2573 self.escaped = false;
2574 } else if c == '\\' {
2575 self.escaped = true;
2576 } else if let Some(quote) = self.quote {
2577 if c == quote {
2578 self.quote = None;
2579 }
2580 } else if c == '\'' || c == '"' {
2581 self.quote = Some(c);
2582 } else if c == '{' {
2583 self.braces += 1;
2584 } else if c == '}' {
2585 self.braces = self.braces.saturating_sub(1);
2586 } else if c == '>' && self.braces == 0 {
2587 return Some(prev == '/');
2588 }
2589 None
2590 }
2591}
2592
2593#[derive(Clone, Copy, PartialEq, Eq)]
2594enum CapturePhase {
2595 Opening,
2597 Suffix {
2600 self_closing: bool,
2601 },
2602 Body,
2603 CloseLine,
2606}
2607
2608enum Inner {
2610 Plain,
2611 Angle,
2612 Open(TagScan),
2613 Close { named: bool, spaced: bool },
2614}
2615
2616struct Capture {
2620 base: usize,
2621 text: String,
2622 inline_bytes: usize,
2624 block_candidate: bool,
2625 phase: CapturePhase,
2626 opener: TagScan,
2627 opener_end: usize,
2628 block: bool,
2629 depth: usize,
2630 braces: usize,
2631 escaped: bool,
2632 inner: Inner,
2633 line_start: usize,
2634 line_blank: bool,
2635 first_line: bool,
2636 cr: bool,
2637}
2638
2639impl Capture {
2640 fn new(base: usize, block_candidate: bool) -> Self {
2641 Self {
2642 base,
2643 text: "<".to_owned(),
2644 inline_bytes: 1,
2645 block_candidate,
2646 phase: CapturePhase::Opening,
2647 opener: TagScan {
2648 prev: '<',
2649 ..TagScan::default()
2650 },
2651 opener_end: 0,
2652 block: false,
2653 depth: 0,
2654 braces: 0,
2655 escaped: false,
2656 inner: Inner::Plain,
2657 line_start: 0,
2658 line_blank: false,
2659 first_line: true,
2660 cr: false,
2661 }
2662 }
2663
2664 fn body(&mut self, c: char) -> bool {
2666 if std::mem::take(&mut self.escaped) {
2667 return false;
2668 }
2669 match &mut self.inner {
2670 Inner::Plain => match c {
2671 '\\' => self.escaped = true,
2672 '<' if self.braces == 0 => self.inner = Inner::Angle,
2673 '{' => self.braces += 1,
2674 '}' => self.braces = self.braces.saturating_sub(1),
2675 _ => {}
2676 },
2677 Inner::Angle => {
2678 if c.is_ascii_uppercase() {
2679 self.inner = Inner::Open(TagScan::default());
2680 } else if c == '/' {
2681 self.inner = Inner::Close {
2682 named: false,
2683 spaced: false,
2684 };
2685 } else {
2686 self.inner = Inner::Plain;
2687 return self.body(c);
2688 }
2689 }
2690 Inner::Open(scan) => {
2691 if let Some(self_closing) = scan.feed(c) {
2692 self.depth += usize::from(!self_closing);
2693 self.inner = Inner::Plain;
2694 }
2695 }
2696 Inner::Close { named, spaced } => {
2697 if c.is_ascii_alphanumeric() && !*spaced && (*named || c.is_ascii_uppercase()) {
2698 *named = true;
2699 } else if c.is_whitespace() && *named {
2700 *spaced = true;
2701 } else if c == '>' && *named {
2702 self.inner = Inner::Plain;
2703 if self.depth == 0 {
2704 return true;
2705 }
2706 self.depth -= 1;
2707 } else {
2708 self.inner = Inner::Plain;
2709 }
2710 }
2711 }
2712 false
2713 }
2714}
2715
2716impl Machine {
2717 fn raw_step(&mut self, item: Item, q: &mut VecDeque<Item>) {
2718 match self.raw_mode.take() {
2719 Some(Raw::Braces(braces)) => self.braces_step(braces, item, q),
2720 Some(Raw::Declaration(declaration)) => self.declaration_step(declaration, item, q),
2721 Some(Raw::Capture(capture)) => self.capture_step(capture, item, q),
2722 None => {}
2723 }
2724 }
2725
2726 fn resume_line_start(&mut self) {
2729 self.line = Line::start();
2730 self.eol = None;
2731 }
2732
2733 fn braces_step(&mut self, mut b: Braces, item: Item, q: &mut VecDeque<Item>) {
2734 let c = item.c;
2735 if let Some(held) = &mut b.held {
2736 if c == '\n' && b.cr {
2737 b.cr = false;
2738 self.literal_char(item);
2739 self.raw_mode = Some(Raw::Braces(b));
2740 return;
2741 }
2742 if c == ' ' || c == '\t' {
2743 held.push(item);
2744 self.raw_mode = Some(Raw::Braces(b));
2745 return;
2746 }
2747 let mut held = std::mem::take(held);
2748 b.held = None;
2749 if eol(c) {
2750 held.push(item);
2752 self.resume_line_start();
2753 self.rerun(q, &held);
2754 return;
2755 }
2756 for item in held {
2757 self.literal_char(item);
2758 }
2759 }
2760 self.literal_char(item);
2761 b.cr = c == '\r';
2762 if eol(c) {
2763 b.escaped = false;
2764 b.held = Some(vec![]);
2765 } else if b.escaped {
2766 b.escaped = false;
2767 } else if c == '\\' {
2768 b.escaped = true;
2769 } else if c == '{' {
2770 b.depth += 1;
2771 } else if c == '}' {
2772 b.depth -= 1;
2773 if b.depth == 0 {
2774 return;
2775 }
2776 }
2777 self.raw_mode = Some(Raw::Braces(b));
2778 }
2779
2780 fn declaration_step(&mut self, mut d: Declaration, item: Item, q: &mut VecDeque<Item>) {
2781 let c = item.c;
2782 if let Some((held, prefix)) = &mut d.held {
2783 if c == '\n' && d.cr && held.len() == 1 {
2784 d.cr = false;
2785 held.push(item);
2786 self.raw_mode = Some(Raw::Declaration(d));
2787 return;
2788 }
2789 if prefix.is_empty() && (c == ' ' || c == '\t') {
2790 held.push(item);
2791 self.raw_mode = Some(Raw::Declaration(d));
2792 return;
2793 }
2794 let continues = if prefix.is_empty() && eol(c) {
2795 false
2796 } else if prefix.is_empty() && d.scan.continues() {
2797 true
2798 } else {
2799 prefix.push(c);
2800 match prefix.as_str() {
2801 "&" | "|" => {
2802 held.push(item);
2803 self.raw_mode = Some(Raw::Declaration(d));
2804 return;
2805 }
2806 "&&" | "||" => true,
2807 p => p.starts_with(['?', ':', '.']),
2808 }
2809 };
2810 let mut held = std::mem::take(held);
2811 d.held = None;
2812 if !continues {
2813 held.push(item);
2816 self.rerun(q, &held);
2817 return;
2818 }
2819 for item in held {
2820 self.literal_char(item);
2821 d.scan.feed(item.c);
2822 }
2823 }
2824 if eol(c) {
2825 d.held = Some((vec![item], String::new()));
2826 d.cr = c == '\r';
2827 } else {
2828 self.literal_char(item);
2829 d.scan.feed(c);
2830 }
2831 self.raw_mode = Some(Raw::Declaration(d));
2832 }
2833
2834 fn capture_step(&mut self, mut cap: Box<Capture>, item: Item, q: &mut VecDeque<Item>) {
2835 let c = item.c;
2836 let crlf = c == '\n' && cap.cr;
2837 let line_end = eol(c) && !crlf;
2838 let blank = |c: char| c == ' ' || c == '\t';
2839 match cap.phase {
2840 CapturePhase::Suffix { self_closing } if line_end => {
2841 if self_closing {
2842 let (end, block) = (cap.text.len(), cap.block_candidate);
2843 return self.complete_capture(&cap, end, block, item, q);
2844 }
2845 cap.block = cap.block_candidate;
2846 cap.phase = CapturePhase::Body;
2847 }
2848 CapturePhase::Suffix { self_closing } if !blank(c) => {
2849 if self_closing {
2850 let end = cap.opener_end;
2851 return self.complete_capture(&cap, end, false, item, q);
2852 }
2853 cap.block = false;
2854 cap.phase = CapturePhase::Body;
2855 }
2856 CapturePhase::CloseLine if line_end => {
2857 let (end, block) = (cap.text.len(), cap.block_candidate);
2858 return self.complete_capture(&cap, end, block, item, q);
2859 }
2860 _ => {}
2861 }
2862 if line_end && !cap.first_line && cap.line_blank {
2863 let ends = match cap.phase {
2866 CapturePhase::Opening => true,
2867 CapturePhase::Body => !cap.block,
2868 _ => false,
2869 };
2870 if ends {
2871 let (end, block) = (cap.line_start, cap.block_candidate);
2872 return self.complete_capture(&cap, end, block, item, q);
2873 }
2874 cap.braces = 0;
2875 cap.inner = Inner::Plain;
2876 }
2877 cap.text.push(c);
2878 if !item.fresh {
2879 cap.inline_bytes = cap.text.len();
2880 }
2881 if line_end || crlf {
2882 cap.line_start = cap.text.len();
2883 cap.line_blank = true;
2884 cap.first_line = false;
2885 } else if !blank(c) {
2886 cap.line_blank = false;
2887 }
2888 cap.cr = c == '\r';
2889 match cap.phase {
2890 CapturePhase::Opening => {
2891 if let Some(self_closing) = cap.opener.feed(c) {
2892 cap.opener_end = cap.text.len();
2893 if cap.block_candidate {
2896 cap.phase = CapturePhase::Suffix { self_closing };
2897 } else if self_closing {
2898 let end = cap.text.len();
2899 return self.complete_capture_now(&cap, end, false, q);
2900 } else {
2901 cap.phase = CapturePhase::Body;
2902 }
2903 } else if cap.text.len() > TAG_OPENING_BYTES {
2904 return self.capture_cap(&cap);
2905 }
2906 }
2907 CapturePhase::Body => {
2908 if cap.body(c) {
2909 if cap.block {
2910 cap.phase = CapturePhase::CloseLine;
2911 } else {
2912 let (end, block) = (cap.text.len(), cap.block_candidate);
2913 return self.complete_capture_now(&cap, end, block, q);
2914 }
2915 }
2916 }
2917 CapturePhase::Suffix { .. } | CapturePhase::CloseLine => {}
2918 }
2919 if cap.text.len() > STREAM_CONTEXT_BYTES {
2920 return self.capture_cap(&cap);
2921 }
2922 self.raw_mode = Some(Raw::Capture(cap));
2923 }
2924
2925 fn capture_cap(&mut self, cap: &Capture) {
2927 self.work.reexamined += cap.text.len();
2928 let node = DisplayNode {
2929 span: Span::new(cap.base, cap.base + cap.text.len()),
2930 kind: Display::Literal(sanitize_str(&cap.text)),
2931 children: vec![],
2932 };
2933 let prev = cap.text.chars().last().unwrap_or('<');
2934 self.emit_node(node, prev);
2935 if eol(prev) {
2936 self.resume_line_start();
2937 }
2938 }
2939
2940 fn complete_capture(
2941 &mut self,
2942 cap: &Capture,
2943 end: usize,
2944 block_candidate: bool,
2945 next: Item,
2946 q: &mut VecDeque<Item>,
2947 ) {
2948 q.push_front(next);
2949 self.complete_capture_now(cap, end, block_candidate, q);
2950 }
2951
2952 fn complete_capture_now(
2955 &mut self,
2956 cap: &Capture,
2957 end: usize,
2958 block_candidate: bool,
2959 q: &mut VecDeque<Item>,
2960 ) {
2961 let text = &cap.text[..end];
2962 self.work.reexamined += end;
2963 let mut engine = Engine::new(text, end, Mode::Reply);
2964 let (node, stop) = match engine.tag(0, end, 1, block_candidate) {
2965 Ok((node, stop, _)) if stop > 0 && stop <= end => (node, stop),
2966 _ => (
2967 Node {
2968 span: Span::new(0, end),
2969 kind: Kind::Literal(text.to_owned()),
2970 children: vec![],
2971 },
2972 end,
2973 ),
2974 };
2975 let display = convert(&node, text, &|o| cap.base + o);
2976 let prev = text[..stop].chars().last().unwrap_or('>');
2977 if matches!(node.kind, Kind::Tag { block: true, .. }) {
2978 if matches!(self.leaf, Leaf::Paragraph { .. }) {
2980 self.close_leaf();
2981 }
2982 self.out.push(display);
2983 } else {
2984 self.emit_node(display, prev);
2985 }
2986 if eol(prev) {
2987 self.resume_line_start();
2988 }
2989 let rest: Vec<Item> = cap.text[stop..]
2990 .char_indices()
2991 .map(|(i, c)| Item {
2992 at: cap.base + stop + i,
2993 c,
2994 fresh: stop + i >= cap.inline_bytes,
2995 })
2996 .collect();
2997 self.rerun(q, &rest);
2998 }
2999
3000 fn finish_raw(&mut self) {
3002 match self.raw_mode.take() {
3003 Some(Raw::Capture(cap)) => self.capture_cap(&cap),
3004 Some(Raw::Declaration(Declaration {
3005 held: Some((held, _)),
3006 ..
3007 })) => {
3008 for item in held {
3009 self.literal_char(item);
3010 }
3011 }
3012 _ => {}
3013 }
3014 }
3015}