proc_macro_faithful_display/
lib.rs1#![feature(proc_macro_span)]
2
3extern crate proc_macro;
28
29use proc_macro::{Delimiter, Group, Ident, Literal, Punct, Span, TokenStream, TokenTree};
30use std::fmt::{self, Display, Write};
31use std::iter::FromIterator;
32
33pub trait FaithfulDisplay {
39 fn faithful_fmt(&self, f: &mut fmt::Formatter, prev_span: Span) -> Result<Span, fmt::Error>;
41}
42
43impl FaithfulDisplay for Ident {
44 fn faithful_fmt(&self, f: &mut fmt::Formatter, prev_span: Span) -> Result<Span, fmt::Error> {
45 let current_span = self.span();
46 whitespace_adjust_span(f, prev_span, current_span.start())?;
47
48 self.fmt(f).map(|_| current_span.end())
49 }
50}
51
52impl FaithfulDisplay for Literal {
53 fn faithful_fmt(&self, f: &mut fmt::Formatter, prev_span: Span) -> Result<Span, fmt::Error> {
54 let current_span = self.span();
55 whitespace_adjust_span(f, prev_span, current_span.start())?;
56
57 self.fmt(f).map(|_| current_span.end())
58 }
59}
60
61impl FaithfulDisplay for Punct {
62 fn faithful_fmt(&self, f: &mut fmt::Formatter, prev_span: Span) -> Result<Span, fmt::Error> {
63 let current_span = self.span();
64 whitespace_adjust_span(f, prev_span, current_span.start())?;
65
66 f.write_char(self.as_char()).map(|_| current_span.end())
67 }
68}
69
70impl FaithfulDisplay for Group {
71 fn faithful_fmt(&self, f: &mut fmt::Formatter, prev_span: Span) -> Result<Span, fmt::Error> {
72 let current_span = self.span_open();
73 whitespace_adjust_span(f, prev_span, current_span.start())?;
74
75 match self.delimiter() {
76 Delimiter::Parenthesis => {
77 faithful_delimited(
78 f,
79 '(',
80 ')',
81 self.stream(),
82 current_span.end(),
83 self.span_close().start(),
84 )?;
85 }
86
87 Delimiter::Brace => {
88 faithful_delimited(
89 f,
90 '{',
91 '}',
92 self.stream(),
93 current_span.end(),
94 self.span_close().start(),
95 )?;
96 }
97
98 Delimiter::Bracket => {
99 faithful_delimited(
100 f,
101 '[',
102 ']',
103 self.stream(),
104 current_span.end(),
105 self.span_close().start(),
106 )?;
107 }
108
109 Delimiter::None => {
110 let line_col = self.stream().faithful_fmt(f, current_span.end())?;
111 whitespace_adjust_span(f, prev_span, line_col)?;
112 }
113 }
114
115 Ok(self.span_close().end())
116 }
117}
118
119impl FaithfulDisplay for TokenStream {
120 fn faithful_fmt(&self, f: &mut fmt::Formatter, prev_span: Span) -> Result<Span, fmt::Error> {
121 let mut current_span = prev_span;
122
123 for tree in self.clone() {
124 current_span = tree.faithful_fmt(f, current_span)?;
125 }
126
127 Ok(current_span)
128 }
129}
130
131impl FaithfulDisplay for TokenTree {
132 fn faithful_fmt(&self, f: &mut fmt::Formatter, prev_span: Span) -> Result<Span, fmt::Error> {
133 match self {
134 TokenTree::Group(gr) => gr.faithful_fmt(f, prev_span),
135 TokenTree::Ident(ident) => ident.faithful_fmt(f, prev_span),
136 TokenTree::Punct(p) => p.faithful_fmt(f, prev_span),
137 TokenTree::Literal(lit) => lit.faithful_fmt(f, prev_span),
138 }
139 }
140}
141
142pub fn faithful_display(stream: &TokenStream) -> impl Display + '_ {
149 struct D<'a>(&'a TokenStream);
150
151 impl<'a> fmt::Display for D<'a> {
152 fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
153 let mut iter = self.0.clone().into_iter();
155 let first = iter.next();
156
157 if let Some(tree) = first {
158 let first_line_col = tree.span().start();
159 let line_col = tree.faithful_fmt(f, first_line_col)?;
160
161 TokenStream::from_iter(iter)
162 .faithful_fmt(f, line_col)
163 .map(|_| ())
164 } else {
165 Ok(())
166 }
167 }
168 }
169
170 D(stream)
171}
172
173fn whitespace_adjust_span(
179 f: &mut fmt::Formatter,
180 prev_span: Span,
181 current_span: Span,
182) -> Result<(), fmt::Error> {
183 if current_span.line() == prev_span.line() {
184 let nb_spaces = current_span.column() - prev_span.column();
186 f.write_str(" ".repeat(nb_spaces).as_str())
187 } else {
188 let nb_newlines = current_span.line() - prev_span.line();
190 let nb_spaces = current_span.column();
191 f.write_str("\n".repeat(nb_newlines).as_str())?;
192 f.write_str(" ".repeat(nb_spaces).as_str())
193 }
194}
195
196fn faithful_delimited(
198 f: &mut fmt::Formatter,
199 del_first: char,
200 del_end: char,
201 stream: TokenStream,
202 prev_span: Span,
203 final_span: Span,
204) -> Result<(), fmt::Error> {
205 f.write_char(del_first)?;
206
207 let current_span = stream.faithful_fmt(f, prev_span)?;
208
209 whitespace_adjust_span(f, current_span, final_span)?;
210 f.write_char(del_end)
211}