1#[cfg(feature = "termcolor")]
141pub extern crate termcolor;
142
143use std::{
144 borrow::Cow,
145 convert::TryInto,
146 fmt, io,
147 ops::{Add, AddAssign, Deref},
148 rc::Rc,
149};
150
151#[cfg(feature = "termcolor")]
152use termcolor::{ColorSpec, WriteColor};
153
154pub mod block;
155mod render;
156
157pub use self::block::{Affixes, BlockDoc};
158#[cfg(feature = "termcolor")]
159pub use self::render::TermColored;
160pub use self::render::{FmtWrite, IoWrite, Render, RenderAnnotated};
161
162#[derive(Clone)]
168pub enum Doc<'a, T, A = ()>
169where
170 T: DocPtr<'a, A>,
171{
172 Nil,
173 Append(T, T),
174 Group(T),
175 FlatAlt(T, T),
176 Nest(isize, T),
177 Hardline,
178 RenderLen(usize, T),
180 OwnedText(Box<str>),
181 BorrowedText(&'a str),
182 SmallText(SmallText),
183 Annotated(A, T),
184 Union(T, T),
185 Column(T::ColumnFn),
186 Nesting(T::ColumnFn),
187 Fail,
188}
189
190impl<'a, T, A> Default for Doc<'a, T, A>
191where
192 T: DocPtr<'a, A>,
193{
194 fn default() -> Self {
195 Self::Nil
196 }
197}
198
199pub type SmallText = arrayvec::ArrayString<[u8; 22]>;
200
201fn append_docs<'a, 'd, T, A>(
202 mut doc: &'d Doc<'a, T, A>,
203 consumer: &mut impl FnMut(&'d Doc<'a, T, A>),
204) where
205 T: DocPtr<'a, A>,
206{
207 loop {
208 match doc {
209 Doc::Append(l, r) => {
210 append_docs(l, consumer);
211 doc = r;
212 }
213 _ => break consumer(doc),
214 }
215 }
216}
217
218impl<'a, T, A> fmt::Debug for Doc<'a, T, A>
219where
220 T: DocPtr<'a, A> + fmt::Debug,
221 A: fmt::Debug,
222{
223 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
224 let is_line = |doc: &Doc<'a, T, A>| match doc {
225 Doc::FlatAlt(x, y) => {
226 matches!((&**x, &**y), (Doc::Hardline, Doc::BorrowedText(" ")))
227 }
228 _ => false,
229 };
230 let is_line_ = |doc: &Doc<'a, T, A>| match doc {
231 Doc::FlatAlt(x, y) => {
232 matches!((&**x, &**y), (Doc::Hardline, Doc::Nil))
233 }
234 _ => false,
235 };
236 match self {
237 Doc::Nil => f.debug_tuple("Nil").finish(),
238 Doc::Append(..) => {
239 let mut f = f.debug_list();
240 append_docs(self, &mut |doc| {
241 f.entry(doc);
242 });
243 f.finish()
244 }
245 _ if is_line(self) => f.debug_tuple("Line").finish(),
246 _ if is_line_(self) => f.debug_tuple("Line_").finish(),
247 Doc::FlatAlt(ref x, ref y) => f.debug_tuple("FlatAlt").field(x).field(y).finish(),
248 Doc::Group(ref doc) => {
249 if is_line(self) {
250 return f.debug_tuple("SoftLine").finish();
251 }
252 if is_line_(self) {
253 return f.debug_tuple("SoftLine_").finish();
254 }
255 f.debug_tuple("Group").field(doc).finish()
256 }
257 Doc::Nest(off, ref doc) => f.debug_tuple("Nest").field(&off).field(doc).finish(),
258 Doc::Hardline => f.debug_tuple("Hardline").finish(),
259 Doc::RenderLen(_, d) => d.fmt(f),
260 Doc::OwnedText(ref s) => s.fmt(f),
261 Doc::BorrowedText(ref s) => s.fmt(f),
262 Doc::SmallText(ref s) => s.fmt(f),
263 Doc::Annotated(ref ann, ref doc) => {
264 f.debug_tuple("Annotated").field(ann).field(doc).finish()
265 }
266 Doc::Union(ref l, ref r) => f.debug_tuple("Union").field(l).field(r).finish(),
267 Doc::Column(_) => f.debug_tuple("Column(..)").finish(),
268 Doc::Nesting(_) => f.debug_tuple("Nesting(..)").finish(),
269 Doc::Fail => f.debug_tuple("Fail").finish(),
270 }
271 }
272}
273
274macro_rules! impl_doc {
275 ($name: ident, $ptr: ident, $allocator: ident) => {
276 #[derive(Clone)]
277 pub struct $name<'a, A = ()>($ptr<Doc<'a, $name<'a, A>, A>>);
278
279 impl<'a, A> fmt::Debug for $name<'a, A>
280 where
281 A: fmt::Debug,
282 {
283 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
284 self.0.fmt(f)
285 }
286 }
287
288 impl<'a, A> $name<'a, A> {
289 pub fn new(doc: Doc<'a, $name<'a, A>, A>) -> $name<'a, A> {
290 $name($ptr::new(doc))
291 }
292 }
293
294 impl<'a, A> From<Doc<'a, Self, A>> for $name<'a, A> {
295 fn from(doc: Doc<'a, $name<'a, A>, A>) -> $name<'a, A> {
296 $name::new(doc)
297 }
298 }
299
300 impl<'a, A> Deref for $name<'a, A> {
301 type Target = Doc<'a, $name<'a, A>, A>;
302
303 fn deref(&self) -> &Self::Target {
304 &self.0
305 }
306 }
307
308 impl<'a, A> DocAllocator<'a, A> for $allocator
309 where
310 A: 'a,
311 {
312 type Doc = $name<'a, A>;
313
314 #[inline]
315 fn alloc(&'a self, doc: Doc<'a, Self::Doc, A>) -> Self::Doc {
316 $name::new(doc)
317 }
318 fn alloc_column_fn(
319 &'a self,
320 f: impl Fn(usize) -> Self::Doc + 'a,
321 ) -> <Self::Doc as DocPtr<'a, A>>::ColumnFn {
322 Rc::new(f)
323 }
324 fn alloc_width_fn(
325 &'a self,
326 f: impl Fn(isize) -> Self::Doc + 'a,
327 ) -> <Self::Doc as DocPtr<'a, A>>::WidthFn {
328 Rc::new(f)
329 }
330 }
331
332 impl<'a, A> DocPtr<'a, A> for $name<'a, A> {
333 type ColumnFn = std::rc::Rc<dyn Fn(usize) -> Self + 'a>;
334 type WidthFn = std::rc::Rc<dyn Fn(isize) -> Self + 'a>;
335 }
336
337 impl<'a, A> StaticDoc<'a, A> for $name<'a, A> {
338 type Allocator = $allocator;
339 const ALLOCATOR: &'static Self::Allocator = &$allocator;
340 }
341
342 impl_doc_methods!($name ('a, A) where () where ());
343
344 impl<'a, A> $name<'a, A> {
345 #[inline]
349 pub fn as_string<U: fmt::Display>(data: U) -> Self {
350 $allocator.as_string(data).into_doc()
351 }
352
353 #[inline]
355 pub fn text<U: Into<Cow<'a, str>>>(data: U) -> Self {
356 $allocator.text(data).into_doc()
357 }
358
359 #[inline]
361 pub fn append<D>(self, that: D) -> Self
362 where
363 D: Pretty<'a, $allocator, A>,
364 {
365 DocBuilder(&$allocator, self.into()).append(that).into_doc()
366 }
367
368 #[inline]
370 pub fn concat<I>(docs: I) -> Self
371 where
372 I: IntoIterator,
373 I::Item: Pretty<'a, $allocator, A>,
374 {
375 $allocator.concat(docs).into_doc()
376 }
377
378 #[inline]
386 pub fn intersperse<I, S>(docs: I, separator: S) -> Self
387 where
388 I: IntoIterator,
389 I::Item: Pretty<'a, $allocator, A>,
390 S: Pretty<'a, $allocator, A> + Clone,
391 A: Clone,
392 {
393 $allocator.intersperse(docs, separator).into_doc()
394 }
395
396 #[inline]
398 pub fn flat_alt<D>(self, doc: D) -> Self
399 where
400 D: Pretty<'a, $allocator, A>,
401 {
402 DocBuilder(&$allocator, self.into())
403 .flat_alt(doc)
404 .into_doc()
405 }
406
407 #[inline]
414 pub fn group(self) -> Self {
415 DocBuilder(&$allocator, self.into()).group().into_doc()
416 }
417
418 #[inline]
420 pub fn nest(self, offset: isize) -> Self {
421 DocBuilder(&$allocator, self.into()).nest(offset).into_doc()
422 }
423
424 #[inline]
425 pub fn annotate(self, ann: A) -> Self {
426 DocBuilder(&$allocator, self.into())
427 .annotate(ann)
428 .into_doc()
429 }
430
431 #[inline]
432 pub fn union<D>(self, other: D) -> Self
433 where
434 D: Into<BuildDoc<'a, Self, A>>,
435 {
436 DocBuilder(&$allocator, self.into()).union(other).into_doc()
437 }
438
439 #[inline]
440 pub fn softline() -> Self {
441 Self::line().group()
442 }
443
444 #[inline]
446 pub fn softline_() -> Self {
447 Self::line_().group()
448 }
449
450 #[inline]
451 pub fn column(f: impl Fn(usize) -> Self + 'static) -> Self {
452 DocBuilder(&$allocator, Doc::Column($allocator.alloc_column_fn(f)).into()).into_doc()
453 }
454
455 #[inline]
456 pub fn nesting(f: impl Fn(usize) -> Self + 'static) -> Self {
457 DocBuilder(&$allocator, Doc::Nesting($allocator.alloc_column_fn(f)).into()).into_doc()
458 }
459 }
460 };
461}
462
463enum FmtText {
464 Small(SmallText),
465 Large(String),
466}
467
468impl fmt::Write for FmtText {
469 fn write_str(&mut self, s: &str) -> fmt::Result {
470 match self {
471 FmtText::Small(buf) => {
472 if buf.try_push_str(s).is_err() {
473 let mut new_str = String::with_capacity(buf.len() + s.len());
474 new_str.push_str(buf);
475 new_str.push_str(s);
476 *self = FmtText::Large(new_str);
477 }
478 }
479 FmtText::Large(buf) => buf.push_str(s),
480 }
481 Ok(())
482 }
483}
484
485macro_rules! impl_doc_methods {
486 ($name: ident ( $($params: tt)* ) where ( $($where_: tt)* ) where ( $($where_2: tt)* )) => {
487 impl< $($params)* > $name< $($params)* >
488 where $($where_)*
489 {
490 #[inline]
492 pub fn nil() -> Self {
493 Doc::Nil.into()
494 }
495
496 #[inline]
498 pub fn hardline() -> Self {
499 Doc::Hardline.into()
500 }
501
502 #[inline]
503 pub fn space() -> Self {
504 Doc::BorrowedText(" ").into()
505 }
506
507 #[inline]
508 pub fn fail() -> Self {
509 Doc::Fail.into()
510 }
511 }
512
513 impl< $($params)* > $name< $($params)* >
514 where $($where_2)*
515 {
516 #[inline]
518 pub fn line() -> Self {
519 Self::hardline().flat_alt(Self::space()).into()
520 }
521
522 #[inline]
524 pub fn line_() -> Self {
525 Self::hardline().flat_alt(Self::nil()).into()
526 }
527 }
528 };
529}
530
531impl_doc!(BoxDoc, Box, BoxAllocator);
532impl_doc!(RcDoc, Rc, RcAllocator);
533
534impl_doc_methods!(Doc ('a, D, A) where (D: DocPtr<'a, A>) where (D: StaticDoc<'a, A>));
535impl_doc_methods!(BuildDoc ('a, D, A) where (D: DocPtr<'a, A>) where (D: StaticDoc<'a, A>));
536
537pub struct BoxAllocator;
538
539pub struct RcAllocator;
540
541impl<'a, T, A> BuildDoc<'a, T, A>
542where
543 T: StaticDoc<'a, A>,
544{
545 #[inline]
549 pub fn as_string<U: fmt::Display>(data: U) -> Self {
550 T::ALLOCATOR.as_string(data).1
551 }
552
553 #[inline]
555 pub fn text<U: Into<Cow<'a, str>>>(data: U) -> Self {
556 T::ALLOCATOR.text(data).1
557 }
558
559 fn flat_alt<D>(self, doc: D) -> Self
560 where
561 D: Pretty<'a, T::Allocator, A>,
562 {
563 DocBuilder(T::ALLOCATOR, self).flat_alt(doc).1
564 }
565}
566
567impl<'a, T, A> Doc<'a, T, A>
568where
569 T: StaticDoc<'a, A>,
570{
571 #[inline]
575 pub fn as_string<U: fmt::Display>(data: U) -> Self {
576 T::ALLOCATOR.as_string(data).into_plain_doc()
577 }
578
579 #[inline]
581 pub fn text<U: Into<Cow<'a, str>>>(data: U) -> Self {
582 T::ALLOCATOR.text(data).into_plain_doc()
583 }
584
585 fn flat_alt<D>(self, doc: D) -> Self
586 where
587 D: Pretty<'a, T::Allocator, A>,
588 {
589 DocBuilder(T::ALLOCATOR, self.into())
590 .flat_alt(doc)
591 .into_plain_doc()
592 }
593}
594
595pub trait StaticDoc<'a, A>: DocPtr<'a, A>
596where
597 A: 'a,
598{
599 type Allocator: DocAllocator<'a, A, Doc = Self> + 'static;
600 const ALLOCATOR: &'static Self::Allocator;
601}
602
603impl<'a, T, A, S> From<S> for Doc<'a, T, A>
604where
605 T: StaticDoc<'a, A>,
606 S: Into<Cow<'a, str>>,
607{
608 fn from(s: S) -> Doc<'a, T, A> {
609 Doc::text(s)
610 }
611}
612
613pub struct PrettyFmt<'a, 'd, T, A>
614where
615 A: 'a,
616 T: DocPtr<'a, A> + 'a,
617{
618 doc: &'d Doc<'a, T, A>,
619 width: usize,
620}
621
622impl<'a, T, A> fmt::Display for PrettyFmt<'a, '_, T, A>
623where
624 T: DocPtr<'a, A>,
625{
626 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
627 self.doc.render_fmt(self.width, f)
628 }
629}
630
631impl<'a, T, A> Doc<'a, T, A>
632where
633 T: DocPtr<'a, A> + 'a,
634{
635 #[inline]
637 pub fn render<W>(&self, width: usize, out: &mut W) -> io::Result<()>
638 where
639 W: ?Sized + io::Write,
640 {
641 self.render_raw(width, &mut IoWrite::new(out))
642 }
643
644 #[inline]
646 pub fn render_fmt<W>(&self, width: usize, out: &mut W) -> fmt::Result
647 where
648 W: ?Sized + fmt::Write,
649 {
650 self.render_raw(width, &mut FmtWrite::new(out))
651 }
652
653 #[inline]
655 pub fn render_raw<W>(&self, width: usize, out: &mut W) -> Result<(), W::Error>
656 where
657 for<'b> W: render::RenderAnnotated<'b, A>,
658 W: ?Sized,
659 {
660 render::best(self, width, out)
661 }
662
663 #[inline]
673 pub fn pretty<'d>(&'d self, width: usize) -> PrettyFmt<'a, 'd, T, A> {
674 PrettyFmt { doc: self, width }
675 }
676}
677
678#[cfg(feature = "termcolor")]
679impl<'a, T> Doc<'a, T, ColorSpec>
680where
681 T: DocPtr<'a, ColorSpec> + 'a,
682{
683 #[inline]
684 pub fn render_colored<W>(&self, width: usize, out: W) -> io::Result<()>
685 where
686 W: WriteColor,
687 {
688 render::best(self, width, &mut TermColored::new(out))
689 }
690}
691
692pub struct DocBuilder<'a, D, A = ()>(pub &'a D, pub BuildDoc<'a, D::Doc, A>)
695where
696 D: ?Sized + DocAllocator<'a, A>;
697
698impl<'a, D, A, P> Add<P> for DocBuilder<'a, D, A>
699where
700 D: ?Sized + DocAllocator<'a, A>,
701 P: Pretty<'a, D, A>,
702{
703 type Output = DocBuilder<'a, D, A>;
704 fn add(self, other: P) -> Self::Output {
705 self.append(other)
706 }
707}
708
709impl<'a, D, A, P> AddAssign<P> for DocBuilder<'a, D, A>
710where
711 D: ?Sized + DocAllocator<'a, A>,
712 P: Pretty<'a, D, A>,
713{
714 fn add_assign(&mut self, other: P) {
715 *self = DocBuilder(self.0, std::mem::take(&mut self.1)).append(other)
716 }
717}
718
719impl<'a, D, A> Deref for DocBuilder<'a, D, A>
720where
721 D: ?Sized + DocAllocator<'a, A>,
722{
723 type Target = Doc<'a, D::Doc, A>;
724 fn deref(&self) -> &Self::Target {
725 match &self.1 {
726 BuildDoc::DocPtr(d) => d,
727 BuildDoc::Doc(d) => d,
728 }
729 }
730}
731
732impl<'a, D, A> fmt::Debug for DocBuilder<'a, D, A>
733where
734 D: ?Sized + DocAllocator<'a, A>,
735 D::Doc: fmt::Debug,
736 A: fmt::Debug,
737{
738 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
739 self.1.fmt(f)
740 }
741}
742
743impl<'a, A, D> Clone for DocBuilder<'a, D, A>
744where
745 A: Clone,
746 D: DocAllocator<'a, A> + 'a,
747 D::Doc: Clone,
748{
749 fn clone(&self) -> Self {
750 DocBuilder(self.0, self.1.clone())
751 }
752}
753
754impl<'a, D, A> From<DocBuilder<'a, D, A>> for BuildDoc<'a, D::Doc, A>
755where
756 D: ?Sized + DocAllocator<'a, A>,
757{
758 fn from(val: DocBuilder<'a, D, A>) -> Self {
759 val.1
760 }
761}
762
763pub trait DocPtr<'a, A>: Deref<Target = Doc<'a, Self, A>> + Sized
764where
765 A: 'a,
766{
767 type ColumnFn: Deref<Target = dyn Fn(usize) -> Self + 'a> + Clone + 'a;
768 type WidthFn: Deref<Target = dyn Fn(isize) -> Self + 'a> + Clone + 'a;
769}
770
771impl<'a, A> DocPtr<'a, A> for RefDoc<'a, A> {
772 type ColumnFn = &'a (dyn Fn(usize) -> Self + 'a);
773 type WidthFn = &'a (dyn Fn(isize) -> Self + 'a);
774}
775
776pub trait Pretty<'a, D, A = ()>
778where
779 A: 'a,
780 D: ?Sized + DocAllocator<'a, A>,
781{
782 fn pretty(self, allocator: &'a D) -> DocBuilder<'a, D, A>;
784}
785
786impl<'a, A> Pretty<'a, BoxAllocator, A> for BoxDoc<'a, A>
787where
788 A: 'a,
789{
790 fn pretty(self, allocator: &'a BoxAllocator) -> DocBuilder<'a, BoxAllocator, A> {
791 DocBuilder(allocator, self.into())
792 }
793}
794
795impl<'a, A> Pretty<'a, RcAllocator, A> for RcDoc<'a, A>
796where
797 A: 'a,
798{
799 fn pretty(self, allocator: &'a RcAllocator) -> DocBuilder<'a, RcAllocator, A> {
800 DocBuilder(allocator, self.into())
801 }
802}
803
804impl<'a, A> Pretty<'a, Arena<'a, A>, A> for RefDoc<'a, A>
805where
806 A: 'a,
807{
808 fn pretty(self, allocator: &'a Arena<'a, A>) -> DocBuilder<'a, Arena<'a, A>, A> {
809 DocBuilder(allocator, self.into())
810 }
811}
812
813impl<'a, D, A> Pretty<'a, D, A> for BuildDoc<'a, D::Doc, A>
814where
815 A: 'a,
816 D: ?Sized + DocAllocator<'a, A>,
817{
818 fn pretty(self, allocator: &'a D) -> DocBuilder<'a, D, A> {
819 DocBuilder(allocator, self)
820 }
821}
822
823impl<'a, D, A> Pretty<'a, D, A> for Doc<'a, D::Doc, A>
824where
825 A: 'a,
826 D: ?Sized + DocAllocator<'a, A>,
827{
828 fn pretty(self, allocator: &'a D) -> DocBuilder<'a, D, A> {
829 DocBuilder(allocator, self.into())
830 }
831}
832
833impl<'a, D, A> Pretty<'a, D, A> for DocBuilder<'a, D, A>
834where
835 A: 'a,
836 D: ?Sized + DocAllocator<'a, A>,
837{
838 fn pretty(self, _: &'a D) -> DocBuilder<'a, D, A> {
839 self
840 }
841}
842
843impl<'a, D, A, T> Pretty<'a, D, A> for Option<T>
844where
845 A: 'a,
846 D: ?Sized + DocAllocator<'a, A>,
847 T: Pretty<'a, D, A>,
848{
849 fn pretty(self, allocator: &'a D) -> DocBuilder<'a, D, A> {
850 match self {
851 Some(x) => x.pretty(allocator),
852 None => allocator.nil(),
853 }
854 }
855}
856
857impl<'a, D, A> Pretty<'a, D, A> for &'a str
858where
859 A: 'a,
860 D: ?Sized + DocAllocator<'a, A>,
861{
862 fn pretty(self, allocator: &'a D) -> DocBuilder<'a, D, A> {
863 allocator.text(self)
864 }
865}
866
867impl<'a, D, A> Pretty<'a, D, A> for &'a String
868where
869 A: 'a,
870 D: ?Sized + DocAllocator<'a, A>,
871{
872 fn pretty(self, allocator: &'a D) -> DocBuilder<'a, D, A> {
873 self[..].pretty(allocator)
874 }
875}
876
877impl<'a, D, A> Pretty<'a, D, A> for String
878where
879 A: 'a,
880 D: ?Sized + DocAllocator<'a, A>,
881{
882 fn pretty(self, allocator: &'a D) -> DocBuilder<'a, D, A> {
883 allocator.text(self)
884 }
885}
886
887impl<'a, D, A, S> Pretty<'a, D, A> for Cow<'a, S>
888where
889 A: 'a,
890 D: ?Sized + DocAllocator<'a, A>,
891 S: ?Sized + ToOwned,
892 &'a S: Pretty<'a, D, A>,
893 S::Owned: Pretty<'a, D, A>,
894{
895 fn pretty(self, allocator: &'a D) -> DocBuilder<'a, D, A> {
896 match self {
897 Cow::Borrowed(s) => s.pretty(allocator),
898 Cow::Owned(s) => s.pretty(allocator),
899 }
900 }
901}
902
903pub trait DocAllocator<'a, A = ()>
905where
906 A: 'a,
907{
908 type Doc: DocPtr<'a, A>;
909
910 fn alloc(&'a self, doc: Doc<'a, Self::Doc, A>) -> Self::Doc;
911
912 fn alloc_column_fn(
913 &'a self,
914 f: impl Fn(usize) -> Self::Doc + 'a,
915 ) -> <Self::Doc as DocPtr<'a, A>>::ColumnFn;
916
917 fn alloc_width_fn(
918 &'a self,
919 f: impl Fn(isize) -> Self::Doc + 'a,
920 ) -> <Self::Doc as DocPtr<'a, A>>::WidthFn;
921
922 fn alloc_cow(&'a self, doc: BuildDoc<'a, Self::Doc, A>) -> Self::Doc {
923 match doc {
924 BuildDoc::DocPtr(d) => d,
925 BuildDoc::Doc(d) => self.alloc(d),
926 }
927 }
928
929 #[inline]
931 fn nil(&'a self) -> DocBuilder<'a, Self, A> {
932 DocBuilder(self, Doc::Nil.into())
933 }
934
935 #[inline]
939 fn fail(&'a self) -> DocBuilder<'a, Self, A> {
940 DocBuilder(self, Doc::Fail.into())
941 }
942
943 #[inline]
945 fn hardline(&'a self) -> DocBuilder<'a, Self, A> {
946 DocBuilder(self, Doc::Hardline.into())
947 }
948
949 #[inline]
950 fn space(&'a self) -> DocBuilder<'a, Self, A> {
951 self.text(" ")
952 }
953
954 #[inline]
956 fn line(&'a self) -> DocBuilder<'a, Self, A> {
957 self.hardline().flat_alt(self.space())
958 }
959
960 #[inline]
981 fn line_(&'a self) -> DocBuilder<'a, Self, A> {
982 self.hardline().flat_alt(self.nil())
983 }
984
985 #[inline]
987 fn softline(&'a self) -> DocBuilder<'a, Self, A> {
988 self.line().group()
989 }
990
991 #[inline]
993 fn softline_(&'a self) -> DocBuilder<'a, Self, A> {
994 self.line_().group()
995 }
996
997 #[inline]
1001 fn as_string<U: fmt::Display>(&'a self, data: U) -> DocBuilder<'a, Self, A> {
1002 use std::fmt::Write;
1003 let mut buf = FmtText::Small(SmallText::new());
1004 write!(buf, "{}", data).unwrap();
1005 let doc = match buf {
1006 FmtText::Small(b) => Doc::SmallText(b),
1007 FmtText::Large(b) => Doc::OwnedText(b.into()),
1008 };
1009 DocBuilder(self, doc.into()).with_utf8_len()
1010 }
1011
1012 #[inline]
1016 fn text<U: Into<Cow<'a, str>>>(&'a self, data: U) -> DocBuilder<'a, Self, A> {
1017 let data: Cow<_> = data.into();
1018 let doc = if data.is_empty() {
1019 Doc::Nil.into()
1020 } else {
1021 match data {
1022 Cow::Owned(t) => Doc::OwnedText(t.into()).into(),
1023 Cow::Borrowed(t) => Doc::BorrowedText(t).into(),
1024 }
1025 };
1026 DocBuilder(self, doc).with_utf8_len()
1027 }
1028
1029 #[inline]
1031 fn concat<I>(&'a self, docs: I) -> DocBuilder<'a, Self, A>
1032 where
1033 I: IntoIterator,
1034 I::Item: Pretty<'a, Self, A>,
1035 {
1036 docs.into_iter().fold(self.nil(), |a, b| a.append(b))
1037 }
1038
1039 #[inline]
1047 fn intersperse<I, S>(&'a self, docs: I, separator: S) -> DocBuilder<'a, Self, A>
1048 where
1049 I: IntoIterator,
1050 I::Item: Pretty<'a, Self, A>,
1051 S: Pretty<'a, Self, A> + Clone,
1052 {
1053 let mut result = self.nil();
1054 let mut iter = docs.into_iter();
1055
1056 if let Some(first) = iter.next() {
1057 result = result.append(first);
1058
1059 for doc in iter {
1060 result = result.append(separator.clone());
1061 result = result.append(doc);
1062 }
1063 }
1064
1065 result
1066 }
1067
1068 #[inline]
1081 fn column(&'a self, f: impl Fn(usize) -> Self::Doc + 'a) -> DocBuilder<'a, Self, A> {
1082 DocBuilder(self, Doc::Column(self.alloc_column_fn(f)).into())
1083 }
1084
1085 #[inline]
1098 fn nesting(&'a self, f: impl Fn(usize) -> Self::Doc + 'a) -> DocBuilder<'a, Self, A> {
1099 DocBuilder(self, Doc::Nesting(self.alloc_column_fn(f)).into())
1100 }
1101
1102 #[inline]
1104 fn reflow(&'a self, text: &'a str) -> DocBuilder<'a, Self, A>
1105 where
1106 Self: Sized,
1107 Self::Doc: Clone,
1108 A: Clone,
1109 {
1110 self.intersperse(text.split(char::is_whitespace), self.softline())
1111 }
1112}
1113
1114#[derive(Clone)]
1116pub enum BuildDoc<'a, D, A>
1117where
1118 D: DocPtr<'a, A>,
1119{
1120 DocPtr(D),
1121 Doc(Doc<'a, D, A>),
1122}
1123
1124impl<'a, D, A> Default for BuildDoc<'a, D, A>
1125where
1126 D: DocPtr<'a, A>,
1127{
1128 fn default() -> Self {
1129 Self::Doc(Doc::default())
1130 }
1131}
1132
1133impl<'a, D, A> fmt::Debug for BuildDoc<'a, D, A>
1134where
1135 D: DocPtr<'a, A> + fmt::Debug,
1136 A: fmt::Debug,
1137{
1138 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1139 (**self).fmt(f)
1140 }
1141}
1142
1143impl<'a, D, A> Deref for BuildDoc<'a, D, A>
1144where
1145 D: DocPtr<'a, A>,
1146{
1147 type Target = Doc<'a, D, A>;
1148 fn deref(&self) -> &Self::Target {
1149 match self {
1150 BuildDoc::DocPtr(d) => d,
1151 BuildDoc::Doc(d) => d,
1152 }
1153 }
1154}
1155
1156impl<'a, A> From<RefDoc<'a, A>> for BuildDoc<'a, RefDoc<'a, A>, A> {
1157 fn from(s: RefDoc<'a, A>) -> Self {
1158 BuildDoc::DocPtr(s)
1159 }
1160}
1161
1162impl<'a, A> From<BoxDoc<'a, A>> for BuildDoc<'a, BoxDoc<'a, A>, A> {
1163 fn from(s: BoxDoc<'a, A>) -> Self {
1164 BuildDoc::DocPtr(s)
1165 }
1166}
1167
1168impl<'a, A> From<RcDoc<'a, A>> for BuildDoc<'a, RcDoc<'a, A>, A> {
1169 fn from(s: RcDoc<'a, A>) -> Self {
1170 BuildDoc::DocPtr(s)
1171 }
1172}
1173
1174impl<'a, T, A> From<Doc<'a, T, A>> for BuildDoc<'a, T, A>
1175where
1176 T: DocPtr<'a, A>,
1177{
1178 fn from(s: Doc<'a, T, A>) -> Self {
1179 BuildDoc::Doc(s)
1180 }
1181}
1182
1183impl<'a, T, A> From<String> for BuildDoc<'a, T, A>
1184where
1185 T: StaticDoc<'a, A>,
1186{
1187 fn from(s: String) -> Self {
1188 BuildDoc::Doc(Doc::text(s))
1189 }
1190}
1191
1192impl<'a, T, A> From<&'a str> for BuildDoc<'a, T, A>
1193where
1194 T: StaticDoc<'a, A>,
1195{
1196 fn from(s: &'a str) -> Self {
1197 BuildDoc::Doc(Doc::text(s))
1198 }
1199}
1200
1201impl<'a, T, A> From<&'a String> for BuildDoc<'a, T, A>
1202where
1203 T: StaticDoc<'a, A>,
1204{
1205 fn from(s: &'a String) -> Self {
1206 BuildDoc::Doc(Doc::text(s))
1207 }
1208}
1209
1210impl<'a, T, A, S> From<Option<S>> for BuildDoc<'a, T, A>
1211where
1212 T: DocPtr<'a, A>,
1213 S: Into<BuildDoc<'a, T, A>>,
1214{
1215 fn from(s: Option<S>) -> Self {
1216 match s {
1217 Some(s) => s.into(),
1218 None => BuildDoc::Doc(Doc::Nil),
1219 }
1220 }
1221}
1222
1223#[macro_export]
1242macro_rules! docs {
1243 ($alloc: expr, $first: expr $(,)?) => {
1244 $crate::Pretty::pretty($first, $alloc)
1245 };
1246 ($alloc: expr, $first: expr $(, $rest: expr)+ $(,)?) => {{
1247 let mut doc = $crate::Pretty::pretty($first, $alloc);
1248 $(
1249 doc = doc.append($rest);
1250 )*
1251 doc
1252 }}
1253}
1254
1255impl<'a, D, A> DocBuilder<'a, D, A>
1256where
1257 A: 'a,
1258 D: ?Sized + DocAllocator<'a, A>,
1259{
1260 fn with_utf8_len(self) -> Self {
1261 let s = match &*self {
1262 Doc::OwnedText(s) => &s[..],
1263 Doc::BorrowedText(s) => s,
1264 Doc::SmallText(s) => s,
1265 _ => return self,
1266 };
1267
1268 if s.is_ascii() {
1269 self
1270 } else {
1271 let display_width = unicode_width::UnicodeWidthStr::width(s);
1272
1273 let DocBuilder(allocator, _) = self;
1274 DocBuilder(
1275 allocator,
1276 Doc::RenderLen(display_width, self.into_doc()).into(),
1277 )
1278 }
1279 }
1280
1281 #[inline]
1283 pub fn append<E>(self, that: E) -> DocBuilder<'a, D, A>
1284 where
1285 E: Pretty<'a, D, A>,
1286 {
1287 let DocBuilder(allocator, _) = self;
1288 let that = that.pretty(allocator);
1289 match (&*self, &*that) {
1290 (Doc::Nil, _) => that,
1291 (_, Doc::Nil) => self,
1292 _ => DocBuilder(
1293 allocator,
1294 Doc::Append(
1295 allocator.alloc_cow(self.into()),
1296 allocator.alloc_cow(that.into()),
1297 )
1298 .into(),
1299 ),
1300 }
1301 }
1302
1303 #[inline]
1328 pub fn flat_alt<E>(self, that: E) -> DocBuilder<'a, D, A>
1329 where
1330 E: Pretty<'a, D, A>,
1331 {
1332 let DocBuilder(allocator, this) = self;
1333 let that = that.pretty(allocator);
1334 DocBuilder(
1335 allocator,
1336 Doc::FlatAlt(allocator.alloc_cow(this), allocator.alloc_cow(that.into())).into(),
1337 )
1338 }
1339
1340 #[inline]
1347 pub fn group(self) -> DocBuilder<'a, D, A> {
1348 match *self.1 {
1349 Doc::Group(_)
1350 | Doc::OwnedText(_)
1351 | Doc::BorrowedText(_)
1352 | Doc::SmallText(_)
1353 | Doc::Nil => self,
1354 _ => {
1355 let DocBuilder(allocator, this) = self;
1356 DocBuilder(allocator, Doc::Group(allocator.alloc_cow(this)).into())
1357 }
1358 }
1359 }
1360
1361 #[inline]
1363 pub fn nest(self, offset: isize) -> DocBuilder<'a, D, A> {
1364 if let Doc::Nil = &*self.1 {
1365 return self;
1366 }
1367 if offset == 0 {
1368 return self;
1369 }
1370 let DocBuilder(allocator, this) = self;
1371 DocBuilder(
1372 allocator,
1373 Doc::Nest(offset, allocator.alloc_cow(this)).into(),
1374 )
1375 }
1376
1377 #[inline]
1378 pub fn annotate(self, ann: A) -> DocBuilder<'a, D, A> {
1379 let DocBuilder(allocator, this) = self;
1380 DocBuilder(
1381 allocator,
1382 Doc::Annotated(ann, allocator.alloc_cow(this)).into(),
1383 )
1384 }
1385
1386 #[inline]
1387 pub fn union<E>(self, other: E) -> DocBuilder<'a, D, A>
1388 where
1389 E: Into<BuildDoc<'a, D::Doc, A>>,
1390 {
1391 let DocBuilder(allocator, this) = self;
1392 let other = other.into();
1393 let doc = Doc::Union(allocator.alloc_cow(this), allocator.alloc_cow(other));
1394 DocBuilder(allocator, doc.into())
1395 }
1396
1397 #[inline]
1417 pub fn align(self) -> DocBuilder<'a, D, A>
1418 where
1419 DocBuilder<'a, D, A>: Clone,
1420 {
1421 let allocator = self.0;
1422 allocator.column(move |col| {
1423 let self_ = self.clone();
1424 allocator
1425 .nesting(move |nest| self_.clone().nest(col as isize - nest as isize).into_doc())
1426 .into_doc()
1427 })
1428 }
1429
1430 #[inline]
1447 pub fn hang(self, adjust: isize) -> DocBuilder<'a, D, A>
1448 where
1449 DocBuilder<'a, D, A>: Clone,
1450 {
1451 self.nest(adjust).align()
1452 }
1453
1454 #[inline]
1475 pub fn indent(self, adjust: usize) -> DocBuilder<'a, D, A>
1476 where
1477 DocBuilder<'a, D, A>: Clone,
1478 {
1479 let spaces = {
1480 use crate::render::SPACES;
1481 let DocBuilder(allocator, _) = self;
1482 let mut doc = allocator.nil();
1483 let mut remaining = adjust;
1484 while remaining != 0 {
1485 let i = SPACES.len().min(remaining);
1486 remaining -= i;
1487 doc = doc.append(allocator.text(&SPACES[..i]))
1488 }
1489 doc
1490 };
1491 spaces.append(self).hang(adjust.try_into().unwrap())
1492 }
1493
1494 #[inline]
1510 pub fn width(self, f: impl Fn(isize) -> D::Doc + 'a) -> DocBuilder<'a, D, A>
1511 where
1512 BuildDoc<'a, D::Doc, A>: Clone,
1513 {
1514 let DocBuilder(allocator, this) = self;
1515 let f = allocator.alloc_width_fn(f);
1516 allocator.column(move |start| {
1517 let f = f.clone();
1518
1519 DocBuilder(allocator, this.clone())
1520 .append(allocator.column(move |end| f(end as isize - start as isize)))
1521 .into_doc()
1522 })
1523 }
1524
1525 #[inline]
1527 pub fn enclose<E, F>(self, before: E, after: F) -> DocBuilder<'a, D, A>
1528 where
1529 E: Pretty<'a, D, A>,
1530 F: Pretty<'a, D, A>,
1531 {
1532 let DocBuilder(allocator, _) = self;
1533 DocBuilder(allocator, before.pretty(allocator).1)
1534 .append(self)
1535 .append(after)
1536 }
1537
1538 pub fn single_quotes(self) -> DocBuilder<'a, D, A> {
1539 self.enclose("'", "'")
1540 }
1541
1542 pub fn double_quotes(self) -> DocBuilder<'a, D, A> {
1543 self.enclose("\"", "\"")
1544 }
1545 pub fn parens(self) -> DocBuilder<'a, D, A> {
1546 self.enclose("(", ")")
1547 }
1548
1549 pub fn angles(self) -> DocBuilder<'a, D, A> {
1550 self.enclose("<", ">")
1551 }
1552 pub fn braces(self) -> DocBuilder<'a, D, A> {
1553 self.enclose("{", "}")
1554 }
1555
1556 pub fn brackets(self) -> DocBuilder<'a, D, A> {
1557 self.enclose("[", "]")
1558 }
1559
1560 pub fn into_doc(self) -> D::Doc {
1561 match self.1 {
1562 BuildDoc::DocPtr(d) => d,
1563 BuildDoc::Doc(d) => self.0.alloc(d),
1564 }
1565 }
1566
1567 fn into_plain_doc(self) -> Doc<'a, D::Doc, A> {
1568 match self.1 {
1569 BuildDoc::DocPtr(_) => unreachable!(),
1570 BuildDoc::Doc(d) => d,
1571 }
1572 }
1573}
1574
1575pub struct RefDoc<'a, A = ()>(pub &'a Doc<'a, RefDoc<'a, A>, A>);
1577
1578impl<A> Copy for RefDoc<'_, A> {}
1579impl<A> Clone for RefDoc<'_, A> {
1580 fn clone(&self) -> Self {
1581 *self
1582 }
1583}
1584
1585impl<'a, A> fmt::Debug for RefDoc<'a, A>
1586where
1587 A: fmt::Debug,
1588{
1589 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1590 self.0.fmt(f)
1591 }
1592}
1593
1594impl<'a, A> Deref for RefDoc<'a, A> {
1595 type Target = Doc<'a, RefDoc<'a, A>, A>;
1596
1597 fn deref(&self) -> &Self::Target {
1598 self.0
1599 }
1600}
1601
1602trait DropT {}
1603impl<T> DropT for T {}
1604
1605pub struct Arena<'a, A = ()> {
1607 docs: typed_arena::Arena<Doc<'a, RefDoc<'a, A>, A>>,
1608 column_fns: typed_arena::Arena<Box<dyn DropT>>,
1609}
1610
1611impl<A> Default for Arena<'_, A> {
1612 fn default() -> Self {
1613 Self::new()
1614 }
1615}
1616
1617impl<'a, A> Arena<'a, A> {
1618 pub fn new() -> Self {
1619 Arena {
1620 docs: typed_arena::Arena::new(),
1621 column_fns: Default::default(),
1622 }
1623 }
1624
1625 fn alloc_any<T>(&'a self, f: T) -> &'a T
1626 where
1627 T: 'a,
1628 {
1629 let f = Box::new(f);
1630 let f_ptr = &*f as *const T;
1631 unsafe {
1640 self.column_fns
1641 .alloc(std::mem::transmute::<Box<dyn DropT>, Box<dyn DropT>>(f));
1642 &*f_ptr
1643 }
1644 }
1645}
1646
1647impl<'a, D, A> DocAllocator<'a, A> for &'a D
1648where
1649 D: ?Sized + DocAllocator<'a, A>,
1650 A: 'a,
1651{
1652 type Doc = D::Doc;
1653
1654 #[inline]
1655 fn alloc(&'a self, doc: Doc<'a, Self::Doc, A>) -> Self::Doc {
1656 (**self).alloc(doc)
1657 }
1658
1659 fn alloc_column_fn(
1660 &'a self,
1661 f: impl Fn(usize) -> Self::Doc + 'a,
1662 ) -> <Self::Doc as DocPtr<'a, A>>::ColumnFn {
1663 (**self).alloc_column_fn(f)
1664 }
1665
1666 fn alloc_width_fn(
1667 &'a self,
1668 f: impl Fn(isize) -> Self::Doc + 'a,
1669 ) -> <Self::Doc as DocPtr<'a, A>>::WidthFn {
1670 (**self).alloc_width_fn(f)
1671 }
1672}
1673
1674impl<'a, A> DocAllocator<'a, A> for Arena<'a, A> {
1675 type Doc = RefDoc<'a, A>;
1676
1677 #[inline]
1678 fn alloc(&'a self, doc: Doc<'a, Self::Doc, A>) -> Self::Doc {
1679 RefDoc(match doc {
1680 Doc::Nil => &Doc::Nil,
1682 Doc::Hardline => &Doc::Hardline,
1683 Doc::Fail => &Doc::Fail,
1684 Doc::FlatAlt(RefDoc(Doc::Hardline), RefDoc(Doc::BorrowedText(" "))) => {
1686 &Doc::FlatAlt(RefDoc(&Doc::Hardline), RefDoc(&Doc::BorrowedText(" ")))
1687 }
1688 Doc::FlatAlt(RefDoc(Doc::Hardline), RefDoc(Doc::Nil)) => {
1690 &Doc::FlatAlt(RefDoc(&Doc::Hardline), RefDoc(&Doc::Nil))
1691 }
1692 Doc::Group(RefDoc(Doc::FlatAlt(
1694 RefDoc(Doc::Hardline),
1695 RefDoc(Doc::BorrowedText(" ")),
1696 ))) => &Doc::Group(RefDoc(&Doc::FlatAlt(
1697 RefDoc(&Doc::Hardline),
1698 RefDoc(&Doc::BorrowedText(" ")),
1699 ))),
1700 Doc::Group(RefDoc(Doc::FlatAlt(RefDoc(Doc::Hardline), RefDoc(Doc::Nil)))) => {
1702 &Doc::Group(RefDoc(&Doc::FlatAlt(
1703 RefDoc(&Doc::Hardline),
1704 RefDoc(&Doc::Nil),
1705 )))
1706 }
1707 _ => self.docs.alloc(doc),
1708 })
1709 }
1710
1711 fn alloc_column_fn(
1712 &'a self,
1713 f: impl Fn(usize) -> Self::Doc + 'a,
1714 ) -> <Self::Doc as DocPtr<'a, A>>::ColumnFn {
1715 self.alloc_any(f)
1716 }
1717
1718 fn alloc_width_fn(
1719 &'a self,
1720 f: impl Fn(isize) -> Self::Doc + 'a,
1721 ) -> <Self::Doc as DocPtr<'a, A>>::WidthFn {
1722 self.alloc_any(f)
1723 }
1724}
1725
1726#[cfg(test)]
1727mod tests {
1728 use super::*;
1729
1730 macro_rules! chain {
1731 ($first: expr $(, $rest: expr)* $(,)?) => {{
1732 #[allow(unused_mut)]
1733 let mut doc = DocBuilder(&BoxAllocator, $first.into());
1734 $(
1735 doc = doc.append($rest);
1736 )*
1737 doc.into_doc()
1738 }}
1739 }
1740
1741 #[cfg(target_pointer_width = "64")]
1742 #[test]
1743 fn doc_size() {
1744 assert_eq!(8 * 3, std::mem::size_of::<Doc<RefDoc>>());
1746 }
1747
1748 macro_rules! test {
1749 ($size:expr, $actual:expr, $expected:expr) => {
1750 let mut s = String::new();
1751 $actual.render_fmt($size, &mut s).unwrap();
1752 difference::assert_diff!(&s, $expected, "\n", 0);
1753 };
1754 ($actual:expr, $expected:expr) => {
1755 test!(70, $actual, $expected)
1756 };
1757 }
1758
1759 #[test]
1760 fn box_doc_inference() {
1761 let doc: BoxDoc<()> = BoxDoc::group(
1762 BoxDoc::text("test")
1763 .append(BoxDoc::line())
1764 .append(BoxDoc::text("test")),
1765 );
1766
1767 test!(doc, "test test");
1768 }
1769
1770 #[test]
1771 fn newline_in_text() {
1772 let doc: BoxDoc<()> = BoxDoc::group(
1773 BoxDoc::text("test").append(
1774 BoxDoc::line()
1775 .append(BoxDoc::text("\"test\n test\""))
1776 .nest(4),
1777 ),
1778 );
1779
1780 test!(5, doc, "test\n \"test\n test\"");
1781 }
1782
1783 #[test]
1784 fn forced_newline() {
1785 let doc: BoxDoc<()> = BoxDoc::group(
1786 BoxDoc::text("test")
1787 .append(BoxDoc::hardline())
1788 .append(BoxDoc::text("test")),
1789 );
1790
1791 test!(doc, "test\ntest");
1792 }
1793
1794 #[test]
1795 fn space_do_not_reset_pos() {
1796 let doc: BoxDoc<()> = BoxDoc::group(BoxDoc::text("test").append(BoxDoc::line()))
1797 .append(BoxDoc::text("test"))
1798 .append(BoxDoc::group(BoxDoc::line()).append(BoxDoc::text("test")));
1799
1800 test!(9, doc, "test test\ntest");
1801 }
1802
1803 #[test]
1806 fn newline_does_not_cause_next_line_to_be_to_long() {
1807 let doc: RcDoc<()> = RcDoc::group(
1808 RcDoc::text("test").append(RcDoc::hardline()).append(
1809 RcDoc::text("test")
1810 .append(RcDoc::line())
1811 .append(RcDoc::text("test")),
1812 ),
1813 );
1814
1815 test!(6, doc, "test\ntest\ntest");
1816 }
1817
1818 #[test]
1819 fn newline_after_group_does_not_affect_it() {
1820 let arena = Arena::<()>::new();
1821 let doc = arena.text("x").append(arena.line()).append("y").group();
1822
1823 test!(100, doc.append(arena.hardline()).1, "x y\n");
1824 }
1825
1826 #[test]
1827 fn block() {
1828 let doc: RcDoc<()> = RcDoc::group(
1829 RcDoc::text("{")
1830 .append(
1831 RcDoc::line()
1832 .append(RcDoc::text("test"))
1833 .append(RcDoc::line())
1834 .append(RcDoc::text("test"))
1835 .nest(2),
1836 )
1837 .append(RcDoc::line())
1838 .append(RcDoc::text("}")),
1839 );
1840
1841 test!(5, doc, "{\n test\n test\n}");
1842 }
1843
1844 #[test]
1845 fn block_with_hardline() {
1846 let doc: RcDoc<()> = RcDoc::group(
1847 RcDoc::text("{")
1848 .append(
1849 RcDoc::line()
1850 .append(RcDoc::text("test"))
1851 .append(RcDoc::hardline())
1852 .append(RcDoc::text("test"))
1853 .nest(2),
1854 )
1855 .append(RcDoc::line())
1856 .append(RcDoc::text("}")),
1857 );
1858
1859 test!(10, doc, "{\n test\n test\n}");
1860 }
1861
1862 #[test]
1863 fn block_with_hardline_negative_nest() {
1864 let doc: RcDoc<()> = RcDoc::group(
1865 RcDoc::text("{")
1866 .append(
1867 RcDoc::line()
1868 .append(RcDoc::text("test"))
1869 .append(RcDoc::hardline())
1870 .append(RcDoc::text("test"))
1871 .nest(-2),
1872 )
1873 .append(RcDoc::line())
1874 .append(RcDoc::text("}")),
1875 );
1876
1877 test!(10, doc, "{\ntest\ntest\n}");
1878 }
1879
1880 #[test]
1881 fn line_comment() {
1882 let doc: BoxDoc<()> = BoxDoc::group(
1883 BoxDoc::text("{")
1884 .append(
1885 BoxDoc::line()
1886 .append(BoxDoc::text("test"))
1887 .append(BoxDoc::line())
1888 .append(BoxDoc::text("// a").append(BoxDoc::hardline()))
1889 .append(BoxDoc::text("test"))
1890 .nest(2),
1891 )
1892 .append(BoxDoc::line())
1893 .append(BoxDoc::text("}")),
1894 );
1895
1896 test!(14, doc, "{\n test\n // a\n test\n}");
1897 }
1898
1899 #[test]
1900 fn annotation_no_panic() {
1901 let doc: BoxDoc<()> = BoxDoc::group(
1902 BoxDoc::text("test")
1903 .annotate(())
1904 .append(BoxDoc::hardline())
1905 .annotate(())
1906 .append(BoxDoc::text("test")),
1907 );
1908
1909 test!(doc, "test\ntest");
1910 }
1911
1912 fn nest_on_line(doc: BoxDoc<'static, ()>) -> BoxDoc<'static, ()> {
1913 BoxDoc::softline().append(BoxDoc::nesting(move |n| {
1914 let doc = doc.clone();
1915 BoxDoc::column(move |c| {
1916 if n == c {
1917 BoxDoc::text(" ").append(doc.clone()).nest(2)
1918 } else {
1919 doc.clone()
1920 }
1921 })
1922 }))
1923 }
1924
1925 #[test]
1926 fn hang_lambda1() {
1927 let doc = chain![
1928 chain!["let", BoxDoc::line(), "x", BoxDoc::line(), "="].group(),
1929 nest_on_line(chain![
1930 "\\y ->",
1931 chain![BoxDoc::line(), "y"].nest(2).group()
1932 ]),
1933 ]
1934 .group();
1935
1936 test!(doc, "let x = \\y -> y");
1937 test!(
1938 8,
1939 doc,
1940 r"let x =
1941 \y ->
1942 y"
1943 );
1944 test!(
1945 14,
1946 doc,
1947 r"let x = \y ->
1948 y"
1949 );
1950 }
1951
1952 #[test]
1953 fn hang_comment() {
1954 let body = chain!["y"].nest(2).group();
1955 let doc = chain![
1956 chain!["let", BoxDoc::line(), "x", BoxDoc::line(), "="].group(),
1957 nest_on_line(chain![
1958 "\\y ->",
1959 nest_on_line(chain!["// abc", BoxDoc::hardline(), body])
1960 ]),
1961 ]
1962 .group();
1963
1964 test!(8, doc, "let x =\n \\y ->\n // abc\n y");
1965 test!(14, doc, "let x = \\y ->\n // abc\n y");
1966 }
1967
1968 #[test]
1969 fn union() {
1970 let doc = chain![
1971 chain!["let", BoxDoc::line(), "x", BoxDoc::line(), "="].group(),
1972 nest_on_line(chain![
1973 "(",
1974 chain![
1975 BoxDoc::line_(),
1976 chain!["x", ","].group(),
1977 BoxDoc::line(),
1978 chain!["1234567890", ","].group()
1979 ]
1980 .nest(2)
1981 .group(),
1982 BoxDoc::line_().append(")"),
1983 ])
1984 ]
1985 .group();
1986
1987 test!(doc, "let x = (x, 1234567890,)");
1988 test!(8, doc, "let x =\n (\n x,\n 1234567890,\n )");
1989 test!(14, doc, "let x = (\n x,\n 1234567890,\n)");
1990 }
1991
1992 fn hang2(
1993 from: BoxDoc<'static, ()>,
1994 body_whitespace: BoxDoc<'static, ()>,
1995 body: BoxDoc<'static, ()>,
1996 trailer: BoxDoc<'static, ()>,
1997 ) -> BoxDoc<'static, ()> {
1998 let body1 = body_whitespace
1999 .append(body.clone())
2000 .nest(2)
2001 .group()
2002 .append(trailer.clone());
2003 let body2 = BoxDoc::hardline()
2004 .append(body.clone())
2005 .nest(2)
2006 .group()
2007 .append(trailer.clone());
2008
2009 let single = from.clone().append(body1.clone()).group();
2010
2011 let hang = from.clone().append(body2).group();
2012
2013 let break_all = from.append(body1).group().nest(2);
2014
2015 BoxDoc::group(single.union(hang.union(break_all)))
2016 }
2017
2018 #[test]
2019 fn hang_lambda2() {
2020 let from = chain![
2021 chain!["let", BoxDoc::line(), "x", BoxDoc::line(), "="].group(),
2022 BoxDoc::line(),
2023 "\\y ->",
2024 ]
2025 .group();
2026
2027 let body = chain!["y"].group();
2028
2029 let trailer = BoxDoc::nil();
2030
2031 let doc = hang2(from, BoxDoc::line(), body, trailer);
2032 eprintln!("{:#?}", doc);
2033
2034 test!(doc, "let x = \\y -> y");
2035 test!(14, doc, "let x = \\y ->\n y");
2036 }
2037
2038 #[test]
2039 fn union2() {
2040 let from = chain![
2041 chain!["let", BoxDoc::line(), "x", BoxDoc::line(), "="].group(),
2042 BoxDoc::line(),
2043 "(",
2044 ]
2045 .group();
2046
2047 let body = chain![
2048 chain!["x", ","].group(),
2049 BoxDoc::line(),
2050 chain!["1234567890", ","].group()
2051 ]
2052 .group();
2053
2054 let trailer = BoxDoc::line_().append(")");
2055
2056 let doc = hang2(from, BoxDoc::line_(), body, trailer);
2057
2058 test!(doc, "let x = (x, 1234567890,)");
2059 test!(14, doc, "let x = (\n x,\n 1234567890,\n)");
2060 }
2061
2062 #[test]
2063 fn usize_max_value() {
2064 let doc: BoxDoc<()> = BoxDoc::group(
2065 BoxDoc::text("test")
2066 .append(BoxDoc::line())
2067 .append(BoxDoc::text("test")),
2068 );
2069
2070 test!(usize::max_value(), doc, "test test");
2071 }
2072
2073 #[test]
2074 fn fail() {
2075 let fail_break: BoxDoc<()> = BoxDoc::fail().flat_alt(Doc::nil());
2076
2077 let doc = fail_break.append(Doc::text("12345")).group().union("abc");
2078
2079 test!(5, doc, "12345");
2080 test!(4, doc, "abc");
2081 }
2082
2083 pub struct TestWriter<W> {
2084 upstream: W,
2085 }
2086
2087 impl<W> TestWriter<W> {
2088 pub fn new(upstream: W) -> Self {
2089 Self { upstream }
2090 }
2091 }
2092
2093 impl<W> Render for TestWriter<W>
2094 where
2095 W: Render,
2096 {
2097 type Error = W::Error;
2098
2099 fn write_str(&mut self, s: &str) -> Result<usize, W::Error> {
2100 self.upstream.write_str(s)
2101 }
2102
2103 fn write_str_all(&mut self, s: &str) -> Result<(), W::Error> {
2104 self.upstream.write_str_all(s)
2105 }
2106
2107 fn fail_doc(&self) -> Self::Error {
2108 self.upstream.fail_doc()
2109 }
2110 }
2111
2112 impl<W> RenderAnnotated<'_, ()> for TestWriter<W>
2113 where
2114 W: Render,
2115 {
2116 fn push_annotation(&mut self, _: &()) -> Result<(), Self::Error> {
2117 self.upstream.write_str_all("[")
2118 }
2119
2120 fn pop_annotation(&mut self) -> Result<(), Self::Error> {
2121 self.upstream.write_str_all("]")
2122 }
2123 }
2124
2125 #[test]
2126 fn annotations() {
2127 let actual = BoxDoc::text("abc").annotate(()).annotate(());
2128 let mut s = String::new();
2129 actual
2130 .render_raw(70, &mut TestWriter::new(FmtWrite::new(&mut s)))
2131 .unwrap();
2132 difference::assert_diff!(&s, "[[abc]]", "\n", 0);
2133 }
2134
2135 #[test]
2136 fn non_ascii_is_not_byte_length() {
2137 let doc: BoxDoc<()> = BoxDoc::group(
2138 BoxDoc::text("ÅÄÖ")
2139 .append(BoxDoc::line())
2140 .append(BoxDoc::text("test")),
2141 );
2142
2143 test!(8, doc, "ÅÄÖ test");
2144 }
2145
2146 #[test]
2147 fn cjk_display_width() {
2148 let arena = Arena::<()>::new();
2149 let doc = arena
2150 .text("你好")
2151 .append(arena.line().append(arena.text("abc")).align())
2152 .into_doc();
2153
2154 test!(doc, "你好\n abc");
2155 }
2156
2157 #[test]
2158 fn pretty_cow() {
2159 let doc: BoxDoc<()> = docs![
2160 &BoxAllocator,
2161 Cow::<str>::Borrowed("abc"),
2162 BoxDoc::line(),
2163 Cow::<str>::Owned("123".to_string()),
2164 ]
2165 .group()
2166 .into_doc();
2167
2168 test!(8, doc, "abc 123");
2169 }
2170
2171 #[test]
2172 fn stress_append_left_assoc() {
2173 let arena = Arena::new();
2174 let mut doc: DocBuilder<'_, Arena<'_, _>, char> = arena.nil();
2175 for _ in 0..100000 {
2176 doc = doc.append("a");
2177 }
2178 let mut s = String::new();
2179 doc.render_fmt(80, &mut s).unwrap();
2180 }
2181
2182 #[test]
2183 fn stress_append_right_assoc() {
2184 let arena = Arena::new();
2185 let mut doc: RefDoc<'_, char> = arena.nil().into_doc();
2186 for _ in 0..100000 {
2187 doc = arena.text("a").append(doc).into_doc();
2188 }
2189 let mut s = String::new();
2190 doc.render_fmt(80, &mut s).unwrap();
2191 }
2192}