1use {
2 loga::{
3 ea,
4 Error,
5 },
6 proc_macro2::{
7 Ident,
8 LineColumn,
9 },
10 quote::ToTokens,
11 serde::{
12 Serialize,
13 Deserialize,
14 },
15 sg_general::append_whitespace,
16 std::{
17 collections::BTreeMap,
18 cell::{
19 Cell,
20 RefCell,
21 },
22 rc::Rc,
23 },
24 syn::File,
25};
26pub use whitespace::{
27 format_md,
28 HashLineColumn,
29};
30
31pub(crate) mod whitespace;
32pub(crate) mod sg_expr;
33pub(crate) mod sg_general;
34pub(crate) mod sg_pat;
35pub(crate) mod sg_statement;
36pub(crate) mod sg_type;
37pub(crate) mod sg_root;
38pub(crate) mod sg_general_lists;
39
40#[derive(PartialEq, Clone, Copy, Debug)]
41pub enum CommentMode {
42 Normal,
43 ExplicitNormal,
44 DocInner,
45 DocOuter,
46 Verbatim,
47}
48
49#[derive(Debug)]
50pub struct Comment {
51 pub mode: CommentMode,
52 pub lines: String,
53 pub orig_start_offset: usize,
56}
57
58#[derive(Debug)]
59pub enum WhitespaceMode {
60 BlankLines(usize),
61 Comment(Comment),
62}
63
64#[derive(Debug)]
65pub struct Whitespace {
66 pub loc: LineColumn,
69 pub mode: WhitespaceMode,
70}
71
72#[derive(Clone, Copy)]
73pub struct SplitGroupIdx(usize);
74
75#[derive(Clone, Copy)]
76pub struct SegmentIdx(usize);
77
78#[derive(Clone, Copy)]
79pub(crate) struct LineIdx(usize);
80
81pub struct SplitGroup {
82 pub(crate) children: Vec<SplitGroupIdx>,
83 pub(crate) split: bool,
84 pub(crate) segments: Vec<SegmentIdx>,
85}
86
87#[derive(Debug, Clone, Copy)]
88pub(crate) enum SegmentMode {
89 All,
90 Unsplit,
91 Split,
92}
93
94pub(crate) struct SegmentLine {
95 pub(crate) line: LineIdx,
96 pub(crate) seg_index: usize,
97}
98
99#[derive(Debug)]
100pub(crate) enum SegmentContent {
101 Text(String),
102 Whitespace((Alignment, Vec<Whitespace>)),
103 Break(Alignment, bool),
104}
105
106pub(crate) struct Segment {
107 pub(crate) node: SplitGroupIdx,
108 pub(crate) line: Option<SegmentLine>,
109 pub(crate) mode: SegmentMode,
110 pub(crate) content: SegmentContent,
111}
112
113pub(crate) struct Line {
114 index: usize,
115 segs: Vec<SegmentIdx>,
116}
117
118struct Lines {
119 owned_lines: Vec<Line>,
120 lines: Vec<LineIdx>,
121}
122
123pub struct MakeSegsState {
124 nodes: Vec<SplitGroup>,
125 segs: Vec<Segment>,
126 whitespaces: BTreeMap<HashLineColumn, Vec<Whitespace>>,
127 config: FormatConfig,
128 macro_depth: Rc<Cell<usize>>,
133}
134
135pub struct IncMacroDepth(Rc<Cell<usize>>);
136
137impl IncMacroDepth {
138 fn new(s: &MakeSegsState) -> Self {
139 s.macro_depth.update(|x| x + 1);
140 return Self(s.macro_depth.clone());
141 }
142}
143
144impl Drop for IncMacroDepth {
145 fn drop(&mut self) {
146 self.0.update(|x| x - 1);
147 }
148}
149
150pub(crate) fn check_split_brace_threshold(out: &MakeSegsState, count: usize) -> bool {
151 out.config.split_brace_threshold.map(|t| count >= t).unwrap_or(false)
152}
153
154pub(crate) fn line_length(out: &MakeSegsState, lines: &Lines, line_i: LineIdx) -> usize {
155 let mut len = 0;
156 for seg_i in &lines.owned_lines.get(line_i.0).unwrap().segs {
157 let seg = out.segs.get(seg_i.0).unwrap();
158 match &seg.content {
159 SegmentContent::Text(t) => len += t.chars().count(),
160 SegmentContent::Break(b, _) => {
161 if out.nodes.get(seg.node.0).unwrap().split {
162 len += out.config.indent_spaces * b.get().0;
163 }
164 },
165 SegmentContent::Whitespace(_) => { },
166 };
167 }
168 len
169}
170
171pub(crate) fn split_group(out: &mut MakeSegsState, lines: &mut Lines, sg_i: SplitGroupIdx) {
172 let sg = out.nodes.get_mut(sg_i.0).unwrap();
173 sg.split = true;
174 for seg_i in &sg.segments.clone() {
175 let res = {
176 let seg = out.segs.get(seg_i.0).unwrap();
177 match (&seg.mode, &seg.content) {
178 (SegmentMode::Split, SegmentContent::Break(_, _)) => {
179 let seg_line = seg.line.as_ref().unwrap();
180 Some((seg_line.line, seg_line.seg_index))
181 },
182 _ => None,
183 }
184 };
185 if let Some((line_i, off)) = res {
186 split_line_at(out, lines, line_i, off, None);
187 };
188 }
189}
190
191pub(crate) fn split_line_at(
192 out: &mut MakeSegsState,
193 lines: &mut Lines,
194 line_idx: LineIdx,
195 off: usize,
196 inject_start: Option<SegmentIdx>,
197) {
198 let line = lines.owned_lines.get_mut(line_idx.0).unwrap();
199 let mut new_segs = vec![];
200 if let Some(s) = inject_start {
201 new_segs.push(s);
202 }
203 new_segs.extend(line.segs.split_off(off));
204 {
205 let seg_i = new_segs.get(0).unwrap();
206 let seg = out.segs.get(seg_i.0).unwrap();
207 match &seg.content {
208 SegmentContent::Break(a, activate) => {
209 if *activate {
210 a.activate();
211 }
212 },
213 SegmentContent::Whitespace((a, _)) => {
214 a.activate();
215 },
216 _ => { },
217 };
218 }
219 let insert_at = line.index + 1;
220 insert_line(out, lines, insert_at, new_segs);
221}
222
223pub(crate) fn insert_line(out: &mut MakeSegsState, lines: &mut Lines, at: usize, segs: Vec<SegmentIdx>) {
224 let line_i = LineIdx(lines.owned_lines.len());
225 lines.owned_lines.push(Line {
226 index: at,
227 segs,
228 });
229 for (i, seg_i) in lines.owned_lines.get(line_i.0).unwrap().segs.iter().enumerate() {
230 let seg = out.segs.get_mut(seg_i.0).unwrap();
231 match seg.line.as_mut() {
232 Some(l) => {
233 l.line = line_i;
234 l.seg_index = i;
235 },
236 None => {
237 seg.line = Some(SegmentLine {
238 line: line_i,
239 seg_index: i,
240 });
241 },
242 };
243 }
244 lines.lines.insert(at, line_i);
245 for (i, line_i) in lines.lines.iter().enumerate().skip(at + 1) {
246 lines.owned_lines.get_mut(line_i.0).unwrap().index = i;
247 }
248 for (i, line_i) in lines.lines.iter().enumerate() {
249 let line = lines.owned_lines.get(line_i.0).unwrap();
250 assert_eq!(line.index, i, "line index wrong; after insert at line {}", at);
251 for (j, seg_i) in line.segs.iter().enumerate() {
252 assert_eq!(
253 out.segs.get(seg_i.0).unwrap().line.as_ref().unwrap().seg_index,
254 j,
255 "seg index wrong; on line {}, after insert at line {}",
256 i,
257 at
258 );
259 }
260 }
261}
262
263pub(crate) struct Alignment_ {
264 pub(crate) parent: Option<Alignment>,
265 pub(crate) active: bool,
266}
267
268struct IndentLevel(usize);
269
270#[derive(Clone)]
271pub struct Alignment(Rc<RefCell<Alignment_>>);
272
273impl std::fmt::Debug for Alignment {
274 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
275 "(align)".fmt(f)
276 }
277}
278
279impl Alignment {
280 pub(crate) fn indent(&self) -> Alignment {
281 Alignment(Rc::new(RefCell::new(Alignment_ {
282 parent: Some(self.clone()),
283 active: false,
284 })))
285 }
286
287 pub(crate) fn activate(&self) {
288 self.0.borrow_mut().active = true;
289 }
290
291 pub(crate) fn get(&self) -> IndentLevel {
292 let parent = match &self.0.as_ref().borrow().parent {
293 Some(p) => p.get(),
294 None => {
295 return IndentLevel(0usize);
296 },
297 };
298 if self.0.as_ref().borrow_mut().active {
299 IndentLevel(parent.0 + 1)
300 } else {
301 parent
302 }
303 }
304}
305
306pub(crate) struct SplitGroupBuilder {
307 node: SplitGroupIdx,
308 initial_split: bool,
309 reverse_children: bool,
310 segs: Vec<SegmentIdx>,
311 children: Vec<SplitGroupIdx>,
312}
313
314impl SplitGroupBuilder {
315 pub(crate) fn add(&mut self, out: &mut MakeSegsState, seg: Segment) {
316 let idx = SegmentIdx(out.segs.len());
317 out.segs.push(seg);
318 self.segs.push(idx);
319 }
320
321 pub(crate) fn initial_split(&mut self) {
322 self.initial_split = true;
323 }
324
325 pub(crate) fn reverse_children(&mut self) {
326 self.reverse_children = true;
327 }
328
329 pub(crate) fn child(&mut self, child: SplitGroupIdx) {
330 self.children.push(child);
331 }
332
333 pub(crate) fn build(self, out: &mut MakeSegsState) -> SplitGroupIdx {
334 let sg = out.nodes.get_mut(self.node.0).unwrap();
335 sg.split = self.initial_split;
336 sg.children = self.children;
337 if self.reverse_children {
338 sg.children.reverse();
339 }
340 sg.segments = self.segs;
341 for seg in &sg.segments {
342 out.segs.get_mut(seg.0).unwrap().node = self.node;
343 }
344 self.node
345 }
346
347 pub(crate) fn seg(&mut self, out: &mut MakeSegsState, text: impl ToString) {
348 self.add(out, Segment {
349 node: self.node,
350 line: None,
351 mode: SegmentMode::All,
352 content: SegmentContent::Text(text.to_string()),
353 });
354 }
355
356 pub(crate) fn seg_split(&mut self, out: &mut MakeSegsState, text: impl ToString) {
357 self.add(out, Segment {
358 node: self.node,
359 line: None,
360 mode: SegmentMode::Split,
361 content: SegmentContent::Text(text.to_string()),
362 });
363 }
364
365 pub(crate) fn seg_unsplit(&mut self, out: &mut MakeSegsState, text: impl ToString) {
366 self.add(out, Segment {
367 node: self.node,
368 line: None,
369 mode: SegmentMode::Unsplit,
370 content: SegmentContent::Text(text.to_string()),
371 });
372 }
373
374 pub(crate) fn split_if(&mut self, out: &mut MakeSegsState, alignment: Alignment, always: bool, activate: bool) {
375 self.add(out, Segment {
376 node: self.node,
377 line: None,
378 mode: if always {
379 SegmentMode::All
380 } else {
381 SegmentMode::Split
382 },
383 content: SegmentContent::Break(alignment, activate),
384 });
385 }
386
387 pub(crate) fn split(&mut self, out: &mut MakeSegsState, alignment: Alignment, activate: bool) {
388 self.add(out, Segment {
389 node: self.node,
390 line: None,
391 mode: SegmentMode::Split,
392 content: SegmentContent::Break(alignment, activate),
393 });
394 }
395
396 pub(crate) fn split_always(&mut self, out: &mut MakeSegsState, alignment: Alignment, activate: bool) {
397 self.add(out, Segment {
398 node: self.node,
399 line: None,
400 mode: SegmentMode::All,
401 content: SegmentContent::Break(alignment, activate),
402 });
403 }
404}
405
406pub(crate) fn new_sg(out: &mut MakeSegsState) -> SplitGroupBuilder {
407 let idx = SplitGroupIdx(out.nodes.len());
408 out.nodes.push(SplitGroup {
409 split: false,
410 segments: vec![],
411 children: vec![],
412 });
413 SplitGroupBuilder {
414 node: idx,
415 segs: vec![],
416 children: vec![],
417 initial_split: false,
418 reverse_children: false,
419 }
420}
421
422pub(crate) fn new_sg_lit(
423 out: &mut MakeSegsState,
424 start: Option<(&Alignment, LineColumn)>,
425 text: impl ToString,
426) -> SplitGroupIdx {
427 let mut sg = new_sg(out);
428 if let Some(loc) = start {
429 append_whitespace(out, loc.0, &mut sg, loc.1);
430 }
431 sg.seg(out, text.to_string());
432 sg.build(out)
433}
434
435#[derive(PartialEq, Debug)]
436pub(crate) enum MarginGroup {
437 Attr,
438 BlockDef,
439 Import,
440 None,
441}
442
443pub(crate) trait FormattablePunct {
444 fn span_start(&self) -> LineColumn;
445}
446
447pub(crate) trait FormattableStmt: ToTokens + Formattable {
448 fn want_margin(&self) -> (MarginGroup, bool);
449}
450
451pub trait Formattable {
452 fn make_segs(&self, out: &mut MakeSegsState, base_indent: &Alignment) -> SplitGroupIdx;
453 fn has_attrs(&self) -> bool;
454}
455
456impl<F: Fn(&mut MakeSegsState, &Alignment) -> SplitGroupIdx> Formattable for F {
457 fn make_segs(&self, line: &mut MakeSegsState, base_indent: &Alignment) -> SplitGroupIdx {
458 self(line, base_indent)
459 }
460
461 fn has_attrs(&self) -> bool {
462 false
463 }
464}
465
466impl Formattable for Ident {
467 fn make_segs(&self, out: &mut MakeSegsState, base_indent: &Alignment) -> SplitGroupIdx {
468 new_sg_lit(out, Some((base_indent, self.span().start())), self)
469 }
470
471 fn has_attrs(&self) -> bool {
472 false
473 }
474}
475
476impl Formattable for &Ident {
477 fn make_segs(&self, out: &mut MakeSegsState, base_indent: &Alignment) -> SplitGroupIdx {
478 (*self).make_segs(out, base_indent)
479 }
480
481 fn has_attrs(&self) -> bool {
482 false
483 }
484}
485
486#[derive(Debug, Copy, Clone, Deserialize, Serialize)]
487#[serde(rename_all = "snake_case")]
488pub enum IndentUnit {
489 Spaces,
490 Tabs,
491}
492
493fn render_indent(config: &FormatConfig, current_indent: IndentLevel) -> String {
494 match config.indent_unit {
495 IndentUnit::Spaces => return " ".repeat(config.indent_spaces * current_indent.0),
496 IndentUnit::Tabs => return "\t".repeat(current_indent.0),
497 }
498}
499
500#[derive(Debug, Copy, Clone, Deserialize, Serialize)]
501#[serde(default)]
502pub struct FormatConfig {
503 pub max_width: usize,
504 pub root_splits: bool,
505 pub split_brace_threshold: Option<usize>,
506 pub split_attributes: bool,
507 pub split_where: bool,
508 pub comment_width: Option<usize>,
509 pub comment_errors_fatal: bool,
510 pub keep_max_blank_lines: usize,
511 pub indent_spaces: usize,
512 pub indent_unit: IndentUnit,
514 pub explicit_markdown_comments: bool,
515}
516
517impl Default for FormatConfig {
518 fn default() -> Self {
519 Self {
520 max_width: 120,
521 root_splits: false,
522 split_brace_threshold: Some(1usize),
523 split_attributes: true,
524 split_where: true,
525 comment_width: Some(80usize),
526 comment_errors_fatal: false,
527 keep_max_blank_lines: 0,
528 indent_spaces: 4,
529 indent_unit: IndentUnit::Spaces,
530 explicit_markdown_comments: false,
531 }
532 }
533}
534
535pub struct FormatRes {
536 pub rendered: String,
537 pub lost_comments: BTreeMap<HashLineColumn, Vec<Whitespace>>,
538 pub warnings: Vec<Error>,
539}
540
541pub use whitespace::extract_whitespaces;
542
543pub fn format_str(source: &str, config: &FormatConfig) -> Result<FormatRes, loga::Error> {
544 let shebang;
545 let shebang_line_off;
546 let source1;
547 if source.starts_with("#!/") {
548 let shebang_end = match source.find("\n") {
549 Some(o) => o + 1,
550 None => source.len(),
551 };
552 shebang = Some(&source[..shebang_end]);
553 source1 = &source[shebang_end..];
554 shebang_line_off = 1;
555 } else {
556 shebang = None;
557 source1 = source;
558 shebang_line_off = 0;
559 }
560 let source = source1;
561 let (whitespaces, tokens) = extract_whitespaces(config.keep_max_blank_lines, source)?;
562 let out =
563 format_ast(
564 syn::parse2::<File>(
565 tokens,
566 ).map_err(
567 |e| loga::err_with(
568 "Syn error parsing Rust code",
569 ea!(line = e.span().start().line + shebang_line_off, column = e.span().start().column, err = e),
570 ),
571 )?,
572 config,
573 whitespaces,
574 )?;
575 if let Some(shebang) = shebang {
576 return Ok(FormatRes {
577 rendered: format!("{}{}", shebang, out.rendered),
578 lost_comments: out.lost_comments,
579 warnings: out.warnings,
580 });
581 } else {
582 return Ok(out);
583 }
584}
585
586pub fn format_ast(
587 ast: impl Formattable,
588 config: &FormatConfig,
589 whitespaces: BTreeMap<HashLineColumn, Vec<Whitespace>>,
590) -> Result<FormatRes, loga::Error> {
591 let mut out = MakeSegsState {
593 nodes: vec![],
594 segs: vec![],
595 whitespaces,
596 config: config.clone(),
597 macro_depth: Default::default(),
598 };
599 let base_indent = Alignment(Rc::new(RefCell::new(Alignment_ {
600 parent: None,
601 active: false,
602 })));
603 let root = ast.make_segs(&mut out, &base_indent);
604 if out.whitespaces.contains_key(&HashLineColumn(LineColumn {
605 line: 0,
606 column: 1,
607 })) {
608 let mut sg = new_sg(&mut out);
609 append_whitespace(&mut out, &base_indent, &mut sg, LineColumn {
610 line: 0,
611 column: 1,
612 });
613 sg.build(&mut out);
614 }
615 let mut lines = Lines {
616 lines: vec![],
617 owned_lines: vec![],
618 };
619 {
620 let line_i = LineIdx(lines.owned_lines.len());
621 lines.owned_lines.push(Line {
622 index: 0,
623 segs: out.segs.iter().enumerate().map(|(i, _)| SegmentIdx(i)).collect(),
624 });
625 lines.lines.push(line_i);
626 for line_i in &lines.lines {
627 for (j, seg_i) in lines.owned_lines.get(line_i.0).unwrap().segs.iter().enumerate() {
628 out.segs.get_mut(seg_i.0).unwrap().line = Some(SegmentLine {
629 line: *line_i,
630 seg_index: j,
631 });
632 }
633 }
634 }
635 for (i, line_i) in lines.lines.iter().enumerate() {
636 let line = lines.owned_lines.get(line_i.0).unwrap();
637 assert_eq!(line.index, i, "line index wrong; initial");
638 for (j, seg_i) in line.segs.iter().enumerate() {
639 assert_eq!(
640 out.segs.get(seg_i.0).unwrap().line.as_ref().unwrap().seg_index,
641 j,
642 "seg index wrong; on line {}, initial",
643 i
644 );
645 }
646 }
647
648 {
656 let synth_seg_node = new_sg(&mut out).build(&mut out);
657 let mut i = 0usize;
658 let mut skip_first = false;
659 let mut prev_comment = None;
660 while i < lines.lines.len() {
661 let mut res = None;
662 {
663 let line_i = lines.lines.get(i).unwrap();
664 'segs : loop {
665 for (i, seg_i) in lines.owned_lines.get(line_i.0).unwrap().segs.iter().enumerate() {
666 if i == 0 && skip_first {
667 skip_first = false;
668 continue;
669 }
670 let seg = out.segs.get(seg_i.0).unwrap();
671 let node = out.nodes.get(seg.node.0).unwrap();
672 match (&seg.content, match (&seg.mode, node.split) {
673 (SegmentMode::All, true) => true,
674 (SegmentMode::All, false) => true,
675 (SegmentMode::Unsplit, true) => false,
676 (SegmentMode::Unsplit, false) => true,
677 (SegmentMode::Split, true) => true,
678 (SegmentMode::Split, false) => false,
679 }) {
680 (SegmentContent::Break(_, _), true) => {
681 res = Some((*line_i, i, None));
682 prev_comment = None;
683 break 'segs;
684 },
685 (SegmentContent::Whitespace(c), _) => {
686 res = Some((*line_i, i, None));
687 prev_comment = Some(c.0.clone());
688 break 'segs;
689 },
690 (_, _) => {
691 if let Some(a) = prev_comment.take() {
692 let seg_i = SegmentIdx(out.segs.len());
693 out.segs.push(Segment {
694 node: synth_seg_node,
695 line: None,
696 mode: SegmentMode::All,
697 content: SegmentContent::Break(a, true),
698 });
699 res = Some((*line_i, i, Some(seg_i)));
700 break 'segs;
701 }
702 },
703 };
704 }
705 prev_comment = None;
706 break;
707 }
708 }
709 if let Some((line_i, at, insert_start)) = res {
710 split_line_at(&mut out, &mut lines, line_i, at, insert_start);
711 skip_first = true;
712 }
713 i += 1;
714 }
715 }
716
717 fn recurse(out: &mut MakeSegsState, lines: &mut Lines, config: &FormatConfig, sg_i: SplitGroupIdx) -> bool {
719 let mut split = false;
720 for seg_i in &out.nodes.get(sg_i.0).unwrap().segments {
721 let seg = out.segs.get(seg_i.0).unwrap();
722 let len = line_length(out, lines, seg.line.as_ref().unwrap().line);
723 if len > config.max_width {
724 split = true;
725 break;
726 }
727 }
728 if split {
729 split_group(out, lines, sg_i);
730 }
731 let mut split_from_child = false;
732 for child_sg_i in &out.nodes.get(sg_i.0).unwrap().children.clone() {
733 let new_split_from_child = recurse(out, lines, config, *child_sg_i);
734 split_from_child = split_from_child || new_split_from_child;
735 }
736 if !split && split_from_child {
737 split_group(out, lines, sg_i);
738 }
739 config.root_splits && (split || split_from_child)
740 }
741
742 recurse(&mut out, &mut lines, config, root);
743
744 let mut rendered = String::new();
746
747 macro_rules! push{
748 ($text: expr) => {
749 rendered.push_str($text);
750 };
751 }
752
753 let mut warnings = vec![];
754 let lines = lines;
755 let mut line_i = 0usize;
756 while line_i < lines.lines.len() {
757 'continue_lineloop : loop {
758 let segs =
759 lines.owned_lines.get(lines.lines.get(line_i).unwrap().0).unwrap().segs.iter().filter_map(|seg_i| {
760 let res = {
761 let seg = out.segs.get(seg_i.0).unwrap();
762 let node = out.nodes.get(seg.node.0).unwrap();
763 match (&seg.mode, node.split) {
764 (SegmentMode::All, _) => true,
765 (SegmentMode::Unsplit, true) => false,
766 (SegmentMode::Unsplit, false) => true,
767 (SegmentMode::Split, true) => true,
768 (SegmentMode::Split, false) => false,
769 }
770 };
771 if res {
772 Some(*seg_i)
773 } else {
774 None
775 }
776 }).collect::<Vec<SegmentIdx>>();
777 if segs.is_empty() {
778 break 'continue_lineloop;
779 }
780 for (seg_i, seg_mem_i) in segs.iter().enumerate() {
781 let seg = out.segs.get(seg_mem_i.0).unwrap();
782 match &seg.content {
783 SegmentContent::Text(t) => {
784 let t = if seg_i == 1 && line_i > 0 {
785 t.trim_start()
788 } else {
789 t
790 };
791 push!(t);
792 },
793 SegmentContent::Break(b, activate) => {
794 let next_line_first_seg_comment =
795 lines
796 .lines
797 .get(line_i + 1)
798 .map(|i| lines.owned_lines.get(i.0).unwrap())
799 .and_then(|l| l.segs.first())
800 .map(|seg_i| {
801 let seg = out.segs.get(seg_i.0).unwrap();
802 matches!(&seg.content, SegmentContent::Whitespace(_))
803 })
804 .unwrap_or(false);
805
806 if segs.len() == 1 && next_line_first_seg_comment {
809 break 'continue_lineloop;
810 }
811 if *activate {
812 b.activate();
813 }
814 if segs.len() > 1 {
815 push!(&render_indent(config, b.get()));
817 }
818 },
819 SegmentContent::Whitespace((b, whitespaces)) => {
820 for (comment_i, whitespace) in whitespaces.iter().enumerate() {
821 match &whitespace.mode {
822 WhitespaceMode::BlankLines(count) => {
823 if *count > 0 {
824 for _ in 0 .. *count {
825 push!("\n");
826 }
827 continue;
828 }
829 },
830 WhitespaceMode::Comment(comment) => {
831 if comment_i > 0 {
832 push!("\n");
833 }
834 let prefix = format!(
835 "{}//{} ",
837 render_indent(config, b.get()),
838 match comment.mode {
839 CommentMode::Normal => "",
840 CommentMode::ExplicitNormal => "?",
841 CommentMode::DocInner => "!",
842 CommentMode::DocOuter => "/",
843 CommentMode::Verbatim => ".",
844 }
845 );
846 let verbatim = match comment.mode {
847 CommentMode::Verbatim => {
848 true
849 },
850 CommentMode::Normal if config.explicit_markdown_comments => {
851 true
852 },
853 _ => {
854 match format_md(
855 &mut rendered,
856 config.max_width,
857 config.comment_width,
858 &prefix,
859 &comment.lines,
860 ) {
861 Err(e) => {
862 let err =
863 loga::err_with(
864 "Error formatting comments",
865 ea!(
866 line = whitespace.loc.line,
867 column = whitespace.loc.column,
868 comments = comment.lines
869 ),
870 );
871 if config.comment_errors_fatal {
872 return Err(err);
873 } else {
874 warnings.push(e);
875 }
876 true
877 },
878 Ok(_) => {
879 false
880 },
881 }
882 },
883 };
884 if verbatim {
885 for (i, line) in comment.lines.lines().enumerate() {
886 if i > 0 {
887 push!("\n");
888 }
889 let line = line.strip_prefix(' ').unwrap_or(line);
890 push!(&format!("{}{}", prefix, line.trim_end()));
891 }
892 }
893 },
894 }
895 }
896 },
897 }
898 }
899 push!("\n");
900 break;
901 }
902 line_i += 1;
903 }
904 Ok(FormatRes {
905 rendered: rendered,
906 lost_comments: out.whitespaces,
907 warnings: warnings,
908 })
909}