#![cfg(not(feature = "codegen-rustfmt"))]
use proc_macro2::{Delimiter, Spacing, TokenStream, TokenTree};
pub(crate) fn format_tokens(tokens: TokenStream) -> String {
let mut out = String::new();
format(FormatState::Start, 0, tokens.into_iter(), &mut out);
out
}
fn indent(n: usize) -> &'static str {
let idents = " ";
let end = n * 4;
&idents[0..end]
}
#[derive(Copy, Clone, Eq, PartialEq)]
enum FormatState {
Start,
NothingSpecial,
PrevJoinedOperator,
PrevDoubleColon,
PrevIdentifier,
PrevClosingBrace,
PrevHash,
}
fn format(
mut state: FormatState,
level: usize,
tts: proc_macro2::token_stream::IntoIter,
s: &mut String,
) {
for tt in tts {
format_one(&mut state, level, tt, s);
}
}
fn format_one(state: &mut FormatState, level: usize, tt: TokenTree, s: &mut String) {
match tt {
TokenTree::Punct(punct) => {
let c = punct.as_char();
match state {
FormatState::Start => {}
FormatState::NothingSpecial => {
if c == ';' || c == ',' {
} else {
s.push(' ');
}
}
FormatState::PrevJoinedOperator => {
}
FormatState::PrevDoubleColon => {}
FormatState::PrevIdentifier => {
if ['.', ';', ',', ':'].contains(&c) {
} else {
s.push(' ');
}
}
FormatState::PrevClosingBrace => {
if c == ';' || c == ',' {
} else {
s.push('\n');
s.push_str(indent(level));
}
}
FormatState::PrevHash => {
}
}
s.push(c);
match (c, *state) {
(';', _) => {
s.push('\n');
s.push_str(indent(level));
*state = FormatState::Start;
}
('#', _) => {
*state = FormatState::PrevHash;
}
('$', _) => {
*state = FormatState::PrevJoinedOperator;
}
('&', FormatState::PrevJoinedOperator) => {
*state = FormatState::NothingSpecial;
}
('&', _) => {
*state = FormatState::PrevJoinedOperator;
}
('!', FormatState::PrevHash) => {
*state = FormatState::PrevHash;
}
('!', FormatState::PrevJoinedOperator) => {
*state = FormatState::NothingSpecial;
}
('!', _) => {
*state = FormatState::PrevJoinedOperator;
}
(':', FormatState::PrevJoinedOperator) => {
*state = FormatState::PrevDoubleColon;
}
('.', FormatState::PrevIdentifier) => {
*state = FormatState::PrevJoinedOperator;
}
(_, FormatState::Start)
| (_, FormatState::NothingSpecial)
| (_, FormatState::PrevJoinedOperator)
| (_, FormatState::PrevDoubleColon)
| (_, FormatState::PrevIdentifier) => {
if punct.spacing() == Spacing::Joint {
*state = FormatState::PrevJoinedOperator;
} else {
*state = FormatState::NothingSpecial;
}
}
(c, FormatState::PrevClosingBrace) if c == ';' || c == ',' => {
s.push('\n');
s.push_str(indent(level));
*state = FormatState::Start;
}
(_, FormatState::PrevClosingBrace) => {
*state = FormatState::NothingSpecial;
}
(_, FormatState::PrevHash) => {
*state = FormatState::PrevJoinedOperator
}
}
}
TokenTree::Ident(ident) => {
match state {
FormatState::NothingSpecial => {
s.push(' ');
}
FormatState::PrevClosingBrace => {
s.push('\n');
s.push_str(indent(level));
}
FormatState::PrevDoubleColon => {}
FormatState::PrevIdentifier => {
s.push(' ');
}
FormatState::PrevJoinedOperator => {
}
FormatState::Start => {}
FormatState::PrevHash => {
}
}
s.push_str(&ident.to_string());
*state = FormatState::PrevIdentifier;
}
TokenTree::Literal(lit) => {
match state {
FormatState::Start => {}
FormatState::NothingSpecial => {
s.push(' ');
}
FormatState::PrevJoinedOperator => {
}
FormatState::PrevDoubleColon => {
}
FormatState::PrevIdentifier => {
s.push(' ');
}
FormatState::PrevClosingBrace => {
s.push('\n');
s.push_str(indent(level));
}
FormatState::PrevHash => {
}
}
s.push_str(&lit.to_string());
*state = FormatState::NothingSpecial;
}
TokenTree::Group(group) => {
match state {
FormatState::Start => {}
FormatState::NothingSpecial => s.push(' '),
FormatState::PrevJoinedOperator => {
}
FormatState::PrevDoubleColon => {
}
FormatState::PrevIdentifier => {
if group.delimiter() == Delimiter::Brace || group.delimiter() == Delimiter::None
{
s.push(' ');
}
}
FormatState::PrevClosingBrace => {
s.push('\n');
s.push_str(indent(level));
}
FormatState::PrevHash => {
}
}
match group.delimiter() {
Delimiter::Brace => {
s.push_str("{\n");
s.push_str(indent(level + 1));
format(FormatState::Start, level + 1, group.stream().into_iter(), s);
s.push('\n');
s.push_str(indent(level));
s.push('}');
*state = FormatState::PrevClosingBrace;
}
Delimiter::Bracket => {
s.push('[');
format(FormatState::Start, level, group.stream().into_iter(), s);
s.push(']');
if *state == FormatState::PrevHash {
s.push('\n');
s.push_str(indent(level));
*state = FormatState::Start;
} else {
*state = FormatState::NothingSpecial;
}
}
Delimiter::Parenthesis => {
s.push('(');
format(FormatState::Start, level, group.stream().into_iter(), s);
s.push(')');
*state = FormatState::NothingSpecial;
}
Delimiter::None => {
format(FormatState::Start, level, group.stream().into_iter(), s);
*state = FormatState::NothingSpecial;
}
}
}
}
}