1use std::fmt;
2
3use super::Value;
4use crate::value::Arg;
5use pretty::{BoxDoc, Doc};
6
7pub struct PrintOptions {
8 pub indent: usize,
9 pub columns: usize,
10}
11
12impl Default for PrintOptions {
13 fn default() -> Self {
14 PrintOptions {
15 indent: 4,
16 columns: 80,
17 }
18 }
19}
20
21impl<'value> Value<'value> {
22 fn seq_to_doc<'iter, I>(
23 open: &'static str,
24 xs: I,
25 close: &'static str,
26 options: &PrintOptions,
27 ) -> Doc<'value, BoxDoc<'value, ()>>
28 where
29 I: Iterator<Item = Doc<'value, BoxDoc<'value, ()>>>,
30 'value: 'iter,
31 {
32 Doc::text(open)
33 .append(Doc::newline().flat_alt(Doc::nil()))
34 .nest(options.indent)
35 .append(Doc::intersperse(xs, Doc::text(",").append(Doc::space())).nest(options.indent))
36 .append(Doc::newline().flat_alt(Doc::nil()))
37 .append(Doc::text(close))
38 .group()
39 }
40
41 fn dictionary_to_doc<'tmp>(
42 pairs: &'tmp [(Value<'value>, Value<'value>)],
43 options: &PrintOptions,
44 ) -> Doc<'value, BoxDoc<'value, ()>>
45 where
46 'value: 'tmp,
47 {
48 Self::seq_to_doc(
49 "{",
50 pairs.iter().map(|(key, value)| {
51 key.to_doc(options)
52 .append(Doc::text(": "))
53 .append(value.to_doc(options))
54 }),
55 "}",
56 options,
57 )
58 .group()
59 }
60
61 fn constructor_to_doc<'tmp>(
62 name: &'value str,
63 args: &'tmp [Arg<'value>],
64 options: &PrintOptions,
65 ) -> Doc<'value, BoxDoc<'value, ()>>
66 where
67 'value: 'tmp,
68 {
69 Doc::text(name)
70 .append(Self::seq_to_doc(
71 "(",
72 args.iter().map(|arg| match arg {
73 Arg::Arg(value) => value.to_doc(options),
74 Arg::Kwarg(key, value) => Doc::text(*key)
75 .append(Doc::text("="))
76 .append(value.to_doc(options)),
77 }),
78 ")",
79 options,
80 ))
81 .group()
82 }
83}
84
85impl<'value> Value<'value> {
86 pub fn to_doc(&self, options: &PrintOptions) -> Doc<'value, BoxDoc<'value, ()>> {
87 match *self {
88 Value::Int(x) => Doc::text(x.to_string()),
89 Value::Float(x) => Doc::text(x.to_string()),
90 Value::Bool(x) => Doc::text(if x { "True" } else { "False" }),
91 Value::Symbol(x) => Doc::text(x),
92 Value::Str(x) => Doc::text(x),
93 Value::List(ref xs) => {
94 Self::seq_to_doc("[", xs.iter().map(|x| x.to_doc(options)), "]", options)
95 }
96 Value::Tuple(ref xs) => {
97 Self::seq_to_doc("(", xs.iter().map(|x| x.to_doc(options)), ")", options)
98 }
99 Value::Set(ref xs) => {
100 Self::seq_to_doc("{", xs.iter().map(|x| x.to_doc(options)), "}", options)
101 }
102 Value::Dict(ref pairs) => Self::dictionary_to_doc(pairs, options),
103 Value::Constructor(name, ref args) => Self::constructor_to_doc(name, args, options),
104 }
105 }
106}
107
108impl<'a> fmt::Display for Value<'a> {
109 fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
110 let options = PrintOptions::default();
111 self.to_doc(&options).render_fmt(options.columns, f)
112 }
113}